From 4c9af627e09c45db7a0f0936641ed747c8a6490c Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Tue, 28 Jan 2020 19:46:32 +0100 Subject: [PATCH] Moving DSP in its own folder Implementing read & write with all registers for DSP Replacing APU registers with internal registers and vice-versa Associate DSP with APU in constructor --- CMakeLists.txt | 4 +- sources/APU/APU.cpp | 55 +++-- sources/APU/APU.hpp | 20 +- sources/DSP/DSP.cpp | 548 ++++++++++++++++++++++++++++++++++++++++++++ sources/DSP/DSP.hpp | 175 ++++++++++++++ 5 files changed, 763 insertions(+), 39 deletions(-) create mode 100644 sources/DSP/DSP.cpp create mode 100644 sources/DSP/DSP.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a19583..29f7d2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,4 +44,6 @@ add_executable(ComSquare sources/Ram/Ram.hpp sources/Memory/MemoryShadow.cpp sources/Memory/MemoryShadow.hpp -) + sources/DSP/DSP.cpp + sources/DSP/DSP.hpp + ) diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index 3a2066e..9f23d88 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -8,37 +8,36 @@ namespace ComSquare::APU { - APU::APU() - { - } + APU::APU() : _dsp(new DSP::DSP) + { } uint8_t APU::read(uint24_t addr) { switch (addr) { case 0xF0: - return this->_internalRegisters.unknown; + return this->_registers.unknown; case 0xF2: - return this->_internalRegisters.dspregAddr; + return this->_registers.dspregAddr; case 0xF3: - return this->_internalRegisters.dspregData; + return this->_registers.dspregData; case 0xF4: - return this->_internalRegisters.port0; + return this->_registers.port0; case 0xF5: - return this->_internalRegisters.port1; + return this->_registers.port1; case 0xF6: - return this->_internalRegisters.port2; + return this->_registers.port2; case 0xF7: - return this->_internalRegisters.port3; + return this->_registers.port3; case 0xF8: - return this->_internalRegisters.regmem1; + return this->_registers.regmem1; case 0xF9: - return this->_internalRegisters.regmem2; + return this->_registers.regmem2; case 0xFD: - return this->_internalRegisters.counter0; + return this->_registers.counter0; case 0xFE: - return this->_internalRegisters.counter1; + return this->_registers.counter1; case 0xFF: - return this->_internalRegisters.counter2; + return this->_registers.counter2; default: throw InvalidAddress("APU Internal Registers read", addr); } @@ -48,43 +47,43 @@ namespace ComSquare::APU { switch (addr) { case 0xF0: - this->_internalRegisters.unknown = data; + this->_registers.unknown = data; break; case 0xF1: - this->_internalRegisters.ctrlreg = data; + this->_registers.ctrlreg = data; break; case 0xF2: - this->_internalRegisters.dspregAddr = data; + this->_registers.dspregAddr = data; break; case 0xF3: - this->_internalRegisters.dspregData = data; + this->_registers.dspregData = data; break; case 0xF4: - this->_internalRegisters.port0 = data; + this->_registers.port0 = data; break; case 0xF5: - this->_internalRegisters.port1 = data; + this->_registers.port1 = data; break; case 0xF6: - this->_internalRegisters.port2 = data; + this->_registers.port2 = data; break; case 0xF7: - this->_internalRegisters.port3 = data; + this->_registers.port3 = data; break; case 0xF8: - this->_internalRegisters.regmem1 = data; + this->_registers.regmem1 = data; break; case 0xF9: - this->_internalRegisters.regmem2 = data; + this->_registers.regmem2 = data; break; case 0xFA: - this->_internalRegisters.timer0 = data; + this->_registers.timer0 = data; break; case 0xFB: - this->_internalRegisters.timer1 = data; + this->_registers.timer1 = data; break; case 0xFC: - this->_internalRegisters.timer2 = data; + this->_registers.timer2 = data; break; default: throw InvalidAddress("APU Internal Registers write", addr); diff --git a/sources/APU/APU.hpp b/sources/APU/APU.hpp index 8088257..0dc3461 100644 --- a/sources/APU/APU.hpp +++ b/sources/APU/APU.hpp @@ -6,11 +6,12 @@ #define COMSQUARE_APU_HPP #include +#include "../DSP/DSP.hpp" #include "../Memory/IMemory.hpp" namespace ComSquare::APU { - struct Registers { + struct InternalRegisters { //! @brief The X index register uint8_t x; @@ -59,7 +60,7 @@ namespace ComSquare::APU }; }; - struct InternalRegisters + struct Registers { //! @brief An undocumented register uint8_t unknown; @@ -102,25 +103,24 @@ namespace ComSquare::APU }; - class DSP { - }; - class APU : public IMemory { private: + //! @brief All the registers of the APU CPU Registers _registers; - InternalRegisters _internalRegisters{}; - public: - explicit APU(); + //! @brief Internal registers of the CPU (accessible from the bus via addr $4200 to $421F). + InternalRegisters _internalRegisters; //! @brief The DSP component used to produce sound - std::shared_ptr _dsp; + std::shared_ptr _dsp; + public: + explicit APU(); //! @brief Read from the internal APU register. //! @param addr The address to read from. The address 0xF0 should refer to the first byte of the register. //! @throw InvalidAddress will be thrown if the address is more than $FF (the number of register). //! @return Return the value of the register. uint8_t read(uint24_t addr) override; - //! @brief Write data to the internal APY register. + //! @brief Write data to the internal APU register. //! @param addr The address to write to. The address 0xF0 should refer to the first byte of register. //! @param data The new value of the register. //! @throw InvalidAddress will be thrown if the address is more than $FF (the number of register). diff --git a/sources/DSP/DSP.cpp b/sources/DSP/DSP.cpp new file mode 100644 index 0000000..31dce99 --- /dev/null +++ b/sources/DSP/DSP.cpp @@ -0,0 +1,548 @@ +// +// Created by Melefo on 28/01/2020. +// + +#include "DSP.hpp" +#include "../Exceptions/InvalidAddress.hpp" + +namespace ComSquare::APU::DSP +{ + DSP::DSP() + { } + + uint8_t DSP::read(uint24_t addr) + { + switch (addr) { + case 0x00: + return this->_registers.volL[0]; + case 0x10: + return this->_registers.volL[1]; + case 0x20: + return this->_registers.volL[2]; + case 0x30: + return this->_registers.volL[3]; + case 0x40: + return this->_registers.volL[4]; + case 0x50: + return this->_registers.volL[5]; + case 0x60: + return this->_registers.volL[6]; + case 0x70: + return this->_registers.volL[7]; + case 0x01: + return this->_registers.volR[0]; + case 0x11: + return this->_registers.volR[1]; + case 0x21: + return this->_registers.volR[2]; + case 0x31: + return this->_registers.volR[3]; + case 0x41: + return this->_registers.volR[4]; + case 0x51: + return this->_registers.volR[5]; + case 0x61: + return this->_registers.volR[6]; + case 0x71: + return this->_registers.volR[7]; + case 0x02: + return this->_registers.pitchL[0]; + case 0x12: + return this->_registers.pitchL[1]; + case 0x22: + return this->_registers.pitchL[2]; + case 0x32: + return this->_registers.pitchL[3]; + case 0x42: + return this->_registers.pitchL[4]; + case 0x52: + return this->_registers.pitchL[5]; + case 0x62: + return this->_registers.pitchL[6]; + case 0x72: + return this->_registers.pitchL[7]; + case 0x03: + return this->_registers.pitchH[0]; + case 0x13: + return this->_registers.pitchH[1]; + case 0x23: + return this->_registers.pitchH[2]; + case 0x33: + return this->_registers.pitchH[3]; + case 0x43: + return this->_registers.pitchH[4]; + case 0x53: + return this->_registers.pitchH[5]; + case 0x63: + return this->_registers.pitchH[6]; + case 0x73: + return this->_registers.pitchH[7]; + case 0x04: + return this->_registers.srcn[0]; + case 0x14: + return this->_registers.srcn[1]; + case 0x24: + return this->_registers.srcn[2]; + case 0x34: + return this->_registers.srcn[3]; + case 0x44: + return this->_registers.srcn[4]; + case 0x54: + return this->_registers.srcn[5]; + case 0x64: + return this->_registers.srcn[6]; + case 0x74: + return this->_registers.srcn[7]; + case 0x05: + return this->_registers.adsr1[0]; + case 0x15: + return this->_registers.adsr1[1]; + case 0x25: + return this->_registers.adsr1[2]; + case 0x35: + return this->_registers.adsr1[3]; + case 0x45: + return this->_registers.adsr1[4]; + case 0x55: + return this->_registers.adsr1[5]; + case 0x65: + return this->_registers.adsr1[6]; + case 0x75: + return this->_registers.adsr1[7]; + case 0x06: + return this->_registers.adsr2[0]; + case 0x16: + return this->_registers.adsr2[1]; + case 0x26: + return this->_registers.adsr2[2]; + case 0x36: + return this->_registers.adsr2[3]; + case 0x46: + return this->_registers.adsr2[4]; + case 0x56: + return this->_registers.adsr2[5]; + case 0x66: + return this->_registers.adsr2[6]; + case 0x76: + return this->_registers.adsr2[7]; + case 0x07: + return this->_registers.gain[0]; + case 0x17: + return this->_registers.gain[1]; + case 0x27: + return this->_registers.gain[2]; + case 0x37: + return this->_registers.gain[3]; + case 0x47: + return this->_registers.gain[4]; + case 0x57: + return this->_registers.gain[5]; + case 0x67: + return this->_registers.gain[6]; + case 0x77: + return this->_registers.gain[7]; + case 0x08: + return this->_registers.envx[0]; + case 0x18: + return this->_registers.envx[1]; + case 0x28: + return this->_registers.envx[2]; + case 0x38: + return this->_registers.envx[3]; + case 0x48: + return this->_registers.envx[4]; + case 0x58: + return this->_registers.envx[5]; + case 0x68: + return this->_registers.envx[6]; + case 0x78: + return this->_registers.envx[7]; + case 0x09: + return this->_registers.outx[0]; + case 0x19: + return this->_registers.outx[1]; + case 0x29: + return this->_registers.outx[2]; + case 0x39: + return this->_registers.outx[3]; + case 0x49: + return this->_registers.outx[4]; + case 0x59: + return this->_registers.outx[5]; + case 0x69: + return this->_registers.outx[6]; + case 0x79: + return this->_registers.outx[7]; + case 0x0C: + return this->_registers.mvolL; + case 0x1C: + return this->_registers.mvolR; + case 0x2C: + return this->_registers.evolL; + case 0x3C: + return this->_registers.evolR; + case 0x4C: + return this->_registers.kon; + case 0x5C: + return this->_registers.kof; + case 0x6C: + return this->_registers.flg; + case 0x7C: + return this->_registers.endx; + case 0x0D: + return this->_registers.efb; + case 0x1D: + return this->_registers.unused; + case 0x2D: + return this->_registers.pmon; + case 0x3D: + return this->_registers.non; + case 0x4D: + return this->_registers.eon; + case 0x5D: + return this->_registers.dir; + case 0x6D: + return this->_registers.esa; + case 0x7D: + return this->_registers.edl; + case 0x0F: + return this->_registers.coeff[0]; + case 0x1F: + return this->_registers.coeff[1]; + case 0x2F: + return this->_registers.coeff[2]; + case 0x3F: + return this->_registers.coeff[3]; + case 0x4F: + return this->_registers.coeff[4]; + case 0x5F: + return this->_registers.coeff[5]; + case 0x6F: + return this->_registers.coeff[6]; + case 0x7F: + return this->_registers.coeff[7]; + default: + throw InvalidAddress("DSP Internal Registers read", addr); + } + } + + void DSP::write(uint24_t addr, uint8_t data) + { + switch (addr) { + case 0x00: + this->_registers.volL[0] = data; + break; + case 0x10: + this->_registers.volL[1] = data; + break; + case 0x20: + this->_registers.volL[2] = data; + break; + case 0x30: + this->_registers.volL[3] = data; + break; + case 0x40: + this->_registers.volL[4] = data; + break; + case 0x50: + this->_registers.volL[5] = data; + break; + case 0x60: + this->_registers.volL[6] = data; + break; + case 0x70: + this->_registers.volL[7] = data; + break; + case 0x01: + this->_registers.volR[0] = data; + break; + case 0x11: + this->_registers.volR[1] = data; + break; + case 0x21: + this->_registers.volR[2] = data; + break; + case 0x31: + this->_registers.volR[3] = data; + break; + case 0x41: + this->_registers.volR[4] = data; + break; + case 0x51: + this->_registers.volR[5] = data; + break; + case 0x61: + this->_registers.volR[6] = data; + break; + case 0x71: + this->_registers.volR[7] = data; + break; + case 0x02: + this->_registers.pitchL[0] = data; + break; + case 0x12: + this->_registers.pitchL[1] = data; + break; + case 0x22: + this->_registers.pitchL[2] = data; + break; + case 0x32: + this->_registers.pitchL[3] = data; + break; + case 0x42: + this->_registers.pitchL[4] = data; + break; + case 0x52: + this->_registers.pitchL[5] = data; + break; + case 0x62: + this->_registers.pitchL[6] = data; + break; + case 0x72: + this->_registers.pitchL[7] = data; + break; + case 0x03: + this->_registers.pitchH[0] = data; + break; + case 0x13: + this->_registers.pitchH[1] = data; + break; + case 0x23: + this->_registers.pitchH[2] = data; + break; + case 0x33: + this->_registers.pitchH[3] = data; + break; + case 0x43: + this->_registers.pitchH[4] = data; + break; + case 0x53: + this->_registers.pitchH[5] = data; + break; + case 0x63: + this->_registers.pitchH[6] = data; + break; + case 0x73: + this->_registers.pitchH[7] = data; + break; + case 0x04: + this->_registers.srcn[0] = data; + break; + case 0x14: + this->_registers.srcn[1] = data; + break; + case 0x24: + this->_registers.srcn[2] = data; + break; + case 0x34: + this->_registers.srcn[3] = data; + break; + case 0x44: + this->_registers.srcn[4] = data; + break; + case 0x54: + this->_registers.srcn[5] = data; + break; + case 0x64: + this->_registers.srcn[6] = data; + break; + case 0x74: + this->_registers.srcn[7] = data; + break; + case 0x05: + this->_registers.adsr1[0] = data; + break; + case 0x15: + this->_registers.adsr1[1] = data; + break; + case 0x25: + this->_registers.adsr1[2] = data; + break; + case 0x35: + this->_registers.adsr1[3] = data; + break; + case 0x45: + this->_registers.adsr1[4] = data; + break; + case 0x55: + this->_registers.adsr1[5] = data; + break; + case 0x65: + this->_registers.adsr1[6] = data; + break; + case 0x75: + this->_registers.adsr1[7] = data; + break; + case 0x06: + this->_registers.adsr2[0] = data; + break; + case 0x16: + this->_registers.adsr2[1] = data; + break; + case 0x26: + this->_registers.adsr2[2] = data; + break; + case 0x36: + this->_registers.adsr2[3] = data; + break; + case 0x46: + this->_registers.adsr2[4] = data; + break; + case 0x56: + this->_registers.adsr2[5] = data; + break; + case 0x66: + this->_registers.adsr2[6] = data; + break; + case 0x76: + this->_registers.adsr2[7] = data; + break; + case 0x07: + this->_registers.gain[0] = data; + break; + case 0x17: + this->_registers.gain[1] = data; + break; + case 0x27: + this->_registers.gain[2] = data; + break; + case 0x37: + this->_registers.gain[3] = data; + break; + case 0x47: + this->_registers.gain[4] = data; + break; + case 0x57: + this->_registers.gain[5] = data; + break; + case 0x67: + this->_registers.gain[6] = data; + break; + case 0x77: + this->_registers.gain[7] = data; + break; + case 0x08: + this->_registers.envx[0] = data; + break; + case 0x18: + this->_registers.envx[1] = data; + break; + case 0x28: + this->_registers.envx[2] = data; + break; + case 0x38: + this->_registers.envx[3] = data; + break; + case 0x48: + this->_registers.envx[4] = data; + break; + case 0x58: + this->_registers.envx[5] = data; + break; + case 0x68: + this->_registers.envx[6] = data; + break; + case 0x78: + this->_registers.envx[7] = data; + break; + case 0x09: + this->_registers.outx[0] = data; + break; + case 0x19: + this->_registers.outx[1] = data; + break; + case 0x29: + this->_registers.outx[2] = data; + break; + case 0x39: + this->_registers.outx[3] = data; + break; + case 0x49: + this->_registers.outx[4] = data; + break; + case 0x59: + this->_registers.outx[5] = data; + break; + case 0x69: + this->_registers.outx[6] = data; + break; + case 0x79: + this->_registers.outx[7] = data; + break; + case 0x0C: + this->_registers.mvolL = data; + break; + case 0x1C: + this->_registers.mvolR = data; + break; + case 0x2C: + this->_registers.evolL = data; + break; + case 0x3C: + this->_registers.evolR = data; + break; + case 0x4C: + this->_registers.kon = data; + break; + case 0x5C: + this->_registers.kof = data; + break; + case 0x6C: + this->_registers.flg = data; + break; + case 0x7C: + this->_registers.endx = data; + break; + case 0x0D: + this->_registers.efb = data; + break; + case 0x1D: + this->_registers.unused = data; + break; + case 0x2D: + this->_registers.pmon = data; + break; + case 0x3D: + this->_registers.non = data; + break; + case 0x4D: + this->_registers.eon = data; + break; + case 0x5D: + this->_registers.dir = data; + break; + case 0x6D: + this->_registers.esa = data; + break; + case 0x7D: + this->_registers.edl = data; + break; + case 0x0F: + this->_registers.coeff[0] = data; + break; + case 0x1F: + this->_registers.coeff[1] = data; + break; + case 0x2F: + this->_registers.coeff[2] = data; + break; + case 0x3F: + this->_registers.coeff[3] = data; + break; + case 0x4F: + this->_registers.coeff[4] = data; + break; + case 0x5F: + this->_registers.coeff[5] = data; + break; + case 0x6F: + this->_registers.coeff[6] = data; + break; + case 0x7F: + this->_registers.coeff[7] = data; + break; + default: + throw InvalidAddress("DSP Internal Registers write", addr); + } + } +} \ No newline at end of file diff --git a/sources/DSP/DSP.hpp b/sources/DSP/DSP.hpp new file mode 100644 index 0000000..313a16a --- /dev/null +++ b/sources/DSP/DSP.hpp @@ -0,0 +1,175 @@ +// +// Created by Melefo on 28/01/2020. +// + +#ifndef COMSQUARE_DSP_HPP +#define COMSQUARE_DSP_HPP + +#include +#include "../Memory/IMemory.hpp" + +namespace ComSquare::APU::DSP +{ + //! @brief All the registers of the DSP + struct Registers { + //! @brief Left channel volume register + uint8_t volL[8]; + //! @brief Left channel volume register + uint8_t volR[8]; + + //! @brief Lower 8 bits of pitch register + uint8_t pitchL[8]; + //! @brief Higher 8 bits of pitch register + uint8_t pitchH[8]; + + //! @brief Source number register + uint8_t srcn[8]; + + //! @brief Envelope register + uint8_t adsr1[8]; + //! @brief Envelope controllers register + uint8_t adsr2[8]; + //! @brief Gain register + uint8_t gain[8]; + //! @brief Envelope value register + uint8_t envx[8]; + //! @brief Wave height register + uint8_t outx[8]; + + //! @brief Left output of the Main Volume register + uint8_t mvolL; + //! @brief Right output of the Main Volume register + uint8_t mvolR; + + //! @brief Left output of the Echo Volume register + uint8_t evolL; + //! @brief Right output of the Echo Volume register + uint8_t evolR; + + //! @brief Key On register + union { + struct { + bool kon7 : 1; + bool kon6 : 1; + bool kon5 : 1; + bool kon4 : 1; + bool kon3 : 1; + bool kon2 : 1; + bool kon1 : 1; + bool kon0 : 1; + }; + uint8_t kon; + }; + //! @brief Key Off register + union { + struct { + bool kof7 : 1; + bool kof6 : 1; + bool kof5 : 1; + bool kof4 : 1; + bool kof3 : 1; + bool kof2 : 1; + bool kof1 : 1; + bool kof0 : 1; + }; + uint8_t kof; + }; + + //! @brief Flags register + uint8_t flg; + + //! @brief Sample end register + union { + struct { + bool endx7 : 1; + bool endx6 : 1; + bool endx5 : 1; + bool endx4 : 1; + bool endx3 : 1; + bool endx2 : 1; + bool endx1 : 1; + bool endx0 : 1; + }; + uint8_t endx; + }; + + //! @brief Echo feedback register + uint8_t efb; + + //! @brief Not used register + uint8_t unused; + + //! @brief Pitch modulation register + union { + struct { + bool pmon7 : 1; + bool pmon6 : 1; + bool pmon5 : 1; + bool pmon4 : 1; + bool pmon3 : 1; + bool pmon2 : 1; + bool pmon1 : 1; + bool __ : 1; + }; + uint8_t pmon; + }; + + //! @brief Noise enable register + union { + struct { + bool non7 : 1; + bool non6 : 1; + bool non5 : 1; + bool non4 : 1; + bool non3 : 1; + bool non2 : 1; + bool non1 : 1; + bool non0 : 1; + }; + uint8_t non; + }; + //! @brief Echo enable register + union { + struct { + bool eon7 : 1; + bool eon6 : 1; + bool eon5 : 1; + bool eon4 : 1; + bool eon3 : 1; + bool eon2 : 1; + bool eon1 : 1; + bool eon0 : 1; + }; + uint8_t eon; + }; + //! @brief Source Directory offset register + uint8_t dir; + + //! @brief Echo data start register + uint8_t esa; + //! @brief Echo delay size register + uint8_t edl; + //! @brief Echo FIR filter coefficients + uint8_t coeff[8]; + }; + + class DSP : public IMemory { + private: + Registers _registers{}; + public: + explicit DSP(); + + //! @brief Read from the internal DSP register. + //! @param addr The address to read from. The address 0x0 should refer to the first byte of the register. + //! @throw InvalidAddress will be thrown if the address is more than $7F (the number of register). + //! @return Return the value of the register. + uint8_t read(uint24_t addr) override; + //! @brief Write data to the internal DSP register. + //! @param addr The address to write to. The address 0x0 should refer to the first byte of register. + //! @param data The new value of the register. + //! @throw InvalidAddress will be thrown if the address is more than $7F (the number of register). + void write(uint24_t addr, uint8_t data) override; + }; +} + +#endif //COMSQUARE_DSP_HPP