mirror of
https://github.com/zoriya/ComSquare.git
synced 2026-05-26 07:50:04 +00:00
Merge branch 'master' of https://github.com/AnonymusRaccoon/ComSquare
This commit is contained in:
+55
-24
@@ -12,6 +12,33 @@ add_executable(unit_tests
|
||||
tests/testCPU.cpp
|
||||
sources/PPU/PPU.cpp
|
||||
sources/PPU/PPU.hpp
|
||||
sources/SNES.cpp
|
||||
sources/SNES.hpp
|
||||
sources/Memory/MemoryBus.cpp
|
||||
sources/Memory/MemoryBus.hpp
|
||||
sources/Memory/IMemory.hpp
|
||||
sources/Memory/IMemory.cpp
|
||||
sources/PPU/PPU.cpp
|
||||
sources/PPU/PPU.hpp
|
||||
sources/CPU/CPU.cpp
|
||||
sources/CPU/CPU.hpp
|
||||
sources/Cartridge/Cartridge.cpp
|
||||
sources/Cartridge/Cartridge.hpp
|
||||
sources/Exceptions/NotImplementedException.hpp
|
||||
sources/APU/APU.hpp
|
||||
sources/APU/APU.cpp
|
||||
sources/Exceptions/InvalidAddress.hpp
|
||||
sources/Exceptions/InvalidRom.hpp
|
||||
sources/Models/Ints.hpp
|
||||
sources/Models/Ints.hpp
|
||||
sources/Ram/Ram.cpp
|
||||
sources/Ram/Ram.hpp
|
||||
sources/Memory/MemoryShadow.cpp
|
||||
sources/Memory/MemoryShadow.hpp
|
||||
sources/Memory/IRectangleMemory.cpp
|
||||
sources/Memory/IRectangleMemory.hpp
|
||||
sources/DSP/DSP.cpp
|
||||
sources/DSP/DSP.hpp
|
||||
)
|
||||
|
||||
# include criterion & coverage
|
||||
@@ -20,28 +47,32 @@ target_compile_options(unit_tests PUBLIC -fprofile-arcs -ftest-coverage)
|
||||
|
||||
# make app
|
||||
add_executable(ComSquare
|
||||
main.cpp
|
||||
sources/SNES.cpp
|
||||
sources/SNES.hpp
|
||||
sources/Memory/MemoryBus.cpp
|
||||
sources/Memory/MemoryBus.hpp
|
||||
sources/Memory/IMemory.hpp
|
||||
sources/Memory/IMemory.cpp
|
||||
sources/PPU/PPU.cpp
|
||||
sources/PPU/PPU.hpp
|
||||
sources/CPU/CPU.cpp
|
||||
sources/CPU/CPU.hpp
|
||||
sources/Cartridge/Cartridge.cpp
|
||||
sources/Cartridge/Cartridge.hpp
|
||||
sources/Exceptions/NotImplementedException.hpp
|
||||
sources/APU/APU.hpp
|
||||
sources/APU/APU.cpp
|
||||
sources/Exceptions/InvalidAddress.hpp
|
||||
sources/Exceptions/InvalidRom.hpp
|
||||
sources/Models/Ints.hpp
|
||||
sources/Models/Ints.hpp
|
||||
sources/Ram/Ram.cpp
|
||||
sources/Ram/Ram.hpp
|
||||
sources/Memory/MemoryShadow.cpp
|
||||
sources/Memory/MemoryShadow.hpp
|
||||
main.cpp
|
||||
sources/SNES.cpp
|
||||
sources/SNES.hpp
|
||||
sources/Memory/MemoryBus.cpp
|
||||
sources/Memory/MemoryBus.hpp
|
||||
sources/Memory/IMemory.hpp
|
||||
sources/Memory/IMemory.cpp
|
||||
sources/PPU/PPU.cpp
|
||||
sources/PPU/PPU.hpp
|
||||
sources/CPU/CPU.cpp
|
||||
sources/CPU/CPU.hpp
|
||||
sources/Cartridge/Cartridge.cpp
|
||||
sources/Cartridge/Cartridge.hpp
|
||||
sources/Exceptions/NotImplementedException.hpp
|
||||
sources/APU/APU.hpp
|
||||
sources/APU/APU.cpp
|
||||
sources/Exceptions/InvalidAddress.hpp
|
||||
sources/Exceptions/InvalidRom.hpp
|
||||
sources/Models/Ints.hpp
|
||||
sources/Models/Ints.hpp
|
||||
sources/Ram/Ram.cpp
|
||||
sources/Ram/Ram.hpp
|
||||
sources/Memory/MemoryShadow.cpp
|
||||
sources/Memory/MemoryShadow.hpp
|
||||
sources/Memory/IRectangleMemory.cpp
|
||||
sources/Memory/IRectangleMemory.hpp
|
||||
sources/DSP/DSP.cpp
|
||||
sources/DSP/DSP.hpp
|
||||
)
|
||||
|
||||
@@ -6,14 +6,16 @@
|
||||
#include <string>
|
||||
#include "sources/SNES.hpp"
|
||||
|
||||
using namespace ComSquare;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
std::cout << "ComSquare:" << std::endl << "\tUsage: " << argv[0] << " rom_path" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
ComSquare::MemoryBus bus;
|
||||
ComSquare::SNES snes(std::make_shared<ComSquare::MemoryBus>(bus), argv[1]);
|
||||
Memory::MemoryBus bus;
|
||||
SNES snes(std::make_shared<Memory::MemoryBus>(bus), argv[1]);
|
||||
bus.mapComponents(snes);
|
||||
return 0;
|
||||
}
|
||||
+29
-30
@@ -8,39 +8,38 @@
|
||||
|
||||
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);
|
||||
throw InvalidAddress("APU Registers read", addr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,46 +47,46 @@ 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);
|
||||
throw InvalidAddress("APU Registers write", addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-11
@@ -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 {
|
||||
class APU : public Memory::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).
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace ComSquare::CPU
|
||||
{
|
||||
CPU::CPU(std::shared_ptr<ComSquare::MemoryBus> bus)
|
||||
CPU::CPU(std::shared_ptr<Memory::MemoryBus> bus)
|
||||
: _bus(std::move(bus))
|
||||
{ }
|
||||
|
||||
|
||||
+3
-3
@@ -174,7 +174,7 @@ namespace ComSquare::CPU
|
||||
};
|
||||
|
||||
//! @brief The main CPU
|
||||
class CPU : public IMemory {
|
||||
class CPU : public Memory::IMemory {
|
||||
private:
|
||||
//! @brief All the registers of the CPU
|
||||
Registers _registers{};
|
||||
@@ -183,13 +183,13 @@ namespace ComSquare::CPU
|
||||
//! @brief Internal registers of the CPU (accessible from the bus via addr $4200 to $421F).
|
||||
InternalRegisters _internalRegisters{};
|
||||
//! @brief The memory bus to use for read/write.
|
||||
std::shared_ptr<MemoryBus> _bus;
|
||||
std::shared_ptr<Memory::MemoryBus> _bus;
|
||||
|
||||
//! @brief Execute a single instruction.
|
||||
//! @return The number of CPU cycles that the instruction took.
|
||||
int executeInstruction();
|
||||
public:
|
||||
explicit CPU(std::shared_ptr<MemoryBus> bus);
|
||||
explicit CPU(std::shared_ptr<Memory::MemoryBus> bus);
|
||||
//! @brief This function continue to execute the Cartridge code.
|
||||
//! @return The number of CPU cycles that elapsed
|
||||
int update();
|
||||
|
||||
@@ -43,14 +43,14 @@ namespace ComSquare::Cartridge
|
||||
}
|
||||
|
||||
|
||||
uint8_t Cartridge::read(uint24_t addr)
|
||||
uint8_t Cartridge::read_internal(uint24_t addr)
|
||||
{
|
||||
if (addr >= this->_size)
|
||||
throw InvalidAddress("Cartridge read", addr);
|
||||
return this->_data[addr];
|
||||
}
|
||||
|
||||
void Cartridge::write(uint24_t addr, uint8_t data)
|
||||
void Cartridge::write_internal(uint24_t addr, uint8_t data)
|
||||
{
|
||||
if (addr >= this->_size)
|
||||
throw InvalidAddress("Cartridge write", addr);
|
||||
|
||||
@@ -8,16 +8,50 @@
|
||||
#include <string>
|
||||
#include "../Memory/IMemory.hpp"
|
||||
#include "../Models/Ints.hpp"
|
||||
#include "../Memory/IRectangleMemory.hpp"
|
||||
|
||||
namespace ComSquare::Cartridge
|
||||
{
|
||||
enum MappingMode {
|
||||
LowRom,
|
||||
HiRom,
|
||||
ExLowRom,
|
||||
EwHiRom,
|
||||
SA1Rom, // unimplemented
|
||||
FastLoRom,
|
||||
FastHiRom
|
||||
};
|
||||
|
||||
struct Header
|
||||
{
|
||||
//! @brief The name of the game
|
||||
std::string gameName;
|
||||
//! @brief The memory mapping of the ROM.
|
||||
MappingMode mappingMode;
|
||||
//! @brief The rom type (special information about the rom, still don't know what).
|
||||
uint8_t romType;
|
||||
//! @brief The size (in bytes) of the ram
|
||||
uint8_t romSize;
|
||||
//! @brief The size of the SRom inside the cartridge.
|
||||
uint8_t sramSize;
|
||||
//! @brief Creator license ID code.
|
||||
uint8_t creatorID;
|
||||
//! @brief The version of the game
|
||||
uint8_t version;
|
||||
//! @brief Checksum complement
|
||||
uint8_t checksumComplement;
|
||||
//! @brief Checksum
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
//! @brief Contains the rom's memory/instructions.
|
||||
class Cartridge : IMemory {
|
||||
class Cartridge : Memory::IRectangleMemory {
|
||||
private:
|
||||
//! @brief The rom data (contains all the instructions).
|
||||
uint8_t *_data;
|
||||
//! @brief The size of the rom data.
|
||||
size_t _size;
|
||||
|
||||
//! @brief Get the size of a rom from it's path.
|
||||
//! @param romPath The path of the rom to get info from.
|
||||
//! @return The size of the rom.
|
||||
@@ -27,16 +61,19 @@ namespace ComSquare::Cartridge
|
||||
explicit Cartridge(const std::string &romPath);
|
||||
//! @brief Destructor that free the cartridge data.
|
||||
~Cartridge();
|
||||
|
||||
//! @brief The header of the cartridge.
|
||||
Header header;
|
||||
//! @brief Read from the rom.
|
||||
//! @param addr The address to read from. The address 0x0 should refer to the first byte of the rom's memory.
|
||||
//! @throw InvalidAddress will be thrown if the address is more than the size of the rom's memory.
|
||||
//! @return Return the data at the address.
|
||||
uint8_t read(uint24_t addr) override;
|
||||
uint8_t read_internal(uint24_t addr) override;
|
||||
//! @brief Write data to the rom.
|
||||
//! @param addr The address to write to. The address 0x0 should refer to the first byte of the rom's memory.
|
||||
//! @param data The data to write.
|
||||
//! @throw InvalidAddress will be thrown if the address is more than the size of the rom's memory.
|
||||
void write(uint24_t addr, uint8_t data) override;
|
||||
void write_internal(uint24_t addr, uint8_t data) override;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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 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 Registers write", addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 Memory::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
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "IMemory.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
namespace ComSquare
|
||||
namespace ComSquare::Memory
|
||||
{
|
||||
void IMemory::setMemoryRegion(uint24_t start, uint24_t end)
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <vector>
|
||||
#include "../Models/Ints.hpp"
|
||||
|
||||
namespace ComSquare
|
||||
namespace ComSquare::Memory
|
||||
{
|
||||
//! @brief Common interface implemented by all components mapping memory.
|
||||
class IMemory {
|
||||
@@ -38,10 +38,10 @@ namespace ComSquare
|
||||
//! @brief Return true if this component has mapped the address.
|
||||
//! @param addr The address to check.
|
||||
//! @return True if this address is mapped to the component. False otherwise.
|
||||
bool hasMemoryAt(uint24_t addr);
|
||||
virtual bool hasMemoryAt(uint24_t addr);
|
||||
//! @brief Get the first address mapped to this component.
|
||||
//! @return the _start value.
|
||||
uint24_t getStart();
|
||||
virtual uint24_t getStart();
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// Created by anonymus-raccoon on 1/29/20.
|
||||
//
|
||||
|
||||
#include "IRectangleMemory.hpp"
|
||||
#include "../Exceptions/InvalidAddress.hpp"
|
||||
|
||||
namespace ComSquare::Memory
|
||||
{
|
||||
uint8_t IRectangleMemory::read(uint24_t addr)
|
||||
{
|
||||
uint8_t bank = addr >> 16u;
|
||||
uint16_t page = addr;
|
||||
unsigned bankCount = bank - this->_startBank;
|
||||
unsigned pageCount = this->_endPage - this->_startPage;
|
||||
|
||||
if (bank < this->_startBank || bank >= this->_endBank)
|
||||
throw InvalidAddress("Rectangle memory read Invalid Bank", addr);
|
||||
if (page < this->_startPage || page >= this->_endPage)
|
||||
throw InvalidAddress("Rectangle memory read Invalid Page", addr);
|
||||
page -= this->_startPage;
|
||||
page += pageCount * bankCount;
|
||||
return this->read_internal(page);
|
||||
}
|
||||
|
||||
void IRectangleMemory::write(uint24_t addr, uint8_t data)
|
||||
{
|
||||
uint8_t bank = addr >> 16u;
|
||||
uint16_t page = addr;
|
||||
unsigned bankCount = bank - this->_startBank;
|
||||
unsigned pageCount = this->_endPage - this->_startPage;
|
||||
|
||||
if (bank < this->_startBank || bank >= this->_endBank)
|
||||
throw InvalidAddress("Rectangle memory write Invalid Bank", addr);
|
||||
if (page < this->_startPage || page >= this->_endPage)
|
||||
throw InvalidAddress("Rectangle memory write Invalid Page", addr);
|
||||
page -= this->_startPage;
|
||||
page += pageCount * bankCount;
|
||||
this->write_internal(page, data);
|
||||
}
|
||||
|
||||
bool IRectangleMemory::hasMemoryAt(uint24_t addr)
|
||||
{
|
||||
uint8_t bank = addr >> 16u;
|
||||
uint16_t page = addr;
|
||||
|
||||
if (this->_startBank <= bank && bank < this->_endBank)
|
||||
if (this->_startPage <= page && page < this->_endPage)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint24_t IRectangleMemory::getStart()
|
||||
{
|
||||
return this->_startBank + this->_startPage;
|
||||
}
|
||||
|
||||
void IRectangleMemory::setMemoryRegion(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage)
|
||||
{
|
||||
this->_startBank = startBank;
|
||||
this->_endBank = endBank;
|
||||
this->_startPage = startPage;
|
||||
this->_endPage = endPage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// Created by anonymus-raccoon on 1/29/20.
|
||||
//
|
||||
|
||||
#ifndef COMSQUARE_IRECTANGLEMEMORY_HPP
|
||||
#define COMSQUARE_IRECTANGLEMEMORY_HPP
|
||||
|
||||
|
||||
#include "IMemory.hpp"
|
||||
|
||||
namespace ComSquare::Memory
|
||||
{
|
||||
//! @brief Superset of the IMemory to map non continuous rectangle to the memory. (A rectangle that spam across more than one bank but that does not start at 0000 or end at FFFF).
|
||||
class IRectangleMemory : public IMemory {
|
||||
private:
|
||||
//! @brief The first bank to map to.
|
||||
uint8_t _startBank = 0;
|
||||
//! @brief The last bank to map to.
|
||||
uint8_t _endBank = 0;
|
||||
//! @brief The first address of each bank to map.
|
||||
uint16_t _startPage = 0;
|
||||
//! @brief The last address of each bank to map.
|
||||
uint16_t _endPage = 0;
|
||||
public:
|
||||
//! @brief Read data from the component using the same method as the basic IMemory.
|
||||
//! @param addr The local address to read from. 0x0 should refer to the first byte of this component on the fist bank. This method is responsible of mapping to the component's read.
|
||||
//! @throw InvalidAddress if the address is not mapped to the component.
|
||||
//! @return Return the data at the address given as parameter.
|
||||
uint8_t read(uint24_t addr) override;
|
||||
//! @brief Write data to this component using the same method as the basic IMemory.
|
||||
//! @param addr The local address to write data 0x0 should refer to the first byte of this component on the fist bank. This method is responsible of mapping to the component's write.
|
||||
//! @param data The new data to write.
|
||||
//! @throw InvalidAddress if the address is not mapped to the component.
|
||||
void write(uint24_t addr, uint8_t data) override;
|
||||
//! @brief Internal component read. Implement this as you would implement a basic IMemory's read.
|
||||
//! @param addr The local address to read from. 0x0 refer to the first byte of your data and the address is in the component's space. That means that you can consider this address as continuous
|
||||
//! @throw This function should thrown an InvalidAddress for address that are not mapped to the component.
|
||||
//! @return Return the data at the address given as parameter.
|
||||
virtual uint8_t read_internal(uint24_t addr) = 0;
|
||||
//! @brief Internal component write. Implement this as you would implement a basic IMemory's write.
|
||||
//! @param addr The local address to write to. 0x0 refer to the first byte of your data and the address is in the component's space. That means that you can consider this address as continuous
|
||||
//! @param data The new data to write.
|
||||
//! @throw This function should thrown an InvalidAddress for address that are not mapped to the component.
|
||||
virtual void write_internal(uint24_t addr, uint8_t data) = 0;
|
||||
//! @brief Return true if this component has mapped the address.
|
||||
//! @param addr The address to check.
|
||||
//! @return True if this address is mapped to the component. False otherwise.
|
||||
bool hasMemoryAt(uint24_t addr) override;
|
||||
//! @brief Get the first address mapped to this component.
|
||||
//! @return the _start value.
|
||||
uint24_t getStart() override;
|
||||
//! @brief Change starting and ending points of this mapped memory.
|
||||
//! @param startBank The first bank mapped to this component.
|
||||
//! @param endBank The last bank mapped to this component.
|
||||
//! @param startPage The first page mapped to this component (every mapped banks will have this page mapped)
|
||||
//! @param endPage The end page mapped to this component (every mapped banks will have this pages lower than this mapped)
|
||||
//! @warning The start/end address should be a rectangle. To mirror memory, use the MemoryShadow class and not this one.
|
||||
void setMemoryRegion(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //COMSQUARE_IRECTANGLEMEMORY_HPP
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "../SNES.hpp"
|
||||
#include "MemoryShadow.hpp"
|
||||
|
||||
namespace ComSquare
|
||||
namespace ComSquare::Memory
|
||||
{
|
||||
std::shared_ptr<IMemory> MemoryBus::getAccessor(uint24_t addr)
|
||||
{
|
||||
@@ -78,6 +78,6 @@ namespace ComSquare
|
||||
for (uint24_t i = 0x800000; i < 0xC00000; i += 0x10000)
|
||||
this->_mirrorComponents(console, i);
|
||||
|
||||
// TODO should map sram, cartridge etc via the mapping mode of the cartridge.
|
||||
// TODO should map SRam, cartridge etc via the mapping mode of the cartridge.
|
||||
}
|
||||
}
|
||||
@@ -12,34 +12,45 @@
|
||||
|
||||
namespace ComSquare
|
||||
{
|
||||
//! @brief The memory bus is the component responsible of mapping addresses to components address and transmitting the data.
|
||||
class MemoryBus {
|
||||
private:
|
||||
//! @brief The list of components registered inside the bus. Every components that can read/write to a public address should be in this vector.
|
||||
std::vector<std::shared_ptr<IMemory>> _memoryAccessors;
|
||||
//! @brief Helper function to get the components that is responsible of read/write at an address.
|
||||
//! @param addr The address you want to look for.
|
||||
//! @return The components responsible for the address param or nullptr if none was found.
|
||||
std::shared_ptr<IMemory> getAccessor(uint24_t addr);
|
||||
//! @brief The last value read via the memory bus.
|
||||
uint8_t _openbus = 0;
|
||||
//! @brief WRam, CPU, PPU & ALU registers are mirrored to all banks of Q1 & Q3. This function is used for the mirroring.
|
||||
//! @param console All the components.
|
||||
//! @param i Base address for the mirrors.
|
||||
inline void _mirrorComponents(struct SNES &console, int i);
|
||||
public:
|
||||
//! @brief Read data at a global address.
|
||||
//! @param addr The address to read from.
|
||||
//! @return The value that the component returned for this address. If the address was mapped to ram, it simply returned the value. If the address was mapped to a register the component returned the register.
|
||||
uint8_t read(uint24_t addr);
|
||||
//! @brief Write a data to a global address.
|
||||
//! @param addr The address to write to.
|
||||
//! @param data The data to write.
|
||||
void write(uint24_t addr, uint8_t data);
|
||||
//! @brief Map components to the address space using the currently loaded cartridge to set the right mapping mode.
|
||||
//! @param console All the components.
|
||||
void mapComponents(struct SNES &console);
|
||||
};
|
||||
struct SNES;
|
||||
|
||||
namespace Memory
|
||||
{
|
||||
//! @brief The memory bus is the component responsible of mapping addresses to components address and transmitting the data.
|
||||
class MemoryBus {
|
||||
private:
|
||||
//! @brief The list of components registered inside the bus. Every components that can read/write to a public address should be in this vector.
|
||||
std::vector<std::shared_ptr<IMemory>> _memoryAccessors;
|
||||
|
||||
//! @brief Helper function to get the components that is responsible of read/write at an address.
|
||||
//! @param addr The address you want to look for.
|
||||
//! @return The components responsible for the address param or nullptr if none was found.
|
||||
std::shared_ptr<IMemory> getAccessor(uint24_t addr);
|
||||
|
||||
//! @brief The last value read via the memory bus.
|
||||
uint8_t _openbus = 0;
|
||||
|
||||
//! @brief WRam, CPU, PPU & ALU registers are mirrored to all banks of Q1 & Q3. This function is used for the mirroring.
|
||||
//! @param console All the components.
|
||||
//! @param i Base address for the mirrors.
|
||||
inline void _mirrorComponents(SNES &console, int i);
|
||||
|
||||
public:
|
||||
//! @brief Read data at a global address.
|
||||
//! @param addr The address to read from.
|
||||
//! @return The value that the component returned for this address. If the address was mapped to ram, it simply returned the value. If the address was mapped to a register the component returned the register.
|
||||
uint8_t read(uint24_t addr);
|
||||
|
||||
//! @brief Write a data to a global address.
|
||||
//! @param addr The address to write to.
|
||||
//! @param data The data to write.
|
||||
void write(uint24_t addr, uint8_t data);
|
||||
|
||||
//! @brief Map components to the address space using the currently loaded cartridge to set the right mapping mode.
|
||||
//! @param console All the components.
|
||||
void mapComponents(SNES &console);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
namespace ComSquare::PPU
|
||||
{
|
||||
//! @brief The struct containing all the registers the PPU
|
||||
class PPU : public IMemory {
|
||||
class PPU : public Memory::IMemory {
|
||||
private:
|
||||
//! @brief INIDISP Register (F-blank and Brightness)
|
||||
union {
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace ComSquare::Ram
|
||||
{
|
||||
class Ram : public IMemory {
|
||||
class Ram : public Memory::IMemory {
|
||||
private:
|
||||
//! @brief The ram. (Can be used for WRam, SRam, VRam etc)
|
||||
uint8_t *_data;
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace ComSquare
|
||||
{
|
||||
SNES::SNES(const std::shared_ptr<MemoryBus> &bus, const std::string &romPath) :
|
||||
SNES::SNES(const std::shared_ptr<Memory::MemoryBus> &bus, const std::string &romPath) :
|
||||
cpu(new CPU::CPU(bus)),
|
||||
ppu(new PPU::PPU()),
|
||||
apu(new APU::APU()),
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ namespace ComSquare
|
||||
std::shared_ptr<Cartridge::Cartridge> cartridge;
|
||||
std::shared_ptr<Ram::Ram> wram;
|
||||
//! @brief Create all the components using a common memory bus for all of them.
|
||||
SNES(const std::shared_ptr<MemoryBus> &bus, const std::string &ramPath);
|
||||
SNES(const std::shared_ptr<Memory::MemoryBus> &bus, const std::string &ramPath);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user