瀏覽代碼

Add CNROM mapper; Fix up CHR ROM writes; Fix collision offset

master
Nathaniel Walizer 1 年之前
父節點
當前提交
be47688d35
共有 12 個文件被更改,包括 162 次插入45 次删除
  1. +1
    -1
      Makefile
  2. +9
    -11
      src/cart.c
  3. +2
    -2
      src/cart.h
  4. +1
    -3
      src/ines.h
  5. +96
    -0
      src/map/cnrom.c
  6. +12
    -6
      src/map/mmc1.c
  7. +15
    -9
      src/map/nrom.c
  8. +2
    -0
      src/mapper.c
  9. +12
    -6
      src/mapper.h
  10. +4
    -0
      src/nes.h
  11. +5
    -4
      src/ppu.c
  12. +3
    -3
      src/sdl_render.c

+ 1
- 1
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



+ 9
- 11
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;
}



+ 2
- 2
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;



+ 1
- 3
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"


+ 96
- 0
src/map/cnrom.c 查看文件

@@ -0,0 +1,96 @@
#include <stdlib.h>

#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,
};

+ 12
- 6
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,
};

+ 15
- 9
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,
};

+ 2
- 0
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,
};

+ 12
- 6
src/mapper.h 查看文件

@@ -4,11 +4,6 @@
#include <stdint.h>


#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,


+ 4
- 0
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)


+ 5
- 4
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) ?


+ 3
- 3
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) {


Loading…
取消
儲存