diff options
| -rwxr-xr-x | build.sh | 5 | ||||
| -rw-r--r-- | mappers/mapper.c | 8 | ||||
| -rw-r--r-- | mappers/mapper.h | 6 | ||||
| -rw-r--r-- | mappers/mapper_000_0.c | 5 | ||||
| -rw-r--r-- | mappers/mapper_001_0.c | 121 | ||||
| -rw-r--r-- | mappers/mapper_001_0.h | 14 | ||||
| -rw-r--r-- | mappers/mapper_002_2.c | 5 | ||||
| -rw-r--r-- | mappers/mapper_003_0.c | 31 | ||||
| -rw-r--r-- | mappers/mapper_003_0.h | 4 | ||||
| -rw-r--r-- | mappers/mapper_003_1.c | 31 | ||||
| -rw-r--r-- | mappers/mapper_003_1.h | 4 | ||||
| -rw-r--r-- | mappers/mapper_003_2.c | 5 | ||||
| -rw-r--r-- | mappers/mapper_007_2.c | 8 | ||||
| -rw-r--r-- | mappers/mapper_011_0.c | 5 | ||||
| -rw-r--r-- | mappers/mapper_066_0.c | 4 | ||||
| -rw-r--r-- | mknes.c | 199 | ||||
| -rw-r--r-- | mknes.h | 17 | ||||
| -rw-r--r-- | opengl.c | 2 | ||||
| -rw-r--r-- | ppu.c | 15 |
19 files changed, 338 insertions, 151 deletions
@@ -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; @@ -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 @@ -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, @@ -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(); @@ -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). |
