diff options
| author | Peter Fors <peter.fors@mindkiller.com> | 2025-04-16 12:37:40 +0200 |
|---|---|---|
| committer | Peter Fors <peter.fors@mindkiller.com> | 2025-04-16 12:37:40 +0200 |
| commit | 6321f071ed2ab36242e857a9414b7f4c53092d72 (patch) | |
| tree | 80eb868cc206c932d32943d101e7f337324fa7f4 | |
| parent | 18a2c1406f1fa585f4574cd687b0791e52ab5d7a (diff) | |
Battletoads working
| -rw-r--r-- | mapper.c | 3 | ||||
| -rw-r--r-- | mapper_0007.c | 22 | ||||
| -rw-r--r-- | mapper_0007.h | 2 | ||||
| -rw-r--r-- | mknes.c | 68 | ||||
| -rw-r--r-- | mknes.h | 8 | ||||
| -rw-r--r-- | ppu.c | 12 | ||||
| -rw-r--r-- | ppu_registers.c | 23 |
7 files changed, 88 insertions, 50 deletions
@@ -38,11 +38,12 @@ static void mapper_default_tick(struct nes_state *state) { // No IRQ or timing l static struct mapper_entry mapper_table[] = { /* Mapper: 0 */ { 0x00, mapper_0000_prg_read, mapper_0000_prg_write, mapper_0000_chr_read, mapper_0000_chr_write, mapper_default_ciram_read, mapper_default_ciram_write, mapper_default_tick, mapper_0000_init }, /* Mapper: 3 */ { 0x03, mapper_0003_prg_read, mapper_0003_prg_write, mapper_0003_chr_read, mapper_0003_chr_write, mapper_default_ciram_read, mapper_default_ciram_write, mapper_default_tick, mapper_0003_init }, -/* Mapper: 7 */ { 0x2007, mapper_0007_prg_read, mapper_0007_prg_write, mapper_0007_chr_read, mapper_0007_chr_write, mapper_0007_ciram_read, mapper_0007_ciram_write, mapper_default_tick, mapper_0007_init }, +/* Mapper: 7 */ { 0x7, mapper_0007_prg_read, mapper_0007_prg_write, mapper_0007_chr_read, mapper_0007_chr_write, mapper_0007_ciram_read, mapper_0007_ciram_write, mapper_default_tick, mapper_0007_init }, /* Mapper: b */ { 0x0b, mapper_000b_prg_read, mapper_000b_prg_write, mapper_000b_chr_read, mapper_000b_chr_write, mapper_default_ciram_read, mapper_default_ciram_write, mapper_default_tick, mapper_000b_init }, /* Mapper: 66 */ { 0x42, mapper_0042_prg_read, mapper_0042_prg_write, mapper_0042_chr_read, mapper_0042_chr_write, mapper_default_ciram_read, mapper_default_ciram_write, mapper_default_tick, mapper_0042_init }, /* Mapper: 2002 */ { 0x2002, mapper_2002_prg_read, mapper_2002_prg_write, mapper_2002_chr_read, mapper_2002_chr_write, mapper_default_ciram_read, mapper_default_ciram_write, mapper_default_tick, mapper_2002_init }, /* Mapper: 2003 */ { 0x2003, mapper_0003_prg_read, mapper_0003_prg_write, mapper_0003_chr_read, mapper_0003_chr_write, mapper_default_ciram_read, mapper_default_ciram_write, mapper_default_tick, mapper_0003_init }, +/* Mapper: 7 */ { 0x2007, mapper_0007_prg_read, mapper_0007_prg_write, mapper_0007_chr_read, mapper_0007_chr_write, mapper_0007_ciram_read, mapper_0007_ciram_write, mapper_default_tick, mapper_0007_init }, }; static void mapper_setup(struct nes_state *state) { diff --git a/mapper_0007.c b/mapper_0007.c index fdb6dbb..235f5bb 100644 --- a/mapper_0007.c +++ b/mapper_0007.c @@ -3,20 +3,20 @@ static void mapper_0007_init(struct nes_state *state) { state->map.m0007.prg_ptr = state->prg_rom; - state->map.m0007.mirroring = 0; + state->map.m0007.ciram_base = 0x000; } static uint8_t mapper_0007_prg_read(struct nes_state *state, uint32_t addr) { if(addr >= 0x8000) { - return state->map.m0007.prg_ptr[addr - 0x8000]; + return state->map.m0007.prg_ptr[addr & 0x7fff]; } - return 0; + return 0; // openbus } static void mapper_0007_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) { if(addr >= 0x8000) { - state->map.m0007.prg_ptr = state->prg_rom + ((value & 0x07) * 0x8000); - state->map.m0007.mirroring = (value & 0x10) ? 1 : 0; + state->map.m0007.prg_ptr = state->prg_rom + ((value & 0x0f) * 0x8000); + state->map.m0007.ciram_base = (value & 0x10) ? 0x400 : 0x000; } } @@ -29,19 +29,11 @@ static void mapper_0007_chr_write(struct nes_state *state, uint32_t addr, uint8_ } static uint8_t mapper_0007_ciram_read(struct nes_state *state, uint32_t addr) { - if(state->map.m0007.mirroring == 0) { - addr = (addr & 0x800) | (addr & 0x3ff); - } else { - addr = addr & 0x7ff; - } + addr = state->map.m0007.ciram_base | (addr & 0x3ff); return state->ciram[addr]; } static void mapper_0007_ciram_write(struct nes_state *state, uint32_t addr, uint8_t value) { - if(state->map.m0007.mirroring == 0) { - addr = (addr & 0x800) | (addr & 0x3ff); - } else { - addr = addr & 0x7ff; - } + addr = state->map.m0007.ciram_base | (addr & 0x3ff); state->ciram[addr] = value; } diff --git a/mapper_0007.h b/mapper_0007.h index 632b57c..775082b 100644 --- a/mapper_0007.h +++ b/mapper_0007.h @@ -2,6 +2,6 @@ struct mapper_0007 { uint8_t *prg_ptr; - uint8_t mirroring; + uint32_t ciram_base; }; @@ -16,7 +16,7 @@ #define PRG_ROM_SIZE (512 * 1024) #define CHR_ROM_SIZE (512 * 1024) #define PIXELS_SIZE (256 * 240) -#define RAM_SIZE 0x800 +#define RAM_SIZE 0x1000 // 0x800 in reality, but for aligned alloc it must be the size of the alignment (4096) #define SRAM_SIZE 0x2000 #define CIRAM_SIZE 0x1000 #define CHR_RAM_SIZE 0x4000 @@ -89,6 +89,7 @@ static GLFWwindow *window; #include "opengl.c" #include "render.c" +static uint32_t frames; // debug information // NES core #include "mapper.h" @@ -104,33 +105,62 @@ static GLFWwindow *window; #include "callbacks.c" struct nes_state nstate; -static uint32_t frames; static struct nes_state *allocate_nes_state(void) { struct nes_state *state = (struct nes_state*)calloc(1, sizeof(struct nes_state)); if(!state) return 0; - size_t total_size = (PRG_ROM_SIZE + CHR_ROM_SIZE + PIXELS_SIZE + RAM_SIZE + SRAM_SIZE + CIRAM_SIZE + CHR_RAM_SIZE+ 4095) & ~0xfff; - - uint8_t *m = (uint8_t*)aligned_alloc(4096, total_size); - memset(m, 0, total_size); - - size_t offset = 0; - state->prg_rom = m + offset; offset += PRG_ROM_SIZE; // DO NOT MOVE THIS, as this is the pointer we free later. - state->chr_rom = m + offset; offset += CHR_ROM_SIZE; - state->pixels = m + offset; offset += PIXELS_SIZE; - state->ram = m + offset; offset += RAM_SIZE; - state->sram = m + offset; offset += SRAM_SIZE; - state->ciram = m + offset; offset += CIRAM_SIZE; - state->chr_ram = m + offset; offset += CHR_RAM_SIZE; + state->prg_rom = aligned_alloc(4096, PRG_ROM_SIZE); + state->chr_rom = aligned_alloc(4096, CHR_ROM_SIZE); + state->pixels = aligned_alloc(4096, PIXELS_SIZE); + state->ram = aligned_alloc(4096, RAM_SIZE); + state->sram = aligned_alloc(4096, SRAM_SIZE); + state->ciram = aligned_alloc(4096, CIRAM_SIZE); + state->chr_ram = aligned_alloc(4096, CHR_RAM_SIZE); + memset(state->prg_rom, 0, PRG_ROM_SIZE); + memset(state->chr_rom, 0, CHR_ROM_SIZE); + memset(state->pixels, 0, PIXELS_SIZE); + memset(state->ram, 0, RAM_SIZE); + memset(state->sram, 0, SRAM_SIZE); + memset(state->ciram, 0, CIRAM_SIZE); + memset(state->chr_ram, 0, CHR_RAM_SIZE); return state; } static void free_nes_state(struct nes_state *s) { free(s->prg_rom); + free(s->chr_rom); + free(s->pixels); + free(s->ram); + free(s->sram); + free(s->ciram); + free(s->chr_ram); free(s); } + + + +static void dump_nametable_text(struct nes_state *state, const char *filename) { + FILE *f = fopen(filename, "w"); + if(!f) return; + + for(int y = 0; y < 30; y++) { + for(int x = 0; x < 32; x++) { + uint16_t addr = y * 32 + x; + uint8_t tile = state->ciram[addr]; // assuming NT0 is mapped to 0x000 + fprintf(f, "%02x ", tile); + } + fprintf(f, "\n"); + } + fclose(f); +} + + + + + + int main(int argc, char **argv) { #ifdef _WIN32 timeBeginPeriod(1); @@ -173,7 +203,7 @@ int main(int argc, char **argv) { // ines2_load(nstate, "data/0003/Friday the 13th (USA).zip"); // ines2_load(nstate, "data/0003/Ghostbusters (Japan).zip"); // ines2_load(nstate, "data/0003/Gradius (USA).zip"); - // ines2_load(nstate, "data/0007/Battletoads (USA).zip"); + ines2_load(nstate, "data/0007/Battletoads (USA).zip"); // ines2_load(nstate, "data/0007/Beetlejuice (USA).zip"); // ines2_load(nstate, "data/0007/Cabal (USA).zip"); @@ -229,7 +259,7 @@ int main(int argc, char **argv) { timer_start(timer); -#if 1 +#if 0 for(uint32_t i = 0; i < 0x5000; ++ i) { while(!nstate->ppu.frame_ready) { // PROFILE_NAMED("nes emulator"); @@ -243,6 +273,8 @@ int main(int argc, char **argv) { timer_wait(timer); glfwPollEvents(); +// printf("Frame: %d\n", frames); + while(!nstate->ppu.frame_ready) { // PROFILE_NAMED("nes emulator"); cpu_tick(nstate); @@ -250,6 +282,8 @@ int main(int argc, char **argv) { nstate->ppu.frame_ready = 0; frames++; +dump_nametable_text(nstate, "_foofbomb.txt"); + uint32_t * restrict dst = display_buffer; //buffer; uint8_t * restrict src = nstate->pixels; for(uint32_t y = 0; y < 240; ++y) { @@ -109,15 +109,15 @@ struct nes_state { uint8_t *pixels; uint8_t *ram; - uint8_t *sram; uint8_t *ciram; + uint8_t *chr_ram; uint8_t *prg_rom; uint8_t *chr_rom; - uint8_t *chr_ram; + uint8_t *sram; }; -__attribute__((aligned(4096))) static uint32_t nes_palette[64] = { +__attribute__((aligned(4096))) static uint32_t nes_palette[65] = { 0x585858ff, 0x00237cff, 0x0d1099ff, 0x300092ff, 0x4f006cff, 0x600035ff, 0x5c0500ff, 0x461800ff, 0x272d00ff, 0x093e00ff, 0x004500ff, 0x004106ff, 0x003545ff, 0x000000ff, 0x000000ff, 0x000000ff, 0xa1a1a1ff, 0x0b53d7ff, 0x3337feff, 0x6621f7ff, 0x9515beff, 0xac166eff, 0xa62721ff, 0x864300ff, @@ -125,5 +125,5 @@ __attribute__((aligned(4096))) static uint32_t nes_palette[64] = { 0xffffffff, 0x51a5feff, 0x8084feff, 0xbc6afeff, 0xf15bfeff, 0xfe5ec4ff, 0xfe7269ff, 0xe19321ff, 0xadb600ff, 0x79d300ff, 0x51df21ff, 0x3ad974ff, 0x39c3dfff, 0x424242ff, 0x000000ff, 0x000000ff, 0xffffffff, 0xb5d9feff, 0xcacafeff, 0xe3befeff, 0xf9b8feff, 0xfebae7ff, 0xfec3bcff, 0xf4d199ff, - 0xdee086ff, 0xc6ec87ff, 0xb2f29dff, 0xa7f0c3ff, 0xa8e7f0ff, 0xacacacff, 0x000000ff, 0x000000ff + 0xdee086ff, 0xc6ec87ff, 0xb2f29dff, 0xa7f0c3ff, 0xa8e7f0ff, 0xacacacff, 0x000000ff, 0x000000ff, 0xffffffff }; @@ -121,9 +121,6 @@ static inline void ppu_render_pixel(struct nes_state *state) { uint8_t sp_prio = 0; uint8_t sp_zero = 0; - // uint8_t bg_mask = (ppu->reg_mask & 0x08) ? 0xff : 0x00; - // uint8_t sp_mask = (ppu->reg_mask & 0x10) ? 0xff : 0x00; - uint8_t show_bg = ppu->reg_mask & 0x08; uint8_t show_sprites = ppu->reg_mask & 0x10; uint8_t left_bg = ppu->reg_mask & 0x02; @@ -139,7 +136,6 @@ static inline void ppu_render_pixel(struct nes_state *state) { uint8_t a1 = !!(ppu->bg_shift_attrib_high & bit); bg_pixel = ((p1 << 1) | p0) & bg_mask; - bg_palette = ((a1 << 1) | a0) & bg_mask; // Sprite @@ -171,6 +167,8 @@ static inline void ppu_render_pixel(struct nes_state *state) { case 3: { ppu->reg_status |= (sp_zero && x < 255) ? 0x40 : 0; // NOTE(peter): Sprite zero hit! palette_index = (sp_prio) ? bg_index : 0x10 | sp_index; +// printf("sprite zero hit: scanline: %3.3d dot: %3.3d\n", ppu->scanline, ppu->dot); + } break; } @@ -414,11 +412,17 @@ static void ppu_tick(struct nes_state *state) { if(dot > 340) { dot = 0; scanline++; + + if(UNLIKELY(scanline == 261 && !ppu->even_frame && (ppu->reg_mask & 0x18))) { + dot = 1; + } + if(scanline > 261) { scanline = 0; ppu->frame_ready = 1; ppu->even_frame = !ppu->even_frame; } + } ppu->dot = dot; diff --git a/ppu_registers.c b/ppu_registers.c index dd8c7fa..e2e7940 100644 --- a/ppu_registers.c +++ b/ppu_registers.c @@ -16,10 +16,12 @@ static inline void ppu_write(struct nes_state *state, uint32_t offset, uint8_t v case 3: { // 2003 ppu->oam_addr = value; + ppu->open_bus = value; } break; case 4: { // 2004 ppu->oam[ppu->oam_addr++] = value; + ppu->open_bus = value; } break; case 5: { // 2005 @@ -47,11 +49,13 @@ static inline void ppu_write(struct nes_state *state, uint32_t offset, uint8_t v } break; case 7: { // 2007 - uint32_t addr = ppu->vram_addr & 0x3fff; - if(addr < 0x2000) { + uint32_t addr = ppu->vram_addr; + if(LIKELY(addr < 0x2000)) { state->mapper.chr_write(state, addr, value); - } else if(addr < 0x3f00) { + + } else if(LIKELY(addr < 0x3f00)) { state->mapper.ciram_write(state, addr, value); + } else if(addr < 0x4000) { uint32_t pal_addr = addr & 0x1f; if((pal_addr & 3) == 0) { @@ -60,6 +64,7 @@ static inline void ppu_write(struct nes_state *state, uint32_t offset, uint8_t v ppu->palette[pal_addr] = value; } ppu->vram_addr += (ppu->reg_ctrl & 0x04) ? 32 : 1; + ppu->open_bus = value; } break; } } @@ -81,13 +86,16 @@ static inline uint8_t ppu_read(struct nes_state *state, uint32_t offset) { } break; case 7: { // 2007 - uint32_t addr = ppu->vram_addr & 0x3fff; + uint32_t addr = ppu->vram_addr; - if(addr < 0x2000) { + if(LIKELY(addr < 0x2000)) { result = ppu->vram_read_buffer; ppu->vram_read_buffer = state->mapper.chr_read(state, addr); - } else if(addr < 0x3f00) { - result = state->mapper.ciram_read(state, addr); + + } else if(LIKELY(addr < 0x3f00)) { + result = ppu->vram_read_buffer; + ppu->vram_read_buffer = state->mapper.ciram_read(state, addr); + } else if(addr < 0x4000) { uint32_t pal_addr = addr & 0x1f; if((pal_addr & 0x13) == 0x10) { @@ -125,7 +133,6 @@ static inline void ppu_dma_4014(struct nes_state *state, uint8_t page) { state->cycles++; ppu_tick(state); - // ppu_write_2004(state, value); ppu_write(state, 4, value); } } |
