summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Fors <peter.fors@mindkiller.com>2025-05-02 23:15:47 +0200
committerPeter Fors <peter.fors@mindkiller.com>2025-05-02 23:15:47 +0200
commit5808f00555c48e1cc1cc110af6a5cd73ddf13010 (patch)
treedff942b61441bafe297e7a99f0e799f32ae978b1
parent9463faa436e1b981ef72000568445a83682f2658 (diff)
cleanup and rewrite of ppu_registers.c
-rw-r--r--.gitignore2
-rwxr-xr-xbuild.sh22
-rw-r--r--callbacks.c32
-rw-r--r--cpu.c10
-rw-r--r--dump_mappers.c21
-rw-r--r--mapper.c67
-rw-r--r--mapper_0000.c24
-rw-r--r--mapper_0003.c22
-rw-r--r--mapper_0003.h4
-rw-r--r--mapper_0007.c39
-rw-r--r--mapper_0007.h7
-rw-r--r--mapper_000b.c27
-rw-r--r--mapper_000b.h6
-rw-r--r--mapper_0042.c30
-rw-r--r--mapper_0042.h5
-rw-r--r--mapper_2002.c28
-rw-r--r--mappers/mapper.c63
-rw-r--r--mappers/mapper.h (renamed from mapper.h)31
-rw-r--r--mappers/mapper_000_0.c22
-rw-r--r--mappers/mapper_000_0.h6
-rw-r--r--mappers/mapper_002_2.c41
-rw-r--r--mappers/mapper_002_2.h (renamed from mapper_2002.h)4
-rw-r--r--mappers/mapper_003_0.c27
-rw-r--r--mappers/mapper_003_0.h4
-rw-r--r--mappers/mapper_007_2.c53
-rw-r--r--mappers/mapper_007_2.h8
-rw-r--r--mappers/mapper_011_0.c37
-rw-r--r--mappers/mapper_011_0.h6
-rw-r--r--mappers/mapper_066_0.c38
-rw-r--r--mappers/mapper_066_0.h5
-rw-r--r--memory.c22
-rw-r--r--mknes.c8
-rw-r--r--mknes.h38
-rw-r--r--ppu.c2
-rw-r--r--ppu_registers.c107
35 files changed, 517 insertions, 351 deletions
diff --git a/.gitignore b/.gitignore
index c185c0a..770f711 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,4 +8,4 @@ fragment_shader.h
vertex_shader.h
*.fm2
fm2h.py
-gmon.out \ No newline at end of file
+gmon.out
diff --git a/build.sh b/build.sh
index 1e88141..02d50d3 100755
--- a/build.sh
+++ b/build.sh
@@ -3,12 +3,13 @@
# Set the project name here
PROJECT_NAME="mknes" # Change this for each new project
+CC=gcc-14
+
# Base configuration common to all builds
CFLAGS="-std=gnu11 -mtune=generic "
-CFLAGS+="-mbmi2 "
-CFLAGS+="-mfunction-return=keep "
-CFLAGS+="-mindirect-branch=keep "
-CFLAGS+="-fwrapv -ffast-math -fno-trapping-math -fwhole-program -fvisibility=hidden "
+CFLAGS+="-mbmi -mbmi2 "
+CFLAGS+="-mfunction-return=keep -mindirect-branch=keep "
+CFLAGS+="-fwrapv -ffast-math -fno-trapping-math -fvisibility=hidden "
CFLAGS+="-fno-stack-protector -fno-PIE -no-pie -fno-strict-aliasing -fcf-protection=none -ffunction-sections -fdata-sections "
# CFLAGS+="-fno-exceptions -fno-rtti -fno-use-cxa-atexit "
CFLAGS+="-fno-non-call-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables "
@@ -47,7 +48,7 @@ case "$BUILD_TYPE" in
CFLAGS+=" -s -Wl,--strip-all -O2"
;;
"profile")
- CFLAGS+=" -g -O2 -fprofile-generate"
+ CFLAGS+=" -g -O2 -fprofile-generate -ftest-coverage"
;;
"profile_release")
CFLAGS+=" -s -Wl,--strip-all -O2 -fprofile-use"
@@ -56,6 +57,15 @@ case "$BUILD_TYPE" in
CFLAGS+=" -g -O0"
LDFLAGS+=" -fno-pie -no-pie"
;;
+ "coverage")
+ gcov -b -c *.c
+ exit 0
+ ;;
+
+ "clean")
+ rm -f *.gcda *.gcno *.gcov
+ exit 0
+ ;;
*)
echo "Unknown build type: $BUILD_TYPE"
exit 1
@@ -72,7 +82,7 @@ set -e
# Build Linux version
(
# ../bin/ctime -begin .${PROJECT_NAME}_linux
- gcc $CFLAGS ${PROJECT_NAME}.c -o ${PROJECT_NAME} $INCLUDE_PATHS $LINUX_INCLUDE $LDFLAGS $LINUX_LIBS
+ $CC $CFLAGS ${PROJECT_NAME}.c -o ${PROJECT_NAME} $INCLUDE_PATHS $LINUX_INCLUDE $LDFLAGS $LINUX_LIBS
# ../bin/ctime -end .${PROJECT_NAME}_linux $?
) &
diff --git a/callbacks.c b/callbacks.c
index 4523a68..6b62ea6 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->ppu.input[0] |= (1 << 0); break; // A
+ case GLFW_KEY_Z: nes_state->ppu.input[0] |= (1 << 1); break; // B
+ case GLFW_KEY_SPACE: nes_state->ppu.input[0] |= (1 << 2); break; // Select
+ case GLFW_KEY_ENTER: nes_state->ppu.input[0] |= (1 << 3); break; // Start
+ case GLFW_KEY_UP: nes_state->ppu.input[0] |= (1 << 4); break;
+ case GLFW_KEY_DOWN: nes_state->ppu.input[0] |= (1 << 5); break;
+ case GLFW_KEY_LEFT: nes_state->ppu.input[0] |= (1 << 6); break;
+ case GLFW_KEY_RIGHT: nes_state->ppu.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->ppu.input[0] &= ~(1 << 0); break;
+ case GLFW_KEY_Z: nes_state->ppu.input[0] &= ~(1 << 1); break;
+ case GLFW_KEY_SPACE: nes_state->ppu.input[0] &= ~(1 << 2); break;
+ case GLFW_KEY_ENTER: nes_state->ppu.input[0] &= ~(1 << 3); break;
+ case GLFW_KEY_UP: nes_state->ppu.input[0] &= ~(1 << 4); break;
+ case GLFW_KEY_DOWN: nes_state->ppu.input[0] &= ~(1 << 5); break;
+ case GLFW_KEY_LEFT: nes_state->ppu.input[0] &= ~(1 << 6); break;
+ case GLFW_KEY_RIGHT: nes_state->ppu.input[0] &= ~(1 << 7); break;
}
}
diff --git a/cpu.c b/cpu.c
index 9f0639d..74d253d 100644
--- a/cpu.c
+++ b/cpu.c
@@ -2,7 +2,7 @@
#include <stdio.h>
#include <string.h>
-// REMOVE FOR NES!!!!!
+// DO NOT ENABLE FOR NES!!!!!
// #define ENABLE_DECIMAL_MODE
__attribute__((hot))
@@ -75,11 +75,11 @@ __attribute__((always_inline, hot))
static inline void check_interrupts(struct nes_state * restrict state) {
struct cpu_state * restrict cpu = &state->cpu;
- if(state->nmi_pending) {
- state->nmi_pending = 0;
+ if(state->cpu.nmi_pending) {
+ state->cpu.nmi_pending = 0;
do_nmi(state);
- } else if(state->irq_pending && cpu->i == 0) {
- state->irq_pending = 0;
+ } else if(state->cpu.irq_pending && cpu->i == 0) {
+ state->cpu.irq_pending = 0;
do_irq(state);
}
}
diff --git a/dump_mappers.c b/dump_mappers.c
index 42034de..98dad4e 100644
--- a/dump_mappers.c
+++ b/dump_mappers.c
@@ -9,6 +9,13 @@
#define INES_HEADER_SIZE 16
+static void print_mapper(uint32_t mapper, const char *path) {
+ uint32_t mapper_id = mapper >> 4;
+ uint32_t submapper = mapper & 0xF;
+
+ printf("%03u_%x %s\n", mapper_id, submapper, path);
+}
+
static void process_nes_file(const char *path) {
FILE *f = fopen(path, "rb");
if(!f) return;
@@ -27,8 +34,10 @@ static void process_nes_file(const char *path) {
uint8_t mapper_ext = header[8] & 0x0F;
uint8_t submapper = header[8] >> 4;
- uint32_t mapper = (submapper << 12) | (mapper_ext << 8) | mapper_high | mapper_low;
- printf("0x%04x %s\n", mapper, path);
+ uint32_t mapper = (mapper_ext << 8) | mapper_high | mapper_low;
+ mapper = (mapper << 4) | submapper;
+
+ print_mapper(mapper, path);
}
static void process_zip_file(const char *path) {
@@ -73,8 +82,10 @@ static void process_zip_file(const char *path) {
uint8_t mapper_ext = header[8] & 0x0F;
uint8_t submapper = header[8] >> 4;
- uint32_t mapper = (submapper << 12) | (mapper_ext << 8) | mapper_high | mapper_low;
- printf("0x%04x %s\n", mapper, path);
+ uint32_t mapper = (mapper_ext << 8) | mapper_high | mapper_low;
+ mapper = (mapper << 4) | submapper;
+
+ print_mapper(mapper, path);
}
static void scan_directory(const char *path) {
@@ -104,7 +115,7 @@ static void scan_directory(const char *path) {
int main(int argc, char **argv) {
if(argc < 2) {
- fprintf(stderr, "usage: %s <romdir>\n", argv[0]);
+ fprintf(stderr, "Usage: %s <romdir>\n", argv[0]);
return 1;
}
scan_directory(argv[1]);
diff --git a/mapper.c b/mapper.c
deleted file mode 100644
index 935ff61..0000000
--- a/mapper.c
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
-#include "mapper_0000.c"
-#include "mapper_0003.c"
-#include "mapper_0007.c"
-#include "mapper_000b.c"
-#include "mapper_0042.c"
-#include "mapper_2002.c"
-
-
-static uint8_t mapper_default_ciram_read(struct nes_state *state, uint32_t addr) {
- if(state->ines.mirroring == 0) { // Horizontal
- addr = (addr & 0x800) | (addr & 0x3ff);
- } else { // Vertical (default fallback)
- addr = addr & 0x7ff;
- }
-
- return state->ciram[addr];
-}
-
-static void mapper_default_ciram_write(struct nes_state *state, uint32_t addr, uint8_t value) {
- if(state->ines.mirroring == 0) {
- addr = (addr & 0x800) | (addr & 0x3ff);
- } else {
- addr = addr & 0x7ff;
- }
- state->ciram[addr] = value;
-}
-
-static void mapper_default_tick(struct nes_state *state) { // No IRQ or timing logic needed
-}
-
-/*
- * Mapper numbers are constructed like this: (submapper << 12 | mapperid) both in hex.
- *
- * NOTE(peter): Mapper 0 always has to be first!
- */
-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 },
-/* 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) {
- uint32_t mapper = (state->ines.submapper << 12) | state->ines.mapper;
- for(uint32_t i = 0; i < sizeof(mapper_table)/sizeof(mapper_table[0]); i++) {
- if(mapper_table[i].id == mapper) {
- printf("Mapper %4.4x\n", mapper);
- memcpy(&state->mapper, &mapper_table[i], sizeof(struct mapper_entry)); // NOTE(peter): BECAUSE GCC IS BROKEN
- // state->mapper = mapper_table[i];
- state->mapper.init(state);
- return;
- }
- }
-
- printf("Unsupported mapper %4.4x, falling back to NROM\n", mapper);
- memcpy(&state->mapper, &mapper_table[0], sizeof(struct mapper_entry)); // NOTE(peter): BECAUSE GCC IS BROKEN
- // state->mapper = mapper_table[0];
- state->mapper.init(state);
-}
-
diff --git a/mapper_0000.c b/mapper_0000.c
deleted file mode 100644
index e075de5..0000000
--- a/mapper_0000.c
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-static void mapper_0000_init(struct nes_state *state) {
- // Nothing to initialize for 001
-}
-
-__attribute__((hot))
-static uint8_t mapper_0000_prg_read(struct nes_state *state, uint32_t addr) {
- uint32_t prg_size = state->ines.prg_size;
-
- uint32_t mask = (state->ines.prg_size == 16384) ? 0x3fff : 0x7fff;
- return state->prg_rom[addr & mask];
-}
-
-static void mapper_0000_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) {
-}
-
-__attribute__((hot))
-static uint8_t mapper_0000_chr_read(struct nes_state *state, uint32_t addr) {
- return state->chr_rom[addr];
-}
-
-static void mapper_0000_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) {
-}
diff --git a/mapper_0003.c b/mapper_0003.c
deleted file mode 100644
index a4ae56c..0000000
--- a/mapper_0003.c
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-static void mapper_0003_init(struct nes_state *state) {
- state->map.m0003.chr_ptr = state->chr_rom;
-}
-
-static uint8_t mapper_0003_prg_read(struct nes_state *state, uint32_t addr) {
- return state->prg_rom[addr & 0x7fff];
-}
-
-static void mapper_0003_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) {
- if(addr >= 0x8000) {
- state->map.m0003.chr_ptr = state->chr_rom + (value & 3) * 0x2000;
- }
-}
-
-static uint8_t mapper_0003_chr_read(struct nes_state *state, uint32_t addr) {
- return state->map.m0003.chr_ptr[addr];
-}
-
-static void mapper_0003_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) {
-}
diff --git a/mapper_0003.h b/mapper_0003.h
deleted file mode 100644
index c562519..0000000
--- a/mapper_0003.h
+++ /dev/null
@@ -1,4 +0,0 @@
-
-struct mapper_0003 {
- uint8_t *chr_ptr;
-};
diff --git a/mapper_0007.c b/mapper_0007.c
deleted file mode 100644
index 235f5bb..0000000
--- a/mapper_0007.c
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-static void mapper_0007_init(struct nes_state *state) {
- state->map.m0007.prg_ptr = state->prg_rom;
- 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 & 0x7fff];
- }
- 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 & 0x0f) * 0x8000);
- state->map.m0007.ciram_base = (value & 0x10) ? 0x400 : 0x000;
- }
-}
-
-static uint8_t mapper_0007_chr_read(struct nes_state *state, uint32_t addr) {
- return state->chr_ram[addr];
-}
-
-static void mapper_0007_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) {
- state->chr_ram[addr] = value;
-}
-
-static uint8_t mapper_0007_ciram_read(struct nes_state *state, uint32_t addr) {
- 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) {
- addr = state->map.m0007.ciram_base | (addr & 0x3ff);
- state->ciram[addr] = value;
-}
diff --git a/mapper_0007.h b/mapper_0007.h
deleted file mode 100644
index 775082b..0000000
--- a/mapper_0007.h
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-struct mapper_0007 {
- uint8_t *prg_ptr;
- uint32_t ciram_base;
-};
-
diff --git a/mapper_000b.c b/mapper_000b.c
deleted file mode 100644
index 9252060..0000000
--- a/mapper_000b.c
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-static void mapper_000b_init(struct nes_state *state) {
- state->map.m000b.prg_ptr = state->prg_rom;
- state->map.m000b.chr_ptr = state->chr_rom;
-}
-
-static uint8_t mapper_000b_prg_read(struct nes_state *state, uint32_t addr) {
- if(addr >= 0x8000) {
- return state->map.m000b.prg_ptr[addr - 0x8000];
- }
- return 0;
-}
-
-static void mapper_000b_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) {
- if(addr >= 0x8000) {
- state->map.m000b.prg_ptr = state->prg_rom + ((value >> 4) & 7) * 0x8000;
- state->map.m000b.chr_ptr = state->chr_rom + (value & 0x0F) * 0x2000;
- }
-}
-
-static uint8_t mapper_000b_chr_read(struct nes_state *state, uint32_t addr) {
- return state->map.m000b.chr_ptr[addr];
-}
-
-static void mapper_000b_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) {
-}
diff --git a/mapper_000b.h b/mapper_000b.h
deleted file mode 100644
index 2c3f15a..0000000
--- a/mapper_000b.h
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-struct mapper_000b {
- uint8_t *prg_ptr;
- uint8_t *chr_ptr;
-};
diff --git a/mapper_0042.c b/mapper_0042.c
deleted file mode 100644
index 4cf4c86..0000000
--- a/mapper_0042.c
+++ /dev/null
@@ -1,30 +0,0 @@
-
-static void mapper_0042_init(struct nes_state *state) {
- state->map.m0042.prg_offset = 0;
- state->map.m0042.chr_offset = 0;
-}
-
-static uint8_t mapper_0042_prg_read(struct nes_state *state, uint32_t addr) {
- if(addr >= 0x8000) {
- uint32_t base = state->map.m0042.prg_offset;
- return state->prg_rom[base + (addr - 0x8000)];
- }
- return 0;
-}
-
-static void mapper_0042_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) {
- if(addr >= 0x8000) {
- uint32_t prg_bank = (value >> 4) & 3;
- uint32_t chr_bank = (value >> 0) & 3;
-
- state->map.m0042.prg_offset = prg_bank * 0x8000;
- state->map.m0042.chr_offset = chr_bank * 0x2000;
- }
-}
-
-static uint8_t mapper_0042_chr_read(struct nes_state *state, uint32_t addr) {
- return state->chr_rom[state->map.m0042.chr_offset + addr];
-}
-
-static void mapper_0042_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) {
-}
diff --git a/mapper_0042.h b/mapper_0042.h
deleted file mode 100644
index cb201d9..0000000
--- a/mapper_0042.h
+++ /dev/null
@@ -1,5 +0,0 @@
-
-struct mapper_0042 {
- uint32_t prg_offset;
- uint32_t chr_offset;
-};
diff --git a/mapper_2002.c b/mapper_2002.c
deleted file mode 100644
index 700a24b..0000000
--- a/mapper_2002.c
+++ /dev/null
@@ -1,28 +0,0 @@
-
-static void mapper_2002_init(struct nes_state *state) {
- state->map.m2002.prg_bank0 = state->prg_rom; // default to bank 0
- state->map.m2002.prg_bank1 = state->prg_rom + state->ines.prg_size - 0x4000;
-}
-
-static uint8_t mapper_2002_prg_read(struct nes_state *state, uint32_t addr) {
- if(addr >= 0x8000 && addr < 0xc000) {
- return state->map.m2002.prg_bank0[addr & 0x3fff];
- } else if(addr >= 0xc000) {
- return state->map.m2002.prg_bank1[addr & 0x3fff];
- }
- return 0;
-}
-
-static void mapper_2002_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) {
- if(addr >= 0x8000) {
- state->map.m2002.prg_bank0 = state->prg_rom + ((value & 0x0f) * 0x4000);
- }
-}
-
-static uint8_t mapper_2002_chr_read(struct nes_state *state, uint32_t addr) {
- return state->chr_ram[addr];
-}
-
-static void mapper_2002_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) {
- state->chr_ram[addr] = value;
-}
diff --git a/mappers/mapper.c b/mappers/mapper.c
new file mode 100644
index 0000000..d63e2a0
--- /dev/null
+++ b/mappers/mapper.c
@@ -0,0 +1,63 @@
+
+static uint8_t mapper_default_ciram_read(struct nes_state *state, uint32_t addr) {
+ if(state->ines.mirroring == 0) { // Horizontal
+ addr = (addr & 0x800) | (addr & 0x3ff);
+ } else { // Vertical (default fallback)
+ addr = addr & 0x7ff;
+ }
+
+ return state->ciram[addr];
+}
+
+static void mapper_default_ciram_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ if(state->ines.mirroring == 0) {
+ addr = (addr & 0x800) | (addr & 0x3ff);
+ } else {
+ addr = addr & 0x7ff;
+ }
+ state->ciram[addr] = value;
+}
+
+static void mapper_default_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) { }
+static void mapper_default_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) { }
+static void mapper_default_tick(struct nes_state *state) { }
+
+#include "mapper_000_0.c"
+#include "mapper_002_2.c"
+#include "mapper_003_0.c"
+#include "mapper_007_2.c"
+#include "mapper_011_0.c"
+#include "mapper_066_0.c"
+
+#define MAPPER_ID(mapper, submapper) (((mapper) << 4) | (submapper))
+
+static void (*mapper_table[4096])(struct nes_state *state) = {
+ [MAPPER_ID( 0, 0)] = mapper_000_0_init,
+ [MAPPER_ID( 2, 2)] = mapper_002_2_init,
+ [MAPPER_ID( 3, 0)] = mapper_003_0_init,
+ [MAPPER_ID( 7, 2)] = mapper_007_2_init,
+ [MAPPER_ID(11, 0)] = mapper_011_0_init,
+ [MAPPER_ID(66, 0)] = mapper_011_0_init,
+};
+
+static void mapper_reset(struct nes_state *state) {
+ state->mapper.prg_read = 0;
+ state->mapper.prg_write = mapper_default_prg_write;
+ state->mapper.chr_read = 0;
+ state->mapper.chr_write = mapper_default_chr_write;
+ state->mapper.ciram_read = mapper_default_ciram_read;
+ state->mapper.ciram_write = mapper_default_ciram_write;
+ state->mapper.tick = mapper_default_tick;
+}
+
+static void mapper_setup(struct nes_state *state) {
+ uint32_t mapper = state->ines.mapper << 4 | state->ines.submapper;
+ mapper_reset(state);
+ if(mapper_table[mapper]) {
+ mapper_table[mapper](state);
+ } else {
+ printf("Unsupported mapper %d_%x, falling back to NROM\n", state->ines.mapper, state->ines.submapper);
+ mapper_table[0](state);
+ }
+}
+
diff --git a/mapper.h b/mappers/mapper.h
index 73fafc0..0961370 100644
--- a/mapper.h
+++ b/mappers/mapper.h
@@ -1,15 +1,14 @@
-// #include "mapper_0000.h" // NOTE(peter): Has no header
-#include "mapper_0003.h"
-#include "mapper_0007.h"
-#include "mapper_000b.h"
-#include "mapper_0042.h"
-#include "mapper_2002.h"
+#include "mapper_000_0.h"
+#include "mapper_002_2.h"
+#include "mapper_003_0.h"
+#include "mapper_007_2.h"
+#include "mapper_011_0.h"
+#include "mapper_066_0.h"
struct nes_state;
-struct mapper_entry {
- uint64_t id;
+struct mapper_functions {
uint8_t (*prg_read)(struct nes_state *state, uint32_t addr);
void (*prg_write)(struct nes_state *state, uint32_t addr, uint8_t value);
uint8_t (*chr_read)(struct nes_state *state, uint32_t addr);
@@ -17,14 +16,14 @@ struct mapper_entry {
uint8_t (*ciram_read)(struct nes_state *state, uint32_t addr);
void (*ciram_write)(struct nes_state *state, uint32_t addr, uint8_t value);
void (*tick)(struct nes_state *state);
- void (*init)(struct nes_state *state);
-};
+} __attribute__((aligned(64)));
union mapper_data {
- struct mapper_0003 m0003;
- struct mapper_0007 m0007;
- struct mapper_000b m000b;
- struct mapper_0042 m0042;
- struct mapper_2002 m2002;
-};
+ struct mapper_000_0 m000_0;
+ struct mapper_002_2 m002_2;
+ struct mapper_003_0 m003_0;
+ struct mapper_007_2 m007_2;
+ struct mapper_011_0 m011_0;
+ struct mapper_066_0 m066_0;
+} __attribute__((aligned(64)));
diff --git a/mappers/mapper_000_0.c b/mappers/mapper_000_0.c
new file mode 100644
index 0000000..b79cdbf
--- /dev/null
+++ b/mappers/mapper_000_0.c
@@ -0,0 +1,22 @@
+
+
+__attribute__((hot))
+static uint8_t mapper_000_0_prg_read(struct nes_state *state, uint32_t addr) {
+ struct mapper_000_0 *mapper = (struct mapper_000_0 *)&state->map;
+
+ return state->prg_rom[addr & mapper->mask];
+}
+
+__attribute__((hot))
+static uint8_t mapper_000_0_chr_read(struct nes_state *state, uint32_t addr) {
+ return state->chr_rom[addr];
+}
+
+static void mapper_000_0_init(struct nes_state *state) {
+ struct mapper_000_0 *mapper = (struct mapper_000_0 *)&state->map;
+ state->mapper.prg_read = mapper_000_0_prg_read;
+ state->mapper.chr_read = mapper_000_0_chr_read;
+ mapper->mask = (state->ines.prg_size == 16384) ? 0x3fff : 0x7fff;
+}
+
+
diff --git a/mappers/mapper_000_0.h b/mappers/mapper_000_0.h
new file mode 100644
index 0000000..86e279c
--- /dev/null
+++ b/mappers/mapper_000_0.h
@@ -0,0 +1,6 @@
+
+
+
+struct mapper_000_0 {
+ uint32_t mask;
+} __attribute__((packed, aligned(64)));
diff --git a/mappers/mapper_002_2.c b/mappers/mapper_002_2.c
new file mode 100644
index 0000000..079fb0b
--- /dev/null
+++ b/mappers/mapper_002_2.c
@@ -0,0 +1,41 @@
+
+
+static uint8_t mapper_002_2_prg_read(struct nes_state *state, uint32_t addr) {
+ struct mapper_002_2 *mapper = (struct mapper_002_2 *)&state->map;
+
+ if(addr >= 0x8000 && addr < 0xc000) {
+ return mapper->prg_bank0[addr & 0x3fff];
+
+ } else if(addr >= 0xc000) {
+ return mapper->prg_bank1[addr & 0x3fff];
+ }
+ return 0;
+}
+
+static void mapper_002_2_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ struct mapper_002_2 *mapper = (struct mapper_002_2 *)&state->map;
+
+ if(addr >= 0x8000) {
+ mapper->prg_bank0 = state->prg_rom + ((value & 0x0f) * 0x4000);
+ }
+}
+
+static uint8_t mapper_002_2_chr_read(struct nes_state *state, uint32_t addr) {
+ return state->chr_ram[addr];
+}
+
+static void mapper_002_2_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ state->chr_ram[addr] = value;
+}
+
+static void mapper_002_2_init(struct nes_state *state) {
+ struct mapper_002_2 *mapper = (struct mapper_002_2 *)&state->map;
+
+ mapper->prg_bank0 = state->prg_rom;
+ mapper->prg_bank1 = state->prg_rom + state->ines.prg_size - 0x4000;
+
+ state->mapper.prg_read = mapper_002_2_prg_read;
+ state->mapper.prg_write = mapper_002_2_prg_write;
+ state->mapper.chr_read = mapper_002_2_chr_read;
+ state->mapper.chr_write = mapper_002_2_chr_write;
+}
diff --git a/mapper_2002.h b/mappers/mapper_002_2.h
index 6c648b5..b136274 100644
--- a/mapper_2002.h
+++ b/mappers/mapper_002_2.h
@@ -1,7 +1,7 @@
-struct mapper_2002 {
+struct mapper_002_2 {
uint8_t *prg_bank0; // $8000–BFFF (switchable)
uint8_t *prg_bank1; // $C000–FFFF (fixed to last 16KB)
-};
+} __attribute__((packed, aligned(64)));
diff --git a/mappers/mapper_003_0.c b/mappers/mapper_003_0.c
new file mode 100644
index 0000000..5ccfb53
--- /dev/null
+++ b/mappers/mapper_003_0.c
@@ -0,0 +1,27 @@
+
+static uint8_t mapper_003_0_prg_read(struct nes_state *state, uint32_t addr) {
+ return state->prg_rom[addr & 0x7fff];
+}
+
+static void mapper_003_0_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ struct mapper_003_0 *mapper = (struct mapper_003_0 *)&state->map;
+
+ if(addr >= 0x8000) {
+ mapper->chr_ptr = state->chr_rom + (value & 3) * 0x2000;
+ }
+}
+
+static uint8_t mapper_003_0_chr_read(struct nes_state *state, uint32_t addr) {
+ struct mapper_003_0 *mapper = (struct mapper_003_0 *)&state->map;
+ return mapper->chr_ptr[addr];
+}
+
+static void mapper_003_0_init(struct nes_state *state) {
+ struct mapper_003_0 *mapper = (struct mapper_003_0 *)&state->map;
+
+ mapper->chr_ptr = state->chr_rom;
+
+ state->mapper.prg_read = mapper_003_0_prg_read;
+ state->mapper.prg_write = mapper_003_0_prg_write;
+ state->mapper.chr_read = mapper_003_0_chr_read;
+}
diff --git a/mappers/mapper_003_0.h b/mappers/mapper_003_0.h
new file mode 100644
index 0000000..f03b106
--- /dev/null
+++ b/mappers/mapper_003_0.h
@@ -0,0 +1,4 @@
+
+struct mapper_003_0 {
+ uint8_t *chr_ptr;
+} __attribute__((packed, aligned(64)));
diff --git a/mappers/mapper_007_2.c b/mappers/mapper_007_2.c
new file mode 100644
index 0000000..ed56dd0
--- /dev/null
+++ b/mappers/mapper_007_2.c
@@ -0,0 +1,53 @@
+
+
+static uint8_t mapper_007_2_prg_read(struct nes_state *state, uint32_t addr) {
+ struct mapper_007_2 *mapper = (struct mapper_007_2 *)&state->map;
+ if(addr >= 0x8000) {
+ return mapper->prg_rom[addr & 0x7fff];
+ }
+ return 0;
+}
+
+static void mapper_007_2_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ struct mapper_007_2 *mapper = (struct mapper_007_2 *)&state->map;
+ if(addr >= 0x8000) {
+ uint32_t prg_off = (value & 0x0f) << 15;
+ uint32_t ciram_off = (value & 0x10) << 11;
+ mapper->prg_rom = state->prg_rom + prg_off;
+ mapper->ciram = state->ciram + ciram_off;
+
+ // mapper->prg_rom = state->prg_rom + ((value & 0x0f) * 0x8000);
+ // mapper->ciram = state->ciram + ((value & 0x10) ? 0x400 : 0x000);
+ }
+}
+
+static uint8_t mapper_007_2_chr_read(struct nes_state *state, uint32_t addr) {
+ return state->chr_ram[addr];
+}
+
+static void mapper_007_2_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ state->chr_ram[addr] = value;
+}
+
+static uint8_t mapper_007_2_ciram_read(struct nes_state *state, uint32_t addr) {
+ struct mapper_007_2 *mapper = (struct mapper_007_2 *)&state->map;
+ return mapper->ciram[addr & 0x3ff];
+}
+
+static void mapper_007_2_ciram_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ struct mapper_007_2 *mapper = (struct mapper_007_2 *)&state->map;
+ mapper->ciram[addr & 0x3ff] = value;
+}
+
+static void mapper_007_2_init(struct nes_state *state) {
+ struct mapper_007_2 *mapper = (struct mapper_007_2 *)&state->map;
+ mapper->prg_rom = state->prg_rom;
+ mapper->ciram = 0;
+
+ state->mapper.prg_read = mapper_007_2_prg_read;
+ state->mapper.prg_write = mapper_007_2_prg_write;
+ state->mapper.chr_read = mapper_007_2_chr_read;
+ state->mapper.chr_write = mapper_007_2_chr_write;
+ state->mapper.ciram_read = mapper_007_2_ciram_read;
+ state->mapper.ciram_write = mapper_007_2_ciram_write;
+}
diff --git a/mappers/mapper_007_2.h b/mappers/mapper_007_2.h
new file mode 100644
index 0000000..c0a2d06
--- /dev/null
+++ b/mappers/mapper_007_2.h
@@ -0,0 +1,8 @@
+
+
+struct mapper_007_2 {
+ uint8_t *prg_rom;
+ uint8_t *ciram;
+ // uint32_t ciram_base;
+} __attribute__((packed, aligned(64)));
+
diff --git a/mappers/mapper_011_0.c b/mappers/mapper_011_0.c
new file mode 100644
index 0000000..ce390a0
--- /dev/null
+++ b/mappers/mapper_011_0.c
@@ -0,0 +1,37 @@
+
+
+static uint8_t mapper_011_0_prg_read(struct nes_state *state, uint32_t addr) {
+ struct mapper_011_0 *mapper = (struct mapper_011_0 *)&state->map;
+
+ if(addr >= 0x8000) {
+ return mapper->prg_rom[addr - 0x8000];
+ }
+ return 0;
+}
+
+static void mapper_011_0_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ struct mapper_011_0 *mapper = (struct mapper_011_0 *)&state->map;
+
+ if(addr >= 0x8000) {
+ mapper->prg_rom = state->prg_rom + ((value >> 4) & 7) * 0x8000;
+ mapper->chr_ptr = state->chr_rom + (value & 0x0F) * 0x2000;
+ }
+}
+
+static uint8_t mapper_011_0_chr_read(struct nes_state *state, uint32_t addr) {
+ struct mapper_011_0 *mapper = (struct mapper_011_0 *)&state->map;
+
+ return mapper->chr_ptr[addr];
+}
+
+static void mapper_011_0_init(struct nes_state *state) {
+ struct mapper_011_0 *mapper = (struct mapper_011_0 *)&state->map;
+
+ mapper->prg_rom = state->prg_rom;
+ mapper->chr_ptr = state->chr_rom;
+
+ state->mapper.prg_read = mapper_011_0_prg_read;
+ state->mapper.prg_write = mapper_011_0_prg_write;
+ state->mapper.chr_read = mapper_011_0_chr_read;
+}
+
diff --git a/mappers/mapper_011_0.h b/mappers/mapper_011_0.h
new file mode 100644
index 0000000..8f41e8e
--- /dev/null
+++ b/mappers/mapper_011_0.h
@@ -0,0 +1,6 @@
+
+
+struct mapper_011_0 {
+ uint8_t *prg_rom;
+ uint8_t *chr_ptr;
+} __attribute__((packed, aligned(64)));
diff --git a/mappers/mapper_066_0.c b/mappers/mapper_066_0.c
new file mode 100644
index 0000000..bf31720
--- /dev/null
+++ b/mappers/mapper_066_0.c
@@ -0,0 +1,38 @@
+
+static uint8_t mapper_066_0_prg_read(struct nes_state *state, uint32_t addr) {
+ struct mapper_066_0 *mapper = (struct mapper_066_0 *)&state->map;
+
+ if(addr >= 0x8000) {
+ return state->prg_rom[addr & 0x7fff];
+ }
+ return 0;
+}
+
+static void mapper_066_0_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ struct mapper_066_0 *mapper = (struct mapper_066_0 *)&state->map;
+
+ if(addr >= 0x8000) {
+ uint32_t prg_bank = (value >> 4) & 3;
+ uint32_t chr_bank = (value >> 0) & 3;
+
+ mapper->prg_offset = state->prg_rom + (prg_bank * 0x8000);
+ mapper->chr_offset = state->chr_rom + (chr_bank * 0x2000);
+ }
+}
+
+static uint8_t mapper_066_0_chr_read(struct nes_state *state, uint32_t addr) {
+ struct mapper_066_0 *mapper = (struct mapper_066_0 *)&state->map;
+ return mapper->chr_offset[addr];
+}
+
+static void mapper_066_0_init(struct nes_state *state) {
+ struct mapper_066_0 *mapper = (struct mapper_066_0 *)&state->map;
+
+ mapper->prg_offset = state->prg_rom;
+ mapper->chr_offset = state->chr_rom;
+
+ state->mapper.prg_read = mapper_066_0_prg_read;
+ state->mapper.prg_write = mapper_066_0_prg_write;
+ state->mapper.chr_read = mapper_066_0_chr_read;
+}
+
diff --git a/mappers/mapper_066_0.h b/mappers/mapper_066_0.h
new file mode 100644
index 0000000..b09ee56
--- /dev/null
+++ b/mappers/mapper_066_0.h
@@ -0,0 +1,5 @@
+
+struct mapper_066_0 {
+ uint8_t *prg_offset;
+ uint8_t *chr_offset;
+} __attribute__((packed, aligned(64)));
diff --git a/memory.c b/memory.c
index e934136..74b0a0f 100644
--- a/memory.c
+++ b/memory.c
@@ -3,7 +3,7 @@
__attribute__((hot))
static uint8_t memory_read(struct nes_state *restrict state, uint32_t offset) {
- state->cycles++;
+ state->cpu.cycles++;
ppu_tick(state);
// apu_tick(state);
@@ -15,8 +15,8 @@ static uint8_t memory_read(struct nes_state *restrict state, uint32_t 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]++;
+ uint8_t value = (state->ppu.input_latch[index] >> state->ppu.input_bit[index]) & 1;
+ state->ppu.input_bit[index]++;
return value | 0x40; // Bit 6 open bus high, bit 7 low
// } else if(offset == 4015) {
@@ -32,7 +32,7 @@ static uint8_t memory_read(struct nes_state *restrict state, uint32_t offset) {
__attribute__((hot))
static void memory_write(struct nes_state *restrict state, uint32_t offset, uint8_t value) {
- state->cycles++;
+ state->cpu.cycles++;
ppu_tick(state);
// apu_tick(state);
@@ -51,15 +51,15 @@ static void memory_write(struct nes_state *restrict state, uint32_t offset, uint
// state->apu.dmc_dma_enabled = (value & 0x10) ? 1 : 0;
} else if(offset == 0x4016) {
- uint8_t prev = state->input_strobe;
- state->input_strobe = value & 1;
+ uint8_t prev = state->ppu.input_strobe;
+ state->ppu.input_strobe = value & 1;
if(prev == 1 && (value & 1) == 0) {
// Latch current inputs
- state->input_latch[0] = state->input[0];
- state->input_latch[1] = state->input[1];
- state->input_bit[0] = 0;
- state->input_bit[1] = 0;
+ state->ppu.input_latch[0] = state->ppu.input[0];
+ state->ppu.input_latch[1] = state->ppu.input[1];
+ state->ppu.input_bit[0] = 0;
+ state->ppu.input_bit[1] = 0;
}
// } else if(offset == 0x4017) { // Frame Counter (APU)
@@ -90,7 +90,7 @@ static uint8_t memory_read_dma(struct nes_state *restrict state, uint32_t offset
__attribute__((hot))
static uint8_t memory_read_dummy(struct nes_state *restrict state, uint32_t offset) {
- state->cycles++;
+ state->cpu.cycles++;
ppu_tick(state);
// apu_tick(state);
diff --git a/mknes.c b/mknes.c
index beceef6..2aff691 100644
--- a/mknes.c
+++ b/mknes.c
@@ -93,7 +93,7 @@ static uint32_t frames; // debug information
// #include "smb_tas.h" // REMOVE ME
// NES core
-#include "mapper.h"
+#include "mappers/mapper.h"
#include "mknes.h"
// #include "apu.c"
#include "ppu.c"
@@ -101,7 +101,7 @@ static uint32_t frames; // debug information
#include "memory.c"
#include "cpu.c"
#include "ines2.c"
-#include "mapper.c"
+#include "mappers/mapper.c"
#include "callbacks.c"
struct nes_state nstate;
@@ -236,7 +236,6 @@ int main(int argc, char **argv) {
return 0;
#endif
-
struct timer_handle *timer = timer_new(FRAME_INTERVAL_NS);
if(!timer) {
fprintf(stderr, "Failed to create timer\n");
@@ -263,7 +262,6 @@ int main(int argc, char **argv) {
framebuffer_callback(window, WINDOW_WIDTH, WINDOW_HEIGHT);
-
for(int jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++) {
if(glfwJoystickPresent(jid)) {
const char *name = glfwGetJoystickName(jid);
@@ -308,7 +306,7 @@ int main(int argc, char **argv) {
render_frame();
glfwSwapBuffers(window);
}
-printf("total frames: %6.6d total cycles: %ld\n", frames, nstate->cycles);
+printf("total frames: %6.6d total cycles: %ld\n", frames, nstate->cpu.cycles);
glfwDestroyWindow(window);
} else {
fprintf(stderr, "Failed to create window\n");
diff --git a/mknes.h b/mknes.h
index fb1228b..e1dc8f2 100644
--- a/mknes.h
+++ b/mknes.h
@@ -64,6 +64,10 @@ struct ppu_state {
uint8_t secondary_oam[32];
uint8_t oam[256];
+ uint8_t input[2]; // Controller 1 & 2
+ uint8_t input_latch[2]; // Latched inputs after strobe
+ uint8_t input_bit[2]; // Current bit position being shifted out
+ uint8_t input_strobe; // Control bit (0 or 1)
uint8_t frame_ready;
} __attribute__((packed, aligned(64)));
@@ -74,9 +78,10 @@ struct apu_state {
uint8_t irq_pending;
uint8_t dmc_dma_enabled;
uint32_t dmc_sample_timer;
-};
+} __attribute__((packed, aligned(64)));
struct cpu_state {
+ size_t cycles;
uint32_t pc; // Program Counter
uint8_t sp; // Stack Pointer
uint8_t a; // Accumulator
@@ -91,42 +96,35 @@ struct cpu_state {
uint8_t z; // Zero Flag
uint8_t c; // Carry Flag
// --
- uint8_t die; // KIL instruction found!
-};// __attribute__((aligned(64)));
+ uint8_t irq_pending;
+ uint8_t nmi_pending;
+} __attribute__((packed, aligned(64)));
struct ines_state {
- uint32_t mapper;
- uint32_t submapper;
+ uint8_t mapper;
+ uint8_t submapper;
uint8_t mirroring; // 0 = H, 1 = V, 2 = 4-screen
uint32_t prg_size;
uint32_t chr_size;
-};
+} __attribute__((packed, aligned(64)));
struct nes_state {
- size_t cycles;
- struct cpu_state cpu;
- uint8_t irq_pending;
- uint8_t nmi_pending;
- uint8_t input[2]; // Controller 1 & 2
- uint8_t input_latch[2]; // Latched inputs after strobe
- uint8_t input_bit[2]; // Current bit position being shifted out
- uint8_t input_strobe; // Control bit (0 or 1)
- // struct apu_state apu;
struct ppu_state ppu;
-
- struct mapper_entry mapper;
+ struct mapper_functions mapper;
union mapper_data map;
struct ines_state ines;
+ struct cpu_state cpu;
+ // struct apu_state apu;
- uint8_t *pixels;
uint8_t *ram;
uint8_t *ciram;
- uint8_t *chr_ram;
uint8_t *prg_rom;
uint8_t *chr_rom;
+ uint8_t *chr_ram;
+ uint8_t *pixels;
uint8_t *sram;
-};
+} __attribute__((packed, aligned(64)));
__attribute__((aligned(4096))) static uint32_t nes_palette[65] = {
diff --git a/ppu.c b/ppu.c
index 48ccbfc..6b57085 100644
--- a/ppu.c
+++ b/ppu.c
@@ -400,7 +400,7 @@ static void ppu_tick(struct nes_state *state) {
ppu->reg_status |= 0x80;
if(ppu->reg_ctrl & 0x80) {
- state->nmi_pending = 1;
+ state->cpu.nmi_pending = 1;
}
}
diff --git a/ppu_registers.c b/ppu_registers.c
index c698bf2..b426f17 100644
--- a/ppu_registers.c
+++ b/ppu_registers.c
@@ -2,6 +2,69 @@ __attribute__((always_inline, hot))
static inline void ppu_write(struct nes_state *state, uint32_t offset, uint8_t value) {
struct ppu_state *ppu = &state->ppu;
+ uint32_t reg = offset & 0x7;
+
+ if(reg == 0) {
+ ppu->reg_ctrl = value;
+ ppu->temp_addr = (ppu->temp_addr & 0xf3ff) | ((value & 0x03) << 10);
+ // ppu->open_bus = value;
+
+ } else if(reg == 1) {
+ ppu->reg_mask = value;
+ // ppu->open_bus = value;
+
+ } else if(reg == 3) {
+ ppu->oam_addr = value;
+ // ppu->open_bus = value;
+
+ } else if(reg == 4) {
+ ppu->oam[ppu->oam_addr++] = value;
+ // ppu->open_bus = value;
+
+ } else if(reg == 5) {
+ if(ppu->write_latch == 0) {
+ ppu->fine_x = value & 0x07;
+ ppu->temp_addr = (ppu->temp_addr & ~0x001f) | (value >> 3);
+ ppu->write_latch = 1;
+ } else {
+ ppu->temp_addr = (ppu->temp_addr & ~0x73e0) | ((value & 0x07) << 12) | ((value & 0xf8) << 2);
+ ppu->write_latch = 0;
+ }
+ // ppu->open_bus = value;
+
+ } else if(reg == 6) {
+ if(ppu->write_latch == 0) {
+ ppu->temp_addr = (ppu->temp_addr & 0x00ff) | ((value & 0x3f) << 8);
+ ppu->write_latch = 1;
+ } else {
+ ppu->temp_addr = (ppu->temp_addr & 0xff00) | value;
+ ppu->vram_addr = ppu->temp_addr;
+ ppu->write_latch = 0;
+ }
+ // ppu->open_bus = value;
+
+ } else if(reg == 7) {
+ uint32_t addr = ppu->vram_addr;
+ if(LIKELY(addr < 0x2000)) {
+ state->mapper.chr_write(state, addr, value);
+
+ } 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) {
+ pal_addr &= ~0x10;
+ }
+ ppu->palette[pal_addr] = value;
+ }
+ ppu->vram_addr += (ppu->reg_ctrl & 0x04) ? 32 : 1;
+ // ppu->open_bus = value;
+ }
+
+ ppu->open_bus = value;
+
+#if 0
switch(offset & 7) {
case 0: { // 2000
ppu->reg_ctrl = value;
@@ -67,6 +130,7 @@ static inline void ppu_write(struct nes_state *state, uint32_t offset, uint8_t v
ppu->open_bus = value;
} break;
}
+#endif
}
__attribute__((always_inline, hot))
@@ -74,6 +138,39 @@ static inline uint8_t ppu_read(struct nes_state *state, uint32_t offset) {
struct ppu_state *ppu = &state->ppu;
uint8_t result = ppu->open_bus;
+ uint32_t reg = offset & 0x7;
+
+ if(reg == 2) {
+ result = ppu->reg_status;
+ ppu->reg_status &= ~0x80;
+ ppu->write_latch = 0;
+
+ } else if(reg == 4) {
+ result = ppu->oam[ppu->oam_addr];
+
+ } else if(reg == 7) {
+ uint32_t addr = ppu->vram_addr;
+
+ if(LIKELY(addr < 0x2000)) {
+ result = ppu->vram_read_buffer;
+ ppu->vram_read_buffer = state->mapper.chr_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) {
+ pal_addr &= ~0x10;
+ }
+ result = ppu->palette[pal_addr];
+ }
+
+ ppu->vram_addr += (ppu->reg_ctrl & 0x04) ? 32 : 1;
+ }
+
+#if 0
switch(offset & 7) {
case 2: { // 2002
result = ppu->reg_status;
@@ -107,6 +204,8 @@ static inline uint8_t ppu_read(struct nes_state *state, uint32_t offset) {
ppu->vram_addr += (ppu->reg_ctrl & 0x04) ? 32 : 1;
} break;
}
+# endif
+
ppu->open_bus = result;
return result;
}
@@ -118,9 +217,9 @@ static void ppu_dma_4014(struct nes_state *state, uint8_t page) {
uint32_t base = page << 8;
// Add 1 or 2 idle cycles depending on current CPU cycle
- uint8_t idle_cycles = (state->cycles & 1) ? 1 : 2;
+ uint8_t idle_cycles = (state->cpu.cycles & 1) ? 1 : 2;
for(uint8_t i = 0; i < idle_cycles; i++) {
- state->cycles++;
+ state->cpu.cycles++;
ppu_tick(state);
// apu_tick(state);
}
@@ -128,12 +227,12 @@ static void ppu_dma_4014(struct nes_state *state, uint8_t page) {
for(uint32_t i = 0; i < 256; i++) {
uint32_t addr = base + i;
- state->cycles++;
+ state->cpu.cycles++;
ppu_tick(state);
// apu_tick(state);
uint8_t value = memory_read_dma(state, addr);
- state->cycles++;
+ state->cpu.cycles++;
ppu_tick(state);
// apu_tick(state);