diff --git a/include/ppu.h b/include/ppu.h index b7c57ab..19a90e4 100644 --- a/include/ppu.h +++ b/include/ppu.h @@ -62,6 +62,10 @@ typedef struct ppu { address t; byte x; bool w; + + unsigned long frame; + unsigned int line; + unsigned int line_x; } PPU; PPU *ppu_get_state(); @@ -102,6 +106,7 @@ bool ppu_read_flag(size_t reg, byte mask); //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/main.c b/main.c index 0ef58b7..900f7ec 100644 --- a/main.c +++ b/main.c @@ -26,7 +26,7 @@ int main() { log_set_level(LOG_INFO); system_init(); - char *rom_path = "../test_roms/smb.nes"; + char *rom_path = "../test_roms/dk_japan.nes"; if (!rom_load(rom_path)) { system_uninit(); diff --git a/ppu/ppu.c b/ppu/ppu.c index 7df396f..4d7a822 100644 --- a/ppu/ppu.c +++ b/ppu/ppu.c @@ -18,6 +18,13 @@ #include "../include/ppu.h" #include "../cpu/cpu.h" +#define PPU_VISIBLE_FRAME_END 240 +#define PPU_POST_RENDER_LINE_START PPU_VISIBLE_FRAME_END +#define PPU_POST_RENDER_LINE_END 242 +#define PPU_PRE_RENDER_LINE 261 +#define PPU_LINE_END PPU_PRE_RENDER_LINE +#define PPU_LINE_WIDTH 340 + PPU ppu_state; void ppu_init(byte *registers_ram, byte *oam_dma_register) { @@ -32,6 +39,10 @@ void ppu_init(byte *registers_ram, byte *oam_dma_register) { ppu_state.registers[PPU_REGISTER_DATA] = 0x00; ppu_state.oam_dma_register = oam_dma_register; ppu_state.odd_frame = false; + + ppu_state.frame = 0; + ppu_state.line = 0; + ppu_state.line_x = 0; } PPU *ppu_get_state() { @@ -55,42 +66,61 @@ void ppu_trigger_vbl_nmi() { cpu_trigger_nmi(); } -long frame = 0; -int x, y = 0; +void ppu_visible_frame(unsigned int x) { + if (x >= 257 && x <= 320) { + // OAMADDR is cleared on sprite loading for pre-render and visible lines + ppu_write_reg(PPU_REGISTER_OAM_ADDR, 0); + } +} -void ppu_cycle() { +void ppu_pre_render(unsigned int x) { if (x == 1) { - if (y == 241) { - // VBlank start - ppu_status_set(PPU_STATUS_VBLANK, true); - ppu_trigger_vbl_nmi(); - } - - if (y == 261) { - // VBlank clear - ppu_status_set(PPU_STATUS_VBLANK, false); - } + // VBlank clear + ppu_status_set(PPU_STATUS_VBLANK, false); } - int frame_width = 341; - int frame_height = 262; + if (x >= 257 && x <= 320) { + // OAMADDR is cleared on sprite loading for pre-render and visible lines + ppu_write_reg(PPU_REGISTER_OAM_ADDR, 0); + } +} + +void ppu_post_render(unsigned int x, unsigned int y) { + if (x == 1 && y == 241) { + // VBlank start + ppu_status_set(PPU_STATUS_VBLANK, true); + ppu_trigger_vbl_nmi(); + } +} + +void ppu_cycle() { + if (ppu_state.line < PPU_VISIBLE_FRAME_END) { + ppu_visible_frame(ppu_state.line_x); + } else if (ppu_state.line >= PPU_POST_RENDER_LINE_START && ppu_state.line <= PPU_POST_RENDER_LINE_END) { + ppu_post_render(ppu_state.line_x, ppu_state.line); + } else if (ppu_state.line == PPU_PRE_RENDER_LINE) { + ppu_pre_render(ppu_state.line_x); + } + + int frame_width = PPU_LINE_WIDTH; + int frame_height = PPU_LINE_END; bool rendering_enabled = ppu_read_flag(PPU_REGISTER_MASK, PPU_MASK_SHOW_BG | PPU_MASK_SHOW_SP); if (rendering_enabled && ppu_state.odd_frame) { // With rendering enabled, the odd frames are shorter // TODO: and doing the last cycle of the last dummy nametable fetch there instead - frame_width = 339; - frame_height = 261; + frame_width = PPU_LINE_WIDTH - 2; + frame_height = PPU_LINE_END - 1; } - x++; - if (x >= frame_width) { - x = 0; - y++; + ppu_state.line_x++; + if (ppu_state.line_x >= frame_width) { + ppu_state.line_x = 0; + ppu_state.line++; } - if (y >= frame_height) { - y = 0; - frame++; + if (ppu_state.line >= frame_height) { + ppu_state.line = 0; + ppu_state.frame++; ppu_state.odd_frame = !ppu_state.odd_frame; } } @@ -152,14 +182,18 @@ void ppu_write_reg(byte reg, byte data) { 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_SCROLL) { + ppu_state.w = !ppu_state.w; + if (!ppu_state.w) { + ppu_state.x = data; + } else { + ppu_state.t = data; + } } else if (reg == PPU_REGISTER_ADDR) { + ppu_state.w = !ppu_state.w; address addr = ppu_state.v; if (ppu_state.w) { - addr &= 0xff & - data; + addr &= 0xff & data; } else { addr &= (data << 8) | 0x0f; } @@ -167,19 +201,16 @@ void ppu_write_reg(byte reg, byte data) { if (addr >= PPU_VRAM_SIZE) { addr -= PPU_VRAM_SIZE; } - ppu_state. - v = addr; + ppu_state.v = addr; } else if (reg == PPU_REGISTER_DATA) { - ppu_state.vram[ppu_state.v] = - 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; + ppu_state.v += increment; if (ppu_state.v >= PPU_VRAM_SIZE) { ppu_state.v -= PPU_VRAM_SIZE; }