diff --git a/Makefile b/Makefile index 421d39f..e866eef 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ SRC_SRCS_1 += cart.c mapper.c SRC_SRCS_1 += sdl_render.c sdl_input.c MAPDIR = src/map -MAP_SRCS_1 = nrom.c mmc1.c +MAP_SRCS_1 = nrom.c mmc1.c cnrom.c EXT_SRCS_1 = e6502/e6502.c diff --git a/src/cart.c b/src/cart.c index 2b25940..7de9313 100644 --- a/src/cart.c +++ b/src/cart.c @@ -10,6 +10,9 @@ int nes_cart_init_mem(nes_cart* cart, void* mem, int len) { ines_Header *hdr = (ines_Header*)mem; void* ptr = &hdr[1]; + cart->ines_mem = mem; + cart->ines_size = len; + status = ines_check_mem(hdr); if (0 == status && (hdr->flags_6 & ines_Flag_Trainer)) { @@ -18,22 +21,21 @@ int nes_cart_init_mem(nes_cart* cart, void* mem, int len) { } if (0 == status) { - int prg_size = ines_prg_rom_chunk * hdr->prg_size_lsb; + int prg_size = nes_prg_rom_page_size * hdr->prg_size_lsb; if (prg_size <= 0) { - INES_ERR("Bad program ROM size: %d / %d", - prg_size, nes_mem_rom_size); + INES_ERR("Bad program ROM size: %#x", prg_size); status = -1; } else { cart->prg_rom = ptr; - cart->prg_rom_size = prg_size; + cart->prg_rom_banks = hdr->prg_size_lsb; } ptr += prg_size; } if (0 == status) { - int chr_size = ines_chr_rom_chunk * hdr->chr_size_lsb; + int chr_size = nes_chr_page_size * hdr->chr_size_lsb; cart->chr_rom = ptr; - cart->chr_rom_size = chr_size; + cart->chr_rom_banks = hdr->chr_size_lsb * 2; ptr += chr_size; int index = (hdr->flags_6 & ines_Mapper_Nibble_Lo) >> 4 | @@ -52,14 +54,10 @@ int nes_cart_init_mem(nes_cart* cart, void* mem, int len) { cart->flags &= ~Cart_Flag_Horizontal; } + // Don't initialize the mapper until all flags are set! status = nes_map_init(cart->mapper, cart); } - if (0 == status) { - cart->ines_mem = mem; - cart->ines_size = len; - } - return status; } diff --git a/src/cart.h b/src/cart.h index bb6c757..868a75f 100644 --- a/src/cart.h +++ b/src/cart.h @@ -12,9 +12,9 @@ typedef enum { typedef struct nes_cart_t { uint8_t* prg_rom; - int prg_rom_size; + int prg_rom_banks; uint8_t* chr_rom; - int chr_rom_size; + int chr_rom_banks; nes_Cart_Flags flags; struct nes_mapper_t* mapper; diff --git a/src/ines.h b/src/ines.h index 9505218..f69c4cf 100644 --- a/src/ines.h +++ b/src/ines.h @@ -12,9 +12,7 @@ #define INES_ERR(...) INES_LOG("E", __VA_ARGS__) -#define ines_trainer_size (512U) -#define ines_prg_rom_chunk (16384U) -#define ines_chr_rom_chunk (8192U) +#define ines_trainer_size (0x200U) #define ines_magic "NES\x1a" diff --git a/src/map/cnrom.c b/src/map/cnrom.c new file mode 100644 index 0000000..5095152 --- /dev/null +++ b/src/map/cnrom.c @@ -0,0 +1,96 @@ +#include + +#include "map.h" + + +typedef struct { + uint8_t* prg_rom; + int prg_rom_banks; + uint8_t* chr_rom; + int chr_rom_banks; + uint8_t mirror; + uint8_t vram[nes_vram_page_size * 2]; + + uint8_t* chr_bank; +} cnrom_mapper; + + +static void cnrom_reset(nes_mapper* nes_map) { + cnrom_mapper* map = (cnrom_mapper*)nes_map->data; + map->chr_bank = 0; +} + +static int cnrom_init(nes_mapper* nes_map, nes_cart* cart) { + cnrom_mapper* map = calloc(1, sizeof(cnrom_mapper)); + nes_map->data = map; + if (NULL != map) { + map->prg_rom = cart->prg_rom; + map->prg_rom_banks = cart->prg_rom_banks; + map->chr_rom = cart->chr_rom; + map->chr_rom_banks = cart->chr_rom_banks; + map->mirror = (cart->flags & Cart_Flag_Horizontal) ? 0 : 1; + cnrom_reset(nes_map); + } + return (NULL == map ? -1 : 0); +} + +static void cnrom_done(nes_mapper* nes_map) { + free(nes_map->data); +} + +static inline uint8_t* cnrom_prg_addr(cnrom_mapper* map, + uint16_t addr) { + addr &= 0x7FFFU; + if (map->prg_rom_banks == 1) { + addr &= 0x3FFF; + } + return &(map->prg_rom[addr]); +} + + +static uint8_t cnrom_read(nes_mapper* map, uint16_t addr) { + uint8_t val = 0; + if (addr >= nes_mem_rom_start) { + val = *(cnrom_prg_addr((cnrom_mapper*)map->data, addr)); + } + return val; +} + +static void cnrom_write(nes_mapper* nes_map, + uint16_t addr, uint8_t val) { + cnrom_mapper* map = (cnrom_mapper*)nes_map->data; + if (addr >= nes_mem_rom_start) { + map->chr_bank = &map->chr_rom[(val % map->chr_rom_banks) * + (nes_chr_page_size * 2)]; + } +} + +static uint8_t* cnrom_chr_addr(nes_mapper* nes_map, + uint16_t addr) { + return &((cnrom_mapper*)nes_map->data)->chr_bank[addr]; +} + +static uint8_t* cnrom_vram_addr(nes_mapper* nes_map, + uint16_t addr) { + cnrom_mapper* map = (cnrom_mapper*)nes_map->data; + int page = addr >> 10U; + page >>= map->mirror; + addr = ((page & 1) << 10U) | (addr & 0x3FFU); + return &map->vram[addr]; +} + +static void cnrom_chr_write(nes_mapper* nes_map, + uint16_t addr, uint8_t val) { + // ROM only. +} + +nes_mapper mapper_cnrom = { + .init = cnrom_init, + .reset = cnrom_reset, + .done = cnrom_done, + .read = cnrom_read, + .write = cnrom_write, + .chr_addr = cnrom_chr_addr, + .vram_addr = cnrom_vram_addr, + .chr_write = cnrom_chr_write, +}; diff --git a/src/map/mmc1.c b/src/map/mmc1.c index 2e71a90..0486300 100644 --- a/src/map/mmc1.c +++ b/src/map/mmc1.c @@ -9,7 +9,7 @@ typedef struct { // TODO: Does this even support CHR ROM? uint8_t* prg_rom; - int prg_rom_size; + int prg_rom_banks; uint8_t reg_shift; uint8_t reg_n_shift; @@ -83,11 +83,10 @@ static void mmc1_update_prg(mmc1_mapper* map) { map->prg_bank[0] = &map->prg_rom[0]; map->prg_bank[1] = &map->prg_rom[bank]; } else if (mode == 3) { - MAP_LOG("PRG: %d + %d", bank, (map->prg_rom_size / - nes_prg_rom_page_size) - 1); + MAP_LOG("PRG: %d + %d", bank, map->prg_rom_banks - 1); bank *= nes_prg_rom_page_size; map->prg_bank[0] = &map->prg_rom[bank]; - map->prg_bank[1] = &map->prg_rom[map->prg_rom_size - + map->prg_bank[1] = &map->prg_rom[(map->prg_rom_banks - 1) * nes_prg_rom_page_size]; } } @@ -108,8 +107,8 @@ static int mmc1_init(nes_mapper* nes_map, nes_cart* cart) { mmc1_mapper* map = calloc(1, sizeof(mmc1_mapper)); nes_map->data = map; if (NULL != map) { - map->prg_rom = cart->prg_rom; - map->prg_rom_size = cart->prg_rom_size; + map->prg_rom = cart->prg_rom; + map->prg_rom_banks = cart->prg_rom_banks; mmc1_reset(nes_map); } return (NULL == map ? -1 : 0); @@ -194,6 +193,12 @@ static uint8_t* mmc1_chr_addr(nes_mapper* nes_map, return &((mmc1_mapper*)nes_map->data)->chr_bank[page][addr]; } +static void mmc1_chr_write(nes_mapper* nes_map, + uint16_t addr, uint8_t val) { + // TODO: Check if this is ROM? + *(mmc1_chr_addr(nes_map, addr)) = val; +} + static uint8_t* mmc1_vram_addr(nes_mapper* nes_map, uint16_t addr) { int page = (addr >> 10) & 3; @@ -211,4 +216,5 @@ nes_mapper mapper_mmc1 = { .write = mmc1_write, .chr_addr = mmc1_chr_addr, .vram_addr = mmc1_vram_addr, + .chr_write = mmc1_chr_write, }; diff --git a/src/map/nrom.c b/src/map/nrom.c index 23937da..7859094 100644 --- a/src/map/nrom.c +++ b/src/map/nrom.c @@ -5,9 +5,9 @@ typedef struct { uint8_t* prg_rom; - int prg_rom_size; + int prg_rom_banks; uint8_t* chr_rom; - int chr_rom_size; + int chr_rom_banks; uint8_t mirror; uint8_t vram[nes_vram_page_size * 2]; uint8_t wram[nes_mem_wram_size]; @@ -20,10 +20,10 @@ static int nrom_init(nes_mapper* nes_map, nes_cart* cart) { nrom_mapper* map = calloc(1, sizeof(nrom_mapper)); nes_map->data = map; if (NULL != map) { - map->prg_rom = cart->prg_rom; - map->prg_rom_size = cart->prg_rom_size; - map->chr_rom = cart->chr_rom; - map->chr_rom_size = cart->chr_rom_size; + map->prg_rom = cart->prg_rom; + map->prg_rom_banks = cart->prg_rom_banks; + map->chr_rom = cart->chr_rom; + map->chr_rom_banks = cart->chr_rom_banks; map->mirror = (cart->flags & Cart_Flag_Horizontal) ? 0 : 1; } return (NULL == map ? -1 : 0); @@ -36,7 +36,7 @@ static void nrom_done(nes_mapper* nes_map) { static inline uint8_t* nrom_prg_addr(nrom_mapper* map, uint16_t addr) { addr &= 0x7FFFU; - if (addr > map->prg_rom_size) { + if (map->prg_rom_banks == 1) { addr &= 0x3FFF; } return &(map->prg_rom[addr]); @@ -66,8 +66,7 @@ static void nrom_write(nes_mapper* map, static uint8_t* nrom_chr_addr(nes_mapper* nes_map, uint16_t addr) { - nrom_mapper* map = (nrom_mapper*)nes_map->data; - return &map->chr_rom[addr % map->chr_rom_size]; + return &(((nrom_mapper*)nes_map->data)->chr_rom[addr]); } static uint8_t* nrom_vram_addr(nes_mapper* nes_map, @@ -79,6 +78,12 @@ static uint8_t* nrom_vram_addr(nes_mapper* nes_map, return &map->vram[addr]; } +static void nrom_chr_write(nes_mapper* map, + uint16_t addr, uint8_t val) { + // ROM only. + printf("CHR ROM Write: $%04x < %02x\n", addr, val); +} + nes_mapper mapper_nrom = { .init = nrom_init, .reset = nrom_reset, @@ -87,4 +92,5 @@ nes_mapper mapper_nrom = { .write = nrom_write, .chr_addr = nrom_chr_addr, .vram_addr = nrom_vram_addr, + .chr_write = nrom_chr_write, }; diff --git a/src/mapper.c b/src/mapper.c index 57f1b4a..2eadbde 100644 --- a/src/mapper.c +++ b/src/mapper.c @@ -3,9 +3,11 @@ extern nes_mapper mapper_nrom; extern nes_mapper mapper_mmc1; +extern nes_mapper mapper_cnrom; nes_mapper* nes_mappers[256] = { [ 0] = &mapper_nrom, [ 1] = &mapper_mmc1, + [ 3] = &mapper_cnrom, }; diff --git a/src/mapper.h b/src/mapper.h index 3b82a52..0f6fd26 100644 --- a/src/mapper.h +++ b/src/mapper.h @@ -4,11 +4,6 @@ #include -#define nes_chr_page_size (0x1000U) -#define nes_vram_page_size (0x0400U) -#define nes_prg_rom_page_size (0x4000U) - - struct nes_cart_t; typedef struct nes_mapper_t { @@ -19,6 +14,7 @@ typedef struct nes_mapper_t { void (*write)(struct nes_mapper_t*, uint16_t addr, uint8_t val); uint8_t* (*chr_addr)(struct nes_mapper_t*, uint16_t addr); uint8_t* (*vram_addr)(struct nes_mapper_t*, uint16_t addr); + void (*chr_write)(struct nes_mapper_t*, uint16_t addr, uint8_t val); void* data; } nes_mapper; @@ -51,9 +47,19 @@ static inline uint8_t* nes_map_chr_addr(nes_mapper* map, return map->chr_addr(map, addr); } +static inline uint8_t nes_chr_read(nes_mapper* map, + uint16_t addr) { + return *(nes_map_chr_addr(map, addr)); +} + +static inline void nes_chr_write(nes_mapper* map, + uint16_t addr, uint8_t val) { + return map->chr_write(map, addr, val); +} + static inline uint8_t* nes_map_vram_addr(nes_mapper* map, uint16_t addr) { - return map->vram_addr(map, addr); + return map->vram_addr(map, addr & 0x1FFFU); } static inline uint8_t nes_vram_read(nes_mapper* map, diff --git a/src/nes.h b/src/nes.h index 5b95dc8..c829ec2 100644 --- a/src/nes.h +++ b/src/nes.h @@ -14,6 +14,10 @@ #define nes_clock_cpu_div (12U) #define nes_clock_ppu_div (4U) +#define nes_chr_page_size (0x1000U) +#define nes_vram_page_size (0x0400U) +#define nes_prg_rom_page_size (0x4000U) + #define nes_mem_ram_start (0x0000U) #define nes_mem_ram_size (0x0800U) #define nes_mem_ppu_start (0x2000U) diff --git a/src/ppu.c b/src/ppu.c index 2a416a4..bf91625 100644 --- a/src/ppu.c +++ b/src/ppu.c @@ -43,8 +43,7 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) { if (ppu->addr < nes_ppu_mem_vram_start) { // printf("PPU: CHR MEM READ %04x > %02x\n", ppu->addr, val); - ppu->data = *(nes_map_chr_addr(ppu->mapper, - ppu->addr)); + ppu->data = nes_chr_read(ppu->mapper, ppu->addr); } else if (ppu->addr < nes_ppu_mem_vram_start + nes_ppu_mem_vram_size) { VRAM_LOG("PPU: VRAM READ %04x > %02x\n", ppu->addr, val); @@ -53,9 +52,11 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) { ppu->addr - nes_ppu_mem_vram_start ); } else if (ppu->addr < nes_ppu_mem_pal_start) { -// printf("PPU: BLANK READ %04x > %02x\n", ppu->addr, val); + printf("PPU: BLANK READ %04x > %02x\n", ppu->addr, val); +/* ppu->data = *(nes_map_chr_addr(ppu->mapper, ppu->addr)); +*/ } } @@ -162,7 +163,7 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) { } else { // printf("PPU: CHR MEM WRITE %04x > %02x\n", ppu->addr, val); - *(nes_map_chr_addr(ppu->mapper, ppu->addr)) = val; + nes_chr_write(ppu->mapper, ppu->addr, val); } ppu->addr += (ppu->control & ppu_Control_VRAM_Inc) ? diff --git a/src/sdl_render.c b/src/sdl_render.c index 651f838..43c7f36 100644 --- a/src/sdl_render.c +++ b/src/sdl_render.c @@ -405,7 +405,7 @@ static int eval_sprite_line(const nes_ppu* ppu, int line, } static void update_sprite_hit(nes_ppu* ppu, int block_line, - const void* back_line, + const void* back_pixels, int back_pitch) { const oam_sprite* sprite = (oam_sprite*)ppu->oam; int x_fine = ppu->scroll_x % 8; @@ -422,11 +422,11 @@ static void update_sprite_hit(nes_ppu* ppu, int block_line, if (start_y < 0) start_y = 0; if (end_y > 8) end_y = 8; int hit = -1; - const uint8_t* back = (uint8_t*)back_line + x_fine; + const uint8_t* back = (uint8_t*)back_pixels + x_fine; back += (render_line + start_y) * back_pitch; for (int y = start_y; y < end_y; ++y) { hit = eval_sprite_line( - ppu, render_line + y, + ppu, render_line + y - y_fine, sprite, chr, back ); if (hit >= 0) {