From 1bc9d4950f14c22558b08bb25d58e66badc0fe5e Mon Sep 17 00:00:00 2001 From: william Date: Mon, 13 May 2024 17:37:36 -0400 Subject: [PATCH] PPU_CTRL, PPU_STATUS --- cpu/memory.c | 11 ++---- include/ppu.h | 15 +++++--- ppu/ppu.c | 98 ++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 94 insertions(+), 30 deletions(-) diff --git a/cpu/memory.c b/cpu/memory.c index 0bc20e2..ffec9c1 100644 --- a/cpu/memory.c +++ b/cpu/memory.c @@ -22,7 +22,7 @@ byte mem_get_byte(address addr) { if (addr >= RAM_MAX_ADDR && addr < PPU_MAX_ADDR) { byte reg = (addr - RAM_MAX_ADDR) % PPU_BANK_SIZE; - ppu_sig_read_register(reg); + return ppu_read_reg(reg); } return ram[addr]; @@ -57,14 +57,7 @@ void mem_set_byte(address addr, byte byte) { } } else if (addr < PPU_MAX_ADDR) { address reg_addr = (addr - RAM_MAX_ADDR) % PPU_BANK_SIZE; - - int bank_count = (PPU_MAX_ADDR - RAM_MAX_ADDR) / PPU_BANK_SIZE; - for (int i = 0; i < bank_count; i++) { - address ram_addr = reg_addr + PPU_BANK_SIZE * i + RAM_MAX_ADDR; - ram[ram_addr] = byte; - } - - ppu_sig_write_register(reg_addr); + ppu_write_reg(reg_addr, byte); } else { ram[addr] = byte; diff --git a/include/ppu.h b/include/ppu.h index 8ee9cee..b7c57ab 100644 --- a/include/ppu.h +++ b/include/ppu.h @@ -12,6 +12,10 @@ #define PPU_REGISTER_SIZE 0x8 #define PPU_VRAM_SIZE 0x4000 #define PPU_OAM_SIZE 0xff +#define PPU_RAM_BASE_ADDR 0x2000 +#define PPU_RAM_MAX_ADDR 0x4000 +#define PPU_RAM_BANK_SIZE 0x8 +#define PPU_RAM_BANK_COUNT ((PPU_RAM_MAX_ADDR - PPU_RAM_BASE_ADDR) / PPU_RAM_BANK_SIZE) #define PPU_REGISTER_CTRL 0x00 #define PPU_REGISTER_MASK 0x01 @@ -22,6 +26,8 @@ #define PPU_REGISTER_ADDR 0x06 #define PPU_REGISTER_DATA 0x07 +#define PPU_CTRL_SCROLL_X 0x1 +#define PPU_CTRL_SCROLL_Y 0x2 #define PPU_CTRL_BASE_NAMETABLE_ADDR 0x3 #define PPU_CTRL_VRAM_ADDR_INCREMENT 0x4 #define PPU_CTRL_SP_PATTERN_TABLE_ADDR 0x8 @@ -56,8 +62,6 @@ typedef struct ppu { address t; byte x; bool w; - - } PPU; PPU *ppu_get_state(); @@ -93,8 +97,11 @@ bool ppu_read_flag(size_t reg, byte mask); * @param reg The register index * @param mask The value mask */ -void ppu_sig_read_register(byte reg); +//void ppu_sig_read_register(byte reg); +// +//void ppu_sig_write_register(byte reg); -void ppu_sig_write_register(byte reg); +byte ppu_read_reg(byte reg); +void ppu_write_reg(byte reg, byte data); #endif //NESEMULATOR_PPU_H diff --git a/ppu/ppu.c b/ppu/ppu.c index 407e901..7df396f 100644 --- a/ppu/ppu.c +++ b/ppu/ppu.c @@ -14,6 +14,7 @@ // 10. This is where I'm stuck. I think I need to read the "sprites" section of https://wiki.nesdev.com/w/index.php/PPU_rendering very carefully. // +#include #include "../include/ppu.h" #include "../cpu/cpu.h" @@ -98,31 +99,94 @@ bool ppu_read_flag(size_t reg, byte mask) { return ppu_state.registers[reg] & mask; } -//byte ppu_sig_read_register(size_t reg, byte mask) { -// return ppu_state.registers[reg] & mask; -//} +byte ppu_read_reg(byte reg) { + assert(reg >= 0); + assert(reg <= PPU_REGISTER_SIZE); -void ppu_sig_read_register(byte reg) { if (reg == PPU_REGISTER_STATUS) { ppu_state.w = false; + ppu_state.registers[PPU_REGISTER_STATUS] &= ~PPU_STATUS_VBLANK; + } + + if (reg == PPU_REGISTER_DATA) { + // Access to VRAM memory is slow, so reading it a first time generally return the memory at the previous address. + // So we get the data first, then update the register. + byte data = ppu_state.registers[reg]; + ppu_state.registers[reg] = ppu_state.vram[ppu_state.v]; + if (ppu_state.v > 0x3eff) { + // But the palette data is returned immediately + data = ppu_state.registers[reg]; + } + + // We then need to increment the VRAM address + byte increment = 1; + if (ppu_read_flag(PPU_REGISTER_CTRL, PPU_CTRL_VRAM_ADDR_INCREMENT)) { + increment = 32; + } + + ppu_state.v += increment; + if (ppu_state.v >= PPU_VRAM_SIZE) { + ppu_state.v -= PPU_VRAM_SIZE; + } + + return data; + } + + return ppu_state.registers[reg]; +} + +void ppu_write_reg_ram(byte reg, byte data) { + byte *ppu_ram = mem_get_ptr(PPU_RAM_BASE_ADDR); + + for (int i = 0; i < PPU_RAM_BANK_COUNT; i++) { + byte ram_offset = (i * PPU_RAM_BANK_SIZE) + reg; + *(ppu_ram + ram_offset) = data; } } -void ppu_sig_write_register(byte reg) { - if (reg == PPU_REGISTER_ADDR) { - byte addr_write = ppu_state.registers[PPU_REGISTER_ADDR]; - if (!ppu_state.w) { - ppu_state.v &= (addr_write << 8) | 0x0f; +void ppu_write_reg(byte reg, byte data) { + ppu_state.registers[reg] = data; + + if (reg == PPU_REGISTER_CTRL && ppu_read_flag(PPU_REGISTER_STATUS, PPU_STATUS_VBLANK) && + !ppu_read_flag(PPU_REGISTER_CTRL, PPU_CTRL_GEN_VBLANK_NMI) && + data & PPU_CTRL_GEN_VBLANK_NMI) { + // The VBlank flag is still set, and the GEN_VBLANK_NMI was set from 0 to 1 + cpu_trigger_nmi(); + } else if (reg == PPU_REGISTER_SCROLL || reg == PPU_REGISTER_ADDR) { + ppu_state. + w = !ppu_state.w; + } else if (reg == PPU_REGISTER_ADDR) { + address addr = ppu_state.v; + if (ppu_state.w) { + addr &= 0xff & + data; } else { - ppu_state.v &= 0xff & addr_write; + addr &= (data << 8) | 0x0f; } + + if (addr >= PPU_VRAM_SIZE) { + addr -= PPU_VRAM_SIZE; + } + ppu_state. + v = addr; + } else if (reg == PPU_REGISTER_DATA) { + ppu_state.vram[ppu_state.v] = + data; + + byte increment = 1; + if (ppu_read_flag(PPU_REGISTER_CTRL, PPU_CTRL_VRAM_ADDR_INCREMENT)) { + increment = 32; + } + + ppu_state.v += + increment; + if (ppu_state.v >= PPU_VRAM_SIZE) { + ppu_state.v -= PPU_VRAM_SIZE; + } + } else if (reg == PPU_REGISTER_OAM_DATA) { + byte oam_addr = ppu_state.registers[PPU_REGISTER_OAM_ADDR]; + ppu_write_reg(PPU_REGISTER_OAM_ADDR, oam_addr + 1); } - if (reg == PPU_REGISTER_SCROLL || reg == PPU_REGISTER_ADDR) { - ppu_state.w = !ppu_state.w; - } - - if (reg == PPU_REGISTER_OAM_DATA) { - ppu_state.registers[PPU_REGISTER_OAM_ADDR]++; - } + ppu_write_reg_ram(reg, data); } \ No newline at end of file