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
This commit is contained in:
Melefo
2020-01-28 19:46:32 +01:00
parent 589252b34e
commit 4c9af627e0
5 changed files with 763 additions and 39 deletions
+3 -1
View File
@@ -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
)
+27 -28
View File
@@ -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);
+10 -10
View File
@@ -6,11 +6,12 @@
#define COMSQUARE_APU_HPP
#include <memory>
#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> _dsp;
std::shared_ptr<DSP::DSP> _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).
+548
View File
@@ -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);
}
}
}
+175
View File
@@ -0,0 +1,175 @@
//
// Created by Melefo on 28/01/2020.
//
#ifndef COMSQUARE_DSP_HPP
#define COMSQUARE_DSP_HPP
#include <cstdint>
#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