Inject SPC700 to APU, add APU and PPU observers
This commit is contained in:
@@ -15,10 +15,11 @@ const int kApuClockSpeed = 1024000; // 1.024 MHz
|
|||||||
const int apuSampleRate = 32000; // 32 KHz
|
const int apuSampleRate = 32000; // 32 KHz
|
||||||
const int apuClocksPerSample = 64; // 64 clocks per sample
|
const int apuClocksPerSample = 64; // 64 clocks per sample
|
||||||
|
|
||||||
class APU : public SPC700, public Observer {
|
class APU : public Observer {
|
||||||
public:
|
public:
|
||||||
// Initializes the APU with the necessary resources and dependencies
|
// Initializes the APU with the necessary resources and dependencies
|
||||||
APU(Memory &memory, VirtualClock &clock) : memory_(memory), clock_(clock) {}
|
APU(Memory &memory, VirtualAudioRAM &aram, VirtualClock &clock)
|
||||||
|
: memory_(memory), clock_(clock), aram_(aram) {}
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
@@ -61,11 +62,12 @@ class APU : public SPC700, public Observer {
|
|||||||
uint8_t ReadDSPMemory(uint16_t address);
|
uint8_t ReadDSPMemory(uint16_t address);
|
||||||
void WriteDSPMemory(uint16_t address, uint8_t value);
|
void WriteDSPMemory(uint16_t address, uint8_t value);
|
||||||
|
|
||||||
// Other internal methods for handling APU functionality
|
|
||||||
|
|
||||||
// Member variables to store internal APU state and resources
|
// Member variables to store internal APU state and resources
|
||||||
Memory &memory_;
|
Memory &memory_;
|
||||||
VirtualClock &clock_;
|
VirtualClock &clock_;
|
||||||
|
VirtualAudioRAM &aram_;
|
||||||
|
|
||||||
|
SPC700 spc700_{aram_};
|
||||||
std::vector<int16_t> audioSamples_;
|
std::vector<int16_t> audioSamples_;
|
||||||
// Other state variables (registers, counters, channel settings, etc.)
|
// Other state variables (registers, counters, channel settings, etc.)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -107,8 +107,6 @@ class ROMInfo {
|
|||||||
uint16_t checksum;
|
uint16_t checksum;
|
||||||
uint16_t nmiVblVector;
|
uint16_t nmiVblVector;
|
||||||
uint16_t resetVector;
|
uint16_t resetVector;
|
||||||
|
|
||||||
// Additional methods and constructors
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Observer {
|
class Observer {
|
||||||
|
|||||||
@@ -30,13 +30,19 @@ class IPPU {
|
|||||||
|
|
||||||
namespace PPURegisters {
|
namespace PPURegisters {
|
||||||
|
|
||||||
|
constexpr uint16_t INIDISP = 0x2100;
|
||||||
|
|
||||||
// OAM Size Register ($2101): Controls the size of the object/sprite, the base
|
// OAM Size Register ($2101): Controls the size of the object/sprite, the base
|
||||||
// address, and the name selection for the OAM (Object Attribute Memory).
|
// address, and the name selection for the OAM (Object Attribute Memory).
|
||||||
|
constexpr uint16_t OBJSEL = 0x2101;
|
||||||
|
|
||||||
// OAM Address Register ($2102-$2103): Sets the address for accessing OAM data.
|
// OAM Address Register ($2102-$2103): Sets the address for accessing OAM data.
|
||||||
|
constexpr uint16_t OAMADDL = 0x2102;
|
||||||
|
constexpr uint16_t OAMADDH = 0x2103;
|
||||||
|
|
||||||
// OAM Data Register ($2104): Holds the data to be written to the OAM at a
|
// OAM Data Register ($2104): Holds the data to be written to the OAM at a
|
||||||
// specified address.
|
// specified address.
|
||||||
|
constexpr uint16_t OAMDATA = 0x2104;
|
||||||
|
|
||||||
// OAM Data Read Register ($2138): Allows reading data from the OAM.
|
// OAM Data Read Register ($2138): Allows reading data from the OAM.
|
||||||
|
|
||||||
@@ -44,37 +50,26 @@ namespace PPURegisters {
|
|||||||
|
|
||||||
// Screen Mode Register ($2105): Defines the screen mode and character size for
|
// Screen Mode Register ($2105): Defines the screen mode and character size for
|
||||||
// each background layer.
|
// each background layer.
|
||||||
|
constexpr uint16_t BGMODE = 0x2105;
|
||||||
|
|
||||||
// Screen Pixelation Register ($2106): Sets the pixel size and screen
|
// Screen Pixelation Register ($2106): Sets the pixel size and screen
|
||||||
// designation for the mosaic display.
|
// designation for the mosaic display.
|
||||||
|
|
||||||
// BGx VRAM Location Registers ($2107-$210A): Define the location in VRAM where
|
|
||||||
// the background screen data is stored.
|
|
||||||
|
|
||||||
// BGx & BGy VRAM Location Registers ($210B-$210C): Set the base address for BG
|
|
||||||
// character data in VRAM.
|
|
||||||
|
|
||||||
// BGx Scroll Registers ($210D-$2114): Control the horizontal and vertical
|
|
||||||
// scroll values for each background layer.
|
|
||||||
|
|
||||||
// Video Port Control Register ($2115): Designates the VRAM address increment
|
|
||||||
// value.
|
|
||||||
|
|
||||||
// Video Port Address Register ($2116-$2117): Sets the initial address for
|
|
||||||
// reading from or writing to VRAM.
|
|
||||||
constexpr uint16_t INIDISP = 0x2100;
|
|
||||||
constexpr uint16_t OBJSEL = 0x2101;
|
|
||||||
constexpr uint16_t OAMADDL = 0x2102;
|
|
||||||
constexpr uint16_t OAMADDH = 0x2103;
|
|
||||||
constexpr uint16_t OAMDATA = 0x2104;
|
|
||||||
constexpr uint16_t BGMODE = 0x2105;
|
|
||||||
constexpr uint16_t MOSAIC = 0x2106;
|
constexpr uint16_t MOSAIC = 0x2106;
|
||||||
|
|
||||||
|
// BGx VRAM Location Registers ($2107-$210A)
|
||||||
|
// Define the location in VRAM where the background screen data is stored.
|
||||||
constexpr uint16_t BG1SC = 0x2107;
|
constexpr uint16_t BG1SC = 0x2107;
|
||||||
constexpr uint16_t BG2SC = 0x2108;
|
constexpr uint16_t BG2SC = 0x2108;
|
||||||
constexpr uint16_t BG3SC = 0x2109;
|
constexpr uint16_t BG3SC = 0x2109;
|
||||||
constexpr uint16_t BG4SC = 0x210A;
|
constexpr uint16_t BG4SC = 0x210A;
|
||||||
|
|
||||||
|
// BGx & BGy VRAM Location Registers ($210B-$210C):
|
||||||
|
// Set the base address for BG character data in VRAM.
|
||||||
constexpr uint16_t BG12NBA = 0x210B;
|
constexpr uint16_t BG12NBA = 0x210B;
|
||||||
constexpr uint16_t BG34NBA = 0x210C;
|
constexpr uint16_t BG34NBA = 0x210C;
|
||||||
|
|
||||||
|
// BGx Scroll Registers ($210D-$2114): Control the horizontal and vertical
|
||||||
|
// scroll values for each background layer.
|
||||||
constexpr uint16_t BG1HOFS = 0x210D;
|
constexpr uint16_t BG1HOFS = 0x210D;
|
||||||
constexpr uint16_t BG1VOFS = 0x210E;
|
constexpr uint16_t BG1VOFS = 0x210E;
|
||||||
constexpr uint16_t BG2HOFS = 0x210F;
|
constexpr uint16_t BG2HOFS = 0x210F;
|
||||||
@@ -83,9 +78,16 @@ constexpr uint16_t BG3HOFS = 0x2111;
|
|||||||
constexpr uint16_t BG3VOFS = 0x2112;
|
constexpr uint16_t BG3VOFS = 0x2112;
|
||||||
constexpr uint16_t BG4HOFS = 0x2113;
|
constexpr uint16_t BG4HOFS = 0x2113;
|
||||||
constexpr uint16_t BG4VOFS = 0x2114;
|
constexpr uint16_t BG4VOFS = 0x2114;
|
||||||
|
|
||||||
|
// Video Port Control Register ($2115): Designates the VRAM address increment
|
||||||
|
// value.
|
||||||
constexpr uint16_t VMAIN = 0x2115;
|
constexpr uint16_t VMAIN = 0x2115;
|
||||||
|
|
||||||
|
// Video Port Address Register ($2116-$2117): Sets the initial address for
|
||||||
|
// reading from or writing to VRAM.
|
||||||
constexpr uint16_t VMADDL = 0x2116;
|
constexpr uint16_t VMADDL = 0x2116;
|
||||||
constexpr uint16_t VMADDH = 0x2117;
|
constexpr uint16_t VMADDH = 0x2117;
|
||||||
|
|
||||||
constexpr uint16_t VMDATAL = 0x2118;
|
constexpr uint16_t VMDATAL = 0x2118;
|
||||||
constexpr uint16_t VMDATAH = 0x2119;
|
constexpr uint16_t VMDATAH = 0x2119;
|
||||||
constexpr uint16_t M7SEL = 0x211A;
|
constexpr uint16_t M7SEL = 0x211A;
|
||||||
@@ -166,12 +168,19 @@ struct MOSAIC {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct BGSC {
|
struct BGSC {
|
||||||
|
explicit BGSC(uint8_t value)
|
||||||
|
: horizontal_tilemap_count(value & 0x01),
|
||||||
|
vertical_tilemap_count((value >> 1) & 0x01),
|
||||||
|
vram_address((value >> 2) & 0x3F) {}
|
||||||
uint8_t horizontal_tilemap_count : 1;
|
uint8_t horizontal_tilemap_count : 1;
|
||||||
uint8_t vertical_tilemap_count : 1;
|
uint8_t vertical_tilemap_count : 1;
|
||||||
uint8_t vram_address : 6;
|
uint8_t vram_address : 6;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BGNBA {
|
struct BGNBA {
|
||||||
|
explicit BGNBA(uint8_t value)
|
||||||
|
: chr_base_address_2(value & 0x0F),
|
||||||
|
chr_base_address_1((value >> 4) & 0x0F) {}
|
||||||
uint8_t chr_base_address_2 : 4;
|
uint8_t chr_base_address_2 : 4;
|
||||||
uint8_t chr_base_address_1 : 4;
|
uint8_t chr_base_address_1 : 4;
|
||||||
};
|
};
|
||||||
@@ -427,12 +436,10 @@ enum class BackgroundMode {
|
|||||||
Mode1, // 2 layers, 4bpp (16 colors), 1 layer, 2bpp (4 colors)
|
Mode1, // 2 layers, 4bpp (16 colors), 1 layer, 2bpp (4 colors)
|
||||||
Mode2, // 2 layers, 4bpp (16 colors), 1 layer for offset-per-tile
|
Mode2, // 2 layers, 4bpp (16 colors), 1 layer for offset-per-tile
|
||||||
Mode3, // 1 layer, 8bpp (256 colors), 1 layer, 4bpp (16 colors)
|
Mode3, // 1 layer, 8bpp (256 colors), 1 layer, 4bpp (16 colors)
|
||||||
Mode4, // 1 layer, 8bpp (256 colors), 1 layer, 2bpp (4 colors), 1 layer for
|
Mode4, // 1 layer, 8bpp (256 colors), 1 layer, 2bpp (4 colors)
|
||||||
// offset-per-tile
|
// 1 layer for offset-per-tile
|
||||||
Mode5, // 1 layer, 4bpp (16 colors), 1 layer, 2bpp (4 colors), high
|
Mode5, // 1 layer, 4bpp (16 colors), 1 layer, 2bpp (4 colors) hi-res
|
||||||
// resolution
|
Mode6, // 1 layer, 4bpp (16 colors), 1 layer for offset-per-tile, hi-res
|
||||||
Mode6, // 1 layer, 4bpp (16 colors), 1 layer for offset-per-tile, high
|
|
||||||
// resolution
|
|
||||||
Mode7, // 1 layer, 8bpp (256 colors), rotation/scaling
|
Mode7, // 1 layer, 8bpp (256 colors), rotation/scaling
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -628,7 +635,7 @@ struct BackgroundLayer {
|
|||||||
|
|
||||||
const int kPpuClockSpeed = 5369318; // 5.369318 MHz
|
const int kPpuClockSpeed = 5369318; // 5.369318 MHz
|
||||||
|
|
||||||
class PPU : public Clock {
|
class PPU : public Clock, public Observer {
|
||||||
public:
|
public:
|
||||||
// Initializes the PPU with the necessary resources and dependencies
|
// Initializes the PPU with the necessary resources and dependencies
|
||||||
PPU(Memory& memory, VirtualClock& clock) : memory_(memory), clock_(clock) {}
|
PPU(Memory& memory, VirtualClock& clock) : memory_(memory), clock_(clock) {}
|
||||||
@@ -647,6 +654,10 @@ class PPU : public Clock {
|
|||||||
void Update();
|
void Update();
|
||||||
void UpdateInternalState(int cycles);
|
void UpdateInternalState(int cycles);
|
||||||
|
|
||||||
|
void Notify(uint32_t address, uint8_t data) override {
|
||||||
|
// Handle communication in the PPU.
|
||||||
|
}
|
||||||
|
|
||||||
// Reads a byte from the specified PPU register
|
// Reads a byte from the specified PPU register
|
||||||
uint8_t ReadRegister(uint16_t address);
|
uint8_t ReadRegister(uint16_t address);
|
||||||
|
|
||||||
|
|||||||
@@ -156,6 +156,10 @@ ROMInfo SNES::ReadRomHeader(uint32_t offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SNES::Init(ROM& rom) {
|
void SNES::Init(ROM& rom) {
|
||||||
|
// Setup observers for the memory space
|
||||||
|
memory_.AddObserver(&apu);
|
||||||
|
memory_.AddObserver(&ppu);
|
||||||
|
|
||||||
// Load the ROM into memory and set up the memory mapping
|
// Load the ROM into memory and set up the memory mapping
|
||||||
memory_.Initialize(rom.vector());
|
memory_.Initialize(rom.vector());
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "app/emu/cpu.h"
|
#include "app/emu/cpu.h"
|
||||||
#include "app/emu/dbg.h"
|
#include "app/emu/dbg.h"
|
||||||
#include "app/emu/ppu.h"
|
#include "app/emu/ppu.h"
|
||||||
|
#include "app/emu/spc700.h"
|
||||||
#include "app/rom.h"
|
#include "app/rom.h"
|
||||||
|
|
||||||
namespace yaze {
|
namespace yaze {
|
||||||
@@ -104,10 +105,11 @@ class SNES : public DMA {
|
|||||||
// Components of the SNES
|
// Components of the SNES
|
||||||
MemoryImpl memory_;
|
MemoryImpl memory_;
|
||||||
Clock clock_;
|
Clock clock_;
|
||||||
|
AudioRAM audio_ram_;
|
||||||
|
|
||||||
CPU cpu{memory_, clock_};
|
CPU cpu{memory_, clock_};
|
||||||
PPU ppu{memory_, clock_};
|
PPU ppu{memory_, clock_};
|
||||||
APU apu{memory_, clock_};
|
APU apu{memory_, audio_ram_, clock_};
|
||||||
|
|
||||||
// Helper classes
|
// Helper classes
|
||||||
ROMInfo rom_info_;
|
ROMInfo rom_info_;
|
||||||
|
|||||||
@@ -9,7 +9,18 @@ namespace yaze {
|
|||||||
namespace app {
|
namespace app {
|
||||||
namespace emu {
|
namespace emu {
|
||||||
|
|
||||||
class AudioRAM {
|
class VirtualAudioRAM {
|
||||||
|
public:
|
||||||
|
virtual ~VirtualAudioRAM() = default;
|
||||||
|
|
||||||
|
// Read a byte from ARAM at the given address
|
||||||
|
virtual uint8_t read(uint16_t address) const = 0;
|
||||||
|
|
||||||
|
// Write a byte to ARAM at the given address
|
||||||
|
virtual void write(uint16_t address, uint8_t value) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AudioRAM : public VirtualAudioRAM {
|
||||||
static const size_t ARAM_SIZE = 64 * 1024; // 64 KB
|
static const size_t ARAM_SIZE = 64 * 1024; // 64 KB
|
||||||
std::vector<uint8_t> ram;
|
std::vector<uint8_t> ram;
|
||||||
|
|
||||||
@@ -17,10 +28,12 @@ class AudioRAM {
|
|||||||
AudioRAM() : ram(ARAM_SIZE, 0) {}
|
AudioRAM() : ram(ARAM_SIZE, 0) {}
|
||||||
|
|
||||||
// Read a byte from ARAM at the given address
|
// Read a byte from ARAM at the given address
|
||||||
uint8_t read(uint16_t address) const { return ram[address % ARAM_SIZE]; }
|
uint8_t read(uint16_t address) const override {
|
||||||
|
return ram[address % ARAM_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
// Write a byte to ARAM at the given address
|
// Write a byte to ARAM at the given address
|
||||||
void write(uint16_t address, uint8_t value) {
|
void write(uint16_t address, uint8_t value) override {
|
||||||
ram[address % ARAM_SIZE] = value;
|
ram[address % ARAM_SIZE] = value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -63,7 +76,11 @@ class SDSP {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class SPC700 {
|
class SPC700 {
|
||||||
AudioRAM aram;
|
private:
|
||||||
|
VirtualAudioRAM& aram_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SPC700(VirtualAudioRAM& aram) : aram_(aram) {}
|
||||||
SDSP sdsp;
|
SDSP sdsp;
|
||||||
uint8_t test_register_;
|
uint8_t test_register_;
|
||||||
uint8_t control_register_;
|
uint8_t control_register_;
|
||||||
@@ -104,7 +121,7 @@ class SPC700 {
|
|||||||
return sdsp.readGlobalReg(dsp_address_register_);
|
return sdsp.readGlobalReg(dsp_address_register_);
|
||||||
default:
|
default:
|
||||||
if (address < 0xFFC0) {
|
if (address < 0xFFC0) {
|
||||||
return aram.read(address);
|
return aram_.read(address);
|
||||||
} else {
|
} else {
|
||||||
// Handle IPL ROM or RAM reads here
|
// Handle IPL ROM or RAM reads here
|
||||||
}
|
}
|
||||||
@@ -129,7 +146,7 @@ class SPC700 {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (address < 0xFFC0) {
|
if (address < 0xFFC0) {
|
||||||
aram.write(address, value);
|
aram_.write(address, value);
|
||||||
} else {
|
} else {
|
||||||
// Handle IPL ROM or RAM writes here
|
// Handle IPL ROM or RAM writes here
|
||||||
}
|
}
|
||||||
@@ -222,7 +239,31 @@ class SPC700 {
|
|||||||
PSW.N = (result & 0x80);
|
PSW.N = (result & 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
// AND OR EOR ASL LSR ROL XCN
|
// AND
|
||||||
|
void AND(uint8_t operand, bool isImmediate = false) {
|
||||||
|
uint8_t value = isImmediate ? imm() : operand;
|
||||||
|
A &= value;
|
||||||
|
PSW.Z = (A == 0);
|
||||||
|
PSW.N = (A & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OR
|
||||||
|
void OR(uint8_t operand, bool isImmediate = false) {
|
||||||
|
uint8_t value = isImmediate ? imm() : operand;
|
||||||
|
A |= value;
|
||||||
|
PSW.Z = (A == 0);
|
||||||
|
PSW.N = (A & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
// EOR
|
||||||
|
void EOR(uint8_t operand, bool isImmediate = false) {
|
||||||
|
uint8_t value = isImmediate ? imm() : operand;
|
||||||
|
A ^= value;
|
||||||
|
PSW.Z = (A == 0);
|
||||||
|
PSW.N = (A & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ASL LSR ROL XCN
|
||||||
// INC DEC
|
// INC DEC
|
||||||
// MOVW INCW DECW ADDW SUBW CMPW MUL DIV
|
// MOVW INCW DECW ADDW SUBW CMPW MUL DIV
|
||||||
// DAA DAS
|
// DAA DAS
|
||||||
|
|||||||
Reference in New Issue
Block a user