diff --git a/LR35902/inc/Audio.h b/LR35902/inc/Audio.h deleted file mode 100644 index 04b6067..0000000 --- a/LR35902/inc/Audio.h +++ /dev/null @@ -1,388 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "AudioFrame.h" - -namespace EightBit { - namespace GameBoy { - - class Envelope final { - public: - Envelope(); - - enum Direction { Attenuate, Amplify }; - - void reset(); - bool zeroed() const; - - int volume() const; - void setVolume(int value); - - Direction direction() const; - void setDirection(int value); - void setDirection(Direction value); - - int period() const; - void setPeriod(int value); - - void step(); - - private: - int m_volume; - int m_direction; - int m_period; - - int m_position; - }; - - class Sweep final { - public: - Sweep(); - - enum Direction { Addition, Subtraction }; - - void reset(); - bool zeroed() const; - - int time() const; - void setTime(int value); - - Direction direction() const; - void setDirection(int value); - void setDirection(Direction value); - - int shift() const; - void setShift(int value); - - private: - int m_time; - int m_direction; - int m_shift; - }; - - class AudioVoice { - public: - AudioVoice(); - - virtual void reset(); - virtual bool zeroed() const; - - enum Type { Continuous, Counter }; - - Type type() const; - void setType(int value); - void setType(Type value); - - bool initialise() const; - void setInitialise(bool value); - - private: - int m_counterContinuous; - int m_initialise; - }; - - class WaveVoice : public AudioVoice { - public: - WaveVoice(int cyclesPerSecond); - - virtual void reset() override; - virtual bool zeroed() const override; - - int frequencyLowOrder() const; - void setFrequencyLowOrder(int value); - int frequencyHighOrder() const; - void setFrequencyHighOrder(int value); - - int frequency() const; - void setFrequency(int value); - - int hertz() const; - - private: - const int m_cyclesPerSecond; - int m_frequencyLowOrder; // 8 bits - int m_frequencyHighOrder; // 3 bits - }; - - class RectangularVoice : public WaveVoice { - public: - RectangularVoice(int cyclesPerSecond); - - virtual void reset() override; - virtual bool zeroed() const override; - - int waveFormDutyCycle() const; - void setWaveFormDutyCycle(int value); - - int length() const; - void setLength(int value); - - private: - int m_waveFormDutyCycle; - int m_soundLength; - }; - - // NR2X - class EnvelopedRectangularVoice : public RectangularVoice { - public: - EnvelopedRectangularVoice(int cyclesPerSecond); - - virtual void reset() override; - virtual bool zeroed() const override; - - Envelope& envelope(); - - private: - Envelope m_envelope; - }; - - // NR1X - class SweptEnvelopedRectangularVoice : public EnvelopedRectangularVoice { - public: - SweptEnvelopedRectangularVoice(int cyclesPerSecond); - - virtual void reset() override; - virtual bool zeroed() const override; - - Sweep& sweep(); - - private: - Sweep m_sweep; - }; - - // NR3X - class UserDefinedWaveVoice : public WaveVoice { - public: - UserDefinedWaveVoice(int cyclesPerSecond); - - virtual void reset() override; - virtual bool zeroed() const override; - - bool enabled() const; - void setEnabled(bool value); - - int length() const; - void setLength(int value); - - int level() const; - void setLevel(int value); - - int packedWaveDatum(int i) const; - void setPackedWaveDatum(int i, uint8_t value); - int waveDatum(int i) const; - - private: - int m_enabled; - int m_soundLength; - int m_outputLevel; - std::array m_waveData; - }; - - // NR4X - class WhiteNoiseWaveVoice : public AudioVoice { - public: - WhiteNoiseWaveVoice(); - - virtual void reset() override; - virtual bool zeroed() const override; - - Envelope& envelope(); - - int length() const; - void setLength(int value); - - int polynomialShiftClockFrequency() const; - void setPolynomialShiftClockFrequency(int value); - - int polynomialCounterSteps() const; - void setPolynomialCounterSteps(int value); - - int frequencyDivisionRatio() const; - void setFrequencyDivisionRatio(int value); - - private: - Envelope m_envelope; - int m_soundLength; - int m_polynomialShiftClockFrequency; - int m_polynomialCounterSteps; - int m_frequencyDivisionRatio; - }; - - class OutputChannel final { - public: - OutputChannel(); - - void reset(); - bool zeroed() const; - - bool vin() const; - void setVin(bool value); - - int outputLevel() const; - void setOutputLevel(int value); - - bool& outputVoice(int voice); - bool& outputVoice1(); - bool& outputVoice2(); - bool& outputVoice3(); - bool& outputVoice4(); - - private: - bool m_vin; - int m_outputLevel; - std::array m_outputVoices; - }; - - class Audio final { - public: - Audio(int cyclesPerSecond); - - std::shared_ptr voice(int i); - SweptEnvelopedRectangularVoice* voice1(); - EnvelopedRectangularVoice* voice2(); - UserDefinedWaveVoice* voice3(); - WhiteNoiseWaveVoice* voice4(); - - OutputChannel& channel(int i); - OutputChannel& channel1(); - OutputChannel& channel2(); - - bool enabled() const; - void setEnabled(bool value); - - void reset(); - bool zeroed() const; - - // - - bool voice1On() const; - bool voice2On() const; - bool voice3On() const; - bool voice4On() const; - - // - - uint8_t toNRx1(int i); - void fromNRx1(int i, uint8_t value); - - uint8_t toNRx2(int i); - void fromNRx2(int i, uint8_t value); - - uint8_t toNRx3(int i); - void fromNRx3(int i, uint8_t value); - - // Sound mode 1 register: Sweep - uint8_t toNR10(); - void fromNR10(uint8_t value); - - // Sound mode 1 register: Sound length / Wave pattern duty - uint8_t toNR11(); - void fromNR11(uint8_t value); - - // Sound mode 1 register: Envelope - uint8_t toNR12(); - void fromNR12(uint8_t value); - - // Sound mode 1 register: Frequency lo - uint8_t toNR13(); - void fromNR13(uint8_t value); - - // Sound mode 1 register: Frequency hi - uint8_t toNR14(); - void fromNR14(uint8_t value); - - // Sound mode 2 register: Sound length / Wave pattern duty - uint8_t toNR21(); - void fromNR21(uint8_t value); - - // Sound mode 2 register: Envelope - uint8_t toNR22(); - void fromNR22(uint8_t value); - - // Sound mode 2 register: Frequency lo - uint8_t toNR23(); - void fromNR23(uint8_t value); - - // Sound mode 2 register: Frequency hi - uint8_t toNR24(); - void fromNR24(uint8_t value); - - // Sound mode 3 register: Sound on/off - uint8_t toNR30(); - void fromNR30(uint8_t value); - - // Sound mode 3 register: Sound length - uint8_t toNR31(); - void fromNR31(uint8_t value); - - // Sound mode 3 register: Select output level - uint8_t toNR32(); - void fromNR32(uint8_t value); - - // Sound mode 3 register: Frequency lo - uint8_t toNR33(); - void fromNR33(uint8_t value); - - // Sound mode 3 register: Frequency hi - uint8_t toNR34(); - void fromNR34(uint8_t value); - - // Sound mode 4 register: Sound length - uint8_t toNR41(); - void fromNR41(uint8_t value); - - // Sound mode 4 register: Envelope - uint8_t toNR42(); - void fromNR42(uint8_t value); - - // Sound mode 4 register: Polynomial counter - uint8_t toNR43(); - void fromNR43(uint8_t value); - - // Sound mode 4 register: counter/consecutive; inital - uint8_t toNR44(); - void fromNR44(uint8_t value); - - // Channel control: on-off/volume - uint8_t toNR50(); - void fromNR50(uint8_t value); - - // Selection of Sound output terminal - uint8_t toNR51(); - void fromNR51(uint8_t value); - - // Sound on/off - uint8_t toNR52(); - void fromNR52(uint8_t value); - - void setPackedWaveDatum(int i, uint8_t value); - uint8_t packedWaveDatum(int i); - - void stepFrame(int cycles); - - void Sequencer_FrameStep(int step); - void Sequencer_LengthStep(int step); - void Sequencer_VolumeStep(int step); - void Sequencer_SweepStep(int step); - - private: - AudioFrame m_frameSequencer; - - std::array, 4> m_voices; - std::array m_channels; - bool m_enabled; - - template - static void stepLength(T* voice) { - if (voice->length() > 0) { - auto current = voice->length(); - voice->setLength(--current); - } - } - }; - } -} \ No newline at end of file diff --git a/LR35902/inc/AudioFrame.h b/LR35902/inc/AudioFrame.h deleted file mode 100644 index eed15ae..0000000 --- a/LR35902/inc/AudioFrame.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include - -namespace EightBit { - namespace GameBoy { - class AudioFrame final { - private: - enum { StepCycle = 7, Frequency = 512 }; - - int m_cyclesPerTick; - int m_currentStep; - int m_currentCycles; - - public: - AudioFrame(int cyclesPerSecond) - : m_cyclesPerTick(cyclesPerSecond / Frequency), - m_currentStep(0), - m_currentCycles(m_cyclesPerTick) { - } - - Signal FrameStep; - Signal LengthStep; - Signal VolumeStep; - Signal SweepStep; - - void step() { - m_currentStep = (m_currentStep + 1) % StepCycle; - FrameStep.fire(m_currentStep); - if ((m_currentStep % 2) == 0) - LengthStep.fire(m_currentStep); - if (m_currentStep == 7) - VolumeStep.fire(m_currentStep); - if ((m_currentStep == 2) || (m_currentStep == 6)) - SweepStep.fire(m_currentStep); - } - - void step(int cycles) { - m_currentCycles -= cycles; - if (m_currentCycles < 0) { - step(); - m_currentCycles += m_cyclesPerTick; - } - } - }; - } -} diff --git a/LR35902/inc/GameBoyBus.h b/LR35902/inc/GameBoyBus.h index b1781af..8af9fd3 100644 --- a/LR35902/inc/GameBoyBus.h +++ b/LR35902/inc/GameBoyBus.h @@ -9,8 +9,6 @@ #include #include -#include "Audio.h" - namespace EightBit { namespace GameBoy { class Bus : public EightBit::Bus { @@ -124,8 +122,6 @@ namespace EightBit { Bus(); - Audio& audio() { return m_audio; } - void reset(); void triggerInterrupt(int cause) { @@ -321,8 +317,6 @@ namespace EightBit { bool m_p11; // left/b bool m_p10; // right/a - Audio m_audio; - void checkTimer(int cycles); void validateCartridgeType(); diff --git a/LR35902/inc/LR35902.h b/LR35902/inc/LR35902.h index fbce5b4..78a7774 100644 --- a/LR35902/inc/LR35902.h +++ b/LR35902/inc/LR35902.h @@ -22,6 +22,11 @@ namespace EightBit { LR35902(Bus& memory); Signal ExecutingInstruction; + Signal ExecutedInstruction; + + int clockCycles() const { + return cycles * 4; + } virtual register16_t& AF() override { af.low &= 0xf0; diff --git a/LR35902/src/Audio.cpp b/LR35902/src/Audio.cpp deleted file mode 100644 index 582b3da..0000000 --- a/LR35902/src/Audio.cpp +++ /dev/null @@ -1,800 +0,0 @@ -#include "stdafx.h" -#include "Audio.h" - -// - -EightBit::GameBoy::Envelope::Envelope() {} - -void EightBit::GameBoy::Envelope::reset() { - m_position = m_volume = m_direction = m_period = 0; -} - -bool EightBit::GameBoy::Envelope::zeroed() const { - return (volume() == 0) && (period() == 0) && (direction() == Attenuate); -} - -int EightBit::GameBoy::Envelope::volume() const { - return m_volume; -} - -void EightBit::GameBoy::Envelope::setVolume(int value) { - m_volume = value; -} - -EightBit::GameBoy::Envelope::Direction EightBit::GameBoy::Envelope::direction() const { - return (Direction)m_direction; -} - -void EightBit::GameBoy::Envelope::setDirection(int value) { - m_direction = value; -} - -void EightBit::GameBoy::Envelope::setDirection(Direction value) { - setDirection((int)value); -} - -int EightBit::GameBoy::Envelope::period() const { - return m_period; -} - -void EightBit::GameBoy::Envelope::setPeriod(int value) { - m_position = m_period = value; -} - -void EightBit::GameBoy::Envelope::step() { - if (m_period != 0) { - if (--m_position == 0) { - auto volume = m_volume + (m_direction == Amplify ? +1 : -1); - if (volume >= 0 && volume <= 15) - m_volume = volume; - m_position = m_period; - } - } -} - -// - -EightBit::GameBoy::Sweep::Sweep() {} - -void EightBit::GameBoy::Sweep::reset() { - m_time = m_direction = m_shift = 0; -} - -bool EightBit::GameBoy::Sweep::zeroed() const { - return (time() == 0) && (shift() == 0) && (direction() == Addition); -} - -int EightBit::GameBoy::Sweep::time() const { - return m_time; -} - -void EightBit::GameBoy::Sweep::setTime(int value) { - m_time = value; -} - -EightBit::GameBoy::Sweep::Direction EightBit::GameBoy::Sweep::direction() const { - return (Direction)m_direction; -} - -void EightBit::GameBoy::Sweep::setDirection(int value) { - m_direction = value; -} - -void EightBit::GameBoy::Sweep::setDirection(Direction value) { - setDirection((int)value); -} - -int EightBit::GameBoy::Sweep::shift() const { - return m_shift; -} - -void EightBit::GameBoy::Sweep::setShift(int value) { - m_shift = value; -} - -// - -EightBit::GameBoy::AudioVoice::AudioVoice() {} - -void EightBit::GameBoy::AudioVoice::reset() { - m_counterContinuous = m_initialise = 0; -} - -bool EightBit::GameBoy::AudioVoice::zeroed() const { - return !initialise() && (type() == Continuous); -} - -EightBit::GameBoy::AudioVoice::Type EightBit::GameBoy::AudioVoice::type() const { - return (Type)m_counterContinuous; -} -void EightBit::GameBoy::AudioVoice::setType(int value) { - m_counterContinuous = value; -} -void EightBit::GameBoy::AudioVoice::setType(Type value) { - setType((int)value); -} - -bool EightBit::GameBoy::AudioVoice::initialise() const { - return !!m_initialise; -} -void EightBit::GameBoy::AudioVoice::setInitialise(bool value) { - m_initialise = value; -} - -// - -EightBit::GameBoy::WaveVoice::WaveVoice(int cyclesPerSecond) -: m_cyclesPerSecond(cyclesPerSecond) {} - -void EightBit::GameBoy::WaveVoice::reset() { - AudioVoice::reset(); - m_frequencyLowOrder = m_frequencyHighOrder = 0; -} - -bool EightBit::GameBoy::WaveVoice::zeroed() const { - return AudioVoice::zeroed() && (frequency() == 0); -} - -int EightBit::GameBoy::WaveVoice::frequencyLowOrder() const { - return m_frequencyLowOrder; -} - -void EightBit::GameBoy::WaveVoice::setFrequencyLowOrder(int value) { - assert(value < Processor::Bit8); - m_frequencyLowOrder = value; -} - -int EightBit::GameBoy::WaveVoice::frequencyHighOrder() const { - return m_frequencyHighOrder; -} - -void EightBit::GameBoy::WaveVoice::setFrequencyHighOrder(int value) { - assert(value < Processor::Bit3); - m_frequencyHighOrder = value; -} - -int EightBit::GameBoy::WaveVoice::frequency() const { - return (m_frequencyHighOrder << 8) | m_frequencyLowOrder; -} - -int EightBit::GameBoy::WaveVoice::hertz() const { - // f = 4194304 / (4 x 8 x (2048 - X)) Hz - auto division = 4 * 8 * (2048 - frequency()); - return m_cyclesPerSecond / division; -} - -void EightBit::GameBoy::WaveVoice::setFrequency(int value) { - assert(value < Processor::Bit11); - m_frequencyHighOrder = (value >> 8) & Processor::Mask3; - m_frequencyLowOrder = value & Processor::Mask8; -} - -// - -EightBit::GameBoy::RectangularVoice::RectangularVoice(int cyclesPerSecond) -: WaveVoice(cyclesPerSecond) {} - -void EightBit::GameBoy::RectangularVoice::reset() { - WaveVoice::reset(); - m_waveFormDutyCycle = m_soundLength = 0; -} - -bool EightBit::GameBoy::RectangularVoice::zeroed() const { - return WaveVoice::zeroed() && (waveFormDutyCycle() == 0) && (length() == 0); -} - -int EightBit::GameBoy::RectangularVoice::waveFormDutyCycle() const { - return m_waveFormDutyCycle; -} - -void EightBit::GameBoy::RectangularVoice::setWaveFormDutyCycle(int value) { - m_waveFormDutyCycle = value; -} - -int EightBit::GameBoy::RectangularVoice::length() const { - return m_soundLength; -} - -void EightBit::GameBoy::RectangularVoice::setLength(int value) { - m_soundLength = value; -} - -// - -EightBit::GameBoy::EnvelopedRectangularVoice::EnvelopedRectangularVoice(int cyclesPerSecond) -: RectangularVoice(cyclesPerSecond) {} - -void EightBit::GameBoy::EnvelopedRectangularVoice::reset() { - RectangularVoice::reset(); - m_envelope.reset(); -} - -bool EightBit::GameBoy::EnvelopedRectangularVoice::zeroed() const { - return RectangularVoice::zeroed() && m_envelope.zeroed(); -} - -EightBit::GameBoy::Envelope& EightBit::GameBoy::EnvelopedRectangularVoice::envelope() { - return m_envelope; -} - -// - -EightBit::GameBoy::SweptEnvelopedRectangularVoice::SweptEnvelopedRectangularVoice(int cyclesPerSecond) -: EnvelopedRectangularVoice(cyclesPerSecond) {} - -void EightBit::GameBoy::SweptEnvelopedRectangularVoice::reset() { - EnvelopedRectangularVoice::reset(); - m_sweep.reset(); -} - -bool EightBit::GameBoy::SweptEnvelopedRectangularVoice::zeroed() const { - return EnvelopedRectangularVoice::zeroed() && m_sweep.zeroed(); -} - -EightBit::GameBoy::Sweep& EightBit::GameBoy::SweptEnvelopedRectangularVoice::sweep() { - return m_sweep; -} - -// - -EightBit::GameBoy::UserDefinedWaveVoice::UserDefinedWaveVoice(int cyclesPerSecond) -: WaveVoice(cyclesPerSecond) {} - -void EightBit::GameBoy::UserDefinedWaveVoice::reset() { - WaveVoice::reset(); - m_enabled = m_soundLength = m_outputLevel = 0; - for (auto& datum : m_waveData) - datum = 0; -} - -bool EightBit::GameBoy::UserDefinedWaveVoice::zeroed() const { - bool dataZeroed = true; - for (const auto& datum : m_waveData) { - if (datum != 0) { - dataZeroed = false; - break; - } - } - return WaveVoice::zeroed() && dataZeroed && !enabled() && (length() == 0) && (level() == 0); -} - -bool EightBit::GameBoy::UserDefinedWaveVoice::enabled() const { - return !!m_enabled; -} - -void EightBit::GameBoy::UserDefinedWaveVoice::setEnabled(bool value) { - m_enabled = value; -} - -int EightBit::GameBoy::UserDefinedWaveVoice::length() const { - return m_soundLength; -} - -void EightBit::GameBoy::UserDefinedWaveVoice::setLength(int value) { - m_soundLength = value; -} - -int EightBit::GameBoy::UserDefinedWaveVoice::level() const { - return m_outputLevel; -} - -void EightBit::GameBoy::UserDefinedWaveVoice::setLevel(int value) { - m_outputLevel = value; -} - -int EightBit::GameBoy::UserDefinedWaveVoice::packedWaveDatum(int i) const { - assert(i < 16); - return m_waveData[i]; -} - -void EightBit::GameBoy::UserDefinedWaveVoice::setPackedWaveDatum(int i, uint8_t value) { - assert(i < 16); - m_waveData[i] = value; -} - -int EightBit::GameBoy::UserDefinedWaveVoice::waveDatum(int i) const { - assert(i < 32); - const auto packed = packedWaveDatum(i >> 1); - return i & 1 ? Processor::lowNibble(packed) : Processor::highNibble(packed); -} - -// - -EightBit::GameBoy::WhiteNoiseWaveVoice::WhiteNoiseWaveVoice() {} - -void EightBit::GameBoy::WhiteNoiseWaveVoice::reset() { - AudioVoice::reset(); - m_envelope.reset(); - m_soundLength = m_polynomialShiftClockFrequency = m_polynomialCounterSteps = m_frequencyDivisionRatio = 0; -} - -bool EightBit::GameBoy::WhiteNoiseWaveVoice::zeroed() const { - return - AudioVoice::zeroed() - && m_envelope.zeroed() - && (length() == 0) - && (polynomialShiftClockFrequency() == 0) - && (polynomialCounterSteps() == 0) - && (frequencyDivisionRatio() == 0); -} - -EightBit::GameBoy::Envelope& EightBit::GameBoy::WhiteNoiseWaveVoice::envelope() { - return m_envelope; -} - -int EightBit::GameBoy::WhiteNoiseWaveVoice::length() const { - return m_soundLength; -} - -void EightBit::GameBoy::WhiteNoiseWaveVoice::setLength(int value) { - m_soundLength = value; -} - -int EightBit::GameBoy::WhiteNoiseWaveVoice::polynomialShiftClockFrequency() const { - return m_polynomialShiftClockFrequency; -} - -void EightBit::GameBoy::WhiteNoiseWaveVoice::setPolynomialShiftClockFrequency(int value) { - m_polynomialShiftClockFrequency = value; -} - -int EightBit::GameBoy::WhiteNoiseWaveVoice::polynomialCounterSteps() const { - return m_polynomialCounterSteps; -} - -void EightBit::GameBoy::WhiteNoiseWaveVoice::setPolynomialCounterSteps(int value) { - m_polynomialCounterSteps = value; -} - -int EightBit::GameBoy::WhiteNoiseWaveVoice::frequencyDivisionRatio() const { - return m_frequencyDivisionRatio; -} - -void EightBit::GameBoy::WhiteNoiseWaveVoice::setFrequencyDivisionRatio(int value) { - m_frequencyDivisionRatio = value; -} - -// - -EightBit::GameBoy::OutputChannel::OutputChannel() {} - -void EightBit::GameBoy::OutputChannel::reset() { - m_vin = false; - m_outputLevel = 0; - for (auto& outputVoice : m_outputVoices) - outputVoice = false; -} - -bool EightBit::GameBoy::OutputChannel::zeroed() const { - return - !vin() - && outputLevel() == 0 - && !m_outputVoices[0] && !m_outputVoices[1] && !m_outputVoices[2] && !m_outputVoices[3]; -} - -bool EightBit::GameBoy::OutputChannel::vin() const { - return m_vin; -} -void EightBit::GameBoy::OutputChannel::setVin(bool value) { - m_vin = value; -} - -int EightBit::GameBoy::OutputChannel::outputLevel() const { - return m_outputLevel; -} -void EightBit::GameBoy::OutputChannel::setOutputLevel(int value) { - m_outputLevel = value; -} - -bool& EightBit::GameBoy::OutputChannel::outputVoice(int voice) { - return m_outputVoices[voice]; -} -bool& EightBit::GameBoy::OutputChannel::outputVoice1() { - return m_outputVoices[0]; -} -bool& EightBit::GameBoy::OutputChannel::outputVoice2() { - return m_outputVoices[1]; -} -bool& EightBit::GameBoy::OutputChannel::outputVoice3() { - return m_outputVoices[2]; -} -bool& EightBit::GameBoy::OutputChannel::outputVoice4() { - return m_outputVoices[3]; -} - -EightBit::GameBoy::Audio::Audio(int cyclesPerSecond) -: m_frameSequencer(cyclesPerSecond), - m_enabled(false) { - - m_voices[0] = std::make_shared(cyclesPerSecond); - m_voices[1] = std::make_shared(cyclesPerSecond); - m_voices[2] = std::make_shared(cyclesPerSecond); - m_voices[3] = std::make_shared(); - - m_frameSequencer.FrameStep.connect(std::bind(&Audio::Sequencer_FrameStep, this, std::placeholders::_1)); - m_frameSequencer.LengthStep.connect(std::bind(&Audio::Sequencer_LengthStep, this, std::placeholders::_1)); - m_frameSequencer.VolumeStep.connect(std::bind(&Audio::Sequencer_VolumeStep, this, std::placeholders::_1)); - m_frameSequencer.SweepStep.connect(std::bind(&Audio::Sequencer_SweepStep, this, std::placeholders::_1)); -} - -std::shared_ptr EightBit::GameBoy::Audio::voice(int i) { - return m_voices[i]; -} - -EightBit::GameBoy::SweptEnvelopedRectangularVoice* EightBit::GameBoy::Audio::voice1() { - return (SweptEnvelopedRectangularVoice*)voice(0).get(); -} - -EightBit::GameBoy::EnvelopedRectangularVoice* EightBit::GameBoy::Audio::voice2() { - return (EnvelopedRectangularVoice*)voice(1).get(); -} - -EightBit::GameBoy::UserDefinedWaveVoice* EightBit::GameBoy::Audio::voice3() { - return (UserDefinedWaveVoice*)voice(2).get(); -} - -EightBit::GameBoy::WhiteNoiseWaveVoice* EightBit::GameBoy::Audio::voice4() { - return (WhiteNoiseWaveVoice*)voice(3).get(); -} - -EightBit::GameBoy::OutputChannel& EightBit::GameBoy::Audio::channel(int i) { - return m_channels[i]; -} -EightBit::GameBoy::OutputChannel& EightBit::GameBoy::Audio::channel1() { - return channel(0); -} -EightBit::GameBoy::OutputChannel& EightBit::GameBoy::Audio::channel2() { - return channel(1); -} - -bool EightBit::GameBoy::Audio::enabled() const { - return m_enabled; -} - -void EightBit::GameBoy::Audio::setEnabled(bool value) { - m_enabled = value; - if (!enabled()) - reset(); -} - -void EightBit::GameBoy::Audio::reset() { - m_enabled = false; - for (auto voice : m_voices) - voice->reset(); - for (auto& channel : m_channels) - channel.reset(); -} - -bool EightBit::GameBoy::Audio::zeroed() const { - auto channelsZeroed = m_channels[0].zeroed() && m_channels[1].zeroed(); - auto voice1Zero = m_voices[0]->zeroed(); - auto voice2Zero = m_voices[1]->zeroed(); - auto voice3Zero = m_voices[2]->zeroed(); - auto voice4Zero = m_voices[3]->zeroed(); - auto voicesZeroed = voice1Zero && voice2Zero && voice3Zero && voice4Zero; - return !enabled() && channelsZeroed && voicesZeroed; -} - -// - -bool EightBit::GameBoy::Audio::voice1On() const { - return true; -} -bool EightBit::GameBoy::Audio::voice2On() const { - return true; -} -bool EightBit::GameBoy::Audio::voice3On() const { - return true; -} -bool EightBit::GameBoy::Audio::voice4On() const { - return true; -} - -// - -uint8_t EightBit::GameBoy::Audio::toNRx1(int i) { - auto voice = (RectangularVoice*)m_voices[i].get(); - return (voice->waveFormDutyCycle() << 6) | Processor::Mask6; -} - -void EightBit::GameBoy::Audio::fromNRx1(int i, uint8_t value) { - auto voice = (RectangularVoice*)m_voices[i].get(); - voice->setWaveFormDutyCycle((value >> 6) & Processor::Mask2); // Bits 6-7 - voice->setLength(value & Processor::Mask6); // Bits 0-5 -} - -uint8_t EightBit::GameBoy::Audio::toNRx2(int i) { - auto voice = (EnvelopedRectangularVoice*)m_voices[i].get(); - auto& envelope = voice->envelope(); - return (envelope.volume() << 4) | (envelope.direction() << 3) | envelope.period(); -} - -void EightBit::GameBoy::Audio::fromNRx2(int i, uint8_t value) { - auto voice = (EnvelopedRectangularVoice*)m_voices[i].get(); - auto& envelope = voice->envelope(); - envelope.setVolume((value >> 4) & Processor::Mask4); // Bits 4-7 - envelope.setDirection((value >> 3) & Processor::Mask1); // Bit 3 - envelope.setPeriod(value & Processor::Mask3); // Bits 0-2 -} - -uint8_t EightBit::GameBoy::Audio::toNRx3(int i) { - return Processor::Mask8; -} - -void EightBit::GameBoy::Audio::fromNRx3(int i, uint8_t value) { - auto voice = (WaveVoice*)m_voices[i].get(); - voice->setFrequencyLowOrder(value); -} - -// Sound mode 1 register: Sweep - -uint8_t EightBit::GameBoy::Audio::toNR10() { - auto& sweep = voice1()->sweep(); - return - Processor::Bit7 - | (sweep.time() << 4) - | (sweep.direction() << 3) - | sweep.shift(); -} - -void EightBit::GameBoy::Audio::fromNR10(uint8_t value) { - auto& sweep = voice1()->sweep(); - sweep.setTime((value >> 4) & Processor::Mask3); // Bits 4-6 - sweep.setDirection((value >> 3) & Processor::Mask1); // Bit 3 - sweep.setShift(value & Processor::Mask3); // Bits 0-2 -} - -// Sound mode 1 register: Sound length / Wave pattern duty -uint8_t EightBit::GameBoy::Audio::toNR11() { - return toNRx1(0); -} -void EightBit::GameBoy::Audio::fromNR11(uint8_t value) { - fromNRx1(0, value); -} - -// Sound mode 1 register: Envelope -uint8_t EightBit::GameBoy::Audio::toNR12() { - return toNRx2(0); -} -void EightBit::GameBoy::Audio::fromNR12(uint8_t value) { - fromNRx2(0, value); -} - -// Sound mode 1 register: Frequency lo -uint8_t EightBit::GameBoy::Audio::toNR13() { - return toNRx3(0); -} -void EightBit::GameBoy::Audio::fromNR13(uint8_t value) { - fromNRx3(0, value); -} - -// Sound mode 1 register: Frequency hi - -uint8_t EightBit::GameBoy::Audio::toNR14() { - return Processor::Bit7 | (voice1()->type() << 6) | Processor::Mask6; -} - -void EightBit::GameBoy::Audio::fromNR14(uint8_t value) { - voice1()->setInitialise((value >> 7) & Processor::Mask1); // Bits 7 - voice1()->setType((value >> 6) & Processor::Mask1); // Bits 6 - voice1()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 -} - -// Sound mode 2 register: Sound length / Wave pattern duty -uint8_t EightBit::GameBoy::Audio::toNR21() { - return toNRx1(1); -} -void EightBit::GameBoy::Audio::fromNR21(uint8_t value) { - fromNRx1(1, value); -} - -// Sound mode 2 register: Envelope -uint8_t EightBit::GameBoy::Audio::toNR22() { - return toNRx2(1); -} -void EightBit::GameBoy::Audio::fromNR22(uint8_t value) { - fromNRx2(1, value); -} - -// Sound mode 2 register: Frequency lo -uint8_t EightBit::GameBoy::Audio::toNR23() { - return toNRx3(1); -} -void EightBit::GameBoy::Audio::fromNR23(uint8_t value) { - fromNRx3(1, value); -} - -// Sound mode 2 register: Frequency hi - -uint8_t EightBit::GameBoy::Audio::toNR24() { - return Processor::Bit7 | (voice2()->type() << 6) | Processor::Mask6; -} - -void EightBit::GameBoy::Audio::fromNR24(uint8_t value) { - voice2()->setInitialise((value >> 7) & Processor::Mask1); // Bits 7 - voice2()->setType((value >> 6) & Processor::Mask1); // Bits 6 - voice2()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 -} - -// Sound mode 3 register: Sound on/off - -uint8_t EightBit::GameBoy::Audio::toNR30() { - return (voice3()->enabled() << 7) | Processor::Mask7; -} - -void EightBit::GameBoy::Audio::fromNR30(uint8_t value) { - voice3()->setEnabled((value >> 7) & Processor::Mask1); // Bit 7 -} - -// Sound mode 3 register: Sound length - -uint8_t EightBit::GameBoy::Audio::toNR31() { - return voice3()->length(); -} - -void EightBit::GameBoy::Audio::fromNR31(uint8_t value) { - voice3()->setLength(value); -} - -// Sound mode 3 register: Select output level - -uint8_t EightBit::GameBoy::Audio::toNR32() { - return Processor::Bit7 | Processor::Bit6 | voice3()->level() << 5 | Processor::Mask5; -} - -void EightBit::GameBoy::Audio::fromNR32(uint8_t value) { - voice3()->setLevel((value >> 5) & Processor::Mask2); // Bits 6-5 -} - -// Sound mode 3 register: Frequency lo -uint8_t EightBit::GameBoy::Audio::toNR33() { - return toNRx3(2); -} -void EightBit::GameBoy::Audio::fromNR33(uint8_t value) { - fromNRx3(2, value); -} - -// Sound mode 3 register: Frequency hi - -uint8_t EightBit::GameBoy::Audio::toNR34() { - return Processor::Bit7 | (voice3()->type() << 6) | Processor::Mask6; -} - -void EightBit::GameBoy::Audio::fromNR34(uint8_t value) { - voice3()->setInitialise((value >> 7) & Processor::Mask1); // Bits 7 - voice3()->setType((value >> 6) & Processor::Mask1); // Bits 6 - voice3()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 -} - -// Sound mode 4 register: Sound length - -uint8_t EightBit::GameBoy::Audio::toNR41() { - return Processor::Bit7 | Processor::Bit6 | voice4()->length(); -} - -void EightBit::GameBoy::Audio::fromNR41(uint8_t value) { - voice4()->setLength(value); -} - -// Sound mode 4 register: Envelope -uint8_t EightBit::GameBoy::Audio::toNR42() { - return toNRx2(3); -} -void EightBit::GameBoy::Audio::fromNR42(uint8_t value) { - fromNRx2(3, value); -} - -// Sound mode 4 register: Polynomial counter - -uint8_t EightBit::GameBoy::Audio::toNR43() { - return - (voice4()->polynomialShiftClockFrequency() << 4) - | voice4()->polynomialCounterSteps() << 3 - | voice4()->frequencyDivisionRatio(); -} - -void EightBit::GameBoy::Audio::fromNR43(uint8_t value) { - voice4()->setPolynomialShiftClockFrequency((value >> 4) & Processor::Mask4); // Bits 4-7 - voice4()->setPolynomialCounterSteps((value >> 3) & Processor::Mask1); // Bit 3 - voice4()->setFrequencyDivisionRatio(value & Processor::Mask3); // Bits 0-2 -} - -// Sound mode 4 register: counter/consecutive; inital - -uint8_t EightBit::GameBoy::Audio::toNR44() { - return Processor::Bit7 | (voice4()->type() << 6) | Processor::Mask6; -} - -void EightBit::GameBoy::Audio::fromNR44(uint8_t value) { - voice4()->setInitialise((value >> 7) & Processor::Mask1); // Bit 7 - voice4()->setType((value >> 6) & Processor::Mask1); // Bit 6 -} - -// Channel control: on-off/volume - -uint8_t EightBit::GameBoy::Audio::toNR50() { - return - (channel2().vin() << 7) - | (channel2().outputLevel() << 4) - | (channel2().vin() << 3) - | channel2().outputLevel(); -} - -void EightBit::GameBoy::Audio::fromNR50(uint8_t value) { - channel2().setVin((value >> 7) & Processor::Mask1); // Bit 7 - channel2().setOutputLevel((value >> 4) & Processor::Mask3); // Bits 4-6 - channel1().setVin((value >> 3) & Processor::Mask1); // Bit 3 - channel1().setOutputLevel(value & Processor::Mask3); // Bits 0-2 -} - -// Selection of Sound output terminal - -uint8_t EightBit::GameBoy::Audio::toNR51() { - return - (channel2().outputVoice4() << 7) - | (channel2().outputVoice3() << 6) - | (channel2().outputVoice2() << 5) - | (channel2().outputVoice1() << 4) - | (channel1().outputVoice4() << 3) - | (channel1().outputVoice3() << 2) - | (channel1().outputVoice2() << 1) - | (int)channel1().outputVoice1(); -} - -void EightBit::GameBoy::Audio::fromNR51(uint8_t value) { - channel2().outputVoice4() = (value >> 7) & Processor::Mask1; // Bit 7 - channel2().outputVoice3() = (value >> 6) & Processor::Mask1; // Bit 6 - channel2().outputVoice2() = (value >> 5) & Processor::Mask1; // Bit 5 - channel2().outputVoice1() = (value >> 4) & Processor::Mask1; // Bit 4 - channel1().outputVoice4() = (value >> 3) & Processor::Mask1; // Bit 3 - channel1().outputVoice3() = (value >> 2) & Processor::Mask1; // Bit 2 - channel1().outputVoice2() = (value >> 1) & Processor::Mask1; // Bit 1 - channel1().outputVoice1() = value & Processor::Mask1; // Bit 0 -} - -// Sound on/off - -uint8_t EightBit::GameBoy::Audio::toNR52() { - return - (enabled() << 7) - | Processor::Bit6 | Processor::Bit5 | Processor::Bit4 - | (voice4On() << 3) - | (voice3On() << 2) - | (voice2On() << 1) - | (int)voice1On(); -} - -void EightBit::GameBoy::Audio::fromNR52(uint8_t value) { - setEnabled((value >> 7) & Processor::Mask1); // Bit 7 -} - -void EightBit::GameBoy::Audio::setPackedWaveDatum(int i, uint8_t value) { - voice3()->setPackedWaveDatum(i, value); -} - -uint8_t EightBit::GameBoy::Audio::packedWaveDatum(int i) { - return voice3()->packedWaveDatum(i); -} - -void EightBit::GameBoy::Audio::stepFrame(int cycles) { - m_frameSequencer.step(cycles); -} - -void EightBit::GameBoy::Audio::Sequencer_FrameStep(const int step) { -} - -void EightBit::GameBoy::Audio::Sequencer_LengthStep(const int step) { - stepLength(voice1()); - stepLength(voice2()); - stepLength(voice3()); - stepLength(voice4()); -} - -void EightBit::GameBoy::Audio::Sequencer_VolumeStep(const int step) { - voice1()->envelope().step(); - voice2()->envelope().step(); - voice4()->envelope().step(); -} - -void EightBit::GameBoy::Audio::Sequencer_SweepStep(const int step) { -} diff --git a/LR35902/src/GameBoyBus.cpp b/LR35902/src/GameBoyBus.cpp index 2e469fc..fe8b358 100644 --- a/LR35902/src/GameBoyBus.cpp +++ b/LR35902/src/GameBoyBus.cpp @@ -30,8 +30,7 @@ EightBit::GameBoy::Bus::Bus() m_p13(true), m_p12(true), m_p11(true), - m_p10(true), - m_audio(CyclesPerSecond) { + m_p10(true) { ReadingByte.connect(std::bind(&GameBoy::Bus::Bus_ReadingByte, this, std::placeholders::_1)); WrittenByte.connect(std::bind(&GameBoy::Bus::Bus_WrittenByte, this, std::placeholders::_1)); m_divCounter.word = 0xabcc; @@ -40,7 +39,6 @@ EightBit::GameBoy::Bus::Bus() void EightBit::GameBoy::Bus::reset() { - audio().reset(); assert(audio().zeroed()); poke(BASE + NR52, 0xf1); @@ -112,71 +110,6 @@ void EightBit::GameBoy::Bus::Bus_ReadingByte(const uint16_t address) { // but all are available for use. break; - // Sound Registers - case NR10: - poke(address, audio().toNR10()); - break; - case NR11: - poke(address, audio().toNR11()); - break; - case NR12: - poke(address, audio().toNR12()); - break; - case NR13: - poke(address, audio().toNR13()); - break; - case NR14: - poke(address, audio().toNR14()); - break; - case NR21: - poke(address, audio().toNR21()); - break; - case NR22: - poke(address, audio().toNR22()); - break; - case NR23: - poke(address, audio().toNR23()); - break; - case NR24: - poke(address, audio().toNR24()); - break; - case NR30: - poke(address, audio().toNR30()); - break; - case NR31: - poke(address, audio().toNR31()); - break; - case NR32: - poke(address, audio().toNR32()); - break; - case NR33: - poke(address, audio().toNR33()); - break; - case NR34: - poke(address, audio().toNR34()); - break; - case NR41: - poke(address, audio().toNR41()); - break; - case NR42: - poke(address, audio().toNR42()); - break; - case NR43: - poke(address, audio().toNR43()); - break; - case NR44: - poke(address, audio().toNR44()); - break; - case NR50: - poke(address, audio().toNR50()); - break; - case NR51: - poke(address, audio().toNR51()); - break; - case NR52: - poke(address, audio().toNR52()); - break; - // LCD Display Registers case LCDC: break; @@ -196,10 +129,7 @@ void EightBit::GameBoy::Bus::Bus_ReadingByte(const uint16_t address) { break; default: - if ((address >= (BASE + WAVE_PATTERN_RAM_START)) && (address <= (BASE + WAVE_PATTERN_RAM_END))) - poke(address, audio().packedWaveDatum(address - WAVE_PATTERN_RAM_START)); - else - mask(0); + mask(0); break; } } @@ -278,91 +208,6 @@ void EightBit::GameBoy::Bus::Bus_WrittenByte(const uint16_t address) { case BASE + IF: // R/W break; - case BASE + NR10: // Sound mode 1 register: Sweep - audio().fromNR10(value); - break; - - case BASE + NR11: // Sound mode 1 register: Sound length / Wave pattern duty - audio().fromNR11(value); - break; - - case BASE + NR12: // Sound mode 1 register: Envelope - audio().fromNR12(value); - break; - - case BASE + NR13: // Sound mode 1 register: Frequency lo - audio().fromNR13(value); - break; - - case BASE + NR14: // Sound mode 1 register: Frequency hi - audio().fromNR14(value); - std::cout << "Voice one frequency: " << audio().voice1()->hertz() << std::endl; - break; - - case BASE + NR21: // Sound mode 2 register: Sound length / Wave pattern duty - audio().fromNR21(value); - break; - - case BASE + NR22: // Sound mode 2 register: Envelope - audio().fromNR22(value); - break; - - case BASE + NR23: // Sound mode 2 register: Frequency lo - audio().fromNR23(value); - break; - - case BASE + NR24: // Sound mode 2 register: Frequency hi - audio().fromNR24(value); - break; - - case BASE + NR30: // Sound mode 3 register: Sound on/off - audio().fromNR30(value); - break; - - case BASE + NR31: // Sound mode 3 register: Sound length - audio().fromNR31(value); - break; - - case BASE + NR32: // Sound mode 3 register: Select output level - audio().fromNR32(value); - break; - - case BASE + NR33: // Sound mode 3 register: Frequency lo - audio().fromNR33(value); - break; - - case BASE + NR34: // Sound mode 3 register: Frequency hi - audio().fromNR34(value); - break; - - case BASE + NR41: // Sound mode 4 register: Sound length - audio().fromNR41(value); - break; - - case BASE + NR42: // Sound mode 4 register: Envelope - audio().fromNR42(value); - break; - - case BASE + NR43: // Sound mode 4 register: Polynomial counter - audio().fromNR43(value); - break; - - case BASE + NR44: // Sound mode 4 register: counter/consecutive; inital - audio().fromNR44(value); - break; - - case BASE + NR50: // Channel control: on-off/volume - audio().fromNR50(value); - break; - - case BASE + NR51: // Selection of Sound output terminal - audio().fromNR51(value); - break; - - case BASE + NR52: // Sound on/off - audio().fromNR52(value); - break; - case BASE + LCDC: case BASE + STAT: case BASE + SCY: @@ -386,10 +231,6 @@ void EightBit::GameBoy::Bus::Bus_WrittenByte(const uint16_t address) { case BASE + BOOT_DISABLE: m_disableBootRom = value != 0; break; - - default: - if ((address >= (BASE + WAVE_PATTERN_RAM_START)) && (address <= (BASE + WAVE_PATTERN_RAM_END))) - audio().setPackedWaveDatum(address - WAVE_PATTERN_RAM_START, value); } } } diff --git a/LR35902/src/LR35902.cpp b/LR35902/src/LR35902.cpp index 2b3542d..0753ccb 100644 --- a/LR35902/src/LR35902.cpp +++ b/LR35902/src/LR35902.cpp @@ -343,7 +343,6 @@ int EightBit::GameBoy::LR35902::runRasterLine() { if ((m_bus.peekRegister(Bus::STAT) & Bit6) && (m_bus.peekRegister(Bus::LYC) == m_bus.peekRegister(Bus::LY))) m_bus.triggerInterrupt(Bus::Interrupts::DisplayControlStatus); } - m_bus.audio().stepFrame(count); return count; } @@ -397,7 +396,9 @@ int EightBit::GameBoy::LR35902::step() { ExecutingInstruction.fire(*this); m_prefixCB = false; cycles = 0; - return fetchExecute(); + auto ran = fetchExecute(); + ExecutedInstruction.fire(*this); + return ran; } #pragma endregion Controlled instruction execution @@ -423,7 +424,7 @@ int EightBit::GameBoy::LR35902::execute(uint8_t opcode) { if (cycles == 0) throw std::logic_error("Unhandled opcode"); - return cycles * 4; + return clockCycles(); } void EightBit::GameBoy::LR35902::executeCB(int x, int y, int z, int p, int q) { diff --git a/LR35902/src/LR35902.vcxproj b/LR35902/src/LR35902.vcxproj index 20e1024..141fb76 100644 --- a/LR35902/src/LR35902.vcxproj +++ b/LR35902/src/LR35902.vcxproj @@ -140,8 +140,6 @@ - - @@ -152,7 +150,6 @@ - diff --git a/LR35902/src/LR35902.vcxproj.filters b/LR35902/src/LR35902.vcxproj.filters index 8fd974c..ed7430e 100644 --- a/LR35902/src/LR35902.vcxproj.filters +++ b/LR35902/src/LR35902.vcxproj.filters @@ -38,12 +38,6 @@ Header Files - - Header Files - - - Header Files - @@ -64,8 +58,5 @@ Source Files - - Source Files - \ No newline at end of file