summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Fors <peter.fors@mindkiller.com>2025-04-21 14:06:43 +0200
committerPeter Fors <peter.fors@mindkiller.com>2025-04-21 14:06:43 +0200
commit19f119e49c91580f49bb02f86bb905a05ba90d6b (patch)
tree1fb671eb5bec6cd723e3708e0085280aee926547
parent6321f071ed2ab36242e857a9414b7f4c53092d72 (diff)
back to 2560fps after wrangling the ppu_state into two cachelines
-rw-r--r--.gitignore1
-rw-r--r--callbacks.c32
-rw-r--r--mapper.c1
-rw-r--r--memory.c10
-rw-r--r--mknes.c15
-rw-r--r--mknes.h17
-rw-r--r--ppu.c3
7 files changed, 52 insertions, 27 deletions
diff --git a/.gitignore b/.gitignore
index f9779a8..25005d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
.vscode
mknes
data
+documentation
TODO
dump_mappers
fragment_shader.h
diff --git a/callbacks.c b/callbacks.c
index a610a43..4523a68 100644
--- a/callbacks.c
+++ b/callbacks.c
@@ -53,25 +53,25 @@ static void key_callback(GLFWwindow *window, int key, int scancode, int action,
if(action == GLFW_PRESS) {
switch(key) {
- case GLFW_KEY_X: nes_state->input[0] |= (1 << 0); break; // A
- case GLFW_KEY_Z: nes_state->input[0] |= (1 << 1); break; // B
- case GLFW_KEY_SPACE: nes_state->input[0] |= (1 << 2); break; // Select
- case GLFW_KEY_ENTER: nes_state->input[0] |= (1 << 3); break; // Start
- case GLFW_KEY_UP: nes_state->input[0] |= (1 << 4); break;
- case GLFW_KEY_DOWN: nes_state->input[0] |= (1 << 5); break;
- case GLFW_KEY_LEFT: nes_state->input[0] |= (1 << 6); break;
- case GLFW_KEY_RIGHT: nes_state->input[0] |= (1 << 7); break;
+ case GLFW_KEY_X: nes_state->input[0] |= (1 << 0); break; // A
+ case GLFW_KEY_Z: nes_state->input[0] |= (1 << 1); break; // B
+ case GLFW_KEY_SPACE: nes_state->input[0] |= (1 << 2); break; // Select
+ case GLFW_KEY_ENTER: nes_state->input[0] |= (1 << 3); break; // Start
+ case GLFW_KEY_UP: nes_state->input[0] |= (1 << 4); break;
+ case GLFW_KEY_DOWN: nes_state->input[0] |= (1 << 5); break;
+ case GLFW_KEY_LEFT: nes_state->input[0] |= (1 << 6); break;
+ case GLFW_KEY_RIGHT: nes_state->input[0] |= (1 << 7); break;
}
} else if(action == GLFW_RELEASE) {
switch(key) {
- case GLFW_KEY_X: nes_state->input[0] &= ~(1 << 0); break;
- case GLFW_KEY_Z: nes_state->input[0] &= ~(1 << 1); break;
- case GLFW_KEY_SPACE: nes_state->input[0] &= ~(1 << 2); break;
- case GLFW_KEY_ENTER: nes_state->input[0] &= ~(1 << 3); break;
- case GLFW_KEY_UP: nes_state->input[0] &= ~(1 << 4); break;
- case GLFW_KEY_DOWN: nes_state->input[0] &= ~(1 << 5); break;
- case GLFW_KEY_LEFT: nes_state->input[0] &= ~(1 << 6); break;
- case GLFW_KEY_RIGHT: nes_state->input[0] &= ~(1 << 7); break;
+ case GLFW_KEY_X: nes_state->input[0] &= ~(1 << 0); break;
+ case GLFW_KEY_Z: nes_state->input[0] &= ~(1 << 1); break;
+ case GLFW_KEY_SPACE: nes_state->input[0] &= ~(1 << 2); break;
+ case GLFW_KEY_ENTER: nes_state->input[0] &= ~(1 << 3); break;
+ case GLFW_KEY_UP: nes_state->input[0] &= ~(1 << 4); break;
+ case GLFW_KEY_DOWN: nes_state->input[0] &= ~(1 << 5); break;
+ case GLFW_KEY_LEFT: nes_state->input[0] &= ~(1 << 6); break;
+ case GLFW_KEY_RIGHT: nes_state->input[0] &= ~(1 << 7); break;
}
}
diff --git a/mapper.c b/mapper.c
index 6d4891b..935ff61 100644
--- a/mapper.c
+++ b/mapper.c
@@ -37,6 +37,7 @@ 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: 2 */ { 0x02, 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: 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 */ { 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 },
diff --git a/memory.c b/memory.c
index a2e094f..54962a5 100644
--- a/memory.c
+++ b/memory.c
@@ -8,15 +8,19 @@ static uint8_t memory_read(struct nes_state *restrict state, uint32_t offset) {
if(LIKELY(offset < 0x2000)) {
return state->ram[offset & 0x07ff];
+
} else if(offset < 0x4000) {
return ppu_read(state, offset);
+
} else if(offset == 0x4016 || offset == 0x4017) {
uint32_t index = offset & 1;
uint8_t value = (state->input_latch[index] >> state->input_bit[index]) & 1;
state->input_bit[index]++;
return value | 0x40; // Bit 6 open bus high, bit 7 low
+
} else if(LIKELY(offset >= 0x6000)) {
return state->mapper.prg_read(state, offset);
+
}
return 0;
}
@@ -28,10 +32,13 @@ static void memory_write(struct nes_state *restrict state, uint32_t offset, uint
if(LIKELY(offset < 0x2000)) {
state->ram[offset & 0x07ff] = value;
+
} else if(offset < 0x4000) {
ppu_write(state, offset, value);
+
} else if(offset == 0x4014) {
ppu_dma_4014(state, value);
+
} else if(offset == 0x4016) {
uint8_t prev = state->input_strobe;
state->input_strobe = value & 1;
@@ -43,6 +50,7 @@ static void memory_write(struct nes_state *restrict state, uint32_t offset, uint
state->input_bit[0] = 0;
state->input_bit[1] = 0;
}
+
} else if(offset >= 0x6000) {
state->mapper.prg_write(state, offset, value);
}
@@ -53,8 +61,10 @@ static uint8_t memory_read_dma(struct nes_state *restrict state, uint32_t offset
// Do not tick CPU/PPU/APU — caller handles timing
if(LIKELY(offset < 0x2000)) {
return state->ram[offset & 0x07ff];
+
} else if(offset >= 0x6000) {
return state->mapper.prg_read(state, offset);
+
}
return 0;
}
diff --git a/mknes.c b/mknes.c
index 9b58753..6bb0475 100644
--- a/mknes.c
+++ b/mknes.c
@@ -90,6 +90,7 @@ static GLFWwindow *window;
#include "render.c"
static uint32_t frames; // debug information
+// #include "smb_tas.h" // REMOVE ME
// NES core
#include "mapper.h"
@@ -160,7 +161,6 @@ static void dump_nametable_text(struct nes_state *state, const char *filename) {
-
int main(int argc, char **argv) {
#ifdef _WIN32
timeBeginPeriod(1);
@@ -179,7 +179,9 @@ int main(int argc, char **argv) {
// ines2_load(nstate, "data/0000/Excitebike (Japan, USA).nes");
// ines2_load(nstate, "data/0000/Ice Climber (USA, Europe, Korea).nes");
// ines2_load(nstate, "data/0000/Kung Fu (Japan, USA).nes");
- ines2_load(nstate, "data/0000/Super Mario Bros. (World) (HVC-SM).nes");
+ // ines2_load(nstate, "data/0000/Super Mario Bros. (World) (HVC-SM).nes");
+ // ines2_load(nstate, "data/Super Mario Bros. (W) (V1.0) [!].nes");
+ ines2_load(nstate, "data/Super Mario Bros. (JU) [!].nes");
// ines2_load(nstate, "data/0000/Urban Champion (World).nes");
// ines2_load(nstate, "data/0000/Wrecking Crew (World).nes");
// ines2_load(nstate, "data/0000/scanline.nes");
@@ -199,11 +201,13 @@ int main(int argc, char **argv) {
// ines2_load(nstate, "data/0000/Xevious - The Avenger (USA).zip");
// ines2_load(nstate, "data/tv.nes");
+ // ines2_load(nstate, "data/Rad Racer II (USA).zip");
+
// ines2_load(nstate, "data/0003/Flipull - An Exciting Cube Game (Japan) (En).zip");
// 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");
@@ -275,6 +279,9 @@ int main(int argc, char **argv) {
// printf("Frame: %d\n", frames);
+
+// static int32_t tas_frame = 0;
+// nstate->input[0] = tas_input[tas_frame++];
while(!nstate->ppu.frame_ready) {
// PROFILE_NAMED("nes emulator");
cpu_tick(nstate);
@@ -282,7 +289,7 @@ int main(int argc, char **argv) {
nstate->ppu.frame_ready = 0;
frames++;
-dump_nametable_text(nstate, "_foofbomb.txt");
+// dump_nametable_text(nstate, "_foofbomb.txt");
uint32_t * restrict dst = display_buffer; //buffer;
uint8_t * restrict src = nstate->pixels;
diff --git a/mknes.h b/mknes.h
index a9e58a0..f8e4be7 100644
--- a/mknes.h
+++ b/mknes.h
@@ -26,11 +26,11 @@ struct ppu_state {
uint16_t bg_shift_attrib_low;
uint16_t bg_shift_attrib_high;
- uint32_t scanline;
- uint32_t dot;
- uint32_t vram_addr;
- uint32_t temp_addr;
- uint32_t fine_x;
+ uint16_t scanline;
+ uint16_t dot;
+ uint16_t vram_addr;
+ uint16_t temp_addr;
+ uint8_t fine_x;
uint8_t bg_next_tile_id;
uint8_t bg_next_tile_attrib;
uint8_t bg_next_tile_lsb;
@@ -49,20 +49,23 @@ struct ppu_state {
uint8_t open_bus;
- uint8_t frame_ready;
uint8_t sprite_zero_hit_possible;
uint8_t sprite_count;
+ uint8_t palette[32];
+
+ // NOTE(peter): CACHELINE 2 start here!
+
uint8_t sprite_indexes[8];
uint8_t sprite_positions[8];
uint8_t sprite_priorities[8];
uint8_t sprite_shift_lo[8];
uint8_t sprite_shift_hi[8];
- uint8_t palette[32];
uint8_t secondary_oam[32];
uint8_t oam[256];
+ uint8_t frame_ready;
} __attribute__((packed, aligned(64)));
struct cpu_state {
diff --git a/ppu.c b/ppu.c
index 7042b19..b34115c 100644
--- a/ppu.c
+++ b/ppu.c
@@ -397,6 +397,9 @@ static void ppu_tick(struct nes_state *state) {
}
if(UNLIKELY(scanline == 241) && dot == 1) {
+ // static int32_t tas_frame = 0;
+ // state->input[0] = tas_input[tas_frame++];
+
ppu->reg_status |= 0x80;
if(ppu->reg_ctrl & 0x80) {
state->nmi_pending = 1;