diff options
| author | Peter Fors <peter.fors@mindkiller.com> | 2025-05-27 15:03:30 +0200 |
|---|---|---|
| committer | Peter Fors <peter.fors@mindkiller.com> | 2025-05-27 15:03:30 +0200 |
| commit | 7cca3bdbec289328b537c8256b43dcfedc5d56b8 (patch) | |
| tree | 181c22764d3d881ccd41d5c0282cd364d3f5197d | |
| parent | a8e0c141b0184d629504b9f0ee8dbc4fefb90934 (diff) | |
renaming
| -rwxr-xr-x | build.sh | 3 | ||||
| -rwxr-xr-x | mapper_add.py | 8 | ||||
| -rw-r--r-- | mappers/mapper.c | 48 | ||||
| -rw-r--r-- | mappers/mapper.h | 10 | ||||
| -rw-r--r-- | mappers/mapper_000_0.c | 11 | ||||
| -rw-r--r-- | mappers/mapper_001_0.c | 24 | ||||
| -rw-r--r-- | mappers/mapper_002_2.c | 19 | ||||
| -rw-r--r-- | mappers/mapper_003_0.c | 16 | ||||
| -rw-r--r-- | mappers/mapper_003_1.c | 16 | ||||
| -rw-r--r-- | mappers/mapper_003_2.c | 16 | ||||
| -rw-r--r-- | mappers/mapper_007_2.c | 27 | ||||
| -rw-r--r-- | mappers/mapper_011_0.c | 18 | ||||
| -rw-r--r-- | mappers/mapper_066_0.c | 18 | ||||
| -rw-r--r-- | memory.c | 25 | ||||
| -rw-r--r-- | mknes.c | 100 | ||||
| -rw-r--r-- | mknes.h | 5 | ||||
| -rw-r--r-- | ppu.c | 29 | ||||
| -rw-r--r-- | ppu_registers.c | 8 |
18 files changed, 216 insertions, 185 deletions
@@ -6,6 +6,7 @@ PROJECT_NAME="mknes" # Change this for each new project CC=gcc # Base configuration common to all builds +# CFLAGS="-std=gnu11 -mtune=generic " CFLAGS="-std=gnu11 -mtune=generic " CFLAGS+="-mbmi " CFLAGS+="-mfunction-return=keep -mindirect-branch=keep " @@ -45,8 +46,8 @@ fi case "$BUILD_TYPE" in "normal") CFLAGS+=" -ggdb -fno-omit-frame-pointer -O2 -DDEBUG_INTERNAL" + # CFLAGS+=" -fsanitize=address,undefined,alignment,object-size,unreachable -fno-omit-frame-pointer" # -pg # for gprof -# -fsanitize=address,undefined,alignment,object-size,unreachable -fno-omit-frame-pointer" ;; "release") CFLAGS+=" -s -Wl,--strip-all -O2" diff --git a/mapper_add.py b/mapper_add.py index 151506b..7092ddb 100755 --- a/mapper_add.py +++ b/mapper_add.py @@ -12,11 +12,11 @@ def generate_mapper_files(mapper_id, submapper_id=0): # Generate C file content c_content = f"""#include "{filename}.h" -static uint8_t {filename}_prg_read(struct nes_state *state, uint32_t addr) {{ +static uint8_t {filename}_prg_rom_read(struct nes_state *state, uint32_t addr) {{ return 0; }} -static void {filename}_prg_write(struct nes_state *state, uint32_t addr, uint8_t value) {{ +static void {filename}_prg_rom_write(struct nes_state *state, uint32_t addr, uint8_t value) {{ }} static uint8_t {filename}_chr_read(struct nes_state *state, uint32_t addr) {{ @@ -37,8 +37,8 @@ static void {filename}_tick(struct nes_state *state) {{ }} void {filename}_init(struct nes_state *state) {{ - state->mapper.prg_read = {filename}_prg_read; - state->mapper.prg_write = {filename}_prg_write; + state->mapper.prg_rom_read = {filename}_prg_read; + state->mapper.prg_rom_write = {filename}_prg_rom_write; state->mapper.chr_read = {filename}_chr_read; state->mapper.chr_write = {filename}_chr_write; state->mapper.ciram_read = {filename}_ciram_read; diff --git a/mappers/mapper.c b/mappers/mapper.c index 5636705..0b5612b 100644 --- a/mappers/mapper.c +++ b/mappers/mapper.c @@ -18,9 +18,32 @@ static void mapper_default_ciram_write(struct nes_state *state, uint32_t addr, u 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) { } +// static void mapper_default_prg_rom_write(struct nes_state *state, uint32_t addr, uint8_t value) { } +// static uint8_t mapper_default_prg_ram_read(struct nes_state *state, uint32_t addr) { return 0; } +// static void mapper_default_prg_ram_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) { } + +__attribute__((naked)) void mapper_default_prg_rom_write(struct nes_state *state, uint32_t addr, uint8_t value) { + __asm__ __volatile__("ret"); +} + +__attribute__((naked)) uint8_t mapper_default_prg_ram_read(struct nes_state *state, uint32_t addr) { + __asm__ __volatile__("xor %%al, %%al\n\t" "ret" : : : "al"); +} + +__attribute__((naked)) void mapper_default_prg_ram_write(struct nes_state *state, uint32_t addr, uint8_t value) { + __asm__ __volatile__("ret"); +} + +__attribute__((naked)) void mapper_default_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) { + __asm__ __volatile__("ret"); +} + +__attribute__((naked)) void mapper_default_tick(struct nes_state *state) { + __asm__ __volatile__("ret"); +} + #include "mapper_000_0.c" #include "mapper_001_0.c" @@ -46,14 +69,17 @@ static void (*mapper_table[4096])(struct nes_state *state) = { [MAPPER_ID(66, 0)] = mapper_066_0_init, }; +// NOTE(peter): The entries with 0x0 will always have to be supplied/set by the mapper! 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; + state->mapper_function.prg_rom_read = 0x0; + state->mapper_function.prg_rom_write = mapper_default_prg_rom_write; + state->mapper_function.prg_ram_read = mapper_default_prg_ram_read; + state->mapper_function.prg_ram_write = mapper_default_prg_ram_write; + state->mapper_function.chr_read = 0x0; + state->mapper_function.chr_write = mapper_default_chr_write; + state->mapper_function.ciram_read = mapper_default_ciram_read; + state->mapper_function.ciram_write = mapper_default_ciram_write; + state->mapper_function.tick = 0; } static void mapper_setup(struct nes_state *state) { @@ -64,7 +90,7 @@ static void mapper_setup(struct nes_state *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); + printf("Unsupported mapper %d_%x, falling back to NROM (mapper 0)\n", state->ines.mapper, state->ines.submapper); mapper_table[0](state); } } diff --git a/mappers/mapper.h b/mappers/mapper.h index 20ee906..d4384ac 100644 --- a/mappers/mapper.h +++ b/mappers/mapper.h @@ -12,8 +12,10 @@ struct nes_state; 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 (*prg_rom_read)(struct nes_state *state, uint32_t addr); + void (*prg_rom_write)(struct nes_state *state, uint32_t addr, uint8_t value); + uint8_t (*prg_ram_read)(struct nes_state *state, uint32_t addr); + void (*prg_ram_write)(struct nes_state *state, uint32_t addr, uint8_t value); uint8_t (*chr_read)(struct nes_state *state, uint32_t addr); void (*chr_write)(struct nes_state *state, uint32_t addr, uint8_t value); uint8_t (*ciram_read)(struct nes_state *state, uint32_t addr); @@ -25,8 +27,8 @@ 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_0 m003_0; + struct mapper_003_1 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 cc7baf8..2faa002 100644 --- a/mappers/mapper_000_0.c +++ b/mappers/mapper_000_0.c @@ -1,8 +1,8 @@ __attribute__((section(".mapper_000_0"))) -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; +static uint8_t mapper_000_0_prg_rom_read(struct nes_state *state, uint32_t addr) { + struct mapper_000_0 *mapper = &state->mapper_data.m000_0; return state->prg_rom[addr & mapper->mask]; } @@ -14,9 +14,10 @@ static uint8_t mapper_000_0_chr_read(struct nes_state *state, uint32_t 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; - state->mapper.chr_read = mapper_000_0_chr_read; + struct mapper_000_0 *mapper = &state->mapper_data.m000_0; + + state->mapper_function.prg_rom_read = mapper_000_0_prg_rom_read; + state->mapper_function.chr_read = mapper_000_0_chr_read; mapper->mask = (state->ines.prg_size == 16384) ? 0x3fff : 0x7fff; } diff --git a/mappers/mapper_001_0.c b/mappers/mapper_001_0.c index 0a03a27..51d22a2 100644 --- a/mappers/mapper_001_0.c +++ b/mappers/mapper_001_0.c @@ -1,7 +1,7 @@ __attribute__((section(".mapper_001_0"))) -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; +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 >= 0x8000) { if(addr < 0xc000) { return mapper->prg_rom_0[addr & 0x3fff]; @@ -13,8 +13,8 @@ static uint8_t mapper_001_0_prg_read(struct nes_state *state, uint32_t addr) { } __attribute__((section(".mapper_001_0"))) -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; +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(addr < 0x8000) return; if(value & 0x80) { @@ -71,7 +71,7 @@ static void mapper_001_0_prg_write(struct nes_state *state, uint32_t addr, uint8 __attribute__((section(".mapper_001_0"))) 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; + struct mapper_001_0 *mapper = &state->mapper_data.m001_0; if(mapper->control & 0x10) { // 4KB mode if(addr < 0x1000) { @@ -103,7 +103,7 @@ static void mapper_001_0_ciram_write(struct nes_state *state, uint32_t addr, uin __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; + struct mapper_001_0 *mapper = &state->mapper_data.m001_0; mapper->control = 0x0c; mapper->prg_rom_0 = state->prg_rom; @@ -112,10 +112,10 @@ static void mapper_001_0_init(struct nes_state *state) { 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; + 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.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; + state->mapper_function.ciram_write = mapper_001_0_ciram_write; } diff --git a/mappers/mapper_002_2.c b/mappers/mapper_002_2.c index 4dbea85..e6cddf7 100644 --- a/mappers/mapper_002_2.c +++ b/mappers/mapper_002_2.c @@ -1,8 +1,9 @@ __attribute__((section(".mapper_002_2"))) -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; +static uint8_t mapper_002_2_prg_rom_read(struct nes_state *state, uint32_t addr) { + struct mapper_002_2 *mapper = &state->mapper_data.m002_2; + if(addr >= 0x8000 && addr < 0xc000) { return mapper->prg_bank0[addr & 0x3fff]; @@ -14,8 +15,8 @@ static uint8_t mapper_002_2_prg_read(struct nes_state *state, uint32_t addr) { } __attribute__((section(".mapper_002_2"))) -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; +static void mapper_002_2_prg_rom_write(struct nes_state *state, uint32_t addr, uint8_t value) { + struct mapper_002_2 *mapper = &state->mapper_data.m002_2; if(addr >= 0x8000) { mapper->prg_bank0 = state->prg_rom + ((value & 0x0f) * 0x4000); @@ -34,13 +35,13 @@ static void mapper_002_2_chr_write(struct nes_state *state, uint32_t addr, uint8 __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; + struct mapper_002_2 *mapper = &state->mapper_data.m002_2; 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; + state->mapper_function.prg_rom_read = mapper_002_2_prg_rom_read; + state->mapper_function.prg_rom_write = mapper_002_2_prg_rom_write; + state->mapper_function.chr_read = mapper_002_2_chr_read; + state->mapper_function.chr_write = mapper_002_2_chr_write; } diff --git a/mappers/mapper_003_0.c b/mappers/mapper_003_0.c index ec38f35..8c754a3 100644 --- a/mappers/mapper_003_0.c +++ b/mappers/mapper_003_0.c @@ -1,12 +1,12 @@ __attribute__((section(".mapper_003_0"))) -static uint8_t mapper_003_0_prg_read(struct nes_state *state, uint32_t addr) { +static uint8_t mapper_003_0_prg_rom_read(struct nes_state *state, uint32_t addr) { return state->prg_rom[addr & 0x7fff]; } __attribute__((section(".mapper_003_0"))) -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; +static void mapper_003_0_prg_rom_write(struct nes_state *state, uint32_t addr, uint8_t value) { + struct mapper_003_0 *mapper = &state->mapper_data.m003_0; if(addr >= 0x8000) { mapper->chr_ptr = state->chr_rom + (value & 3) * 0x2000; @@ -15,17 +15,17 @@ static void mapper_003_0_prg_write(struct nes_state *state, uint32_t addr, uint8 __attribute__((section(".mapper_003_0"))) 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; + struct mapper_003_0 *mapper = &state->mapper_data.m003_0; 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; + struct mapper_003_0 *mapper = &state->mapper_data.m003_0; 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; + state->mapper_function.prg_rom_read = mapper_003_0_prg_rom_read; + state->mapper_function.prg_rom_write = mapper_003_0_prg_rom_write; + state->mapper_function.chr_read = mapper_003_0_chr_read; } diff --git a/mappers/mapper_003_1.c b/mappers/mapper_003_1.c index 0032fbc..68e67c7 100644 --- a/mappers/mapper_003_1.c +++ b/mappers/mapper_003_1.c @@ -1,12 +1,12 @@ __attribute__((section(".mapper_003_1"))) -static uint8_t mapper_003_1_prg_read(struct nes_state *state, uint32_t addr) { +static uint8_t mapper_003_1_prg_rom_read(struct nes_state *state, uint32_t addr) { return state->prg_rom[addr & 0x7fff]; } __attribute__((section(".mapper_003_1"))) -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; +static void mapper_003_1_prg_rom_write(struct nes_state *state, uint32_t addr, uint8_t value) { + struct mapper_003_1 *mapper = &state->mapper_data.m003_1; if(addr >= 0x8000) { mapper->chr_ptr = state->chr_rom + (value & 3) * 0x2000; @@ -15,17 +15,17 @@ static void mapper_003_1_prg_write(struct nes_state *state, uint32_t addr, uint8 __attribute__((section(".mapper_003_1"))) 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; + struct mapper_003_1 *mapper = &state->mapper_data.m003_1; 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; + struct mapper_003_1 *mapper = &state->mapper_data.m003_1; 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; + state->mapper_function.prg_rom_read = mapper_003_1_prg_rom_read; + state->mapper_function.prg_rom_write = mapper_003_1_prg_rom_write; + state->mapper_function.chr_read = mapper_003_1_chr_read; } diff --git a/mappers/mapper_003_2.c b/mappers/mapper_003_2.c index 73cfdc6..9c0d40d 100644 --- a/mappers/mapper_003_2.c +++ b/mappers/mapper_003_2.c @@ -1,12 +1,12 @@ __attribute__((section(".mapper_003_2"))) -static uint8_t mapper_003_2_prg_read(struct nes_state *state, uint32_t addr) { +static uint8_t mapper_003_2_prg_rom_read(struct nes_state *state, uint32_t addr) { return state->prg_rom[addr & 0x7fff]; } __attribute__((section(".mapper_003_2"))) -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; +static void mapper_003_2_prg_rom_write(struct nes_state *state, uint32_t addr, uint8_t value) { + struct mapper_003_2 *mapper = &state->mapper_data.m003_2; if(addr >= 0x8000) { value &= state->prg_rom[addr & 0x7fff]; @@ -16,17 +16,17 @@ static void mapper_003_2_prg_write(struct nes_state *state, uint32_t addr, uint8 __attribute__((section(".mapper_003_2"))) 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; + struct mapper_003_2 *mapper = &state->mapper_data.m003_2; 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; + struct mapper_003_2 *mapper = &state->mapper_data.m003_2; mapper->chr_ptr = state->chr_rom; - state->mapper.prg_read = mapper_003_2_prg_read; - state->mapper.prg_write = mapper_003_2_prg_write; - state->mapper.chr_read = mapper_003_2_chr_read; + state->mapper_function.prg_rom_read = mapper_003_2_prg_rom_read; + state->mapper_function.prg_rom_write = mapper_003_2_prg_rom_write; + state->mapper_function.chr_read = mapper_003_2_chr_read; } diff --git a/mappers/mapper_007_2.c b/mappers/mapper_007_2.c index c42bc62..7f5963f 100644 --- a/mappers/mapper_007_2.c +++ b/mappers/mapper_007_2.c @@ -1,7 +1,8 @@ __attribute__((section(".mapper_007_2"))) -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; +static uint8_t mapper_007_2_prg_rom_read(struct nes_state *state, uint32_t addr) { + struct mapper_007_2 *mapper = &state->mapper_data.m007_2; + if(addr >= 0x8000) { return mapper->prg_rom[addr & 0x7fff]; } @@ -9,8 +10,8 @@ static uint8_t mapper_007_2_prg_read(struct nes_state *state, uint32_t addr) { } __attribute__((section(".mapper_007_2"))) -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; +static void mapper_007_2_prg_rom_write(struct nes_state *state, uint32_t addr, uint8_t value) { + struct mapper_007_2 *mapper = &state->mapper_data.m007_2; if(addr >= 0x8000) { uint32_t prg_off = (value & 0x0f) << 15; uint32_t ciram_off = (value & 0x10) << 11; @@ -34,26 +35,26 @@ static void mapper_007_2_chr_write(struct nes_state *state, uint32_t addr, uint8 __attribute__((section(".mapper_007_2"))) 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; + struct mapper_007_2 *mapper = &state->mapper_data.m007_2; return mapper->ciram[addr & 0x3ff]; } __attribute__((section(".mapper_007_2"))) 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; + struct mapper_007_2 *mapper = &state->mapper_data.m007_2; 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; + struct mapper_007_2 *mapper = &state->mapper_data.m007_2; 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; + state->mapper_function.prg_rom_read = mapper_007_2_prg_rom_read; + state->mapper_function.prg_rom_write = mapper_007_2_prg_rom_write; + state->mapper_function.chr_read = mapper_007_2_chr_read; + state->mapper_function.chr_write = mapper_007_2_chr_write; + state->mapper_function.ciram_read = mapper_007_2_ciram_read; + state->mapper_function.ciram_write = mapper_007_2_ciram_write; } diff --git a/mappers/mapper_011_0.c b/mappers/mapper_011_0.c index e5db02c..d324fcf 100644 --- a/mappers/mapper_011_0.c +++ b/mappers/mapper_011_0.c @@ -1,7 +1,7 @@ __attribute__((section(".mapper_011_0"))) -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; +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]; @@ -10,8 +10,8 @@ static uint8_t mapper_011_0_prg_read(struct nes_state *state, uint32_t addr) { } __attribute__((section(".mapper_011_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; +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; @@ -21,20 +21,20 @@ static void mapper_011_0_prg_write(struct nes_state *state, uint32_t addr, uint8 __attribute__((section(".mapper_011_0"))) 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; + struct mapper_011_0 *mapper = &state->mapper_data.m011_0; 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; + struct mapper_011_0 *mapper = &state->mapper_data.m011_0; 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; + state->mapper_function.prg_rom_read = mapper_011_0_prg_rom_read; + state->mapper_function.prg_rom_write = mapper_011_0_prg_rom_write; + state->mapper_function.chr_read = mapper_011_0_chr_read; } diff --git a/mappers/mapper_066_0.c b/mappers/mapper_066_0.c index 9629fb2..ccd00fe 100644 --- a/mappers/mapper_066_0.c +++ b/mappers/mapper_066_0.c @@ -1,7 +1,7 @@ __attribute__((section(".mapper_066_0"))) -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; +static uint8_t mapper_066_0_prg_rom_read(struct nes_state *state, uint32_t addr) { + struct mapper_066_0 *mapper = &state->mapper_data.m066_0; if(addr >= 0x8000) { return state->prg_rom[addr & 0x7fff]; @@ -10,8 +10,8 @@ static uint8_t mapper_066_0_prg_read(struct nes_state *state, uint32_t addr) { } __attribute__((section(".mapper_066_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; +static void mapper_066_0_prg_rom_write(struct nes_state *state, uint32_t addr, uint8_t value) { + struct mapper_066_0 *mapper = &state->mapper_data.m066_0; if(addr >= 0x8000) { uint32_t prg_bank = (value >> 4) & 3; @@ -24,19 +24,19 @@ static void mapper_066_0_prg_write(struct nes_state *state, uint32_t addr, uint8 __attribute__((section(".mapper_066_0"))) 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; + struct mapper_066_0 *mapper = &state->mapper_data.m066_0; 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; + struct mapper_066_0 *mapper = &state->mapper_data.m066_0; 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; + state->mapper_function.prg_rom_read = mapper_066_0_prg_rom_read; + state->mapper_function.prg_rom_write = mapper_066_0_prg_rom_write; + state->mapper_function.chr_read = mapper_066_0_chr_read; } @@ -1,6 +1,5 @@ - __attribute__((hot)) static inline uint8_t memory_read(struct nes_state *state, uint32_t offset) { state->cpu.cycles++; @@ -8,7 +7,10 @@ static inline uint8_t memory_read(struct nes_state *state, uint32_t offset) { // apu_tick(state); if(LIKELY(offset >= 0x6000)) { // MOST - return state->mapper.prg_read(state, offset); + if(UNLIKELY(offset < 0x8000)) { + return state->mapper_function.prg_ram_read(state, offset); + } + return state->mapper_function.prg_rom_read(state, offset); } else if(LIKELY(offset < 0x2000)) { // SECOND return state->ram[offset & 0x07ff]; @@ -66,21 +68,20 @@ static inline void memory_write(struct nes_state *state, uint32_t offset, uint8_ // state->apu.irq_pending = 0; // } } - } else if(offset >= 0x6000) { - state->mapper.prg_write(state, offset, value); + + } else if(offset >= 0x6000) { // NOTE(peter): Might need to move this upwards when we implement a mapper that has prg_ram_* + if(offset < 0x8000) { + state->mapper_function.prg_ram_write(state, offset, value); + } else { + state->mapper_function.prg_rom_write(state, offset, value); + } } } + static inline uint8_t memory_read_dma(struct nes_state *state, uint32_t offset) { // Do not tick CPU/PPU/APU — caller handles timing - if(LIKELY(offset < 0x2000)) { - return state->ram[offset & 0x07ff]; - - } else if(offset >= 0x6000) { - return state->mapper.prg_read(state, offset); - - } - return 0; + return state->ram[offset & 0x07ff]; } static inline uint8_t memory_read_dummy(struct nes_state *state, uint32_t offset) { @@ -121,65 +121,63 @@ int main(int argc, char **argv) { init_opcode_ud_lut(); // protect_opcode_lut(); - struct nes_state *nstate = aligned_alloc(4096, (sizeof(struct nes_state) + 4095) & ~4096); - + struct nes_state *nstate = aligned_alloc(4096, (sizeof(struct nes_state) + 4095) & ~4095); 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/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/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/0007/Beetlejuice (USA).zip"); + // ines2_load(nstate, "data/0007/Cabal (USA).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/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/Blaster Master (USA).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); + uint32_t lo = nstate->mapper_function.prg_rom_read(nstate, 0xfffc); + uint32_t hi = nstate->mapper_function.prg_rom_read(nstate, 0xfffd); nstate->cpu.pc = (hi << 8) | lo; #if 1 - for(uint32_t i = 0; i < 0x5000; ++ i) { + for(uint32_t i = 0; i < 0x5000; ++i) { while(!nstate->ppu.frame_ready) { // PROFILE_NAMED("nes emulator"); cpu_tick(nstate); @@ -230,12 +228,15 @@ int main(int argc, char **argv) { timer_start(timer); - while(!glfwWindowShouldClose(window)) { + for(;;) { timer_wait(timer); glfwPollEvents(); - uint8_t input = 0; + // exit + if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) break; + // Joypad input + uint8_t input = 0; if(glfwGetKey(window, GLFW_KEY_X) == GLFW_PRESS) { input |= (1 << 0); } if(glfwGetKey(window, GLFW_KEY_Z) == GLFW_PRESS) { input |= (1 << 1); } if(glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) { input |= (1 << 2); } @@ -244,7 +245,6 @@ int main(int argc, char **argv) { if(glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) { input |= (1 << 5); } if(glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) { input |= (1 << 6); } if(glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) { input |= (1 << 7); } - nstate->ppu.input[0] = input; while(!nstate->ppu.frame_ready) { @@ -106,9 +106,8 @@ struct ines_state { struct nes_state { struct ppu_state ppu; - struct mapper_functions mapper; - // union mapper_data map; - char map[sizeof(union mapper_data)] __attribute__((aligned(64))); // NOTE(peter): Only way due to aliasing rules in the C standard. + struct mapper_functions mapper_function; + union mapper_data mapper_data; struct cpu_state cpu; struct ines_state ines; // struct apu_state apu; @@ -89,11 +89,11 @@ static inline void ppu_fetch_sprite_patterns(struct nes_state *state) { addr = bank + tile * 16 + row; if(attr & 0x40) { - lsb = ppu_bitreverse_lut[state->mapper.chr_read(state, addr)]; - msb = ppu_bitreverse_lut[state->mapper.chr_read(state, addr + 8)]; + lsb = ppu_bitreverse_lut[state->mapper_function.chr_read(state, addr)]; + msb = ppu_bitreverse_lut[state->mapper_function.chr_read(state, addr + 8)]; } else { - lsb = state->mapper.chr_read(state, addr); - msb = state->mapper.chr_read(state, addr + 8); + lsb = state->mapper_function.chr_read(state, addr); + msb = state->mapper_function.chr_read(state, addr + 8); } ppu->sprite_shift_lo[i] = lsb; @@ -232,12 +232,12 @@ static inline void ppu_tick(struct nes_state *state) { switch(dot % 8) { case 1: { uint32_t nt_addr = 0x2000 | (ppu->vram_addr & 0x0fff); - ppu->bg_next_tile_id = state->mapper.ciram_read(state, nt_addr); + ppu->bg_next_tile_id = state->mapper_function.ciram_read(state, nt_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.ciram_read(state, attr_addr & 0x0fff); + uint8_t attr = state->mapper_function.ciram_read(state, attr_addr & 0x0fff); uint8_t shift = ((ppu->vram_addr >> 4) & 4) | (ppu->vram_addr & 2); ppu->bg_next_tile_attrib = (attr >> shift) & 3; } break; @@ -247,7 +247,7 @@ static inline void ppu_tick(struct nes_state *state) { uint32_t tile = ppu->bg_next_tile_id; uint32_t fine_y = (ppu->vram_addr >> 12) & 7; uint32_t addr_lsb = (base + tile * 16 + fine_y) & 0x1fff; - ppu->bg_next_tile_lsb = state->mapper.chr_read(state, addr_lsb); + ppu->bg_next_tile_lsb = state->mapper_function.chr_read(state, addr_lsb); } break; case 7: { @@ -255,7 +255,7 @@ static inline void ppu_tick(struct nes_state *state) { uint32_t tile = ppu->bg_next_tile_id; uint32_t fine_y = (ppu->vram_addr >> 12) & 7; uint32_t addr_msb = (base + tile * 16 + fine_y + 8) & 0x1fff; - ppu->bg_next_tile_msb = state->mapper.chr_read(state, addr_msb); + ppu->bg_next_tile_msb = state->mapper_function.chr_read(state, addr_msb); } break; case 0: { @@ -331,12 +331,12 @@ static inline void ppu_tick(struct nes_state *state) { switch(dot % 8) { case 1: { uint32_t nt_addr = 0x2000 | (ppu->vram_addr & 0x0fff); - ppu->bg_next_tile_id = state->mapper.ciram_read(state, nt_addr); + ppu->bg_next_tile_id = state->mapper_function.ciram_read(state, nt_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.ciram_read(state, attr_addr & 0x0fff); + uint8_t attr = state->mapper_function.ciram_read(state, attr_addr & 0x0fff); uint8_t shift = ((ppu->vram_addr >> 4) & 4) | (ppu->vram_addr & 2); ppu->bg_next_tile_attrib = (attr >> shift) & 3; } break; @@ -346,7 +346,7 @@ static inline void ppu_tick(struct nes_state *state) { uint32_t tile = ppu->bg_next_tile_id; uint32_t fine_y = (ppu->vram_addr >> 12) & 7; uint32_t addr_lsb = (base + tile * 16 + fine_y) & 0x1fff; - ppu->bg_next_tile_lsb = state->mapper.chr_read(state, addr_lsb); + ppu->bg_next_tile_lsb = state->mapper_function.chr_read(state, addr_lsb); } break; case 7: { @@ -354,7 +354,7 @@ static inline void ppu_tick(struct nes_state *state) { uint32_t tile = ppu->bg_next_tile_id; uint32_t fine_y = (ppu->vram_addr >> 12) & 7; uint32_t addr_msb = (base + tile * 16 + fine_y + 8) & 0x1fff; - ppu->bg_next_tile_msb = state->mapper.chr_read(state, addr_msb); + ppu->bg_next_tile_msb = state->mapper_function.chr_read(state, addr_msb); } break; case 0: { @@ -399,9 +399,7 @@ static inline void ppu_tick(struct nes_state *state) { // state->input[0] = tas_input[tas_frame++]; ppu->reg_status |= 0x80; - if(ppu->reg_ctrl & 0x80) { - state->cpu.nmi_pending = 1; - } + state->cpu.nmi_pending = (ppu->reg_ctrl & 0x80); // NOTE(peter): Set NMI if enabled. } if(UNLIKELY(scanline == 261) && dot == 1) { @@ -428,5 +426,6 @@ static inline void ppu_tick(struct nes_state *state) { ppu->dot = dot; ppu->scanline = scanline; + if(UNLIKELY(state->mapper_function.tick)) state->mapper_function.tick(state); } } diff --git a/ppu_registers.c b/ppu_registers.c index 98e2c7d..0e67890 100644 --- a/ppu_registers.c +++ b/ppu_registers.c @@ -52,10 +52,10 @@ static inline void ppu_write(struct nes_state *state, uint32_t offset, uint8_t v } else if(reg == 7) { uint32_t addr = ppu->vram_addr; if(addr < 0x2000) { - state->mapper.chr_write(state, addr, value); + state->mapper_function.chr_write(state, addr, value); } else if(LIKELY(addr < 0x3f00)) { - state->mapper.ciram_write(state, addr, value); + state->mapper_function.ciram_write(state, addr, value); } else if(addr < 0x4000) { uint32_t pal_addr = addr & 0x1f; @@ -94,11 +94,11 @@ static inline uint8_t ppu_read(struct nes_state *state, uint32_t offset) { if(LIKELY(addr < 0x2000)) { result = ppu->vram_read_buffer; - ppu->vram_read_buffer = state->mapper.chr_read(state, addr); + ppu->vram_read_buffer = state->mapper_function.chr_read(state, addr); } else if(LIKELY(addr < 0x3f00)) { result = ppu->vram_read_buffer; - ppu->vram_read_buffer = state->mapper.ciram_read(state, addr); + ppu->vram_read_buffer = state->mapper_function.ciram_read(state, addr); } else if(addr < 0x4000) { uint32_t pal_addr = addr & 0x1f; |
