Add PPU registers and structs
This commit is contained in:
@@ -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<uint8_t>& 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<BackgroundMode>(
|
||||
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
|
||||
|
||||
@@ -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<uint8_t>& data) = 0;
|
||||
virtual std::vector<uint8_t> getOAMData() const = 0;
|
||||
virtual void setVRAMData(const std::vector<uint8_t>& data) = 0;
|
||||
virtual std::vector<uint8_t> getVRAMData() const = 0;
|
||||
virtual void setCGRAMData(const std::vector<uint8_t>& data) = 0;
|
||||
virtual std::vector<uint8_t> getCGRAMData() const = 0;
|
||||
virtual void renderFrame() = 0;
|
||||
virtual std::vector<uint32_t> 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<TilemapEntry> 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<uint8_t> &GetFrameBuffer() const;
|
||||
const std::vector<uint8_t>& 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<uint8_t> frameBuffer_;
|
||||
// Other state variables (registers, counters, mode settings, etc.)
|
||||
Memory& memory_;
|
||||
std::vector<uint8_t> frame_buffer_;
|
||||
|
||||
// The VRAM memory area holds tiles and tile maps.
|
||||
std::array<uint8_t, 64 * 1024> vram_;
|
||||
|
||||
// The OAM memory area holds sprite properties.
|
||||
std::array<uint8_t, 544> oam_;
|
||||
|
||||
// The CGRAM memory area holds the color palette data.
|
||||
std::array<uint8_t, 512> cgram_;
|
||||
|
||||
uint16_t oam_address_;
|
||||
|
||||
BackgroundMode bg_mode_;
|
||||
std::vector<SpriteAttributes> sprites_;
|
||||
std::vector<uint8_t> tileData_;
|
||||
Tilemap tilemap_;
|
||||
uint16_t tileDataSize_;
|
||||
uint16_t oamBaseAddress_;
|
||||
uint16_t vramBaseAddress_;
|
||||
uint16_t tilemapBaseAddress_;
|
||||
};
|
||||
|
||||
} // namespace emu
|
||||
|
||||
Reference in New Issue
Block a user