diff --git a/cpu.c b/cpu.c index 97ece60..a04c603 100644 --- a/cpu.c +++ b/cpu.c @@ -28,9 +28,7 @@ #define MEMORY_MIRROR(addr) \ if (addr < 0x2000) \ - addr &= 0x07FF; \ - else if (addr < 0x4000) \ - addr &= 0x2007; + addr &= 0x07FF; #define PUSH(b) \ (memwrite(0x0100 + regs.sp--, b)) diff --git a/ppu.c b/ppu.c index 5dc20a3..52837ad 100644 --- a/ppu.c +++ b/ppu.c @@ -2,6 +2,38 @@ struct ppu ppu = {0}; +static void +vram_addr_inc(void) +{ + ppu.regs.v += (ppu.ctrl.inc_mode) ? 32 : 1; +} + +static uint16_t +vram_addr_mirror(uint16_t addr) +{ + uint8_t nametable; + + addr &= 0x2fff; + addr -= 0x2000; + nametable = addr / 0x400; + + switch (ppu.rom->mirror) { + case M_HORIZONTAL: + if (nametable == 1 || nametable == 2) + return addr - 0x400; + else if (nametable == 3) + return addr - 0x800; + break; + case M_VERTICAL: + if (nametable == 2 || nametable == 3) + return addr - 0x800; + default: + break; + }; + + return addr; +} + void ppu_tick(void) { @@ -17,6 +49,36 @@ ppu_tick(void) uint8_t ppu_read(uint16_t addr) { + uint8_t tmp; + + switch (addr) { + case 0x2002: + tmp = (ppu.status.vblank << 7) + | (ppu.status.sprite0_hit << 6) + | (ppu.status.sprite_overflow << 5); + + ppu.status.vblank = 0; + ppu.regs.w = 0; + + return tmp; + case 0x2004: + return ppu.oam[ppu.oam_addr]; + case 0x2007: + vram_addr_inc(); + + if (addr <= 0x1fff) { + tmp = ppu.last_read; + ppu.last_read = ppu.rom->chr_rom[ppu.regs.v]; + return tmp; + } else if (addr <= 0x2fff) { + tmp = ppu.last_read; + ppu.last_read = ppu.vram[vram_addr_mirror(addr)]; + return tmp; + } + default: + fprintf(stderr, "Invalid PPU read at address $%04\n", addr); + return 0; + } } void diff --git a/ppu.h b/ppu.h index ffd66d7..c5483e1 100644 --- a/ppu.h +++ b/ppu.h @@ -7,12 +7,23 @@ #include "rom.h" struct ppu { - uint8_t oam[64*4]; uint8_t vram[2048]; + uint8_t oam[64*4]; + uint8_t oam_addr; /* $2003 */ uint8_t palette[16*2]; uint16_t cycles, scanlines; struct rom *rom; + uint8_t last_read; + + struct ppu_regs { + uint16_t v : 15; /* current vram address */ + uint16_t t : 15; /* temporary vram address */ + uint8_t x : 3; /* fine x scroll */ + uint8_t w : 1; /* first/second write toggle */ + uint8_t padding : 6; + } regs; + struct ppu_ctrl { /* $2000 */ uint8_t nmi_enable : 1; uint8_t master_slave : 1; @@ -36,8 +47,6 @@ struct ppu { uint8_t sprite_overflow : 1; uint8_t pad : 5; } status; - uint8_t oam_addr; /* $2003 */ - uint8_t oam_data; /* $2004 */ }; extern struct ppu ppu;