| @@ -15,8 +15,8 @@ TARGET_1 = nese | |||||
| LDLIBS_1 = -lSDL2 | LDLIBS_1 = -lSDL2 | ||||
| SRC_SRCS_1 = nese.c ines.c | SRC_SRCS_1 = nese.c ines.c | ||||
| SRC_SRCS_1 += nes.c ppu.c cart.c input.c | |||||
| SRC_SRCS_1 += vram.c mapper.c | |||||
| SRC_SRCS_1 += nes.c ppu.c input.c | |||||
| SRC_SRCS_1 += cart.c mapper.c | |||||
| SRC_SRCS_1 += sdl_render.c sdl_input.c | SRC_SRCS_1 += sdl_render.c sdl_input.c | ||||
| MAPDIR = src/map | MAPDIR = src/map | ||||
| @@ -54,10 +54,6 @@ int nes_cart_init_mem(nes_cart* cart, void* mem, int len) { | |||||
| } | } | ||||
| } | } | ||||
| if (0 == status) { | |||||
| status = nes_map_init(cart->mapper, cart); | |||||
| } | |||||
| if (0 == status) { | if (0 == status) { | ||||
| if (hdr->flags_6 & ines_Flag_Horizontal) { | if (hdr->flags_6 & ines_Flag_Horizontal) { | ||||
| cart->flags |= Cart_Flag_Horizontal; | cart->flags |= Cart_Flag_Horizontal; | ||||
| @@ -65,6 +61,10 @@ int nes_cart_init_mem(nes_cart* cart, void* mem, int len) { | |||||
| cart->flags &= ~Cart_Flag_Horizontal; | cart->flags &= ~Cart_Flag_Horizontal; | ||||
| } | } | ||||
| status = nes_map_init(cart->mapper, cart); | |||||
| } | |||||
| if (0 == status) { | |||||
| cart->ines_mem = mem; | cart->ines_mem = mem; | ||||
| cart->ines_size = len; | cart->ines_size = len; | ||||
| } | } | ||||
| @@ -1,8 +1,72 @@ | |||||
| #include "map.h" | #include "map.h" | ||||
| // Stub | |||||
| typedef struct { | |||||
| uint8_t* prg_rom; | |||||
| int prg_rom_size; | |||||
| uint8_t* prg_ram; | |||||
| int prg_ram_size; | |||||
| uint8_t* chr_rom; | |||||
| int chr_rom_size; | |||||
| nes_mapper mapper_mmc1 = { | |||||
| uint8_t reg_shift; | |||||
| uint8_t reg_control; | |||||
| uint8_t reg_chr_0; | |||||
| uint8_t reg_chr_1; | |||||
| uint8_t reg_prg; | |||||
| } mmc1_mapper; | |||||
| /* | |||||
| int mmc1_init(nes_mapper* nes_map, nes_cart* cart) { | |||||
| nrom_mapper* map = malloc(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_ram = cart->wram; | |||||
| map->prg_ram_size = nes_mem_wram_size; | |||||
| map->shift_reg = 0; | |||||
| } | |||||
| return (NULL == map ? -1 : 0); | |||||
| } | |||||
| void nrom_done(nes_mapper* nes_map) { | |||||
| free(nes_map->data); | |||||
| } | |||||
| static inline uint8_t* nrom_prg_addr(nrom_mapper* map, | |||||
| uint16_t addr) { | |||||
| if (addr > map->prg_rom_size) { | |||||
| addr &= 0x3FFF; | |||||
| } | |||||
| return &(map->prg_rom[addr]); | |||||
| } | |||||
| uint8_t nrom_prg_read(nes_mapper* map, uint16_t addr) { | |||||
| return *(nrom_prg_addr((nrom_mapper*)map->data, addr)); | |||||
| } | |||||
| void nrom_prg_write(nes_mapper* map, uint16_t addr, uint8_t val) { | |||||
| // No ROM writes. | |||||
| } | |||||
| 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]; | |||||
| } | |||||
| */ | |||||
| nes_mapper mapper_mmc1 = { | |||||
| /* | |||||
| .init = mmc1_init, | |||||
| .done = mmc1_done, | |||||
| .prg_read = mmc1_prg_read, | |||||
| .prg_write = mmc1_prg_write, | |||||
| .chr_addr = mmc1_chr_addr, | |||||
| .vram_addr = mmc1_chr_addr, | |||||
| */ | |||||
| }; | }; | ||||
| @@ -10,12 +10,13 @@ typedef struct { | |||||
| int prg_ram_size; | int prg_ram_size; | ||||
| uint8_t* chr_rom; | uint8_t* chr_rom; | ||||
| int chr_rom_size; | int chr_rom_size; | ||||
| uint8_t mirror; | |||||
| uint8_t vram[nes_vram_page_size * 2]; | |||||
| } nrom_mapper; | } nrom_mapper; | ||||
| // TODO: PRG_ROM region mirroring | |||||
| int nrom_init(nes_mapper* nes_map, nes_cart* cart) { | int nrom_init(nes_mapper* nes_map, nes_cart* cart) { | ||||
| nrom_mapper* map = malloc(sizeof(nrom_mapper)); | |||||
| nrom_mapper* map = calloc(1, sizeof(nrom_mapper)); | |||||
| nes_map->data = map; | nes_map->data = map; | ||||
| if (NULL != map) { | if (NULL != map) { | ||||
| map->prg_rom = cart->prg_rom; | map->prg_rom = cart->prg_rom; | ||||
| @@ -24,6 +25,7 @@ int nrom_init(nes_mapper* nes_map, nes_cart* cart) { | |||||
| map->chr_rom_size = cart->chr_rom_size; | map->chr_rom_size = cart->chr_rom_size; | ||||
| map->prg_ram = cart->wram; | map->prg_ram = cart->wram; | ||||
| map->prg_ram_size = nes_mem_wram_size; | map->prg_ram_size = nes_mem_wram_size; | ||||
| map->mirror = (cart->flags & Cart_Flag_Horizontal) ? 0 : 1; | |||||
| } | } | ||||
| return (NULL == map ? -1 : 0); | return (NULL == map ? -1 : 0); | ||||
| } | } | ||||
| @@ -53,10 +55,19 @@ uint8_t* nrom_chr_addr(nes_mapper* nes_map, uint16_t addr) { | |||||
| return &map->chr_rom[addr % map->chr_rom_size]; | return &map->chr_rom[addr % map->chr_rom_size]; | ||||
| } | } | ||||
| uint8_t* nrom_vram_addr(nes_mapper* nes_map, uint16_t addr) { | |||||
| nrom_mapper* map = (nrom_mapper*)nes_map->data; | |||||
| int page = addr >> 10U; | |||||
| page >>= map->mirror; | |||||
| addr = ((page & 1) << 10U) | (addr & 0x3FFU); | |||||
| return &map->vram[addr]; | |||||
| } | |||||
| nes_mapper mapper_nrom = { | nes_mapper mapper_nrom = { | ||||
| .init = nrom_init, | .init = nrom_init, | ||||
| .done = nrom_done, | .done = nrom_done, | ||||
| .prg_read = nrom_prg_read, | .prg_read = nrom_prg_read, | ||||
| .prg_write = nrom_prg_write, | .prg_write = nrom_prg_write, | ||||
| .chr_addr = nrom_chr_addr, | .chr_addr = nrom_chr_addr, | ||||
| .vram_addr = nrom_vram_addr, | |||||
| }; | }; | ||||
| @@ -4,6 +4,10 @@ | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #define nes_chr_page_size (0x1000U) | |||||
| #define nes_vram_page_size (0x0400U) | |||||
| struct nes_cart_t; | struct nes_cart_t; | ||||
| typedef struct nes_mapper_t { | typedef struct nes_mapper_t { | ||||
| @@ -12,6 +16,7 @@ typedef struct nes_mapper_t { | |||||
| uint8_t (*prg_read)(struct nes_mapper_t*, uint16_t addr); | uint8_t (*prg_read)(struct nes_mapper_t*, uint16_t addr); | ||||
| void (*prg_write)(struct nes_mapper_t*, uint16_t addr, uint8_t val); | void (*prg_write)(struct nes_mapper_t*, uint16_t addr, uint8_t val); | ||||
| uint8_t* (*chr_addr)(struct nes_mapper_t*, uint16_t addr); | uint8_t* (*chr_addr)(struct nes_mapper_t*, uint16_t addr); | ||||
| uint8_t* (*vram_addr)(struct nes_mapper_t*, uint16_t addr); | |||||
| void* data; | void* data; | ||||
| } nes_mapper; | } nes_mapper; | ||||
| @@ -40,6 +45,20 @@ static inline uint8_t* nes_map_chr_addr(nes_mapper* map, | |||||
| return map->chr_addr(map, addr); | return map->chr_addr(map, addr); | ||||
| } | } | ||||
| static inline uint8_t* nes_map_vram_addr(nes_mapper* map, | |||||
| uint16_t addr) { | |||||
| return map->vram_addr(map, addr); | |||||
| } | |||||
| static inline uint8_t nes_vram_read(nes_mapper* map, | |||||
| uint16_t addr) { | |||||
| return *(nes_map_vram_addr(map, addr)); | |||||
| } | |||||
| static inline void nes_vram_write(nes_mapper* map, | |||||
| uint16_t addr, uint8_t val) { | |||||
| *(nes_map_vram_addr(map, addr)) = val; | |||||
| } | |||||
| extern nes_mapper* nes_mappers[]; | extern nes_mapper* nes_mappers[]; | ||||
| @@ -49,7 +49,7 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) { | |||||
| nes_ppu_mem_vram_size) { | nes_ppu_mem_vram_size) { | ||||
| VRAM_LOG("PPU: VRAM READ %04x > %02x\n", ppu->addr, val); | VRAM_LOG("PPU: VRAM READ %04x > %02x\n", ppu->addr, val); | ||||
| ppu->data = nes_vram_read( | ppu->data = nes_vram_read( | ||||
| ppu->vram_map, | |||||
| ppu->mapper, | |||||
| ppu->addr - nes_ppu_mem_vram_start | ppu->addr - nes_ppu_mem_vram_start | ||||
| ); | ); | ||||
| } else if (ppu->addr < nes_ppu_mem_pal_start) { | } else if (ppu->addr < nes_ppu_mem_pal_start) { | ||||
| @@ -158,7 +158,7 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) { | |||||
| } | } | ||||
| #endif // DEBUG_VRAM | #endif // DEBUG_VRAM | ||||
| // printf("PPU: VRAM %04x < %02x\n", vram_addr, val); | // printf("PPU: VRAM %04x < %02x\n", vram_addr, val); | ||||
| nes_vram_write(ppu->vram_map, vram_addr, val); | |||||
| nes_vram_write(ppu->mapper, vram_addr, val); | |||||
| } | } | ||||
| ppu->addr += (ppu->control & ppu_Control_VRAM_Inc) ? | ppu->addr += (ppu->control & ppu_Control_VRAM_Inc) ? | ||||
| @@ -183,11 +183,8 @@ int nes_ppu_init(nes_ppu* ppu, const nes_cart* cart) { | |||||
| ppu->status = 0; | ppu->status = 0; | ||||
| ppu->oam_addr = 0; | ppu->oam_addr = 0; | ||||
| ppu->addr = 0; | ppu->addr = 0; | ||||
| ppu->vram_map = ( (cart->flags & Cart_Flag_Horizontal) ? | |||||
| &vram_horizontal : | |||||
| &vram_vertical ); | |||||
| nes_ppu_reset(ppu); | nes_ppu_reset(ppu); | ||||
| return nes_vram_init(ppu->vram_map); | |||||
| return 0; | |||||
| } | } | ||||
| int nes_ppu_run(nes_ppu* ppu, int cycles) { | int nes_ppu_run(nes_ppu* ppu, int cycles) { | ||||
| @@ -3,8 +3,6 @@ | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include "vram.h" | |||||
| struct nes_mapper_t; | struct nes_mapper_t; | ||||
| struct nes_cart_t; | struct nes_cart_t; | ||||
| @@ -110,7 +108,6 @@ typedef struct { | |||||
| struct nes_mapper_t* mapper; | struct nes_mapper_t* mapper; | ||||
| uint8_t oam[nes_ppu_oam_size]; | uint8_t oam[nes_ppu_oam_size]; | ||||
| uint8_t palette[nes_ppu_mem_pal_size]; | uint8_t palette[nes_ppu_mem_pal_size]; | ||||
| nes_vram_map* vram_map; | |||||
| // Timing | // Timing | ||||
| int frame; | int frame; | ||||
| @@ -194,8 +194,8 @@ static void render_background_area(const nes_ppu* ppu, int page, | |||||
| void* buffer, int pitch, | void* buffer, int pitch, | ||||
| int xs, int ys, int w, int h) { | int xs, int ys, int w, int h) { | ||||
| int bank = (ppu->control & ppu_Control_Back_Bank) ? 0x100 : 0; | int bank = (ppu->control & ppu_Control_Back_Bank) ? 0x100 : 0; | ||||
| const uint8_t* index_line = nes_vram_page(ppu->vram_map, | |||||
| page); | |||||
| const uint8_t* index_line = nes_map_vram_addr(ppu->mapper, | |||||
| page << 10); | |||||
| const uint8_t* attrs = index_line + 960U; | const uint8_t* attrs = index_line + 960U; | ||||
| index_line += xs + (ys * nes_ppu_blocks_w); | index_line += xs + (ys * nes_ppu_blocks_w); | ||||
| uint8_t* dst_line = (uint8_t*)buffer; | uint8_t* dst_line = (uint8_t*)buffer; | ||||
| @@ -1,92 +0,0 @@ | |||||
| #include <stdlib.h> | |||||
| #include "vram.h" | |||||
| typedef enum { | |||||
| Mirror_Method_Vertical, | |||||
| Mirror_Method_Horizontal, | |||||
| } vram_Mirror_Method; | |||||
| typedef struct { | |||||
| vram_Mirror_Method method; | |||||
| uint8_t vram[nes_vram_page_size * 2]; | |||||
| } vram_mirror; | |||||
| static vram_mirror* vram_mirror_create(vram_Mirror_Method method) { | |||||
| vram_mirror* mirror = calloc(1, sizeof(vram_mirror)); | |||||
| if (NULL != mirror) mirror->method = method; | |||||
| return mirror; | |||||
| } | |||||
| static void vram_mirror_destroy(vram_mirror* mirror) { | |||||
| free(mirror); | |||||
| } | |||||
| static inline uint8_t* vram_mirror_page(vram_mirror* mirror, | |||||
| int page) { | |||||
| if (mirror->method == Mirror_Method_Vertical) { | |||||
| page >>= 1; | |||||
| } | |||||
| return &mirror->vram[(page & 1) ? nes_vram_page_size : 0]; | |||||
| } | |||||
| static inline uint8_t* vram_mirror_map(vram_mirror* mirror, | |||||
| uint16_t addr) { | |||||
| uint8_t* page = vram_mirror_page(mirror, (addr >> 10)); | |||||
| return &page[addr & nes_vram_addr_mask]; | |||||
| } | |||||
| static int vram_map_mirror_init_method(nes_vram_map* map, | |||||
| vram_Mirror_Method method) { | |||||
| map->data = vram_mirror_create(method); | |||||
| return (NULL == map->data ? -1 : 0); | |||||
| } | |||||
| static int vram_map_mirror_init_horz(nes_vram_map* map) { | |||||
| return vram_map_mirror_init_method( | |||||
| map, Mirror_Method_Horizontal | |||||
| ); | |||||
| } | |||||
| static int vram_map_mirror_init_vert(nes_vram_map* map) { | |||||
| return vram_map_mirror_init_method( | |||||
| map, Mirror_Method_Vertical | |||||
| ); | |||||
| } | |||||
| static void vram_map_mirror_done(nes_vram_map* map) { | |||||
| vram_mirror_destroy((vram_mirror*)map->data); | |||||
| } | |||||
| static uint8_t vram_map_mirror_read(nes_vram_map* map, | |||||
| uint16_t addr) { | |||||
| return *(vram_mirror_map((vram_mirror*)map->data, addr)); | |||||
| } | |||||
| static void vram_map_mirror_write(nes_vram_map* map, | |||||
| uint16_t addr, | |||||
| uint8_t val) { | |||||
| *(vram_mirror_map((vram_mirror*)map->data, addr)) = val; | |||||
| } | |||||
| static uint8_t* vram_map_mirror_page(nes_vram_map* map, int page) { | |||||
| return vram_mirror_page((vram_mirror*)map->data, page); | |||||
| } | |||||
| nes_vram_map vram_horizontal = { | |||||
| .init = vram_map_mirror_init_horz, | |||||
| .done = vram_map_mirror_done, | |||||
| .read = vram_map_mirror_read, | |||||
| .write = vram_map_mirror_write, | |||||
| .page = vram_map_mirror_page, | |||||
| }; | |||||
| nes_vram_map vram_vertical = { | |||||
| .init = vram_map_mirror_init_vert, | |||||
| .done = vram_map_mirror_done, | |||||
| .read = vram_map_mirror_read, | |||||
| .write = vram_map_mirror_write, | |||||
| .page = vram_map_mirror_page, | |||||
| }; | |||||
| @@ -1,48 +0,0 @@ | |||||
| #ifndef NES_VRAM_ | |||||
| #define NES_VRAM_ | |||||
| #include <stdint.h> | |||||
| #define nes_vram_page_size (0x400U) | |||||
| #define nes_vram_page_mask (0xC00U) | |||||
| #define nes_vram_addr_mask (0x3FFU) | |||||
| typedef struct nes_vram_map_t { | |||||
| int (*init)(struct nes_vram_map_t*); | |||||
| void (*done)(struct nes_vram_map_t*); | |||||
| uint8_t* (*page)(struct nes_vram_map_t*, int page); | |||||
| uint8_t (*read)(struct nes_vram_map_t*, uint16_t addr); | |||||
| void (*write)(struct nes_vram_map_t*, uint16_t addr, uint8_t val); | |||||
| void* data; | |||||
| } nes_vram_map; | |||||
| static inline int nes_vram_init(nes_vram_map* map) { | |||||
| return map->init(map); | |||||
| } | |||||
| static inline void nes_vram_done(nes_vram_map* map) { | |||||
| map->done(map); | |||||
| } | |||||
| static inline uint8_t* nes_vram_page(nes_vram_map* map, int page) { | |||||
| return map->page(map, page); | |||||
| } | |||||
| static inline uint8_t nes_vram_read(nes_vram_map* map, | |||||
| uint16_t addr) { | |||||
| return map->read(map, addr); | |||||
| } | |||||
| static inline void nes_vram_write(nes_vram_map* map, | |||||
| uint16_t addr, uint8_t val) { | |||||
| map->write(map, addr, val); | |||||
| } | |||||
| extern nes_vram_map vram_horizontal; | |||||
| extern nes_vram_map vram_vertical; | |||||
| #endif // NES_VRAM_ | |||||