diff --git a/LR35902/inc/Audio.h b/LR35902/inc/Audio.h index 94787c7..5d6653a 100644 --- a/LR35902/inc/Audio.h +++ b/LR35902/inc/Audio.h @@ -24,17 +24,6 @@ namespace EightBit { return (default() == 0) && (stepLength() == 0) && (direction() == Attenuate); } - uint8_t toNR() const { - return (default() << 4) | (direction() << 3) | stepLength(); - } - - void fromNR(uint8_t value) { - setDefault((value >> 4) & Processor::Mask4); // Bits 4-7 - setDirection((value >> 3) & Processor::Mask1); // Bit 3 - setStepLength(value & Processor::Mask3); // Bits 0-2 - } - - int default() const { return m_defaultValue; } void setDefault(int value) { m_defaultValue = value; } @@ -65,16 +54,6 @@ namespace EightBit { m_time = m_direction = m_shift = 0; } - uint8_t toNR() const { - return Processor::Bit7 | (time() << 4) | (direction() << 3) | shift(); - } - - void fromNR(uint8_t value) { - setTime((value >> 4) & Processor::Mask3); // Bits 4-6 - setDirection((value >> 3) & Processor::Mask1); // Bit 3 - setShift(value & Processor::Mask3); // Bits 0-2 - } - bool zeroed() const { return (time() == 0) && (shift() == 0) && (direction() == Addition); } @@ -196,15 +175,6 @@ namespace EightBit { return WaveVoice::zeroed() && (waveFormDutyCycle() == 0) && (length() == 0); } - uint8_t toNR() const { - return Processor::Bit7 | (waveFormDutyCycle() << 6) | length(); - } - - void fromNR(uint8_t value) { - setWaveFormDutyCycle((value >> 6) & Processor::Mask2); // Bits 6-7 - setLength(value & Processor::Mask6); // Bits 0-5 - } - int waveFormDutyCycle() const { return m_waveFormDutyCycle; } void setWaveFormDutyCycle(int value) { m_waveFormDutyCycle = value; } @@ -502,6 +472,286 @@ namespace EightBit { dumpChannels(); } + // + + bool voice1On() const { return true; } + bool voice2On() const { return true; } + bool voice3On() const { return true; } + bool voice4On() const { return true; } + + // + + uint8_t toNRx1(int i) { + auto voice = (RectangularVoice*)m_voices[i].get(); + return + (voice->waveFormDutyCycle() << 6) + | Processor::Mask6; + } + + void 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 toNRx2(int i) { + auto voice = (EnvelopedRectangularVoice*)m_voices[i].get(); + auto& envelope = voice->envelope(); + return + (envelope.default() << 4) + | (envelope.direction() << 3) + | envelope.stepLength(); + } + + void fromNRx2(int i, uint8_t value) { + auto voice = (EnvelopedRectangularVoice*)m_voices[i].get(); + auto& envelope = voice->envelope(); + envelope.setDefault((value >> 4) & Processor::Mask4); // Bits 4-7 + envelope.setDirection((value >> 3) & Processor::Mask1); // Bit 3 + envelope.setStepLength(value & Processor::Mask3); // Bits 0-2 + } + + uint8_t toNRx3(int i) { + return Processor::Mask8; + } + + void fromNRx3(int i, uint8_t value) { + auto voice = (WaveVoice*)m_voices[i].get(); + voice->setFrequencyLowOrder(value); + } + + // Sound mode 1 register: Sweep + + uint8_t toNR10() { + auto& sweep = voice1()->sweep(); + return + Processor::Bit7 + | (sweep.time() << 4) + | (sweep.direction() << 3) + | sweep.shift(); + } + + void 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 toNR11() { return toNRx1(0); } + void fromNR11(uint8_t value) { fromNRx1(0, value); } + + // Sound mode 1 register: Envelope + uint8_t toNR12() { return toNRx2(0); } + void fromNR12(uint8_t value) { fromNRx2(0, value); } + + // Sound mode 1 register: Frequency lo + uint8_t toNR13() { return toNRx3(0); } + void fromNR13(uint8_t value) { fromNRx3(0, value); } + + // Sound mode 1 register: Frequency hi + + uint8_t toNR14() { + return + Processor::Bit7 + | (voice1()->type() << 6) + | Processor::Mask6; + } + + void 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 toNR21() { return toNRx1(1); } + void fromNR21(uint8_t value) { fromNRx1(1, value); } + + // Sound mode 2 register: Envelope + uint8_t toNR22() { return toNRx2(1); } + void fromNR22(uint8_t value) { fromNRx2(1, value); } + + // Sound mode 2 register: Frequency lo + uint8_t toNR23() { return toNRx3(1); } + void fromNR23(uint8_t value) { fromNRx3(1, value); } + + // Sound mode 2 register: Frequency hi + + uint8_t toNR24() { + return + Processor::Bit7 + | (voice2()->type() << 6) + | Processor::Mask6; + } + + void 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 toNR30() { + return + (voice3()->enabled() << 7) + | Processor::Mask7; + } + + void fromNR30(uint8_t value) { + voice3()->setEnabled((value >> 7) & Processor::Mask1); // Bit 7 + } + + // Sound mode 3 register: Sound length + + uint8_t toNR31() { + return voice3()->length(); + } + + void fromNR31(uint8_t value) { + voice3()->setLength(value); + } + + // Sound mode 3 register: Select output level + + uint8_t toNR32() { + return + Processor::Bit7 + | Processor::Bit6 + | voice3()->level() << 5 + | Processor::Mask5; + } + + void fromNR32(uint8_t value) { + voice3()->setLevel((value >> 5) & Processor::Mask2); // Bits 6-5 + } + + // Sound mode 3 register: Frequency lo + uint8_t toNR33() { return toNRx3(2); } + void fromNR33(uint8_t value) { fromNRx3(2, value); } + + // Sound mode 3 register: Frequency hi + + uint8_t toNR34() { + return + Processor::Bit7 + | (voice3()->type() << 6) + | Processor::Mask6; + } + + void 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 toNR41() { + return + Processor::Bit7 + | Processor::Bit6 + | voice4()->length(); + } + + void fromNR41(uint8_t value) { + voice4()->setLength(value); + } + + // Sound mode 4 register: Envelope + uint8_t toNR42() { return toNRx2(3); } + void fromNR42(uint8_t value) { fromNRx2(3, value); } + + // Sound mode 4 register: Polynomial counter + + uint8_t toNR43() { + return + (voice4()->polynomialShiftClockFrequency() << 4) + | voice4()->polynomialCounterSteps() << 3 + | voice4()->frequencyDivisionRatio(); + } + + void 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 toNR44() { + return + Processor::Bit7 + | (voice4()->type() << 6) + | Processor::Mask6; + } + + void 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 toNR50() { + return + (channel2().vin() << 7) + | (channel2().outputLevel() << 4) + | (channel2().vin() << 3) + | channel2().outputLevel(); + } + + void 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 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 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 toNR52() { + return + (enabled() << 7) + | Processor::Bit6 | Processor::Bit5 | Processor::Bit4 + | (voice4On() << 3) + | (voice3On() << 2) + | (voice2On() << 1) + | voice1On(); + } + + void fromNR52(uint8_t value) { + setEnabled((value >> 7) & Processor::Mask1); // Bit 7 + } + + private: std::array, 4> m_voices; std::array m_channels; diff --git a/LR35902/src/GameBoyBus.cpp b/LR35902/src/GameBoyBus.cpp index 3fa87f3..f836cc0 100644 --- a/LR35902/src/GameBoyBus.cpp +++ b/LR35902/src/GameBoyBus.cpp @@ -113,51 +113,67 @@ void EightBit::GameBoy::Bus::Bus_ReadingByte(const uint16_t address) { // Sound Registers case NR10: - poke(address, audio().voice1()->sweep().toNR()); + poke(address, audio().toNR10()); break; case NR11: - poke(address, audio().voice1()->toNR()); + poke(address, audio().toNR11()); break; case NR12: - poke(address, audio().voice1()->envelope().toNR()); + 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().voice2()->envelope().toNR()); + poke(address, audio().toNR22()); break; case NR23: + poke(address, audio().toNR23()); + break; case NR24: + poke(address, audio().toNR24()); break; case NR30: - mask(Processor::Bit7); + poke(address, audio().toNR30()); break; case NR31: + poke(address, audio().toNR31()); break; case NR32: - mask(Processor::Bit6 | Processor::Bit5); + poke(address, audio().toNR32()); break; case NR33: + poke(address, audio().toNR33()); + break; case NR34: + poke(address, audio().toNR34()); break; case NR41: - mask(Processor::Mask6); + poke(address, audio().toNR41()); break; case NR42: - poke(address, audio().voice4()->envelope().toNR()); + poke(address, audio().toNR42()); break; case NR43: + poke(address, audio().toNR43()); break; case NR44: - mask(Processor::Bit6 | Processor::Bit7); + poke(address, audio().toNR44()); break; case NR50: + poke(address, audio().toNR50()); + break; case NR51: + poke(address, audio().toNR51()); break; case NR52: - mask(Processor::Bit7 | Processor::Mask4); + poke(address, audio().toNR52()); break; // LCD Display Registers @@ -259,126 +275,107 @@ void EightBit::GameBoy::Bus::Bus_WrittenByte(const uint16_t address) { break; case BASE + NR10: // Sound mode 1 register: Sweep - audio().voice1()->sweep().fromNR(value); + audio().fromNR10(value); audio().dumpVoice(0); break; case BASE + NR11: // Sound mode 1 register: Sound length / Wave pattern duty - audio().voice1()->fromNR(value); + audio().fromNR11(value); audio().dumpVoice(0); break; case BASE + NR12: // Sound mode 1 register: Envelope - audio().voice1()->envelope().fromNR(value); + audio().fromNR12(value); audio().dumpVoice(0); break; case BASE + NR13: // Sound mode 1 register: Frequency lo - audio().voice1()->setFrequencyLowOrder(value); + audio().fromNR13(value); audio().dumpVoice(0); break; case BASE + NR14: // Sound mode 1 register: Frequency hi - audio().voice1()->setInitialise((value >> 7) & Processor::Mask1); // Bits 7 - audio().voice1()->setType((value >> 6) & Processor::Mask1); // Bits 6 - audio().voice1()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 + audio().fromNR14(value); audio().dumpVoice(0); break; case BASE + NR21: // Sound mode 2 register: Sound length / Wave pattern duty - audio().voice2()->fromNR(value); + audio().fromNR21(value); audio().dumpVoice(1); break; case BASE + NR22: // Sound mode 2 register: Envelope - audio().voice2()->envelope().fromNR(value); + audio().fromNR22(value); audio().dumpVoice(1); break; case BASE + NR23: // Sound mode 2 register: Frequency lo - audio().voice2()->setFrequencyLowOrder(value); + audio().fromNR23(value); audio().dumpVoice(1); break; case BASE + NR24: // Sound mode 2 register: Frequency hi - audio().voice2()->setInitialise((value >> 7) & Processor::Mask1); // Bit 7 - audio().voice2()->setType((value >> 6) & Processor::Mask1); // Bit 6 - audio().voice2()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 + audio().fromNR24(value); audio().dumpVoice(1); break; case BASE + NR30: // Sound mode 3 register: Sound on/off - audio().voice3()->setEnabled((value >> 7) & Processor::Mask1); // Bit 7 + audio().fromNR30(value); audio().dumpVoice(2); break; case BASE + NR31: // Sound mode 3 register: Sound length - audio().voice3()->setLength(value); + audio().fromNR31(value); audio().dumpVoice(2); break; case BASE + NR32: // Sound mode 3 register: Select output level - audio().voice3()->setLevel(value); + audio().fromNR32(value); audio().dumpVoice(2); break; case BASE + NR33: // Sound mode 3 register: Frequency lo - audio().voice3()->setFrequencyLowOrder(value); + audio().fromNR33(value); audio().dumpVoice(2); break; case BASE + NR34: // Sound mode 3 register: Frequency hi - audio().voice3()->setInitialise((value >> 7) & Processor::Mask1); // Bits 7 - audio().voice3()->setType((value >> 6) & Processor::Mask1); // Bits 6 - audio().voice3()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 + audio().fromNR34(value); audio().dumpVoice(2); break; case BASE + NR41: // Sound mode 4 register: Sound length - audio().voice4()->setLength(value & Processor::Mask6); // Bits 0-5 + audio().fromNR41(value); audio().dumpVoice(3); break; case BASE + NR42: // Sound mode 4 register: Envelope - audio().voice4()->envelope().fromNR(value); + audio().fromNR42(value); audio().dumpVoice(3); break; case BASE + NR43: // Sound mode 4 register: Polynomial counter - audio().voice4()->setPolynomialShiftClockFrequency((value >> 4) & Processor::Mask4); // Bits 4-7 - audio().voice4()->setPolynomialCounterSteps((value >> 3) & Processor::Mask1); // Bit 3 - audio().voice4()->setFrequencyDivisionRatio(value & Processor::Mask3); // Bits 0-2 + audio().fromNR43(value); audio().dumpVoice(3); break; case BASE + NR44: // Sound mode 4 register: counter/consecutive; inital - audio().voice4()->setInitialise((value >> 7) & Processor::Mask1); // Bit 7 - audio().voice4()->setType((value >> 6) & Processor::Mask1); // Bit 6 + audio().fromNR44(value); audio().dumpVoice(3); break; case BASE + NR50: // Channel control: on-off/volume - audio().channel2().setVin((value >> 7) & Processor::Mask1); // Bit 7 - audio().channel2().setOutputLevel((value >> 4) & Processor::Mask3); // Bits 4-6 - audio().channel1().setVin((value >> 3) & Processor::Mask1); // Bit 3 - audio().channel1().setOutputLevel(value & Processor::Mask3); // Bits 0-2 + audio().fromNR50(value); audio().dumpChannels(); break; case BASE + NR51: - audio().channel2().outputVoice4() = (value >> 7) & Processor::Mask1; // Bit 7 - audio().channel2().outputVoice3() = (value >> 6) & Processor::Mask1; // Bit 6 - audio().channel2().outputVoice2() = (value >> 5) & Processor::Mask1; // Bit 5 - audio().channel2().outputVoice1() = (value >> 4) & Processor::Mask1; // Bit 4 - audio().channel1().outputVoice4() = (value >> 3) & Processor::Mask1; // Bit 3 - audio().channel1().outputVoice3() = (value >> 2) & Processor::Mask1; // Bit 2 - audio().channel1().outputVoice2() = (value >> 1) & Processor::Mask1; // Bit 1 - audio().channel1().outputVoice1() = value & Processor::Mask1; // Bit 0 + audio().fromNR51(value); audio().dumpChannels(); break; case BASE + NR52: // Sound on/off - audio().setEnabled((value >> 7) & Processor::Mask1); // Bit 7 + audio().fromNR52(value); break; case BASE + LCDC: