summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Fors <peter.fors@mindkiller.com>2025-11-02 09:16:03 +0100
committerPeter Fors <peter.fors@mindkiller.com>2025-11-02 09:16:03 +0100
commited41715142f419021ed8fef5522ea1f363f16441 (patch)
tree9cf0049db6ac5b0da5552bba9e0376b82eaeb2b4
parente137c881d835703d1030746cd7262899de7169c6 (diff)
fix multiple mappers
-rwxr-xr-xbuild.sh4
-rw-r--r--mappers/mapper_001_0.c231
-rw-r--r--mappers/mapper_001_0.h2
-rw-r--r--mappers/mapper_007_2.c2
-rw-r--r--mappers/mapper_011_0.c16
-rw-r--r--mappers/mapper_011_0.h2
-rw-r--r--mknes.c50
-rw-r--r--mknes.h4
-rw-r--r--mknes_mapper.c13
-rw-r--r--mknes_memory.c24
-rw-r--r--mknes_ppu.c7
-rw-r--r--mknes_ppu_registers.c16
12 files changed, 203 insertions, 168 deletions
diff --git a/build.sh b/build.sh
index 36aa12d..a5e2f9d 100755
--- a/build.sh
+++ b/build.sh
@@ -36,7 +36,7 @@ INCLUDE_PATHS="-Ibase -I../mkfw "
# Linux-specific includes and libraries
LINUX_INCLUDE=" "
-LINUX_LIBS="-lXi -lX11 -lGL -lm -ldl -pthread -larchive "
+LINUX_LIBS="-lXi -lX11 -lGL -lm -ldl -pthread -larchive -lSDL2"
# Windows-specific includes and libraries
WINDOWS_INCLUDE=""
@@ -93,7 +93,7 @@ set -e
# Build Linux version
(
- $CC $CFLAGS ${PROJECT_NAME}.c -o ${PROJECT_NAME} $INCLUDE_PATHS $LINUX_INCLUDE $LDFLAGS $LINUX_LIBS
+ $CC $CFLAGS ${PROJECT_NAME}_sdl.c -o ${PROJECT_NAME} $INCLUDE_PATHS $LINUX_INCLUDE $LDFLAGS $LINUX_LIBS
objdump -d -Mintel mknes > mknes.s
) &
diff --git a/mappers/mapper_001_0.c b/mappers/mapper_001_0.c
index a449fe7..bf2f5db 100644
--- a/mappers/mapper_001_0.c
+++ b/mappers/mapper_001_0.c
@@ -1,90 +1,102 @@
-static uint8_t mapper_001_0_prg_rom_read(struct nes_state *state, uint32_t addr) {
+
+__attribute__((always_inline))
+static inline void mapper_001_0_apply_chr_banks(struct nes_state *state) {
struct mapper_001_0 *mapper = &state->mapper_data.m001_0;
- if(addr >= 0x8000) {
- if(addr < 0xc000) {
- return mapper->prg_rom_0[addr & 0x3fff];
+ if(!state->ines.chr_size) {
+ return;
+ }
+
+ if(mapper->control & 0x10) {
+ // 4KB CHR mode
+ mapper->chr_bank_0 = state->chr_rom + (mapper->chr_bank0 * 0x1000);
+ mapper->chr_bank_1 = state->chr_rom + (mapper->chr_bank1 * 0x1000);
+ } else {
+ // 8KB CHR mode - ignore bit 0 of bank number
+ mapper->chr_bank_0 = state->chr_rom + ((mapper->chr_bank0 & 0xfe) * 0x1000);
+ mapper->chr_bank_1 = state->chr_rom + ((mapper->chr_bank0 & 0xfe) * 0x1000) + 0x1000;
+ }
+}
+
+__attribute__((always_inline))
+static inline void mapper_001_0_apply_prg_banks(struct nes_state *state) {
+ struct mapper_001_0 *mapper = &state->mapper_data.m001_0;
+
+ if(mapper->control & 0x08) {
+ // 16KB PRG mode
+ if(mapper->control & 0x04) {
+ // Fix last bank at $C000, switch first bank at $8000
+ mapper->prg_rom_0 = state->prg_rom + (mapper->prg_bank * 0x4000);
+ mapper->prg_rom_1 = state->prg_rom + (state->ines.prg_size - 0x4000);
} else {
- return mapper->prg_rom_1[addr & 0x3fff];
+ // Fix first bank at $8000, switch last bank at $C000
+ mapper->prg_rom_0 = state->prg_rom;
+ mapper->prg_rom_1 = state->prg_rom + (mapper->prg_bank * 0x4000);
}
+ } else {
+ // 32KB PRG mode - ignore bit 0
+ uint32_t base = (mapper->prg_bank & 0x0e) * 0x4000;
+ mapper->prg_rom_0 = state->prg_rom + base;
+ mapper->prg_rom_1 = state->prg_rom + base + 0x4000;
}
- return 0;
}
-static void mapper_001_0_prg_rom_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+__attribute__((always_inline))
+static inline void mapper_001_0_write_control(struct nes_state *state, uint8_t value) {
struct mapper_001_0 *mapper = &state->mapper_data.m001_0;
-printf("MMC1 write: addr=%04x val=%02x\n", addr, value);
+ mapper->control = value;
+ mapper_001_0_apply_chr_banks(state);
+ mapper_001_0_apply_prg_banks(state);
+}
- if(addr < 0x8000) {
- return;
+static uint8_t mapper_001_0_prg_rom_read(struct nes_state *state, uint32_t addr) {
+ struct mapper_001_0 *mapper = &state->mapper_data.m001_0;
+
+ if(addr < 0xc000) {
+ return mapper->prg_rom_0[addr & 0x3fff];
}
+ return mapper->prg_rom_1[addr & 0x3fff];
+}
+
+static void mapper_001_0_prg_rom_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ struct mapper_001_0 *mapper = &state->mapper_data.m001_0;
if(value & 0x80) {
- mapper->shift = 0;
+ mapper->shift_accumulator = 0;
mapper->shift_count = 0;
- mapper->control |= 0x0c;
+ mapper_001_0_write_control(state, mapper->control | 0x0c);
return;
}
- mapper->shift |= (value & 1) << mapper->shift_count;
+ mapper->shift_accumulator |= (value & 1) << mapper->shift_count;
mapper->shift_count++;
if(mapper->shift_count == 5) {
uint8_t reg = (addr >> 13) & 3;
switch(reg) {
- case 0: {
- mapper->control = mapper->shift;
- switch(mapper->control & 3) {
- case 0: {
- state->ines.mirroring = MIRROR_ONESCREEN_LOW;
- } break;
-
- case 1: {
- state->ines.mirroring = MIRROR_ONESCREEN_HIGH;
- } break;
-
- case 2: {
- state->ines.mirroring = MIRROR_VERTICAL;
- } break;
-
- case 3: {
- state->ines.mirroring = MIRROR_HORIZONTAL;
- } break;
- }
- } break;
-
- case 1: {
- mapper->chr_bank0 = mapper->shift;
- mapper->chr_bank_0 = state->chr_rom + (mapper->chr_bank0 * 0x1000);
- } break;
-
- case 2: {
- mapper->chr_bank1 = mapper->shift;
- mapper->chr_bank_1 = state->chr_rom + (mapper->chr_bank1 * 0x1000);
- } break;
-
- case 3: {
- mapper->prg_bank = mapper->shift & 0x0f;
-
- if(mapper->control & 0x08) {
- if(mapper->control & 0x04) {
- mapper->prg_rom_0 = state->prg_rom;
- mapper->prg_rom_1 = state->prg_rom + (mapper->prg_bank * 0x4000);
- } else {
- mapper->prg_rom_0 = state->prg_rom + (mapper->prg_bank * 0x4000);
- mapper->prg_rom_1 = state->prg_rom + (state->ines.prg_size - 0x4000);
- }
- } else {
- uint32_t base = (mapper->prg_bank & 0x0e) * 0x4000;
- mapper->prg_rom_0 = state->prg_rom + base;
- mapper->prg_rom_1 = state->prg_rom + base + 0x4000;
- }
- } break;
+ case 0:
+ mapper_001_0_write_control(state, mapper->shift_accumulator);
+ break;
+
+ case 1:
+ mapper->chr_bank0 = mapper->shift_accumulator;
+ mapper_001_0_apply_chr_banks(state);
+ break;
+
+ case 2:
+ mapper->chr_bank1 = mapper->shift_accumulator;
+ mapper_001_0_apply_chr_banks(state);
+ break;
+
+ case 3:
+ mapper->prg_bank = mapper->shift_accumulator & 0x0f;
+ mapper_001_0_apply_prg_banks(state);
+ break;
}
- mapper->shift = 0;
+ mapper->shift_accumulator = 0;
mapper->shift_count = 0;
}
}
@@ -92,83 +104,92 @@ printf("MMC1 write: addr=%04x val=%02x\n", addr, value);
static uint8_t mapper_001_0_chr_read(struct nes_state *state, uint32_t addr) {
struct mapper_001_0 *mapper = &state->mapper_data.m001_0;
+ if(state->ines.chr_size == 0) {
+ // CHR-RAM - no banking
+ return state->chr_ram[addr];
+ }
+
+ // CHR-ROM - use banking
+ uint8_t val;
if(mapper->control & 0x10) {
+ // 4KB CHR mode
if(addr < 0x1000) {
- return mapper->chr_bank_0[addr & 0xfff];
+ val = mapper->chr_bank_0[addr & 0xfff];
} else {
- return mapper->chr_bank_1[addr & 0xfff];
+ val = mapper->chr_bank_1[addr & 0xfff];
}
} else {
- return mapper->chr_bank_0[addr & 0x1fff];
+ // 8KB CHR mode
+ val = mapper->chr_bank_0[addr & 0x1fff];
}
+ return val;
}
static void mapper_001_0_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) {
state->chr_ram[addr] = value;
}
+static uint8_t mapper_001_0_prg_ram_read(struct nes_state *state, uint32_t addr) {
+ return state->sram[addr & 0x1fff];
+}
+
+static void mapper_001_0_prg_ram_write(struct nes_state *state, uint32_t addr, uint8_t value) {
+ state->sram[addr & 0x1fff] = value;
+}
+
static uint8_t mapper_001_0_ciram_read(struct nes_state *state, uint32_t addr) {
- // MMC1 can set mirroring mode dynamically via control register
- switch(state->ines.mirroring) {
- case MIRROR_ONESCREEN_LOW:
- addr = addr & 0x3ff;
- break;
- case MIRROR_ONESCREEN_HIGH:
- addr = 0x400 | (addr & 0x3ff);
- break;
- case MIRROR_HORIZONTAL: // Horizontal: NT0↔NT1, NT2↔NT3
- addr = ((addr >> 1) & 0x400) | (addr & 0x3ff);
- break;
- case MIRROR_VERTICAL: // Vertical: NT0↔NT2, NT1↔NT3
- addr = addr & 0x7ff;
- break;
+ struct mapper_001_0 *mapper = &state->mapper_data.m001_0;
+
+ switch(mapper->control & 3) {
+ case 0: return state->ciram[addr & 0x3ff]; // one-screen lower
+ case 1: return state->ciram[0x400 | (addr & 0x3ff)]; // one-screen upper
+ case 2: return state->ciram[addr & 0x7ff]; // vertical
+ case 3: return state->ciram[((addr >> 1) & 0x400) | (addr & 0x3ff)]; // horizontal
}
- return state->ciram[addr];
+ return 0;
}
static void mapper_001_0_ciram_write(struct nes_state *state, uint32_t addr, uint8_t value) {
- // MMC1 can set mirroring mode dynamically via control register
- switch(state->ines.mirroring) {
- case MIRROR_ONESCREEN_LOW:
- addr = addr & 0x3ff;
- break;
- case MIRROR_ONESCREEN_HIGH:
- addr = 0x400 | (addr & 0x3ff);
- break;
- case MIRROR_HORIZONTAL: // Horizontal: NT0↔NT1, NT2↔NT3
- addr = ((addr >> 1) & 0x400) | (addr & 0x3ff);
- break;
- case MIRROR_VERTICAL: // Vertical: NT0↔NT2, NT1↔NT3
- addr = addr & 0x7ff;
- break;
+ struct mapper_001_0 *mapper = &state->mapper_data.m001_0;
+
+ switch(mapper->control & 3) {
+ case 0: { // one-screen lower
+ state->ciram[addr & 0x3ff] = value;
+ } break;
+ case 1: { // one-screen upper
+ state->ciram[0x400 | (addr & 0x3ff)] = value;
+ } break;
+ case 2: { // vertical
+ state->ciram[addr & 0x7ff] = value;
+ } break;
+ case 3: { // horizontal
+ state->ciram[((addr >> 1) & 0x400) | (addr & 0x3ff)] = value;
+ } break;
}
- state->ciram[addr] = value;
}
static void mapper_001_0_init(struct nes_state *state) {
struct mapper_001_0 *mapper = &state->mapper_data.m001_0;
- mapper->shift = 0;
- mapper->shift_count = 0;
- mapper->control = 0x0c;
+ memset(mapper, 0, sizeof(struct mapper_001_0));
- mapper->prg_bank = 0;
- mapper->chr_bank0 = 0;
- mapper->chr_bank1 = 0;
+ mapper->control = 0x0c;
- mapper->prg_rom_0 = state->prg_rom;
- mapper->prg_rom_1 = state->prg_rom + (state->ines.prg_size - 0x4000);
+ mapper_001_0_apply_prg_banks(state);
if(state->ines.chr_size) {
- mapper->chr_bank_0 = state->chr_rom;
- mapper->chr_bank_1 = state->chr_rom + 0x1000;
+ // CHR-ROM - apply banking
+ mapper_001_0_apply_chr_banks(state);
} else {
+ // CHR-RAM - no banking, point directly to RAM
mapper->chr_bank_0 = state->chr_ram;
mapper->chr_bank_1 = state->chr_ram + 0x1000;
}
state->mapper_function.prg_rom_read = mapper_001_0_prg_rom_read;
state->mapper_function.prg_rom_write = mapper_001_0_prg_rom_write;
+ state->mapper_function.prg_ram_read = mapper_001_0_prg_ram_read;
+ state->mapper_function.prg_ram_write = mapper_001_0_prg_ram_write;
state->mapper_function.chr_read = mapper_001_0_chr_read;
state->mapper_function.chr_write = mapper_001_0_chr_write;
state->mapper_function.ciram_read = mapper_001_0_ciram_read;
diff --git a/mappers/mapper_001_0.h b/mappers/mapper_001_0.h
index deb0e29..18dfec9 100644
--- a/mappers/mapper_001_0.h
+++ b/mappers/mapper_001_0.h
@@ -1,6 +1,6 @@
struct mapper_001_0 {
- uint8_t shift;
+ uint8_t shift_accumulator;
uint8_t shift_count;
uint8_t control;
uint8_t prg_bank;
diff --git a/mappers/mapper_007_2.c b/mappers/mapper_007_2.c
index 9f5a3dc..3987956 100644
--- a/mappers/mapper_007_2.c
+++ b/mappers/mapper_007_2.c
@@ -42,7 +42,7 @@ static void mapper_007_2_ciram_write(struct nes_state *state, uint32_t addr, uin
static void mapper_007_2_init(struct nes_state *state) {
struct mapper_007_2 *mapper = &state->mapper_data.m007_2;
mapper->prg_rom = state->prg_rom;
- mapper->ciram = 0;
+ mapper->ciram = state->ciram; // << THIS WAS THE BUG, set ciram = 0, zero understanding to how this worked for 6+ months.
state->mapper_function.prg_rom_read = mapper_007_2_prg_rom_read;
state->mapper_function.prg_rom_write = mapper_007_2_prg_rom_write;
diff --git a/mappers/mapper_011_0.c b/mappers/mapper_011_0.c
index 12b68ba..6b31f26 100644
--- a/mappers/mapper_011_0.c
+++ b/mappers/mapper_011_0.c
@@ -1,33 +1,27 @@
static uint8_t mapper_011_0_prg_rom_read(struct nes_state *state, uint32_t addr) {
struct mapper_011_0 *mapper = &state->mapper_data.m011_0;
-
- if(addr >= 0x8000) {
- return mapper->prg_rom[addr - 0x8000];
- }
- return 0;
+ return mapper->prg_rom[addr & 0x7fff];
}
static void mapper_011_0_prg_rom_write(struct nes_state *state, uint32_t addr, uint8_t value) {
struct mapper_011_0 *mapper = &state->mapper_data.m011_0;
- if(addr >= 0x8000) {
- mapper->prg_rom = state->prg_rom + ((value >> 4) & 7) * 0x8000;
- mapper->chr_ptr = state->chr_rom + (value & 0x0F) * 0x2000;
- }
+ mapper->prg_rom = state->prg_rom + (value & 0x3) * 0x8000;
+ mapper->chr_rom = state->chr_rom + ((value >> 4) & 0x3) * 0x2000;
}
static uint8_t mapper_011_0_chr_read(struct nes_state *state, uint32_t addr) {
struct mapper_011_0 *mapper = &state->mapper_data.m011_0;
- return mapper->chr_ptr[addr];
+ return mapper->chr_rom[addr];
}
static void mapper_011_0_init(struct nes_state *state) {
struct mapper_011_0 *mapper = &state->mapper_data.m011_0;
mapper->prg_rom = state->prg_rom;
- mapper->chr_ptr = state->chr_rom;
+ mapper->chr_rom = state->chr_rom;
state->mapper_function.prg_rom_read = mapper_011_0_prg_rom_read;
state->mapper_function.prg_rom_write = mapper_011_0_prg_rom_write;
diff --git a/mappers/mapper_011_0.h b/mappers/mapper_011_0.h
index 8f41e8e..5cb6ebf 100644
--- a/mappers/mapper_011_0.h
+++ b/mappers/mapper_011_0.h
@@ -2,5 +2,5 @@
struct mapper_011_0 {
uint8_t *prg_rom;
- uint8_t *chr_ptr;
+ uint8_t *chr_rom;
} __attribute__((packed, aligned(64)));
diff --git a/mknes.c b/mknes.c
index f68493c..8169fae 100644
--- a/mknes.c
+++ b/mknes.c
@@ -299,9 +299,9 @@ int main(int argc, char **argv) {
// 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/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");
@@ -342,8 +342,8 @@ int main(int argc, char **argv) {
// ines2_load(nstate, "data/2002/Best of the Best - Championship Karate (USA).zip");
// ines2_load(nstate, "data/0001/Kid Icarus (UE) (V1.1) [!].nes");
- // ines2_load(nstate, "data/0001/Metroid (U) [!].nes");
- // ines2_load(nstate, "data/0001/Legend of Zelda, The (U) (V1.1) [!].nes");
+ ines2_load(nstate, "data/0001/Metroid (U) [!].nes");
+ ines2_load(nstate, "data/0001/Legend of Zelda, The (U) (V1.1) [!].nes");
// ines2_load(nstate, "data/Blaster Master (USA).zip"); // mapper 1
// ines2_load(nstate, "AccuracyCoin.nes"); // mapper 1
@@ -377,17 +377,37 @@ int main(int argc, char **argv) {
// // Check for ESC key
if(mkfw_is_key_pressed(window, MKS_KEY_ESCAPE)) running = false;
+ uint32_t n = -1;
+ if(mkfw_is_key_pressed(window, MKS_KEY_Q)) n = 0;
+ if(mkfw_is_key_pressed(window, MKS_KEY_W)) n = 1;
+ if(mkfw_is_key_pressed(window, MKS_KEY_E)) n = 2;
+ if(mkfw_is_key_pressed(window, MKS_KEY_R)) n = 3;
+
+ if(n != -1) {
+ printf("\033[2J\033[H");
+ uint8_t *d = nstate->ciram + n * 960;
+ for(size_t i = 0; i < 30; ++i, d += 32) {
+ for(size_t j = 0; j < 32; ++j) {
+ uint8_t tile = d[j];
+ if(tile == 0x00) printf(" ");
+ else if(tile == 0xff) printf("##");
+ else printf("%02d", tile % 100);
+ }
+ printf("\n");
+ }
+ }
+
// Joypad input
uint8_t input = 0;
- // if(window->keyboard_state[MKS_KEY_X]) { input |= (1 << 0); }
- // if(window->keyboard_state[MKS_KEY_Z]) { input |= (1 << 1); }
- // if(window->keyboard_state[MKS_KEY_SPACE]) { input |= (1 << 2); }
- // if(window->keyboard_state[MKS_KEY_RETURN]) { input |= (1 << 3); }
- // if(window->keyboard_state[MKS_KEY_UP]) { input |= (1 << 4); }
- // if(window->keyboard_state[MKS_KEY_DOWN]) { input |= (1 << 5); }
- // if(window->keyboard_state[MKS_KEY_LEFT]) { input |= (1 << 6); }
- // if(window->keyboard_state[MKS_KEY_RIGHT]) { input |= (1 << 7); }
- // nstate->ppu.input[0] = input;
+ if(window->keyboard_state[MKS_KEY_X]) { input |= (1 << 0); }
+ if(window->keyboard_state[MKS_KEY_Z]) { input |= (1 << 1); }
+ if(window->keyboard_state[MKS_KEY_SPACE]) { input |= (1 << 2); }
+ if(window->keyboard_state[MKS_KEY_RETURN]) { input |= (1 << 3); }
+ if(window->keyboard_state[MKS_KEY_UP]) { input |= (1 << 4); }
+ if(window->keyboard_state[MKS_KEY_DOWN]) { input |= (1 << 5); }
+ if(window->keyboard_state[MKS_KEY_LEFT]) { input |= (1 << 6); }
+ if(window->keyboard_state[MKS_KEY_RIGHT]) { input |= (1 << 7); }
+ nstate->ppu.input[0] = input;
// Run NES emulation for one frame
while(!nstate->ppu.frame_ready) {
@@ -402,7 +422,7 @@ int main(int argc, char **argv) {
// }
// nstate->ppu.open_bus = v;
// }
- nstate->ppu.input[0] = tas_input[tas_frame++];
+ // nstate->ppu.input[0] = tas_input[tas_frame++];
frames++;
@@ -435,7 +455,7 @@ int main(int argc, char **argv) {
}
}
- printf("total frames: %6d total cycles: %12llu\n", frames, (unsigned long long)nstate->cpu.cycles);
+ // printf("total frames: %6d total cycles: %12llu\n", frames, (unsigned long long)nstate->cpu.cycles);
printf("state dumps created: %zu\n", state_dump_count);
if(state_dump_file) {
diff --git a/mknes.h b/mknes.h
index e9d3e0e..b6739d3 100644
--- a/mknes.h
+++ b/mknes.h
@@ -61,14 +61,14 @@ struct ppu_state {
// NOTE(peter): CACHELINE 2
uint8_t secondary_oam[32] __attribute__((aligned(64)));
- // NOTE(peter): CACHELINE 3
+ // NOTE(peter): CACHELINE 2 + 3, first 5 sprites in same cacheline as secondary_oam
struct sprite_data {
uint8_t shift_lo;
uint8_t shift_hi;
uint8_t position;
uint8_t priority;
uint8_t palette;
- } __attribute__((packed)) sprites[8] __attribute__((aligned(64)));
+ } __attribute__((packed)) sprites[8];
uint8_t input[2]; // 40 - Controller 1 & 2
uint8_t input_latch[2]; // 42 - Latched inputs after strobe
diff --git a/mknes_mapper.c b/mknes_mapper.c
index 4202769..a05707e 100644
--- a/mknes_mapper.c
+++ b/mknes_mapper.c
@@ -7,19 +7,16 @@
static uint8_t mapper_default_ciram_read(struct nes_state *state, uint32_t addr) {
- if(state->ines.mirroring == MIRROR_HORIZONTAL) { // Horizontal: NT0↔NT1, NT2↔NT3
- addr = ((addr >> 1) & 0x400) | (addr & 0x3ff);
- } else { // Vertical (default fallback): NT0↔NT2, NT1↔NT3
- addr = addr & 0x7ff;
+ if(state->ines.mirroring == MIRROR_HORIZONTAL) {
+ return state->ciram[((addr >> 1) & 0x400) | (addr & 0x3ff)];
}
-
- return state->ciram[addr];
+ return state->ciram[addr & 0x7ff];
}
static void mapper_default_ciram_write(struct nes_state *state, uint32_t addr, uint8_t value) {
- if(state->ines.mirroring == MIRROR_HORIZONTAL) { // Horizontal: NT0↔NT1, NT2↔NT3
+ if(state->ines.mirroring == MIRROR_HORIZONTAL) { // Horizontal: NT0+NT1, NT2+NT3
addr = ((addr >> 1) & 0x400) | (addr & 0x3ff);
- } else { // Vertical (default fallback): NT0↔NT2, NT1↔NT3
+ } else { // Vertical (default fallback): NT0+NT2, NT1+NT3
addr = addr & 0x7ff;
}
state->ciram[addr] = value;
diff --git a/mknes_memory.c b/mknes_memory.c
index 7280f81..20d77e8 100644
--- a/mknes_memory.c
+++ b/mknes_memory.c
@@ -73,19 +73,17 @@ static inline void memory_write(struct nes_state *state, uint32_t offset, uint8_
// joypad strobe
uint8_t s = value & 1;
- // if(s) {
- uint8_t prev = state->ppu.input_strobe;
- state->ppu.input_strobe = s;
-
- if(prev == 1 && (s) == 0) {
- // state->ppu.input[0] = tas_input[tas_frame_count];
-
- 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;
- }
- // }
+ uint8_t prev = state->ppu.input_strobe;
+ state->ppu.input_strobe = s;
+
+ if(prev == 1 && (s) == 0) {
+ // state->ppu.input[0] = tas_input[tas_frame_count];
+
+ 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 >= 0x4000 && offset <= 0x4017) {
apu_write(state, offset, value);
diff --git a/mknes_ppu.c b/mknes_ppu.c
index 1a40de0..8006ff6 100644
--- a/mknes_ppu.c
+++ b/mknes_ppu.c
@@ -277,13 +277,14 @@ shift_and_fetch:
switch(dot % 8) {
case 1: {
- uint32_t nt_addr = 0x2000 | (ppu->vram_addr & 0x0fff);
- ppu->bg_next_tile_id = state->mapper_function.ciram_read(state, nt_addr);
+ // uint32_t nt_addr = 0x2000 | (ppu->vram_addr & 0xfff);
+ // ppu->bg_next_tile_id = state->mapper_function.ciram_read(state, nt_addr);
+ ppu->bg_next_tile_id = state->mapper_function.ciram_read(state, ppu->vram_addr);
} break;
case 3: {
uint32_t attr_addr = 0x23c0 | (ppu->vram_addr & 0x0c00) | ((ppu->vram_addr >> 4) & 0x38) | ((ppu->vram_addr >> 2) & 0x07);
- uint8_t attr = state->mapper_function.ciram_read(state, attr_addr & 0x0fff);
+ uint8_t attr = state->mapper_function.ciram_read(state, attr_addr);
uint8_t shift = ((ppu->vram_addr >> 4) & 4) | (ppu->vram_addr & 2);
ppu->bg_next_tile_attrib = (attr >> shift) & 3;
} break;
diff --git a/mknes_ppu_registers.c b/mknes_ppu_registers.c
index 6720958..0defd0c 100644
--- a/mknes_ppu_registers.c
+++ b/mknes_ppu_registers.c
@@ -47,11 +47,13 @@ static inline void ppu_write(struct nes_state *state, uint32_t offset, uint8_t v
case 7: {
uint32_t addr = ppu->vram_addr;
- if(addr <= 0x1fff) {
+ if(addr < 0x2000) {
state->mapper_function.chr_write(state, addr, value);
- } else if(addr >= 0x2000 && addr <= 0x3eff) {
+
+ } else if(addr < 0x3f00) {
state->mapper_function.ciram_write(state, addr, value);
- } else if(addr >= 0x3f00 && addr <= 0x3fff) {
+
+ } else if(addr < 0x4000) {
uint32_t pal_addr = addr & 0x1f;
if((pal_addr & 3) == 0) {
pal_addr &= ~0x10;
@@ -92,13 +94,15 @@ static inline uint8_t ppu_read(struct nes_state *state, uint32_t offset) {
case 7: {
uint32_t addr = ppu->vram_addr;
- if(addr <= 0x1fff) {
+ if(addr < 0x2000) {
result = ppu->vram_read_buffer;
ppu->vram_read_buffer = state->mapper_function.chr_read(state, addr);
- } else if(addr >= 0x2000 && addr <= 0x3eff) {
+
+ } else if(addr < 0x3f00) {
result = ppu->vram_read_buffer;
ppu->vram_read_buffer = state->mapper_function.ciram_read(state, addr);
- } else if(addr >= 0x3f00 && addr <= 0x3fff) {
+
+ } else if(addr < 0x4000) {
uint32_t pal_addr = addr & 0x1f;
if((pal_addr & 0x13) == 0x10) {
pal_addr &= ~0x10;