From a024b5993ea98ab9fe0031db0d1b04772db32222 Mon Sep 17 00:00:00 2001 From: scawful Date: Sun, 20 Aug 2023 11:47:35 -0400 Subject: [PATCH] Add PPU registers and structs --- src/app/emu/ppu.cc | 172 +++++++++++- src/app/emu/ppu.h | 657 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 809 insertions(+), 20 deletions(-) diff --git a/src/app/emu/ppu.cc b/src/app/emu/ppu.cc index 604ba491..b5c79657 100644 --- a/src/app/emu/ppu.cc +++ b/src/app/emu/ppu.cc @@ -12,11 +12,6 @@ namespace emu { PPU::PPU(Memory& memory) : memory_(memory) {} -void PPU::Init() { - // Initialize registers - // ... -} - void PPU::RenderScanline() { // Render background layers // ... @@ -26,22 +21,113 @@ void PPU::RenderScanline() { } void PPU::Run(int cycles) { - // ... + // Fetch the tile data from VRAM, tile map data from memory, and palette data + // from CGRAM + UpdateTileData(); // Fetches the tile data from VRAM and stores it in an + // internal buffer + UpdateTileMapData(); // Fetches the tile map data from memory and stores it + // in an internal buffer + UpdatePaletteData(); // Fetches the palette data from CGRAM and stores it in + // an internal buffer + + // Render the background layers, taking into account the current mode and + // layer priorities + for (int layer = 1; layer <= 4; ++layer) { + RenderBackground(layer); // Renders the specified background layer into an + // internal layer buffer + } + + // Render the sprite layer, taking into account sprite priorities and + // transparency + RenderSprites(); // Renders the sprite layer into an internal sprite buffer + + // Apply effects to the layers, such as scaling, rotation, and blending + ApplyEffects(); // Applies effects to the layers based on the current mode + // and register settings + + // Combine the layers into a single image and store it in the frame buffer + ComposeLayers(); // Combines the layers into a single image and stores it in + // the frame buffer + + // Display the frame buffer on the screen + DisplayFrameBuffer(); // Sends the frame buffer to the display hardware + // (e.g., SDL2) } +// Reads a byte from the specified PPU register uint8_t PPU::ReadRegister(uint16_t address) { - // ... + switch (address) { + case 0x2102: // OAM Address Register (low byte) + return oam_address_ & 0xFF; + case 0x2103: // OAM Address Register (high byte) + return (oam_address_ >> 8) & 0xFF; + // ... handle other PPU registers + default: + // Invalid register address, return 0 + return 0; + } } +// Writes a byte to the specified PPU register void PPU::WriteRegister(uint16_t address, uint8_t value) { - // ... -} - -const std::vector& PPU::GetFrameBuffer() const { - // ... + switch (address) { + case 0x2102: // OAM Address Register (low byte) + oam_address_ = (oam_address_ & 0xFF00) | value; + break; + case 0x2103: // OAM Address Register (high byte) + oam_address_ = (oam_address_ & 0x00FF) | (value << 8); + break; + // ... handle other PPU registers + default: + // Invalid register address, do nothing + break; + } } void PPU::UpdateModeSettings() { + // Read the PPU mode settings from the PPU registers + uint8_t modeRegister = ReadRegister(PPURegisters::INIDISP); + + // Extract the PPU mode and other relevant settings from the register value + BackgroundMode mode = static_cast( + modeRegister & 0x07); // Mode is stored in the lower 3 bits + bool backgroundEnabled = + (modeRegister >> 7) & 0x01; // Background enabled flag is stored in bit 7 + bool spritesEnabled = + (modeRegister >> 6) & 0x01; // Sprites enabled flag is stored in bit 6 + + // Update the internal mode settings based on the extracted values + // modeSettings_.backgroundEnabled = backgroundEnabled; + // modeSettings_.spritesEnabled = spritesEnabled; + + // Update the tilemap, tile data, and palette settings based on the selected + // mode + switch (mode) { + case BackgroundMode::Mode0: + // Mode 0: 4 background layers, all with 2bpp + // Update the tilemap, tile data, and palette settings accordingly + // ... + break; + + case BackgroundMode::Mode1: + // Mode 1: 3 background layers (2 with 4bpp, 1 with 2bpp) + // Update the tilemap, tile data, and palette settings accordingly + // ... + break; + + // Handle other modes and update the settings accordingly + // ... + + default: + // Invalid mode setting, handle the error or set default settings + // ... + break; + } + + // Update the internal state of the PPU based on the mode settings + // Update tile data, tilemaps, sprites, and palette based on the mode settings + UpdateTileData(); + UpdatePaletteData(); // ... } @@ -73,6 +159,68 @@ void PPU::WriteOAM(uint16_t address, uint8_t value) { // ... } +uint8_t PPU::ReadCGRAM(uint16_t address) { + // ... +} + +void PPU::WriteCGRAM(uint16_t address, uint8_t value) { + // ... +} + +// Internal methods to handle PPU rendering and operations +void PPU::UpdateTileData() { + // Fetch tile data from VRAM and store it in the internal buffer + for (uint16_t address = 0; address < tileDataSize_; ++address) { + tileData_[address] = memory_.ReadByte(vramBaseAddress_ + address); + } + + // Update the tilemap entries based on the fetched tile data + for (uint16_t entryIndex = 0; entryIndex < tilemap_.entries.size(); + ++entryIndex) { + uint16_t tilemapAddress = + tilemapBaseAddress_ + entryIndex * sizeof(TilemapEntry); + uint16_t tileData = memory_.ReadWord( + tilemapAddress); // Assume ReadWord reads a 16-bit value from VRAM + + // Extract tilemap entry attributes from the tile data + TilemapEntry entry; + entry.tileNumber = + tileData & 0x03FF; // Tile number is stored in the lower 10 bits + entry.palette = (tileData >> 10) & 0x07; // Palette is stored in bits 10-12 + entry.priority = (tileData >> 13) & 0x01; // Priority is stored in bit 13 + entry.hFlip = + (tileData >> 14) & 0x01; // Horizontal flip is stored in bit 14 + entry.vFlip = (tileData >> 15) & 0x01; // Vertical flip is stored in bit 15 + + tilemap_.entries[entryIndex] = entry; + } + + // Update the sprites based on the fetched tile data + for (uint16_t spriteIndex = 0; spriteIndex < sprites_.size(); ++spriteIndex) { + uint16_t spriteAddress = + oamBaseAddress_ + spriteIndex * sizeof(SpriteAttributes); + uint16_t spriteData = memory_.ReadWord( + spriteAddress); // Assume ReadWord reads a 16-bit value from VRAM + + // Extract sprite attributes from the sprite data + SpriteAttributes sprite; + sprite.x = memory_.ReadByte(spriteAddress); + sprite.y = memory_.ReadByte(spriteAddress + 1); + sprite.tile = + spriteData & 0x01FF; // Tile number is stored in the lower 9 bits + sprite.palette = + (spriteData >> 9) & 0x07; // Palette is stored in bits 9-11 + sprite.priority = + (spriteData >> 12) & 0x03; // Priority is stored in bits 12-13 + sprite.hFlip = + (spriteData >> 14) & 0x01; // Horizontal flip is stored in bit 14 + sprite.vFlip = + (spriteData >> 15) & 0x01; // Vertical flip is stored in bit 15 + + sprites_[spriteIndex] = sprite; + } +} + } // namespace emu } // namespace app } // namespace yaze diff --git a/src/app/emu/ppu.h b/src/app/emu/ppu.h index d9adcd4b..59d6ffaa 100644 --- a/src/app/emu/ppu.h +++ b/src/app/emu/ppu.h @@ -10,15 +10,609 @@ namespace yaze { namespace app { namespace emu { +class IPPU { + public: + virtual ~IPPU() = default; + + virtual void writeRegister(uint16_t address, uint8_t data) = 0; + virtual uint8_t readRegister(uint16_t address) const = 0; + virtual void setOAMData(const std::vector& data) = 0; + virtual std::vector getOAMData() const = 0; + virtual void setVRAMData(const std::vector& data) = 0; + virtual std::vector getVRAMData() const = 0; + virtual void setCGRAMData(const std::vector& data) = 0; + virtual std::vector getCGRAMData() const = 0; + virtual void renderFrame() = 0; + virtual std::vector getFrameBuffer() const = 0; +}; + +namespace PPURegisters { + +// OAM Size Register ($2101): Controls the size of the object/sprite, the base +// address, and the name selection for the OAM (Object Attribute Memory). + +// OAM Address Register ($2102-$2103): Sets the address for accessing OAM data. + +// OAM Data Register ($2104): Holds the data to be written to the OAM at a +// specified address. + +// OAM Data Read Register ($2138): Allows reading data from the OAM. + +// Screen Display Register ($2100): Controls screen on/off and brightness. + +// Screen Mode Register ($2105): Defines the screen mode and character size for +// each background layer. + +// 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; +constexpr uint16_t BG1SC = 0x2107; +constexpr uint16_t BG2SC = 0x2108; +constexpr uint16_t BG3SC = 0x2109; +constexpr uint16_t BG4SC = 0x210A; +constexpr uint16_t BG12NBA = 0x210B; +constexpr uint16_t BG34NBA = 0x210C; +constexpr uint16_t BG1HOFS = 0x210D; +constexpr uint16_t BG1VOFS = 0x210E; +constexpr uint16_t BG2HOFS = 0x210F; +constexpr uint16_t BG2VOFS = 0x2110; +constexpr uint16_t BG3HOFS = 0x2111; +constexpr uint16_t BG3VOFS = 0x2112; +constexpr uint16_t BG4HOFS = 0x2113; +constexpr uint16_t BG4VOFS = 0x2114; +constexpr uint16_t VMAIN = 0x2115; +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; +constexpr uint16_t M7A = 0x211B; +constexpr uint16_t M7B = 0x211C; +constexpr uint16_t M7C = 0x211D; +constexpr uint16_t M7D = 0x211E; +constexpr uint16_t M7X = 0x211F; +constexpr uint16_t M7Y = 0x2120; +constexpr uint16_t CGADD = 0x2121; +constexpr uint16_t CGDATA = 0x2122; +constexpr uint16_t W12SEL = 0x2123; +constexpr uint16_t W34SEL = 0x2124; +constexpr uint16_t WOBJSEL = 0x2125; +constexpr uint16_t WH0 = 0x2126; +constexpr uint16_t WH1 = 0x2127; +constexpr uint16_t WH2 = 0x2128; +constexpr uint16_t WH3 = 0x2129; +constexpr uint16_t WBGLOG = 0x212A; +constexpr uint16_t WOBJLOG = 0x212B; +constexpr uint16_t TM = 0x212C; +constexpr uint16_t TS = 0x212D; +constexpr uint16_t TMW = 0x212E; +constexpr uint16_t TSW = 0x212F; +constexpr uint16_t CGWSEL = 0x2130; +constexpr uint16_t CGADSUB = 0x2131; +constexpr uint16_t COLDATA = 0x2132; +constexpr uint16_t SETINI = 0x2133; +constexpr uint16_t MPYL = 0x2134; +constexpr uint16_t MPYM = 0x2135; +constexpr uint16_t MPYH = 0x2136; +constexpr uint16_t SLHV = 0x2137; +constexpr uint16_t OAMDATAREAD = 0x2138; +constexpr uint16_t VMDATALREAD = 0x2139; +constexpr uint16_t VMDATAHREAD = 0x213A; +constexpr uint16_t CGDATAREAD = 0x213B; +constexpr uint16_t OPHCT = 0x213C; +constexpr uint16_t OPVCT = 0x213D; +constexpr uint16_t STAT77 = 0x213E; +constexpr uint16_t STAT78 = 0x213F; + +struct INIDISP { + uint8_t brightness : 4; + uint8_t forced_blanking : 1; + uint8_t unused : 3; +}; + +struct OBJSEL { + uint8_t name_base_address : 2; + uint8_t name_secondary_select : 1; + uint8_t sprite_size : 2; + uint8_t unused : 3; +}; + +struct OAMADDL { + uint8_t address : 8; +}; + +struct OAMADDH { + uint8_t high_bit : 1; + uint8_t priority_rotation : 1; + uint8_t unused : 6; +}; + +struct OAMDATA { + uint8_t data : 8; +}; + +struct BGMODE { + uint8_t bg_mode : 3; + uint8_t bg3_priority : 1; + uint8_t tile_size : 4; +}; + +struct MOSAIC { + uint8_t bg_enable : 4; + uint8_t mosaic_size : 4; +}; + +struct BGSC { + uint8_t horizontal_tilemap_count : 1; + uint8_t vertical_tilemap_count : 1; + uint8_t vram_address : 6; +}; + +struct BGNBA { + uint8_t chr_base_address_2 : 4; + uint8_t chr_base_address_1 : 4; +}; + +struct BGHOFS { + uint16_t horizontal_scroll : 10; + uint8_t unused : 6; +}; + +struct BGVOFS { + uint16_t vertical_scroll : 10; + uint8_t unused : 6; +}; + +struct VMAIN { + uint8_t increment_size : 2; + uint8_t remapping : 2; + uint8_t address_increment_mode : 1; + uint8_t unused : 3; +}; + +struct VMADDL { + uint8_t address_low : 8; +}; + +struct VMADDH { + uint8_t address_high : 8; +}; + +struct VMDATA { + uint8_t data : 8; +}; + +struct M7SEL { + uint8_t flip_horizontal : 1; + uint8_t flip_vertical : 1; + uint8_t fill : 1; + uint8_t tilemap_repeat : 1; + uint8_t unused : 4; +}; + +struct M7A { + int16_t matrix_a : 16; +}; + +struct M7B { + int16_t matrix_b : 16; +}; + +struct M7C { + int16_t matrix_c : 16; +}; + +struct M7D { + int16_t matrix_d : 16; +}; + +struct M7X { + uint16_t center_x : 13; + uint8_t unused : 3; +}; + +struct M7Y { + uint16_t center_y : 13; + uint8_t unused : 3; +}; + +struct CGADD { + uint8_t address : 8; +}; + +struct CGDATA { + uint16_t data : 15; + uint8_t unused : 1; +}; + +struct W12SEL { + uint8_t enable_bg1_a : 1; + uint8_t invert_bg1_a : 1; + uint8_t enable_bg1_b : 1; + uint8_t invert_bg1_b : 1; + uint8_t enable_bg2_c : 1; + uint8_t invert_bg2_c : 1; + uint8_t enable_bg2_d : 1; + uint8_t invert_bg2_d : 1; +}; + +struct W34SEL { + uint8_t enable_bg3_e : 1; + uint8_t invert_bg3_e : 1; + uint8_t enable_bg3_f : 1; + uint8_t invert_bg3_f : 1; + uint8_t enable_bg4_g : 1; + uint8_t invert_bg4_g : 1; + uint8_t enable_bg4_h : 1; + uint8_t invert_bg4_h : 1; +}; + +struct WOBJSEL { + uint8_t enable_obj_i : 1; + uint8_t invert_obj_i : 1; + uint8_t enable_obj_j : 1; + uint8_t invert_obj_j : 1; + uint8_t enable_color_k : 1; + uint8_t invert_color_k : 1; + uint8_t enable_color_l : 1; + uint8_t invert_color_l : 1; +}; + +struct WH0 { + uint8_t left_position : 8; +}; + +struct WH1 { + uint8_t right_position : 8; +}; + +struct WH2 { + uint8_t left_position : 8; +}; + +struct WH3 { + uint8_t right_position : 8; +}; + +struct WBGLOG { + uint8_t mask_logic_bg4 : 2; + uint8_t mask_logic_bg3 : 2; + uint8_t mask_logic_bg2 : 2; + uint8_t mask_logic_bg1 : 2; +}; + +struct WOBJLOG { + uint8_t unused : 4; + uint8_t mask_logic_color : 2; + uint8_t mask_logic_obj : 2; +}; + +struct TM { + uint8_t enable_layer : 5; + uint8_t unused : 3; +}; + +struct TS { + uint8_t enable_layer : 5; + uint8_t unused : 3; +}; + +struct TMW { + uint8_t enable_window : 5; + uint8_t unused : 3; +}; + +struct TSW { + uint8_t enable_window : 5; + uint8_t unused : 3; +}; + +struct CGWSEL { + uint8_t direct_color : 1; + uint8_t fixed_subscreen : 1; + uint8_t sub_color_window : 2; + uint8_t main_color_window : 2; + uint8_t unused : 2; +}; + +struct CGADSUB { + uint8_t enable_layer : 5; + uint8_t backdrop : 1; + uint8_t half : 1; + uint8_t add_subtract : 1; +}; + +struct COLDATA { + uint8_t value : 4; + uint8_t channel_select : 3; + uint8_t unused : 1; +}; + +struct SETINI { + uint8_t screen_interlace : 1; + uint8_t obj_interlace : 1; + uint8_t overscan : 1; + uint8_t hi_res : 1; + uint8_t extbg : 1; + uint8_t external_sync : 1; + uint8_t unused : 2; +}; + +struct MPYL { + uint8_t multiplication_result_low : 8; +}; + +struct MPYM { + uint8_t multiplication_result_mid : 8; +}; + +struct MPYH { + uint8_t multiplication_result_high : 8; +}; + +struct SLHV { + uint8_t software_latch : 8; +}; + +struct OAMDATAREAD { + uint8_t oam_data_read : 8; +}; + +struct VMDATALREAD { + uint8_t vram_data_read_low : 8; +}; + +struct VMDATAHREAD { + uint8_t vram_data_read_high : 8; +}; + +struct CGDATAREAD { + uint8_t cgram_data_read : 8; +}; + +struct OPHCT { + uint16_t horizontal_counter_output : 9; + uint8_t unused : 7; +}; + +struct OPVCT { + uint16_t vertical_counter_output : 9; + uint8_t unused : 7; +}; + +struct STAT77 { + uint8_t ppu1_version : 4; + uint8_t master_slave : 1; + uint8_t sprite_tile_overflow : 1; + uint8_t sprite_overflow : 1; + uint8_t unused : 1; +}; + +struct STAT78 { + uint8_t ppu2_version : 4; + uint8_t ntsc_pal : 1; + uint8_t counter_latch_value : 1; + uint8_t interlace_field : 1; + uint8_t unused : 1; +}; + +} // namespace PPURegisters + +// Enum representing different background modes +enum class BackgroundMode { + Mode0, // 4 layers, each 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 + 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 + Mode7, // 1 layer, 8bpp (256 colors), rotation/scaling +}; + +// Enum representing sprite sizes +enum class SpriteSize { Size8x8, Size16x16, Size32x32, Size64x64 }; + +// Struct representing a sprite's attributes +struct SpriteAttributes { + uint8_t x; // X position of the sprite + uint8_t y; // Y position of the sprite + uint16_t tile; // Tile number for the sprite + uint8_t palette; // Palette number for the sprite + uint8_t priority; // Priority for the sprite + bool hFlip; // Horizontal flip flag + bool vFlip; // Vertical flip flag +}; + +// Struct representing a tilemap entry +struct TilemapEntry { + uint16_t tileNumber; // Tile number for the tile + uint8_t palette; // Palette number for the tile + uint8_t priority; // Priority for the tile + bool hFlip; // Horizontal flip flag + bool vFlip; // Vertical flip flag +}; + +// Struct representing a tilemap +struct Tilemap { + std::vector entries; // Entries for the tilemap +}; + +// Struct representing a color +struct Color { + uint8_t r; // Red component + uint8_t g; // Green component + uint8_t b; // Blue component +}; + +// Registers +struct OAMSize { + uint8_t base_selection : 3; + uint8_t name_selection : 2; + uint8_t object_size : 3; +}; + +struct OAMAddress { + uint8_t oam_address_low : 8; + uint8_t oam_address_msb : 1; + uint8_t oam_priority_rotation : 1; + uint8_t unused : 6; +}; + +struct TileMapLocation { + uint8_t SC_size : 2; + uint8_t tile_map_address : 5; + uint8_t unused : 1; +}; + +struct CharacterLocation { + uint8_t BG1_address : 4; + uint8_t BG2_address : 4; + uint8_t BG3_address : 4; + uint8_t BG4_address : 4; +}; + +struct VideoPortControl { + uint8_t increment_rate : 2; + uint8_t full_graphic : 2; + uint8_t increment_mode : 1; + uint8_t unused : 3; +}; + +struct ScreenDisplay { + uint8_t brightness : 4; + uint8_t disable_screen : 1; + uint8_t unused : 3; +}; + +struct ScreenMode { + uint8_t general_screen_mode : 3; + uint8_t priority : 1; + uint8_t BG1_tile_size : 1; + uint8_t BG2_tile_size : 1; + uint8_t BG3_tile_size : 1; + uint8_t BG4_tile_size : 1; +}; + +struct ScrollRegister { + uint8_t offset : 8; + uint8_t mode7_bits : 3; + uint8_t unused : 5; +}; + +struct MainSubScreenDesignation { + uint8_t BG1_enable : 1; + uint8_t BG2_enable : 1; + uint8_t BG3_enable : 1; + uint8_t BG4_enable : 1; + uint8_t sprites_enable : 1; + uint8_t unused : 3; +}; + +struct WindowMaskSettings { + uint8_t BG1_clip_in_out : 1; + uint8_t BG1_enable : 1; + uint8_t BG2_clip_in_out : 1; + uint8_t BG2_enable : 1; + uint8_t BG3_clip_in_out : 1; + uint8_t BG3_enable : 1; + uint8_t BG4_clip_in_out : 1; + uint8_t BG4_enable : 1; +}; + +struct WindowMaskSettings2 { + uint8_t sprites_clip_in_out : 1; + uint8_t sprites_enable : 1; + uint8_t color_windows_clip_in_out : 1; + uint8_t color_windows_enable : 1; + uint8_t unused : 4; +}; + +struct WindowPosition { + uint8_t position : 8; +}; + +struct MaskLogicSettings { + uint8_t BG1_mask_logic : 2; + uint8_t BG2_mask_logic : 2; + uint8_t BG3_mask_logic : 2; + uint8_t BG4_mask_logic : 2; +}; + +// Counter/IRQ/NMI Registers +struct CounterIrqNmiRegisters { + uint8_t softwareLatchHvCounter; // Register $2137 + uint16_t horizontalScanLocation; // Register $213C + uint16_t verticalScanLocation; // Register $213D + uint8_t counterEnable; // Register $4200 + uint16_t horizontalIrqTrigger; // Register $4207/$4208 + uint16_t verticalIrqTrigger; // Register $4209/$420A + uint8_t nmiRegister; // Register $4210 + uint8_t irqRegister; // Register $4211 + uint8_t statusRegisterIrq; // Register $4212 +}; + +// Joypad Registers +struct JoypadRegisters { + uint16_t joypadData[4]; // Register $4218 to $421F + uint8_t oldStyleJoypadRegisters[2]; // Registers $4016/$4217 +}; + +// DMA Registers +struct DmaRegisters { + uint8_t startDmaTransfer; // Register $420B + uint8_t enableHDmaTransfer; // Register $420C + uint8_t dmaControlRegister[8]; // Register $43?0 + uint8_t dmaDestinationAddress[8]; // Register $43?1 + uint32_t dmaSourceAddress[8]; // Register $43?2/$43?3/$43?4 + uint16_t bytesToTransfer[8]; // Register $43?5/$43?6/$43?7 + uint16_t hdmaCountPointer[8]; // Register $43?8/$43?9 + uint8_t scanlinesLeft[8]; // Register $43?A +}; + +// WRAM access Registers +struct WramAccessRegisters { + uint8_t dataByte; // Register $2180 + uint32_t address; // Register $2181/$2182/$2183 +}; + class PPU { public: // Initializes the PPU with the necessary resources and dependencies - PPU(Memory &memory); + PPU(Memory& memory); - void Init(); + void Init() { + // Initialize the frame buffer with a size that corresponds to the + // screen resolution + frame_buffer_.resize(256 * 240, 0); + } // Resets the PPU to its initial state - void Reset(); + void Reset() { std::fill(frame_buffer_.begin(), frame_buffer_.end(), 0); } // Runs the PPU for a specified number of clock cycles void Run(int cycles); @@ -33,10 +627,11 @@ class PPU { void RenderScanline(); // Returns the pixel data for the current frame - const std::vector &GetFrameBuffer() const; + const std::vector& GetFrameBuffer() const { return frame_buffer_; } private: // Internal methods to handle PPU rendering and operations + void UpdateTileData(); // Updates internal state based on PPU register settings void UpdateModeSettings(); @@ -47,6 +642,30 @@ class PPU { // Renders sprites (also known as objects) void RenderSprites(); + void UpdateTileMapData() { + // Fetches the tile map data from memory and stores it in an internal + // buffer + } + + void UpdatePaletteData() { + // Fetches the palette data from CGRAM and stores it in an internal + // buffer + } + + void ApplyEffects() { + // Applies effects to the layers based on the current mode and register + // settings + } + + void ComposeLayers() { + // Combines the layers into a single image and stores it in the frame + // buffer + } + + void DisplayFrameBuffer() { + // Sends the frame buffer to the display hardware (e.g., SDL2) + } + // Retrieves a pixel color from the palette uint32_t GetPaletteColor(uint8_t colorIndex); @@ -58,12 +677,34 @@ class PPU { uint8_t ReadOAM(uint16_t address); void WriteOAM(uint16_t address, uint8_t value); - // Other internal methods for handling PPU functionality + // Handle CGRAM (Color Palette RAM) reads and writes + uint8_t ReadCGRAM(uint16_t address); + void WriteCGRAM(uint16_t address, uint8_t value); + // =========================================================== // Member variables to store internal PPU state and resources - Memory &memory_; - std::vector frameBuffer_; - // Other state variables (registers, counters, mode settings, etc.) + Memory& memory_; + std::vector frame_buffer_; + + // The VRAM memory area holds tiles and tile maps. + std::array vram_; + + // The OAM memory area holds sprite properties. + std::array oam_; + + // The CGRAM memory area holds the color palette data. + std::array cgram_; + + uint16_t oam_address_; + + BackgroundMode bg_mode_; + std::vector sprites_; + std::vector tileData_; + Tilemap tilemap_; + uint16_t tileDataSize_; + uint16_t oamBaseAddress_; + uint16_t vramBaseAddress_; + uint16_t tilemapBaseAddress_; }; } // namespace emu