diff --git a/src/cpu_bus.c b/src/cpu_bus.c index 5e25784..7ca8099 100644 --- a/src/cpu_bus.c +++ b/src/cpu_bus.c @@ -144,18 +144,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; + address_t vram_addr = bus->ppu->v & 0x3FFF; + result = bus->buffer2007; + bus->buffer2007 = read_ppu_bus(bus->ppu->bus, vram_addr); // Set high 2 bits from palette to io latch and apply PPU effects - if (bus->ppu->v >= 0x3F00) { + if (bus->ppu->v >= PPU_MAP_PALETTE && !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; - } } + increment_vram_address_ppu(bus->ppu); bus->ppu->io_databus = result; } @@ -245,9 +245,14 @@ 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 >= PPU_MAP_PALETTE) { + address_t palette_addr = bus->ppu->v & 0x1F; + write_palette_ppu(bus->ppu, palette_addr, value); + } else { + address_t vram_addr = bus->ppu->v & 0x3FFF; + write_ppu_bus(bus->ppu->bus, vram_addr, 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..936d30c 100644 --- a/src/ppu.c +++ b/src/ppu.c @@ -103,6 +103,28 @@ void create_event_tables_ppu(ppu_t *ppu) { } } +unsigned char read_palette_ppu(ppu_t *ppu, unsigned char palette_index) { + unsigned char value = ppu->palette[palette_index]; + if (ppu->mask & PPU_MASK_GREYSCALE) { + value &= 0x30; + } + return value; +} + +void write_palette_ppu(ppu_t *ppu, + unsigned char palette_index, + unsigned char value) { + ppu->palette[palette_index] = value; + if ((palette_index & 0x3) == 0) { + ppu->palette[palette_index ^ 0x10] = 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 +269,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.c b/src/ppu_bus.c index 886b733..6c03b28 100644 --- a/src/ppu_bus.c +++ b/src/ppu_bus.c @@ -24,32 +24,15 @@ address_t mirror_address_ppu_bus(address_t address, rom_mirroring_t mirroring) { } } } - } else if (address >= PPU_MAP_PALETTE && address < PPU_MAP_PALETTE_MIRROR) { - // Mirrored palette table regions - switch (address) { - case 0x3f10: - return 0x3f00; - case 0x3f14: - return 0x3f04; - case 0x3f18: - return 0x3f08; - case 0x3f1c: - return 0x3f0c; - default: - return address; - } - } else if (address >= PPU_MAP_PALETTE_MIRROR) { + } else if (address >= PPU_MAP_PALETTE) { // Mirrored palette table regions address_t norm = PPU_MAP_PALETTE + ((address - PPU_MAP_PALETTE) % 0x20); switch (norm) { - case 0x3f10: - return 0x3f00; - case 0x3f14: - return 0x3f04; - case 0x3f18: - return 0x3f08; - case 0x3f1c: - return 0x3f0c; + case 0x3F10: + case 0x3F14: + case 0x3F18: + case 0x3F1C: + return norm - 0x10; default: return norm; } diff --git a/src/ppu_bus.h b/src/ppu_bus.h index 568e82c..c29755f 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 @@ -14,10 +17,10 @@ #define PPU_MAP_NAMETABLE_0 0x2000 #define PPU_MAP_NAMETABLE_1 0x2400 #define PPU_MAP_NAMETABLE_2 0x2800 -#define PPU_MAP_NAMETABLE_3 0x2c00 +#define PPU_MAP_NAMETABLE_3 0x2C00 #define PPU_MAP_NAMETABLE_MIRROR 0x3000 -#define PPU_MAP_PALETTE 0x3f00 -#define PPU_MAP_PALETTE_MIRROR 0x3f20 +#define PPU_MAP_PALETTE 0x3F00 +#define PPU_MAP_PALETTE_MIRROR 0x3F20 /** * @brief PPU bus subsystem.