summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Fors <peter.fors@mindkiller.com>2025-04-16 12:37:40 +0200
committerPeter Fors <peter.fors@mindkiller.com>2025-04-16 12:37:40 +0200
commit6321f071ed2ab36242e857a9414b7f4c53092d72 (patch)
tree80eb868cc206c932d32943d101e7f337324fa7f4
parent18a2c1406f1fa585f4574cd687b0791e52ab5d7a (diff)
Battletoads working
-rw-r--r--mapper.c3
-rw-r--r--mapper_0007.c22
-rw-r--r--mapper_0007.h2
-rw-r--r--mknes.c68
-rw-r--r--mknes.h8
-rw-r--r--ppu.c12
-rw-r--r--ppu_registers.c23
7 files changed, 88 insertions, 50 deletions
diff --git a/mapper.c b/mapper.c
index e10c97c..6d4891b 100644
--- a/mapper.c
+++ b/mapper.c
@@ -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;
};
diff --git a/mknes.c b/mknes.c
index b959230..9b58753 100644
--- a/mknes.c
+++ b/mknes.c
@@ -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) {
diff --git a/mknes.h b/mknes.h
index f038fa6..a9e58a0 100644
--- a/mknes.h
+++ b/mknes.h
@@ -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
};
diff --git a/ppu.c b/ppu.c
index 9e081de..7042b19 100644
--- a/ppu.c
+++ b/ppu.c
@@ -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);
}
}