PPU registers

This commit is contained in:
william 2024-05-15 13:02:40 -04:00
parent 1bc9d4950f
commit 9629efeeb9
3 changed files with 72 additions and 36 deletions

View File

@ -62,6 +62,10 @@ typedef struct ppu {
address t; address t;
byte x; byte x;
bool w; bool w;
unsigned long frame;
unsigned int line;
unsigned int line_x;
} PPU; } PPU;
PPU *ppu_get_state(); PPU *ppu_get_state();
@ -102,6 +106,7 @@ bool ppu_read_flag(size_t reg, byte mask);
//void ppu_sig_write_register(byte reg); //void ppu_sig_write_register(byte reg);
byte ppu_read_reg(byte reg); byte ppu_read_reg(byte reg);
void ppu_write_reg(byte reg, byte data); void ppu_write_reg(byte reg, byte data);
#endif //NESEMULATOR_PPU_H #endif //NESEMULATOR_PPU_H

2
main.c
View File

@ -26,7 +26,7 @@ int main() {
log_set_level(LOG_INFO); log_set_level(LOG_INFO);
system_init(); system_init();
char *rom_path = "../test_roms/smb.nes"; char *rom_path = "../test_roms/dk_japan.nes";
if (!rom_load(rom_path)) { if (!rom_load(rom_path)) {
system_uninit(); system_uninit();

101
ppu/ppu.c
View File

@ -18,6 +18,13 @@
#include "../include/ppu.h" #include "../include/ppu.h"
#include "../cpu/cpu.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; PPU ppu_state;
void ppu_init(byte *registers_ram, byte *oam_dma_register) { 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.registers[PPU_REGISTER_DATA] = 0x00;
ppu_state.oam_dma_register = oam_dma_register; ppu_state.oam_dma_register = oam_dma_register;
ppu_state.odd_frame = false; ppu_state.odd_frame = false;
ppu_state.frame = 0;
ppu_state.line = 0;
ppu_state.line_x = 0;
} }
PPU *ppu_get_state() { PPU *ppu_get_state() {
@ -55,42 +66,61 @@ void ppu_trigger_vbl_nmi() {
cpu_trigger_nmi(); cpu_trigger_nmi();
} }
long frame = 0; void ppu_visible_frame(unsigned int x) {
int x, y = 0; 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 (x == 1) {
if (y == 241) { // VBlank clear
// VBlank start ppu_status_set(PPU_STATUS_VBLANK, false);
ppu_status_set(PPU_STATUS_VBLANK, true);
ppu_trigger_vbl_nmi();
}
if (y == 261) {
// VBlank clear
ppu_status_set(PPU_STATUS_VBLANK, false);
}
} }
int frame_width = 341; if (x >= 257 && x <= 320) {
int frame_height = 262; // 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); bool rendering_enabled = ppu_read_flag(PPU_REGISTER_MASK, PPU_MASK_SHOW_BG | PPU_MASK_SHOW_SP);
if (rendering_enabled && ppu_state.odd_frame) { if (rendering_enabled && ppu_state.odd_frame) {
// With rendering enabled, the odd frames are shorter // With rendering enabled, the odd frames are shorter
// TODO: and doing the last cycle of the last dummy nametable fetch there instead // TODO: and doing the last cycle of the last dummy nametable fetch there instead
frame_width = 339; frame_width = PPU_LINE_WIDTH - 2;
frame_height = 261; frame_height = PPU_LINE_END - 1;
} }
x++; ppu_state.line_x++;
if (x >= frame_width) { if (ppu_state.line_x >= frame_width) {
x = 0; ppu_state.line_x = 0;
y++; ppu_state.line++;
} }
if (y >= frame_height) { if (ppu_state.line >= frame_height) {
y = 0; ppu_state.line = 0;
frame++; ppu_state.frame++;
ppu_state.odd_frame = !ppu_state.odd_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) { data & PPU_CTRL_GEN_VBLANK_NMI) {
// The VBlank flag is still set, and the GEN_VBLANK_NMI was set from 0 to 1 // The VBlank flag is still set, and the GEN_VBLANK_NMI was set from 0 to 1
cpu_trigger_nmi(); cpu_trigger_nmi();
} else if (reg == PPU_REGISTER_SCROLL || reg == PPU_REGISTER_ADDR) { } else if (reg == PPU_REGISTER_SCROLL) {
ppu_state. ppu_state.w = !ppu_state.w;
w = !ppu_state.w; if (!ppu_state.w) {
ppu_state.x = data;
} else {
ppu_state.t = data;
}
} else if (reg == PPU_REGISTER_ADDR) { } else if (reg == PPU_REGISTER_ADDR) {
ppu_state.w = !ppu_state.w;
address addr = ppu_state.v; address addr = ppu_state.v;
if (ppu_state.w) { if (ppu_state.w) {
addr &= 0xff & addr &= 0xff & data;
data;
} else { } else {
addr &= (data << 8) | 0x0f; addr &= (data << 8) | 0x0f;
} }
@ -167,19 +201,16 @@ void ppu_write_reg(byte reg, byte data) {
if (addr >= PPU_VRAM_SIZE) { if (addr >= PPU_VRAM_SIZE) {
addr -= PPU_VRAM_SIZE; addr -= PPU_VRAM_SIZE;
} }
ppu_state. ppu_state.v = addr;
v = addr;
} else if (reg == PPU_REGISTER_DATA) { } else if (reg == PPU_REGISTER_DATA) {
ppu_state.vram[ppu_state.v] = ppu_state.vram[ppu_state.v] = data;
data;
byte increment = 1; byte increment = 1;
if (ppu_read_flag(PPU_REGISTER_CTRL, PPU_CTRL_VRAM_ADDR_INCREMENT)) { if (ppu_read_flag(PPU_REGISTER_CTRL, PPU_CTRL_VRAM_ADDR_INCREMENT)) {
increment = 32; increment = 32;
} }
ppu_state.v += ppu_state.v += increment;
increment;
if (ppu_state.v >= PPU_VRAM_SIZE) { if (ppu_state.v >= PPU_VRAM_SIZE) {
ppu_state.v -= PPU_VRAM_SIZE; ppu_state.v -= PPU_VRAM_SIZE;
} }