diff --git a/src/cpu_bus.c b/src/cpu_bus.c index 5e25784..30a4abf 100644 --- a/src/cpu_bus.c +++ b/src/cpu_bus.c @@ -1,4 +1,5 @@ #include "./cpu_bus.h" +#include "ppu.h" void create_cpu_bus(cpu_bus_t *bus, rom_t *rom, @@ -144,18 +145,18 @@ unsigned char read_cpu_bus(cpu_bus_t *bus, address_t address) { // Read from PPUDATA (overwrite result with value from VRAM) if (ptr == &bus->ppu->data) { - result = read_ppu_bus(bus->ppu->bus, bus->ppu->v & 0x3FFF); - bus->ppu->v++; - bus->ppu->v += ((bus->ppu->ctrl >> 2) & 1) * 31; - // Set high 2 bits from palette to io latch and apply PPU effects - if (bus->ppu->v >= 0x3F00) { + if (bus->ppu->v >= 0x3F00 && !is_rendering_ppu(bus->ppu)) { + address_t palette_addr = bus->ppu->v & 0x1F; + result = read_palette_ppu(bus->ppu, palette_addr); result &= ~0xC0; result |= bus->ppu->io_databus & 0xC0; - if (bus->ppu->mask & PPU_MASK_GREYSCALE) { - result &= 0x30; - } + } else { + address_t vram_addr = bus->ppu->v & 0x3FFF; + result = bus->buffer2007; + bus->buffer2007 = read_ppu_bus(bus->ppu->bus, vram_addr); } + increment_vram_address_ppu(bus->ppu); bus->ppu->io_databus = result; } @@ -245,9 +246,12 @@ void write_cpu_bus(cpu_bus_t *bus, address_t address, unsigned char value) { // Write to PPUDATA if (ptr == &bus->ppu->data) { - write_ppu_bus(bus->ppu->bus, bus->ppu->v & 0x3FFF, value); - bus->ppu->v++; - bus->ppu->v += ((bus->ppu->ctrl >> 2) & 1) * 31; + if (bus->ppu->v >= 0x3F00) { + write_palette_ppu(bus->ppu, bus->ppu->v & 0x1F, value); + } else { + write_ppu_bus(bus->ppu->bus, bus->ppu->v & 0x3FFF, value); + } + increment_vram_address_ppu(bus->ppu); bus->ppu->io_databus = value; // TODO: diff --git a/src/cpu_bus.h b/src/cpu_bus.h index 9cda4c6..4f08ea1 100644 --- a/src/cpu_bus.h +++ b/src/cpu_bus.h @@ -69,6 +69,12 @@ typedef struct { */ unsigned char memory[CPU_RAM_SIZE]; + /** + * @brief Internal buffer for reading from PPU data register. + * + */ + unsigned char buffer2007; + /** * @brief Pointer to the ROM. * diff --git a/src/ppu.c b/src/ppu.c index 3846145..6240c6f 100644 --- a/src/ppu.c +++ b/src/ppu.c @@ -103,6 +103,41 @@ void create_event_tables_ppu(ppu_t *ppu) { } } +unsigned char read_palette_ppu(ppu_t *ppu, unsigned char palette_index) { + switch (palette_index) { + case 0x10: + case 0x14: + case 0x18: + case 0x1C: + palette_index -= 0x10; + break; + } + unsigned char color = ppu->palette[palette_index]; + if (ppu->mask & PPU_MASK_GREYSCALE) { + color &= 0x30; + } + return color; +} + +void write_palette_ppu(ppu_t *ppu, + unsigned char palette_index, + unsigned char value) { + switch (palette_index) { + case 0x10: + case 0x14: + case 0x18: + case 0x1C: + palette_index -= 0x10; + break; + } + ppu->palette[palette_index] = value; +} + +void increment_vram_address_ppu(ppu_t *ppu) { + ppu->v++; + ppu->v += ((ppu->ctrl >> 2) & 1) * 31; +} + void read_state_ppu(ppu_t *ppu, char *buffer, unsigned buffer_size) { snprintf(buffer, buffer_size, @@ -247,8 +282,8 @@ void draw_dot_ppu(ppu_t *ppu) { unsigned char color = pt0 | (pt1 << 1); // Fetch the actual color value from the palette - address_t color_address = PPU_MAP_PALETTE | (palette << 2) | color; - unsigned char palette_byte = read_ppu_bus(ppu->bus, color_address); + unsigned char palette_index = (palette << 2) | color; + unsigned char palette_byte = read_palette_ppu(ppu, palette_index); // Write to the color buffer unsigned buffer_index = ppu->scanline * PPU_LINEDOTS + ppu->dot; diff --git a/src/ppu.h b/src/ppu.h index fb2ac3d..4c72cf9 100644 --- a/src/ppu.h +++ b/src/ppu.h @@ -185,13 +185,19 @@ typedef struct { * @brief Primary object attribute memory. * */ - unsigned char primary_oam[256]; + unsigned char primary_oam[PPU_PRIMARY_OAM_SIZE]; /** * @brief Secondary object attribute memory. * */ - unsigned char secondary_oam[32]; + unsigned char secondary_oam[PPU_SECONDARY_OAM_SIZE]; + + /** + * @brief Internal palette memory. + * + */ + unsigned char palette[PPU_PALETTE_SIZE]; /** * @brief Data bus for communicating with the CPU. @@ -295,6 +301,32 @@ void destroy_ppu(ppu_t *ppu); */ void create_event_tables_ppu(ppu_t *ppu); +/** + * @brief Read from the internal palette memory. + * + * @param ppu + * @return unsigned char + */ +unsigned char read_palette_ppu(ppu_t *ppu, unsigned char palette_index); + +/** + * @brief Write to the internal palette memory. + * + * @param ppu + * @param palette_index + * @param value + */ +void write_palette_ppu(ppu_t *ppu, + unsigned char palette_index, + unsigned char value); + +/** + * @brief Increment the VRAM address. + * + * @param ppu + */ +void increment_vram_address_ppu(ppu_t *ppu); + /** * @brief Read the current state of the CPU for debugging. * diff --git a/src/ppu_bus.h b/src/ppu_bus.h index 568e82c..a93171b 100644 --- a/src/ppu_bus.h +++ b/src/ppu_bus.h @@ -6,7 +6,10 @@ #include "./rom.h" // 2C02 has a 16-bit address bus (64k) -#define PPU_RAM_SIZE 1 << 16 +#define PPU_RAM_SIZE 1 << 16 +#define PPU_PRIMARY_OAM_SIZE 1 << 8 +#define PPU_SECONDARY_OAM_SIZE 1 << 5 +#define PPU_PALETTE_SIZE 1 << 5 // PPU memory map address offsets #define PPU_MAP_PATTERNTABLE_0 0x0000