From 453a2575f4571bf41f640947daadc1552588415f Mon Sep 17 00:00:00 2001 From: scawful Date: Thu, 24 Aug 2023 22:54:52 -0400 Subject: [PATCH] Inject SPC700 to APU, add APU and PPU observers --- src/app/emu/apu.h | 10 ++++--- src/app/emu/mem.h | 2 -- src/app/emu/ppu.h | 67 ++++++++++++++++++++++++++------------------ src/app/emu/snes.cc | 4 +++ src/app/emu/snes.h | 4 ++- src/app/emu/spc700.h | 55 +++++++++++++++++++++++++++++++----- 6 files changed, 100 insertions(+), 42 deletions(-) diff --git a/src/app/emu/apu.h b/src/app/emu/apu.h index b7ef7e51..237f90ed 100644 --- a/src/app/emu/apu.h +++ b/src/app/emu/apu.h @@ -15,10 +15,11 @@ const int kApuClockSpeed = 1024000; // 1.024 MHz const int apuSampleRate = 32000; // 32 KHz const int apuClocksPerSample = 64; // 64 clocks per sample -class APU : public SPC700, public Observer { +class APU : public Observer { public: // 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(); @@ -61,11 +62,12 @@ class APU : public SPC700, public Observer { uint8_t ReadDSPMemory(uint16_t address); void WriteDSPMemory(uint16_t address, uint8_t value); - // Other internal methods for handling APU functionality - // Member variables to store internal APU state and resources Memory &memory_; VirtualClock &clock_; + VirtualAudioRAM &aram_; + + SPC700 spc700_{aram_}; std::vector audioSamples_; // Other state variables (registers, counters, channel settings, etc.) }; diff --git a/src/app/emu/mem.h b/src/app/emu/mem.h index a7d7bcc6..b1933c81 100644 --- a/src/app/emu/mem.h +++ b/src/app/emu/mem.h @@ -107,8 +107,6 @@ class ROMInfo { uint16_t checksum; uint16_t nmiVblVector; uint16_t resetVector; - - // Additional methods and constructors }; class Observer { diff --git a/src/app/emu/ppu.h b/src/app/emu/ppu.h index 1be7405f..c8ab89a8 100644 --- a/src/app/emu/ppu.h +++ b/src/app/emu/ppu.h @@ -30,13 +30,19 @@ class IPPU { namespace PPURegisters { +constexpr uint16_t INIDISP = 0x2100; + // OAM Size Register ($2101): Controls the size of the object/sprite, the base // 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. +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 // specified address. +constexpr uint16_t OAMDATA = 0x2104; // 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 // each background layer. +constexpr uint16_t BGMODE = 0x2105; // Screen Pixelation Register ($2106): Sets the pixel size and screen // 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; + +// 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 BG2SC = 0x2108; constexpr uint16_t BG3SC = 0x2109; 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 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 BG1VOFS = 0x210E; constexpr uint16_t BG2HOFS = 0x210F; @@ -83,9 +78,16 @@ constexpr uint16_t BG3HOFS = 0x2111; constexpr uint16_t BG3VOFS = 0x2112; constexpr uint16_t BG4HOFS = 0x2113; constexpr uint16_t BG4VOFS = 0x2114; + +// Video Port Control Register ($2115): Designates the VRAM address increment +// value. 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 VMADDH = 0x2117; + constexpr uint16_t VMDATAL = 0x2118; constexpr uint16_t VMDATAH = 0x2119; constexpr uint16_t M7SEL = 0x211A; @@ -166,12 +168,19 @@ struct MOSAIC { }; 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 vertical_tilemap_count : 1; uint8_t vram_address : 6; }; 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_1 : 4; }; @@ -427,12 +436,10 @@ enum class BackgroundMode { Mode1, // 2 layers, 4bpp (16 colors), 1 layer, 2bpp (4 colors) Mode2, // 2 layers, 4bpp (16 colors), 1 layer for offset-per-tile 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 - // offset-per-tile - Mode5, // 1 layer, 4bpp (16 colors), 1 layer, 2bpp (4 colors), high - // resolution - Mode6, // 1 layer, 4bpp (16 colors), 1 layer for offset-per-tile, high - // resolution + Mode4, // 1 layer, 8bpp (256 colors), 1 layer, 2bpp (4 colors) + // 1 layer for offset-per-tile + Mode5, // 1 layer, 4bpp (16 colors), 1 layer, 2bpp (4 colors) hi-res + Mode6, // 1 layer, 4bpp (16 colors), 1 layer for offset-per-tile, hi-res Mode7, // 1 layer, 8bpp (256 colors), rotation/scaling }; @@ -628,7 +635,7 @@ struct BackgroundLayer { const int kPpuClockSpeed = 5369318; // 5.369318 MHz -class PPU : public Clock { +class PPU : public Clock, public Observer { public: // Initializes the PPU with the necessary resources and dependencies PPU(Memory& memory, VirtualClock& clock) : memory_(memory), clock_(clock) {} @@ -647,6 +654,10 @@ class PPU : public Clock { void Update(); 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 uint8_t ReadRegister(uint16_t address); diff --git a/src/app/emu/snes.cc b/src/app/emu/snes.cc index a540f1b6..4f0d11fe 100644 --- a/src/app/emu/snes.cc +++ b/src/app/emu/snes.cc @@ -156,6 +156,10 @@ ROMInfo SNES::ReadRomHeader(uint32_t offset) { } 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 memory_.Initialize(rom.vector()); diff --git a/src/app/emu/snes.h b/src/app/emu/snes.h index 586c1ff2..7f35722f 100644 --- a/src/app/emu/snes.h +++ b/src/app/emu/snes.h @@ -6,6 +6,7 @@ #include "app/emu/cpu.h" #include "app/emu/dbg.h" #include "app/emu/ppu.h" +#include "app/emu/spc700.h" #include "app/rom.h" namespace yaze { @@ -104,10 +105,11 @@ class SNES : public DMA { // Components of the SNES MemoryImpl memory_; Clock clock_; + AudioRAM audio_ram_; CPU cpu{memory_, clock_}; PPU ppu{memory_, clock_}; - APU apu{memory_, clock_}; + APU apu{memory_, audio_ram_, clock_}; // Helper classes ROMInfo rom_info_; diff --git a/src/app/emu/spc700.h b/src/app/emu/spc700.h index 37cf715a..1a51605d 100644 --- a/src/app/emu/spc700.h +++ b/src/app/emu/spc700.h @@ -9,7 +9,18 @@ namespace yaze { namespace app { 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 std::vector ram; @@ -17,10 +28,12 @@ class AudioRAM { AudioRAM() : ram(ARAM_SIZE, 0) {} // 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 - void write(uint16_t address, uint8_t value) { + void write(uint16_t address, uint8_t value) override { ram[address % ARAM_SIZE] = value; } }; @@ -63,7 +76,11 @@ class SDSP { }; class SPC700 { - AudioRAM aram; + private: + VirtualAudioRAM& aram_; + + public: + explicit SPC700(VirtualAudioRAM& aram) : aram_(aram) {} SDSP sdsp; uint8_t test_register_; uint8_t control_register_; @@ -104,7 +121,7 @@ class SPC700 { return sdsp.readGlobalReg(dsp_address_register_); default: if (address < 0xFFC0) { - return aram.read(address); + return aram_.read(address); } else { // Handle IPL ROM or RAM reads here } @@ -129,7 +146,7 @@ class SPC700 { break; default: if (address < 0xFFC0) { - aram.write(address, value); + aram_.write(address, value); } else { // Handle IPL ROM or RAM writes here } @@ -222,7 +239,31 @@ class SPC700 { 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 // MOVW INCW DECW ADDW SUBW CMPW MUL DIV // DAA DAS