summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Fors <peter.fors@mindkiller.com>2025-05-08 21:03:43 +0200
committerPeter Fors <peter.fors@mindkiller.com>2025-05-08 21:03:43 +0200
commite28ad1546509de31b706f0fd300a906e5bc55199 (patch)
tree40d708336cf770b8c68302bd32b069951a3df428
parentda9d961bbc3662064599f4b0b4759a2c641924a2 (diff)
new and changed mappers
-rwxr-xr-xbuild.sh5
-rw-r--r--mappers/mapper.c8
-rw-r--r--mappers/mapper.h6
-rw-r--r--mappers/mapper_000_0.c5
-rw-r--r--mappers/mapper_001_0.c121
-rw-r--r--mappers/mapper_001_0.h14
-rw-r--r--mappers/mapper_002_2.c5
-rw-r--r--mappers/mapper_003_0.c31
-rw-r--r--mappers/mapper_003_0.h4
-rw-r--r--mappers/mapper_003_1.c31
-rw-r--r--mappers/mapper_003_1.h4
-rw-r--r--mappers/mapper_003_2.c5
-rw-r--r--mappers/mapper_007_2.c8
-rw-r--r--mappers/mapper_011_0.c5
-rw-r--r--mappers/mapper_066_0.c4
-rw-r--r--mknes.c199
-rw-r--r--mknes.h17
-rw-r--r--opengl.c2
-rw-r--r--ppu.c15
19 files changed, 338 insertions, 151 deletions
diff --git a/build.sh b/build.sh
index de8ecc5..cbe8e64 100755
--- a/build.sh
+++ b/build.sh
@@ -7,7 +7,7 @@ CC=gcc
# Base configuration common to all builds
CFLAGS="-std=gnu11 -mtune=generic "
-CFLAGS+="-mbmi -mbmi2 "
+CFLAGS+="-mbmi "
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 "
@@ -19,13 +19,14 @@ CFLAGS+="-Wno-unused-variable -Wno-unused-const-variable -Wno-unused-function -W
CFLAGS+="-U_FORTIFY_SOURCE -fno-pic "
LDFLAGS="-Wl,--gc-sections -Wl,--as-needed "
+# LDFLAGS+="-Wl,--script=mknes.ld "
# Base include paths (common for all platforms)
INCLUDE_PATHS="-Ibase -I.."
# Linux-specific includes and libraries
LINUX_INCLUDE="-I/usr/include/pipewire-0.3 -I/usr/include/spa-0.2"
-LINUX_LIBS="-lpipewire-0.3 -lXi -lX11 -lGL -lm -ldl -pthread -lglfw -larchive"
+LINUX_LIBS="-lpipewire-0.3 -lXi -lX11 -lGL -lm -ldl -pthread -lglfw -larchive "
# Windows-specific includes and libraries
# WINDOWS_INCLUDE=""
diff --git a/mappers/mapper.c b/mappers/mapper.c
index 099b6d7..71caff1 100644
--- a/mappers/mapper.c
+++ b/mappers/mapper.c
@@ -23,7 +23,10 @@ static void mapper_default_chr_write(struct nes_state *state, uint32_t addr, uin
static void mapper_default_tick(struct nes_state *state) { }
#include "mapper_000_0.c"
+#include "mapper_001_0.c"
#include "mapper_002_2.c"
+#include "mapper_003_0.c"
+#include "mapper_003_1.c"
#include "mapper_003_2.c"
#include "mapper_007_2.c"
#include "mapper_011_0.c"
@@ -33,7 +36,10 @@ static void mapper_default_tick(struct nes_state *state) { }
static void (*mapper_table[4096])(struct nes_state *state) = {
[MAPPER_ID( 0, 0)] = mapper_000_0_init,
+ [MAPPER_ID( 1, 0)] = mapper_001_0_init,
[MAPPER_ID( 2, 2)] = mapper_002_2_init,
+ [MAPPER_ID( 3, 0)] = mapper_003_0_init,
+ [MAPPER_ID( 3, 1)] = mapper_003_1_init,
[MAPPER_ID( 3, 2)] = mapper_003_2_init,
[MAPPER_ID( 7, 2)] = mapper_007_2_init,
[MAPPER_ID(11, 0)] = mapper_011_0_init,
@@ -52,6 +58,8 @@ static void mapper_reset(struct nes_state *state) {
static void mapper_setup(struct nes_state *state) {
uint32_t mapper = state->ines.mapper << 4 | state->ines.submapper;
+ printf("Mapper %d_%x requested.\n", state->ines.mapper, state->ines.submapper);
+
mapper_reset(state);
if(mapper_table[mapper]) {
mapper_table[mapper](state);
diff --git a/mappers/mapper.h b/mappers/mapper.h
index 863201b..20ee906 100644
--- a/mappers/mapper.h
+++ b/mappers/mapper.h
@@ -1,6 +1,9 @@
#include "mapper_000_0.h"
+#include "mapper_001_0.h"
#include "mapper_002_2.h"
+#include "mapper_003_0.h"
+#include "mapper_003_1.h"
#include "mapper_003_2.h"
#include "mapper_007_2.h"
#include "mapper_011_0.h"
@@ -20,7 +23,10 @@ struct mapper_functions {
union mapper_data {
struct mapper_000_0 m000_0;
+ struct mapper_001_0 m001_0;
struct mapper_002_2 m002_2;
+ struct mapper_003_2 m003_0;
+ struct mapper_003_2 m003_1;
struct mapper_003_2 m003_2;
struct mapper_007_2 m007_2;
struct mapper_011_0 m011_0;
diff --git a/mappers/mapper_000_0.c b/mappers/mapper_000_0.c
index b79cdbf..8e46090 100644
--- a/mappers/mapper_000_0.c
+++ b/mappers/mapper_000_0.c
@@ -1,17 +1,18 @@
-__attribute__((hot))
+__attribute__((section(".mapper_000_0"), 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))
+__attribute__((section(".mapper_000_0"), hot))
static uint8_t mapper_000_0_chr_read(struct nes_state *state, uint32_t addr) {
return state->chr_rom[addr];
}
+__attribute__((section(".mapper_000_0")))
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;
diff --git a/mappers/mapper_001_0.c b/mappers/mapper_001_0.c
new file mode 100644
index 0000000..519738e
--- /dev/null
+++ b/mappers/mapper_001_0.c
@@ -0,0 +1,121 @@
+
+__attribute__((section(".mapper_001_0"), hot))
+static uint8_t mapper_001_0_prg_read(struct nes_state *state, uint32_t addr) {
+ struct mapper_001_0 *mapper = (struct mapper_001_0 *)&state->map;
+ if(addr >= 0x8000) {
+ if(addr < 0xc000) {
+ return mapper->prg_rom_0[addr & 0x3fff];
+ } else {
+ return mapper->prg_rom_1[addr & 0x3fff];
+ }
+ }
+ return 0;
+}
+
+__attribute__((section(".mapper_001_0"), hot))
+static void mapper_001_0_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ struct mapper_001_0 *mapper = (struct mapper_001_0 *)&state->map;
+ if(addr < 0x8000) return;
+
+ if(value & 0x80) {
+ mapper->shift = 0;
+ mapper->shift_count = 0;
+ mapper->control |= 0x0c;
+ return;
+ }
+
+ mapper->shift |= (value & 1) << mapper->shift_count;
+ mapper->shift_count++;
+
+ if(mapper->shift_count == 5) {
+ uint32_t bank;
+ uint8_t reg = (addr >> 13) & 0x03;
+ switch(reg) {
+ case 0: {// Control
+ mapper->control = mapper->shift;
+ } break;
+
+ case 1: { // CHR bank 0
+ mapper->chr_bank0 = mapper->shift;
+ mapper->chr_bank_0 = state->chr_rom + (mapper->chr_bank0 * 0x1000);
+ } break;
+
+ case 2: { // CHR bank 1
+ mapper->chr_bank1 = mapper->shift;
+ mapper->chr_bank_1 = state->chr_rom + (mapper->chr_bank1 * 0x1000);
+ } break;
+
+ case 3: { // PRG bank
+ mapper->prg_bank = mapper->shift & 0x0f;
+ if(mapper->control & 0x08) {
+ // 16KB bank switching
+ if(mapper->control & 0x04) {
+ mapper->prg_rom_0 = state->prg_rom + 0x4000 * 0;
+ mapper->prg_rom_1 = state->prg_rom + 0x4000 * mapper->prg_bank;
+ } else {
+ mapper->prg_rom_0 = state->prg_rom + 0x4000 * mapper->prg_bank;
+ mapper->prg_rom_1 = state->prg_rom + 0x4000 * (state->ines.prg_size / 0x4000 - 1);
+ }
+ } else {
+ // 32KB mode
+ bank = (mapper->prg_bank & 0x0e) * 0x4000;
+ mapper->prg_rom_0 = state->prg_rom + bank;
+ mapper->prg_rom_1 = state->prg_rom + bank + 0x4000;
+ }
+ } break;
+ }
+ mapper->shift = 0;
+ mapper->shift_count = 0;
+ }
+}
+
+__attribute__((section(".mapper_001_0"), hot))
+static uint8_t mapper_001_0_chr_read(struct nes_state *state, uint32_t addr) {
+ struct mapper_001_0 *mapper = (struct mapper_001_0 *)&state->map;
+ if(mapper->control & 0x10) {
+ // 4KB mode
+ if(addr < 0x1000) {
+ return mapper->chr_bank_0[addr];
+ } else {
+ return mapper->chr_bank_1[addr - 0x1000];
+ }
+ } else {
+ // 8KB mode
+ return mapper->chr_bank_0[addr];
+ }
+}
+
+__attribute__((section(".mapper_001_0"), hot))
+static void mapper_001_0_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ // CHR RAM write (if present)
+ state->chr_ram[addr] = value;
+}
+
+__attribute__((section(".mapper_001_0"), hot))
+static uint8_t mapper_001_0_ciram_read(struct nes_state *state, uint32_t addr) {
+ return state->ciram[addr & 0x3ff];
+}
+
+__attribute__((section(".mapper_001_0"), hot))
+static void mapper_001_0_ciram_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ state->ciram[addr & 0x3ff] = value;
+}
+
+__attribute__((section(".mapper_001_0")))
+static void mapper_001_0_init(struct nes_state *state) {
+ struct mapper_001_0 *mapper = (struct mapper_001_0 *)&state->map;
+
+ mapper->control = 0x0c;
+ mapper->prg_rom_0 = state->prg_rom;
+ mapper->prg_rom_1 = state->prg_rom + (state->ines.prg_size - 0x4000);
+
+ mapper->chr_bank_0 = state->chr_rom;
+ mapper->chr_bank_1 = state->chr_rom + 0x1000;
+
+ state->mapper.prg_read = mapper_001_0_prg_read;
+ state->mapper.prg_write = mapper_001_0_prg_write;
+ state->mapper.chr_read = mapper_001_0_chr_read;
+ state->mapper.chr_write = mapper_001_0_chr_write;
+ state->mapper.ciram_read = mapper_001_0_ciram_read;
+ state->mapper.ciram_write = mapper_001_0_ciram_write;
+}
diff --git a/mappers/mapper_001_0.h b/mappers/mapper_001_0.h
new file mode 100644
index 0000000..deb0e29
--- /dev/null
+++ b/mappers/mapper_001_0.h
@@ -0,0 +1,14 @@
+
+struct mapper_001_0 {
+ uint8_t shift;
+ uint8_t shift_count;
+ uint8_t control;
+ uint8_t prg_bank;
+ uint8_t chr_bank0;
+ uint8_t chr_bank1;
+
+ uint8_t *prg_rom_0;
+ uint8_t *prg_rom_1;
+ uint8_t *chr_bank_0;
+ uint8_t *chr_bank_1;
+} __attribute__((packed, aligned(64)));
diff --git a/mappers/mapper_002_2.c b/mappers/mapper_002_2.c
index 079fb0b..b88c95b 100644
--- a/mappers/mapper_002_2.c
+++ b/mappers/mapper_002_2.c
@@ -1,5 +1,6 @@
+__attribute__((section(".mapper_002_2"), hot))
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;
@@ -12,6 +13,7 @@ static uint8_t mapper_002_2_prg_read(struct nes_state *state, uint32_t addr) {
return 0;
}
+__attribute__((section(".mapper_002_2"), hot))
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;
@@ -20,14 +22,17 @@ static void mapper_002_2_prg_write(struct nes_state *state, uint32_t addr, uint8
}
}
+__attribute__((section(".mapper_002_2"), hot))
static uint8_t mapper_002_2_chr_read(struct nes_state *state, uint32_t addr) {
return state->chr_ram[addr];
}
+__attribute__((section(".mapper_002_2"), hot))
static void mapper_002_2_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) {
state->chr_ram[addr] = value;
}
+__attribute__((section(".mapper_002_2")))
static void mapper_002_2_init(struct nes_state *state) {
struct mapper_002_2 *mapper = (struct mapper_002_2 *)&state->map;
diff --git a/mappers/mapper_003_0.c b/mappers/mapper_003_0.c
new file mode 100644
index 0000000..e85d995
--- /dev/null
+++ b/mappers/mapper_003_0.c
@@ -0,0 +1,31 @@
+
+__attribute__((section(".mapper_003_0"), hot))
+static uint8_t mapper_003_0_prg_read(struct nes_state *state, uint32_t addr) {
+ return state->prg_rom[addr & 0x7fff];
+}
+
+__attribute__((section(".mapper_003_0"), hot))
+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;
+ }
+}
+
+__attribute__((section(".mapper_003_0"), hot))
+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];
+}
+
+__attribute__((section(".mapper_003_0")))
+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_003_1.c b/mappers/mapper_003_1.c
new file mode 100644
index 0000000..fd7cd27
--- /dev/null
+++ b/mappers/mapper_003_1.c
@@ -0,0 +1,31 @@
+
+__attribute__((section(".mapper_003_1"), hot))
+static uint8_t mapper_003_1_prg_read(struct nes_state *state, uint32_t addr) {
+ return state->prg_rom[addr & 0x7fff];
+}
+
+__attribute__((section(".mapper_003_1"), hot))
+static void mapper_003_1_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ struct mapper_003_1 *mapper = (struct mapper_003_1 *)&state->map;
+
+ if(addr >= 0x8000) {
+ mapper->chr_ptr = state->chr_rom + (value & 3) * 0x2000;
+ }
+}
+
+__attribute__((section(".mapper_003_1"), hot))
+static uint8_t mapper_003_1_chr_read(struct nes_state *state, uint32_t addr) {
+ struct mapper_003_1 *mapper = (struct mapper_003_1 *)&state->map;
+ return mapper->chr_ptr[addr];
+}
+
+__attribute__((section(".mapper_003_1")))
+static void mapper_003_1_init(struct nes_state *state) {
+ struct mapper_003_1 *mapper = (struct mapper_003_1 *)&state->map;
+
+ mapper->chr_ptr = state->chr_rom;
+
+ state->mapper.prg_read = mapper_003_1_prg_read;
+ state->mapper.prg_write = mapper_003_1_prg_write;
+ state->mapper.chr_read = mapper_003_1_chr_read;
+}
diff --git a/mappers/mapper_003_1.h b/mappers/mapper_003_1.h
new file mode 100644
index 0000000..c233a1a
--- /dev/null
+++ b/mappers/mapper_003_1.h
@@ -0,0 +1,4 @@
+
+struct mapper_003_1 {
+ uint8_t *chr_ptr;
+} __attribute__((packed, aligned(64)));
diff --git a/mappers/mapper_003_2.c b/mappers/mapper_003_2.c
index e93916a..b780a8f 100644
--- a/mappers/mapper_003_2.c
+++ b/mappers/mapper_003_2.c
@@ -1,21 +1,26 @@
+__attribute__((section(".mapper_003_2"), hot))
static uint8_t mapper_003_2_prg_read(struct nes_state *state, uint32_t addr) {
return state->prg_rom[addr & 0x7fff];
}
+__attribute__((section(".mapper_003_2"), hot))
static void mapper_003_2_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) {
struct mapper_003_2 *mapper = (struct mapper_003_2 *)&state->map;
if(addr >= 0x8000) {
+ value &= state->prg_rom[addr & 0x7fff];
mapper->chr_ptr = state->chr_rom + (value & 3) * 0x2000;
}
}
+__attribute__((section(".mapper_003_2"), hot))
static uint8_t mapper_003_2_chr_read(struct nes_state *state, uint32_t addr) {
struct mapper_003_2 *mapper = (struct mapper_003_2 *)&state->map;
return mapper->chr_ptr[addr];
}
+__attribute__((section(".mapper_003_2")))
static void mapper_003_2_init(struct nes_state *state) {
struct mapper_003_2 *mapper = (struct mapper_003_2 *)&state->map;
diff --git a/mappers/mapper_007_2.c b/mappers/mapper_007_2.c
index ed56dd0..27125b9 100644
--- a/mappers/mapper_007_2.c
+++ b/mappers/mapper_007_2.c
@@ -1,5 +1,5 @@
-
+__attribute__((section(".mapper_007_2"), hot))
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) {
@@ -8,6 +8,7 @@ static uint8_t mapper_007_2_prg_read(struct nes_state *state, uint32_t addr) {
return 0;
}
+__attribute__((section(".mapper_007_2"), hot))
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) {
@@ -21,24 +22,29 @@ static void mapper_007_2_prg_write(struct nes_state *state, uint32_t addr, uint8
}
}
+__attribute__((section(".mapper_007_2"), hot))
static uint8_t mapper_007_2_chr_read(struct nes_state *state, uint32_t addr) {
return state->chr_ram[addr];
}
+__attribute__((section(".mapper_007_2"), hot))
static void mapper_007_2_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) {
state->chr_ram[addr] = value;
}
+__attribute__((section(".mapper_007_2"), hot))
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];
}
+__attribute__((section(".mapper_007_2"), hot))
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;
}
+__attribute__((section(".mapper_007_2")))
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;
diff --git a/mappers/mapper_011_0.c b/mappers/mapper_011_0.c
index ce390a0..d6d518c 100644
--- a/mappers/mapper_011_0.c
+++ b/mappers/mapper_011_0.c
@@ -1,5 +1,5 @@
-
+__attribute__((section(".mapper_011_0"), hot))
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;
@@ -9,6 +9,7 @@ static uint8_t mapper_011_0_prg_read(struct nes_state *state, uint32_t addr) {
return 0;
}
+__attribute__((section(".mapper_011_0"), hot))
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;
@@ -18,12 +19,14 @@ static void mapper_011_0_prg_write(struct nes_state *state, uint32_t addr, uint8
}
}
+__attribute__((section(".mapper_011_0"), hot))
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];
}
+__attribute__((section(".mapper_011_0")))
static void mapper_011_0_init(struct nes_state *state) {
struct mapper_011_0 *mapper = (struct mapper_011_0 *)&state->map;
diff --git a/mappers/mapper_066_0.c b/mappers/mapper_066_0.c
index bf31720..7a8f49c 100644
--- a/mappers/mapper_066_0.c
+++ b/mappers/mapper_066_0.c
@@ -1,4 +1,5 @@
+__attribute__((section(".mapper_066_0"), hot))
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;
@@ -8,6 +9,7 @@ static uint8_t mapper_066_0_prg_read(struct nes_state *state, uint32_t addr) {
return 0;
}
+__attribute__((section(".mapper_066_0"), hot))
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;
@@ -20,11 +22,13 @@ static void mapper_066_0_prg_write(struct nes_state *state, uint32_t addr, uint8
}
}
+__attribute__((section(".mapper_066_0"), hot))
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];
}
+__attribute__((section(".mapper_066_0")))
static void mapper_066_0_init(struct nes_state *state) {
struct mapper_066_0 *mapper = (struct mapper_066_0 *)&state->map;
diff --git a/mknes.c b/mknes.c
index b5f05d3..7220450 100644
--- a/mknes.c
+++ b/mknes.c
@@ -13,8 +13,8 @@
#define WINDOW_WIDTH 320 * 3
#define WINDOW_HEIGHT 240 * 3
-#define PRG_ROM_SIZE (512 * 1024)
-#define CHR_ROM_SIZE (512 * 1024)
+#define PRG_ROM_SIZE (2 * 1024 * 1024)
+#define CHR_ROM_SIZE (1 * 1024 * 1024)
#define PIXELS_SIZE (256 * 240)
#define RAM_SIZE 0x1000 // 0x800 in reality, but for aligned alloc it must be the size of the alignment (4096)
#define SRAM_SIZE 0x2000
@@ -104,62 +104,8 @@ static uint32_t frames; // debug information
#include "mappers/mapper.c"
#include "callbacks.c"
-struct nes_state nstate;
-
-
-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;
-
- 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);
-}
-
-
-
+struct nes_state nstate;
int main(int argc, char **argv) {
#ifdef _WIN32
@@ -167,70 +113,72 @@ int main(int argc, char **argv) {
#endif
state.toggle_crt_emulation = 1;
- struct nes_state *nstate = allocate_nes_state();
setbuf(stdout, 0);
init_opcode_lut();
init_opcode_ud_lut();
// protect_opcode_lut();
- ppu_reset(nstate);
- // ines2_load(nstate, "data/0000/10-Yard Fight (USA, Europe).nes");
- // ines2_load(nstate, "data/0000/Balloon Fight (USA).nes");
- // 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/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");
- // ines2_load(nstate, "data/0000/Sayoonara!.NES");
- // ines2_load(nstate, "data/0000/raster_demos/RasterChromaLuma.NES");
- // ines2_load(nstate, "data/0000/raster_demos/RasterTest1.NES");
- // ines2_load(nstate, "data/0000/raster_demos/RasterTest2.NES");
- // ines2_load(nstate, "data/0000/raster_demos/RasterTest3.NES");
- // ines2_load(nstate, "data/0000/raster_demos/RasterTest3a.NES");
- // ines2_load(nstate, "data/0000/raster_demos/RasterTest3b.NES");
- // ines2_load(nstate, "data/0000/raster_demos/RasterTest3c.NES");
- // ines2_load(nstate, "data/0000/raster_demos/RasterTest3d.NES");
- // ines2_load(nstate, "data/0000/raster_demos/RasterTest3e.NES");
- // ines2_load(nstate, "data/0000/NEStress.NES");
- // ines2_load(nstate, "data/0000/Super Mario Bros. (World) (HVC-SM).zip");
- // ines2_load(nstate, "data/0042/Super Mario Bros. + Duck Hunt (USA).zip");
- // ines2_load(nstate, "data/0000/Xevious - The Avenger (USA).zip");
- // ines2_load(nstate, "data/tv.nes");
-
- // ines2_load(nstate, "data/Life Force (USA).zip"); // 2002
-
- // 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/Beetlejuice (USA).zip");
- // ines2_load(nstate, "data/0007/Cabal (USA).zip");
-
- // ines2_load(nstate, "data/000b/Baby Boomer (USA) (Unl).zip");
- // ines2_load(nstate, "data/000b/Captain Comic - The Adventure (USA) (Unl).zip");
- // ines2_load(nstate, "data/000b/King Neptune's Adventure (USA) (Unl).zip");
-
- // ines2_load(nstate, "data/2002/Attack Animal Gakuen (Japan).zip");
- // ines2_load(nstate, "data/2002/Ballblazer (Japan).zip");
- // ines2_load(nstate, "data/2002/Best of the Best - Championship Karate (USA).zip");
-
- mapper_setup(nstate);
- uint32_t lo = nstate->mapper.prg_read(nstate, 0xfffc);
- uint32_t hi = nstate->mapper.prg_read(nstate, 0xfffd);
- nstate->cpu.pc = (hi << 8) | lo;
-
-#if 0
+ ppu_reset(&nstate);
+ // ines2_load(&nstate, "data/0000/10-Yard Fight (USA, Europe).nes");
+ // ines2_load(&nstate, "data/0000/Balloon Fight (USA).nes");
+ // 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/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");
+ // ines2_load(&nstate, "data/0000/Sayoonara!.NES");
+ // ines2_load(&nstate, "data/0000/raster_demos/RasterChromaLuma.NES");
+ // ines2_load(&nstate, "data/0000/raster_demos/RasterTest1.NES");
+ // ines2_load(&nstate, "data/0000/raster_demos/RasterTest2.NES");
+ // ines2_load(&nstate, "data/0000/raster_demos/RasterTest3.NES");
+ // ines2_load(&nstate, "data/0000/raster_demos/RasterTest3a.NES");
+ // ines2_load(&nstate, "data/0000/raster_demos/RasterTest3b.NES");
+ // ines2_load(&nstate, "data/0000/raster_demos/RasterTest3c.NES");
+ // ines2_load(&nstate, "data/0000/raster_demos/RasterTest3d.NES");
+ // ines2_load(&nstate, "data/0000/raster_demos/RasterTest3e.NES");
+ // ines2_load(&nstate, "data/0000/NEStress.NES");
+ // ines2_load(&nstate, "data/0000/Super Mario Bros. (World) (HVC-SM).zip");
+ // ines2_load(&nstate, "data/0042/Super Mario Bros. + Duck Hunt (USA).zip");
+ // ines2_load(&nstate, "data/0000/Xevious - The Avenger (USA).zip");
+ // ines2_load(&nstate, "data/tv.nes");
+
+ ines2_load(&nstate, "data/Life Force (USA).zip"); // 2002
+
+ // 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/Beetlejuice (USA).zip");
+ // ines2_load(&nstate, "data/0007/Cabal (USA).zip");
+
+ // ines2_load(&nstate, "data/000b/Baby Boomer (USA) (Unl).zip");
+ // ines2_load(&nstate, "data/000b/Captain Comic - The Adventure (USA) (Unl).zip");
+ // ines2_load(&nstate, "data/000b/King Neptune's Adventure (USA) (Unl).zip");
+
+ // ines2_load(&nstate, "data/2002/Attack Animal Gakuen (Japan).zip");
+ // ines2_load(&nstate, "data/2002/Ballblazer (Japan).zip");
+ // ines2_load(&nstate, "data/2002/Best of the Best - Championship Karate (USA).zip");
+
+ // ines2_load(&nstate, "data/Blaster Master (USA).zip");
+
+
+ mapper_setup(&nstate);
+ uint32_t lo = nstate.mapper.prg_read(&nstate, 0xfffc);
+ uint32_t hi = nstate.mapper.prg_read(&nstate, 0xfffd);
+ nstate.cpu.pc = (hi << 8) | lo;
+
+#if 1
for(uint32_t i = 0; i < 0x5000; ++ i) {
- while(!nstate->ppu.frame_ready) {
+ while(!nstate.ppu.frame_ready) {
// PROFILE_NAMED("nes emulator");
- cpu_tick(nstate);
+ cpu_tick(&nstate);
}
- nstate->ppu.frame_ready = 0;
+ nstate.ppu.frame_ready = 0;
frames++;
}
return 0;
@@ -250,8 +198,8 @@ int main(int argc, char **argv) {
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "NES Emulator", 0, 0);
if(window) {
- glfwSetWindowUserPointer(window, (void*)nstate);
- glfwSetWindowAspectRatio(window, 320, 240); // Need to set a 4:3 resolution for it to look correct!
+ glfwSetWindowUserPointer(window, (void*)&nstate);
+ glfwSetWindowAspectRatio(window, 320, 240); // Need to set a 4:3 resolution for things to look correct!
glfwSetWindowSizeLimits(window, WINDOW_WIDTH, WINDOW_HEIGHT, GLFW_DONT_CARE, GLFW_DONT_CARE);
glfwMakeContextCurrent(window);
@@ -278,22 +226,15 @@ int main(int argc, char **argv) {
timer_wait(timer);
glfwPollEvents();
-// printf("Frame: %d\n", frames);
-
-
-// static int32_t tas_frame = 0;
-// nstate->input[0] = tas_input[tas_frame++];
- while(!nstate->ppu.frame_ready) {
+ while(!nstate.ppu.frame_ready) {
// PROFILE_NAMED("nes emulator");
- cpu_tick(nstate);
+ cpu_tick(&nstate);
}
- nstate->ppu.frame_ready = 0;
+ 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;
+ uint8_t * restrict src = nstate.pixels;
for(uint32_t y = 0; y < 240; ++y) {
for(uint32_t x = 0; x < 256; ++x) {
uint8_t val = *src++;
@@ -306,8 +247,10 @@ int main(int argc, char **argv) {
render_frame();
glfwSwapBuffers(window);
}
-printf("total frames: %6.6d total cycles: %ld\n", frames, nstate->cpu.cycles);
+
+ printf("total frames: %6.6d total cycles: %ld\n", frames, nstate.cpu.cycles);
glfwDestroyWindow(window);
+
} else {
fprintf(stderr, "Failed to create window\n");
}
@@ -317,7 +260,7 @@ printf("total frames: %6.6d total cycles: %ld\n", frames, nstate->cpu.cycles);
fprintf(stderr, "Failed to initialize GLFW\n");
}
timer_destroy(timer);
- free_nes_state(nstate);
+ // free_nes_state(&nstate);
#ifdef _WIN32
timeEndPeriod(1);
#endif
diff --git a/mknes.h b/mknes.h
index e1dc8f2..fba1406 100644
--- a/mknes.h
+++ b/mknes.h
@@ -117,15 +117,14 @@ struct nes_state {
struct cpu_state cpu;
// struct apu_state apu;
- uint8_t *ram;
- uint8_t *ciram;
- uint8_t *prg_rom;
- uint8_t *chr_rom;
- uint8_t *chr_ram;
- uint8_t *pixels;
- uint8_t *sram;
-} __attribute__((packed, aligned(64)));
-
+ uint8_t ram[RAM_SIZE] __attribute__((aligned(4096)));
+ uint8_t ciram[CIRAM_SIZE] __attribute__((aligned(4096)));
+ uint8_t prg_rom[PRG_ROM_SIZE] __attribute__((aligned(4096)));
+ uint8_t chr_rom[CHR_ROM_SIZE] __attribute__((aligned(4096)));
+ uint8_t chr_ram[CHR_RAM_SIZE] __attribute__((aligned(4096)));
+ uint8_t pixels[PIXELS_SIZE] __attribute__((aligned(4096)));
+ uint8_t sram[SRAM_SIZE] __attribute__((aligned(4096)));
+} __attribute__((packed, aligned(4096)));
__attribute__((aligned(4096))) static uint32_t nes_palette[65] = {
0x585858ff, 0x00237cff, 0x0d1099ff, 0x300092ff, 0x4f006cff, 0x600035ff, 0x5c0500ff, 0x461800ff,
diff --git a/opengl.c b/opengl.c
index 255eac3..953a494 100644
--- a/opengl.c
+++ b/opengl.c
@@ -5,6 +5,7 @@
#include "vertex_shader.h"
/* [=]===^=[ compile_shader ]==============================================================^===[=] */
+__attribute__((cold, noinline, section(".init_section")))
static GLuint compile_shader(GLenum shader_type, const char *shader_source) {
GLuint shader = glCreateShader(shader_type);
glShaderSource(shader, 1, &shader_source, 0);
@@ -21,6 +22,7 @@ static GLuint compile_shader(GLenum shader_type, const char *shader_source) {
}
/* [=]===^=[ opengl_setup ]================================================================^===[=] */
+__attribute__((cold, noinline, section(".init_section")))
static void opengl_setup(void) {
gl_loader();
diff --git a/ppu.c b/ppu.c
index fe54be5..6f5a4eb 100644
--- a/ppu.c
+++ b/ppu.c
@@ -155,19 +155,18 @@ static inline void ppu_render_pixel(struct nes_state *state) {
}
// Final pixel composition
- uint8_t palette_index = 0;
uint8_t bg_index = (bg_palette << 2) + bg_pixel;
uint8_t sp_index = (sp_palette << 2) + sp_pixel;
uint8_t selector = (bg_pixel ? 2 : 0) | (sp_pixel ? 1 : 0);
+ // uint8_t palette_index;
+ uint8_t palette_index = (sp_prio) ? bg_index : 0x10 | sp_index;
+
switch(selector) {
- case 0: { palette_index = 0; } break;
- case 1: { palette_index = 0x10 | sp_index; } break;
- case 2: { palette_index = bg_index; } break;
- 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;
- } break;
+ case 0: { palette_index = 0; } break;
+ case 1: { palette_index = 0x10 | sp_index; } break;
+ case 2: { palette_index = bg_index; } break;
+ case 3: { ppu->reg_status |= (sp_zero && x < 255) ? 0x40 : 0; } break; // NOTE(peter): Sprite zero hit!
}
state->pixels[y * 256 + x] = ppu->palette[palette_index]; // NOTE(peter): Add color_emphasis bits (expand palette to 8x).