This required a significant refactor to move the mapper data out of the static struct, but in the end is a saner architecture.master
| @@ -63,7 +63,8 @@ int nes_cart_init_mem(nes_cart* cart, void* mem, int len) { | |||
| } | |||
| // Don't initialize the mapper until all flags are set! | |||
| status = nes_map_init(cart->mapper, cart); | |||
| cart->map_data = nes_map_init(cart->mapper, cart); | |||
| status = (NULL == cart->map_data ? -1 : 0); | |||
| } | |||
| return status; | |||
| @@ -71,8 +72,9 @@ int nes_cart_init_mem(nes_cart* cart, void* mem, int len) { | |||
| void nes_cart_done(nes_cart* cart) { | |||
| if (NULL != cart->mapper) { | |||
| nes_map_done(cart->mapper); | |||
| nes_map_done(cart->mapper, cart->map_data); | |||
| cart->mapper = NULL; | |||
| cart->map_data = NULL; | |||
| } | |||
| if (NULL != cart->ines_mem) { | |||
| unmap_file(cart->ines_mem, cart->ines_size); | |||
| @@ -17,7 +17,9 @@ typedef struct nes_cart_t { | |||
| uint8_t* chr_rom; | |||
| int chr_rom_banks; | |||
| nes_Cart_Flags flags; | |||
| struct nes_mapper_t* mapper; | |||
| void* map_data; | |||
| void* ines_mem; | |||
| int ines_size; | |||
| @@ -24,27 +24,26 @@ static void cnrom_set_bank(cnrom_mapper* map, uint8_t bank) { | |||
| ]; | |||
| } | |||
| static void cnrom_reset(nes_mapper* nes_map) { | |||
| cnrom_mapper* map = (cnrom_mapper*)nes_map->data; | |||
| static void cnrom_reset(void* _map) { | |||
| cnrom_mapper* map = (cnrom_mapper*)_map; | |||
| cnrom_set_bank(map, 0); | |||
| } | |||
| static int cnrom_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| static void* 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); | |||
| cnrom_reset(map); | |||
| } | |||
| return (NULL == map ? -1 : 0); | |||
| return map; | |||
| } | |||
| static void cnrom_done(nes_mapper* nes_map) { | |||
| free(nes_map->data); | |||
| static void cnrom_done(void* _map) { | |||
| free(_map); | |||
| } | |||
| static inline uint8_t* cnrom_prg_addr(cnrom_mapper* map, | |||
| @@ -57,37 +56,34 @@ static inline uint8_t* cnrom_prg_addr(cnrom_mapper* map, | |||
| } | |||
| static uint8_t cnrom_read(nes_mapper* map, uint16_t addr) { | |||
| static uint8_t cnrom_read(void* _map, uint16_t addr) { | |||
| uint8_t val = 0; | |||
| if (addr >= nes_mem_rom_start) { | |||
| val = *(cnrom_prg_addr((cnrom_mapper*)map->data, addr)); | |||
| val = *(cnrom_prg_addr((cnrom_mapper*)_map, 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; | |||
| static void cnrom_write(void* _map, uint16_t addr, uint8_t val) { | |||
| cnrom_mapper* map = (cnrom_mapper*)_map; | |||
| if (addr >= nes_mem_rom_start) { | |||
| cnrom_set_bank(map, val); | |||
| } | |||
| } | |||
| 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_chr_addr(void* _map, uint16_t addr) { | |||
| return &((cnrom_mapper*)_map)->chr_bank[addr]; | |||
| } | |||
| static uint8_t* cnrom_vram_addr(nes_mapper* nes_map, | |||
| uint16_t addr) { | |||
| cnrom_mapper* map = (cnrom_mapper*)nes_map->data; | |||
| static uint8_t* cnrom_vram_addr(void* _map, uint16_t addr) { | |||
| cnrom_mapper* map = (cnrom_mapper*)_map; | |||
| 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, | |||
| static void cnrom_chr_write(void* _map, | |||
| uint16_t addr, uint8_t val) { | |||
| // ROM only. | |||
| } | |||
| @@ -95,13 +91,13 @@ static void cnrom_chr_write(nes_mapper* nes_map, | |||
| /* Save State */ | |||
| int cnrom_state_size(const nes_mapper* nes_map) { | |||
| cnrom_mapper* map = (cnrom_mapper*)nes_map->data; | |||
| static int cnrom_state_size(const void* _map) { | |||
| cnrom_mapper* map = (cnrom_mapper*)_map; | |||
| return (sizeof(map->bank) + sizeof(map->vram)); | |||
| } | |||
| int cnrom_state_read(nes_mapper* nes_map, const void* data) { | |||
| cnrom_mapper* map = (cnrom_mapper*)nes_map->data; | |||
| static int cnrom_state_read(void* _map, const void* data) { | |||
| cnrom_mapper* map = (cnrom_mapper*)_map; | |||
| const void* ptr = data; | |||
| memcpy(&map->bank, ptr, sizeof(map->bank)); | |||
| @@ -115,8 +111,8 @@ int cnrom_state_read(nes_mapper* nes_map, const void* data) { | |||
| return (ptr - data); | |||
| } | |||
| int cnrom_state_write(const nes_mapper* nes_map, void* data) { | |||
| cnrom_mapper* map = (cnrom_mapper*)nes_map->data; | |||
| static int cnrom_state_write(const void* _map, void* data) { | |||
| cnrom_mapper* map = (cnrom_mapper*)_map; | |||
| void* ptr = data; | |||
| memcpy(ptr, &map->bank, sizeof(map->bank)); | |||
| @@ -90,8 +90,8 @@ static void mmc1_update_prg(mmc1_mapper* map) { | |||
| map->prg_bank[1] = &map->prg_rom[bank_1 * nes_prg_rom_page_size]; | |||
| } | |||
| static void mmc1_reset(nes_mapper* nes_map) { | |||
| mmc1_mapper* map = (mmc1_mapper*)nes_map->data; | |||
| static void mmc1_reset(void* data) { | |||
| mmc1_mapper* map = (mmc1_mapper*)data; | |||
| map->reg_shift = 0b10000; | |||
| map->reg_control = 0b01100; | |||
| map->reg_chr_0 = 0; | |||
| @@ -102,9 +102,8 @@ static void mmc1_reset(nes_mapper* nes_map) { | |||
| mmc1_update_vram(map); | |||
| } | |||
| static int mmc1_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| static void* 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_banks = cart->prg_rom_banks; | |||
| @@ -121,15 +120,15 @@ static int mmc1_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| map->battery = !!(cart->flags & Cart_Flag_Battery); | |||
| mmc1_reset(nes_map); | |||
| mmc1_reset(map); | |||
| } | |||
| return (NULL == map ? -1 : 0); | |||
| return map; | |||
| } | |||
| static void mmc1_done(nes_mapper* nes_map) { | |||
| if (NULL != nes_map->data) { | |||
| free(((mmc1_mapper*)nes_map->data)->chr_ram); | |||
| free(nes_map->data); | |||
| static void mmc1_done(void* data) { | |||
| if (NULL != data) { | |||
| free(((mmc1_mapper*)data)->chr_ram); | |||
| free(data); | |||
| } | |||
| } | |||
| @@ -145,19 +144,18 @@ static inline uint8_t* mmc1_wram_addr(mmc1_mapper* map, | |||
| return &(map->wram[addr & 0x1FFFU]); | |||
| } | |||
| static uint8_t mmc1_read(nes_mapper* map, uint16_t addr) { | |||
| static uint8_t mmc1_read(void* data, uint16_t addr) { | |||
| uint8_t val = 0; | |||
| if (addr >= nes_mem_rom_start) { | |||
| val = *(mmc1_prg_addr((mmc1_mapper*)map->data, addr)); | |||
| val = *(mmc1_prg_addr((mmc1_mapper*)data, addr)); | |||
| } else if (addr >= nes_mem_wram_start) { | |||
| val = *(mmc1_wram_addr((mmc1_mapper*)map->data, addr)); | |||
| val = *(mmc1_wram_addr((mmc1_mapper*)data, addr)); | |||
| } | |||
| return val; | |||
| } | |||
| static void mmc1_write(nes_mapper* nes_map, | |||
| uint16_t addr, uint8_t val) { | |||
| mmc1_mapper* map = (mmc1_mapper*)nes_map->data; | |||
| static void mmc1_write(void* data, uint16_t addr, uint8_t val) { | |||
| mmc1_mapper* map = (mmc1_mapper*)data; | |||
| if (addr >= nes_mem_rom_start) { | |||
| MAP_LOG("Write $%04x < %02x", addr, val); | |||
| if (val & 0x80U) { | |||
| @@ -201,53 +199,51 @@ static void mmc1_write(nes_mapper* nes_map, | |||
| } | |||
| } | |||
| static uint8_t* mmc1_chr_addr(nes_mapper* nes_map, | |||
| uint16_t addr) { | |||
| static uint8_t* mmc1_chr_addr(void* data, uint16_t addr) { | |||
| int page = (addr >> 12) & 1; | |||
| addr &= 0xFFFU; | |||
| return &((mmc1_mapper*)nes_map->data)->chr_bank[page][addr]; | |||
| return &((mmc1_mapper*)data)->chr_bank[page][addr]; | |||
| } | |||
| static void mmc1_chr_write(nes_mapper* nes_map, | |||
| static void mmc1_chr_write(void* data, | |||
| uint16_t addr, uint8_t val) { | |||
| if (NULL != ((mmc1_mapper*)nes_map->data)->chr_ram) { | |||
| *(mmc1_chr_addr(nes_map, addr)) = val; | |||
| if (NULL != ((mmc1_mapper*)data)->chr_ram) { | |||
| *(mmc1_chr_addr(data, addr)) = val; | |||
| } | |||
| } | |||
| static uint8_t* mmc1_vram_addr(nes_mapper* nes_map, | |||
| uint16_t addr) { | |||
| static uint8_t* mmc1_vram_addr(void* data, uint16_t addr) { | |||
| int page = (addr >> 10) & 3; | |||
| int loc = addr & 0x3FFU; | |||
| // MAP_LOG("VRAM $%04x -> %p", addr, ((mmc1_mapper*)nes_map->data)->vram_bank[page]); | |||
| return &((mmc1_mapper*)nes_map->data)->vram_bank[page][loc]; | |||
| return &((mmc1_mapper*)data)->vram_bank[page][loc]; | |||
| } | |||
| static void* mmc1_sram(nes_mapper* nes_map) { | |||
| mmc1_mapper* map = (mmc1_mapper*)nes_map->data; | |||
| static void* mmc1_sram(void* data) { | |||
| mmc1_mapper* map = (mmc1_mapper*)data; | |||
| return (map->battery ? map->wram : NULL); | |||
| } | |||
| static int mmc1_sram_size(nes_mapper* nes_map) { | |||
| mmc1_mapper* map = (mmc1_mapper*)nes_map->data; | |||
| static int mmc1_sram_size(void* data) { | |||
| mmc1_mapper* map = (mmc1_mapper*)data; | |||
| return (map->battery ? sizeof(map->wram) : 0); | |||
| } | |||
| /* Save State */ | |||
| int mmc1_state_size(const nes_mapper* nes_map) { | |||
| mmc1_mapper* map = (mmc1_mapper*)nes_map->data; | |||
| static int mmc1_state_size(const void* _map) { | |||
| mmc1_mapper* map = (mmc1_mapper*)_map; | |||
| return ( (void*)map + | |||
| sizeof(*map) - | |||
| (void*)&(map->reg_shift)); | |||
| } | |||
| int mmc1_state_read(nes_mapper* nes_map, const void* data) { | |||
| mmc1_mapper* map = (mmc1_mapper*)nes_map->data; | |||
| static int mmc1_state_read(void* _map, const void* data) { | |||
| mmc1_mapper* map = (mmc1_mapper*)_map; | |||
| int size = mmc1_state_size(nes_map); | |||
| int size = mmc1_state_size(_map); | |||
| memcpy(&(map->reg_shift), data, size); | |||
| mmc1_update_prg(map); | |||
| @@ -257,9 +253,9 @@ int mmc1_state_read(nes_mapper* nes_map, const void* data) { | |||
| return size; | |||
| } | |||
| int mmc1_state_write(const nes_mapper* nes_map, void* data) { | |||
| mmc1_mapper* map = (mmc1_mapper*)nes_map->data; | |||
| int size = mmc1_state_size(nes_map); | |||
| static int mmc1_state_write(const void* _map, void* data) { | |||
| mmc1_mapper* map = (mmc1_mapper*)_map; | |||
| int size = mmc1_state_size(_map); | |||
| memcpy(data, &(map->reg_shift), size); | |||
| return size; | |||
| } | |||
| @@ -267,6 +263,7 @@ int mmc1_state_write(const nes_mapper* nes_map, void* data) { | |||
| nes_mapper mapper_mmc1 = { | |||
| .name = "MMC1", | |||
| .init = mmc1_init, | |||
| .reset = mmc1_reset, | |||
| .done = mmc1_done, | |||
| @@ -3,6 +3,7 @@ | |||
| #include "map.h" | |||
| typedef enum { | |||
| mmc3_Flag_Horizontal = 0b00000001, | |||
| mmc3_Flag_IRQ_Enabled = 0b00000010, | |||
| @@ -25,6 +26,8 @@ typedef struct { | |||
| uint8_t* chr_rom; | |||
| int chr_rom_banks; // 4 KB / 1 KB = 4 | |||
| nes_mapper* mapper; | |||
| uint8_t* prg_bank[4]; // 8 KB | |||
| uint8_t* chr_bank[8]; // 1 KB | |||
| uint8_t* vram_bank[4]; | |||
| @@ -146,8 +149,8 @@ static inline void mmc3_update_vram(mmc3_mapper* map) { | |||
| } | |||
| } | |||
| static void mmc3_reset(nes_mapper* nes_map) { | |||
| mmc3_mapper* map = (mmc3_mapper*)nes_map->data; | |||
| static void mmc3_reset(void* data) { | |||
| mmc3_mapper* map = (mmc3_mapper*)data; | |||
| map->irq_count = 0; | |||
| map->irq_latch = 0; | |||
| mmc3_update_rom_mode(map, 0); | |||
| @@ -155,10 +158,10 @@ static void mmc3_reset(nes_mapper* nes_map) { | |||
| mmc3_update_vram(map); | |||
| } | |||
| static int mmc3_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| static void* mmc3_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| mmc3_mapper* map = calloc(1, sizeof(mmc3_mapper)); | |||
| nes_map->data = map; | |||
| if (NULL != map) { | |||
| map->mapper = nes_map; | |||
| map->flags = (cart->flags & Cart_Flag_Horizontal) ? | |||
| mmc3_Flag_Horizontal : 0; | |||
| map->prg_rom = cart->prg_rom; | |||
| @@ -179,18 +182,18 @@ static int mmc3_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| map->bank_select = mmc3_Bank_Select_PRG | | |||
| mmc3_Bank_Select_CHR; | |||
| mmc3_reset(nes_map); | |||
| mmc3_reset(map); | |||
| } | |||
| return (NULL == map ? -1 : 0); | |||
| return map; | |||
| } | |||
| static void mmc3_done(nes_mapper* nes_map) { | |||
| mmc3_mapper* map = (mmc3_mapper*)nes_map->data; | |||
| static void mmc3_done(void* data) { | |||
| mmc3_mapper* map = (mmc3_mapper*)data; | |||
| if (NULL != map) { | |||
| if (map->flags & mmc3_Flag_CHR_RAM) { | |||
| free(map->chr_rom); | |||
| } | |||
| free(nes_map->data); | |||
| free(map); | |||
| } | |||
| } | |||
| @@ -204,9 +207,9 @@ static inline uint8_t* mmc3_wram_addr(mmc3_mapper* map, | |||
| return &(map->wram[addr & 0x1FFFU]); | |||
| } | |||
| static uint8_t mmc3_read(nes_mapper* nes_map, uint16_t addr) { | |||
| static uint8_t mmc3_read(void* data, uint16_t addr) { | |||
| uint8_t* ptr = NULL; | |||
| mmc3_mapper* map = (mmc3_mapper*)nes_map->data; | |||
| mmc3_mapper* map = (mmc3_mapper*)data; | |||
| if (addr >= nes_mem_rom_start) { | |||
| ptr = mmc3_prg_addr(map, addr); | |||
| } else if ( addr >= nes_mem_wram_start && | |||
| @@ -222,9 +225,9 @@ static uint8_t mmc3_read(nes_mapper* nes_map, uint16_t addr) { | |||
| return val; | |||
| } | |||
| static void mmc3_write(nes_mapper* nes_map, | |||
| static void mmc3_write(void* data, | |||
| uint16_t addr, uint8_t val) { | |||
| mmc3_mapper* map = (mmc3_mapper*)nes_map->data; | |||
| mmc3_mapper* map = (mmc3_mapper*)data; | |||
| if (addr >= nes_mem_rom_start) MAP_LOG("$%04x < %02x", addr, val); | |||
| @@ -284,13 +287,13 @@ static void mmc3_write(nes_mapper* nes_map, | |||
| map->flags |= mmc3_Flag_IRQ_Enabled; | |||
| } else { | |||
| map->flags &= ~mmc3_Flag_IRQ_Enabled; | |||
| nes_map_trigger_irq(nes_map, 0); | |||
| nes_map_trigger_irq(map->mapper, 0); | |||
| } | |||
| } | |||
| } | |||
| static void mmc3_scanline(nes_mapper* nes_map) { | |||
| mmc3_mapper* map = (mmc3_mapper*)nes_map->data; | |||
| static void mmc3_scanline(void* data) { | |||
| mmc3_mapper* map = (mmc3_mapper*)data; | |||
| if ( map->irq_count <= 0 || | |||
| (map->flags & mmc3_Flag_IRQ_Reload)) { | |||
| @@ -303,42 +306,42 @@ static void mmc3_scanline(nes_mapper* nes_map) { | |||
| if ( map->irq_count <= 0 && | |||
| (map->flags & mmc3_Flag_IRQ_Enabled)) { | |||
| MAP_LOG("IRQ Trigger"); | |||
| nes_map_trigger_irq(nes_map, 1); | |||
| nes_map_trigger_irq(map->mapper, 1); | |||
| map->irq_count = 0; | |||
| } | |||
| } | |||
| static uint8_t* mmc3_chr_addr(nes_mapper* nes_map, | |||
| static uint8_t* mmc3_chr_addr(void* data, | |||
| uint16_t addr) { | |||
| mmc3_mapper* map = (mmc3_mapper*)nes_map->data; | |||
| mmc3_mapper* map = (mmc3_mapper*)data; | |||
| return &map->chr_bank[(addr >> 10) & 7][addr & 0x3FFU]; | |||
| } | |||
| static uint8_t* mmc3_vram_addr(nes_mapper* nes_map, | |||
| static uint8_t* mmc3_vram_addr(void* data, | |||
| uint16_t addr) { | |||
| mmc3_mapper* map = (mmc3_mapper*)nes_map->data; | |||
| mmc3_mapper* map = (mmc3_mapper*)data; | |||
| return &map->vram_bank[(addr >> 10) & 3][addr & 0x3FFU]; | |||
| } | |||
| static void mmc3_chr_write(nes_mapper* nes_map, | |||
| static void mmc3_chr_write(void* data, | |||
| uint16_t addr, uint8_t val) { | |||
| mmc3_mapper* map = (mmc3_mapper*)nes_map->data; | |||
| mmc3_mapper* map = (mmc3_mapper*)data; | |||
| if (map->flags & mmc3_Flag_CHR_RAM) { | |||
| *(mmc3_chr_addr(nes_map, addr)) = val; | |||
| *(mmc3_chr_addr(data, addr)) = val; | |||
| } | |||
| // MAP_LOG("CHR ROM Write: $%04x < %02x\n", addr, val); | |||
| } | |||
| static void* mmc3_sram(nes_mapper* nes_map) { | |||
| mmc3_mapper* map = (mmc3_mapper*)nes_map->data; | |||
| static void* mmc3_sram(void* data) { | |||
| mmc3_mapper* map = (mmc3_mapper*)data; | |||
| return ( (map->flags & mmc3_Flag_Battery) ? | |||
| map->wram : NULL); | |||
| } | |||
| static int mmc3_sram_size(nes_mapper* nes_map) { | |||
| mmc3_mapper* map = (mmc3_mapper*)nes_map->data; | |||
| static int mmc3_sram_size(void* data) { | |||
| mmc3_mapper* map = (mmc3_mapper*)data; | |||
| return ( (map->flags & mmc3_Flag_Battery) ? | |||
| sizeof(map->wram) : 0); | |||
| } | |||
| @@ -346,19 +349,19 @@ static int mmc3_sram_size(nes_mapper* nes_map) { | |||
| /* Save State */ | |||
| int mmc3_state_size(const nes_mapper* nes_map) { | |||
| mmc3_mapper* map = (mmc3_mapper*)nes_map->data; | |||
| static int mmc3_state_size(const void* data) { | |||
| const mmc3_mapper* map = (mmc3_mapper*)data; | |||
| return ( (map->wram - map->r) + | |||
| sizeof(map->wram) + | |||
| sizeof(map->vram)); | |||
| } | |||
| int mmc3_state_read(nes_mapper* nes_map, const void* data) { | |||
| mmc3_mapper* map = (mmc3_mapper*)nes_map->data; | |||
| static int mmc3_state_read(void* _map, const void* data) { | |||
| mmc3_mapper* map = (mmc3_mapper*)_map; | |||
| uint8_t old_bank_select = map->bank_select; | |||
| int size = mmc3_state_size(nes_map); | |||
| int size = mmc3_state_size(_map); | |||
| memcpy(map->r, data, size); | |||
| uint8_t new_bank_select = map->bank_select; | |||
| @@ -370,9 +373,9 @@ int mmc3_state_read(nes_mapper* nes_map, const void* data) { | |||
| return size; | |||
| } | |||
| int mmc3_state_write(const nes_mapper* nes_map, void* data) { | |||
| mmc3_mapper* map = (mmc3_mapper*)nes_map->data; | |||
| int size = mmc3_state_size(nes_map); | |||
| static int mmc3_state_write(const void* _map, void* data) { | |||
| mmc3_mapper* map = (mmc3_mapper*)_map; | |||
| int size = mmc3_state_size(_map); | |||
| memcpy(data, map->r, size); | |||
| return size; | |||
| } | |||
| @@ -380,6 +383,7 @@ int mmc3_state_write(const nes_mapper* nes_map, void* data) { | |||
| nes_mapper mapper_mmc3 = { | |||
| .name = "MMC3", | |||
| .init = mmc3_init, | |||
| .reset = mmc3_reset, | |||
| .done = mmc3_done, | |||
| @@ -15,11 +15,10 @@ typedef struct { | |||
| } nrom_mapper; | |||
| static void nrom_reset(nes_mapper* nes_map) {} | |||
| static void nrom_reset(void* data) {} | |||
| static int nrom_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| static void* 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_banks = cart->prg_rom_banks; | |||
| @@ -31,16 +30,16 @@ static int nrom_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| map->chr_rom_banks = cart->chr_rom_banks; | |||
| map->mirror = (cart->flags & Cart_Flag_Horizontal) ? 0 : 1; | |||
| } | |||
| return (NULL == map ? -1 : 0); | |||
| return map; | |||
| } | |||
| static void nrom_done(nes_mapper* nes_map) { | |||
| nrom_mapper* map = (nrom_mapper*)nes_map->data; | |||
| static void nrom_done(void* data) { | |||
| nrom_mapper* map = (nrom_mapper*)data; | |||
| if (NULL != map) { | |||
| if (map->chr_rom_banks <= 0) { | |||
| free(map->chr_rom); | |||
| } | |||
| free(nes_map->data); | |||
| free(data); | |||
| } | |||
| } | |||
| @@ -58,42 +57,39 @@ static inline uint8_t* nrom_wram_addr(nrom_mapper* map, | |||
| return &(map->wram[addr & 0x1FFFU]); | |||
| } | |||
| static uint8_t nrom_read(nes_mapper* map, uint16_t addr) { | |||
| static uint8_t nrom_read(void* data, uint16_t addr) { | |||
| uint8_t val = 0; | |||
| if (addr >= nes_mem_rom_start) { | |||
| val = *(nrom_prg_addr((nrom_mapper*)map->data, addr)); | |||
| val = *(nrom_prg_addr((nrom_mapper*)data, addr)); | |||
| } else if (addr >= nes_mem_wram_start) { | |||
| val = *(nrom_wram_addr((nrom_mapper*)map->data, addr)); | |||
| val = *(nrom_wram_addr((nrom_mapper*)data, addr)); | |||
| } | |||
| return val; | |||
| } | |||
| static void nrom_write(nes_mapper* map, | |||
| uint16_t addr, uint8_t val) { | |||
| static void nrom_write(void* data, uint16_t addr, uint8_t val) { | |||
| if (addr < nes_mem_rom_start && addr >= nes_mem_wram_start) { | |||
| *(nrom_wram_addr((nrom_mapper*)map->data, addr)) = val; | |||
| *(nrom_wram_addr((nrom_mapper*)data, addr)) = val; | |||
| } | |||
| } | |||
| static uint8_t* nrom_chr_addr(nes_mapper* nes_map, | |||
| uint16_t addr) { | |||
| return &(((nrom_mapper*)nes_map->data)->chr_rom[addr]); | |||
| static uint8_t* nrom_chr_addr(void* data, uint16_t addr) { | |||
| return &(((nrom_mapper*)data)->chr_rom[addr]); | |||
| } | |||
| static uint8_t* nrom_vram_addr(nes_mapper* nes_map, | |||
| uint16_t addr) { | |||
| nrom_mapper* map = (nrom_mapper*)nes_map->data; | |||
| static uint8_t* nrom_vram_addr(void* data, uint16_t addr) { | |||
| nrom_mapper* map = (nrom_mapper*)data; | |||
| int page = addr >> 10U; | |||
| page >>= map->mirror; | |||
| addr = ((page & 1) << 10U) | (addr & 0x3FFU); | |||
| return &map->vram[addr]; | |||
| } | |||
| static void nrom_chr_write(nes_mapper* nes_map, | |||
| static void nrom_chr_write(void* data, | |||
| uint16_t addr, uint8_t val) { | |||
| nrom_mapper* map = (nrom_mapper*)nes_map->data; | |||
| nrom_mapper* map = (nrom_mapper*)data; | |||
| if (map->chr_rom_banks <= 0) { | |||
| *(nrom_chr_addr(nes_map, addr)) = val; | |||
| *(nrom_chr_addr(data, addr)) = val; | |||
| } | |||
| // printf("CHR ROM Write: $%04x < %02x\n", addr, val); | |||
| } | |||
| @@ -101,20 +97,20 @@ static void nrom_chr_write(nes_mapper* nes_map, | |||
| /* Save State */ | |||
| int nrom_state_size(const nes_mapper* nes_map) { | |||
| nrom_mapper* map = (nrom_mapper*)nes_map->data; | |||
| static int nrom_state_size(const void* _map) { | |||
| nrom_mapper* map = (nrom_mapper*)_map; | |||
| return (sizeof(map->vram) + sizeof(map->wram)); | |||
| } | |||
| int nrom_state_read(nes_mapper* nes_map, const void* data) { | |||
| nrom_mapper* map = (nrom_mapper*)nes_map->data; | |||
| static int nrom_state_read(void* _map, const void* data) { | |||
| nrom_mapper* map = (nrom_mapper*)_map; | |||
| memcpy(map->vram, data, sizeof(map->vram)); | |||
| memcpy(map->wram, data + sizeof(map->vram), sizeof(map->wram)); | |||
| return (sizeof(map->vram) + sizeof(map->wram)); | |||
| } | |||
| int nrom_state_write(const nes_mapper* nes_map, void* data) { | |||
| nrom_mapper* map = (nrom_mapper*)nes_map->data; | |||
| static int nrom_state_write(const void* _map, void* data) { | |||
| nrom_mapper* map = (nrom_mapper*)_map; | |||
| memcpy(data, map->vram, sizeof(map->vram)); | |||
| memcpy(data + sizeof(map->vram), map->wram, sizeof(map->wram)); | |||
| return (sizeof(map->vram) + sizeof(map->wram)); | |||
| @@ -24,28 +24,27 @@ static void uxrom_set_bank(uxrom_mapper* map, uint8_t bank) { | |||
| ]; | |||
| } | |||
| static void uxrom_reset(nes_mapper* nes_map) { | |||
| uxrom_mapper* map = (uxrom_mapper*)nes_map->data; | |||
| static void uxrom_reset(void* data) { | |||
| uxrom_mapper* map = (uxrom_mapper*)data; | |||
| uxrom_set_bank(map, 0); | |||
| map->prg_bank_lo = map->prg_rom; | |||
| } | |||
| static int uxrom_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| static void* uxrom_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| uxrom_mapper* map = calloc(1, sizeof(uxrom_mapper)); | |||
| nes_map->data = map; | |||
| if (NULL != map) { | |||
| map->prg_rom = cart->prg_rom; | |||
| map->prg_rom_banks = cart->prg_rom_banks; | |||
| map->mirror = (cart->flags & Cart_Flag_Horizontal) ? 0 : 1; | |||
| map->prg_bank_hi = &map->prg_rom[(map->prg_rom_banks - 1) * | |||
| nes_prg_rom_page_size]; | |||
| uxrom_reset(nes_map); | |||
| uxrom_reset(map); | |||
| } | |||
| return (NULL == map ? -1 : 0); | |||
| return map; | |||
| } | |||
| static void uxrom_done(nes_mapper* nes_map) { | |||
| free(nes_map->data); | |||
| static void uxrom_done(void* data) { | |||
| free(data); | |||
| } | |||
| static inline uint8_t* uxrom_prg_addr(uxrom_mapper* map, | |||
| @@ -56,53 +55,50 @@ static inline uint8_t* uxrom_prg_addr(uxrom_mapper* map, | |||
| } | |||
| static uint8_t uxrom_read(nes_mapper* map, uint16_t addr) { | |||
| static uint8_t uxrom_read(void* _map, uint16_t addr) { | |||
| uint8_t val = 0; | |||
| if (addr >= nes_mem_rom_start) { | |||
| val = *(uxrom_prg_addr((uxrom_mapper*)map->data, addr)); | |||
| val = *(uxrom_prg_addr((uxrom_mapper*)_map, addr)); | |||
| } | |||
| return val; | |||
| } | |||
| static void uxrom_write(nes_mapper* nes_map, | |||
| uint16_t addr, uint8_t val) { | |||
| uxrom_mapper* map = (uxrom_mapper*)nes_map->data; | |||
| static void uxrom_write(void* _map, uint16_t addr, uint8_t val) { | |||
| uxrom_mapper* map = (uxrom_mapper*)_map; | |||
| if (addr >= nes_mem_rom_start) { | |||
| uxrom_set_bank(map, val); | |||
| } | |||
| } | |||
| static uint8_t* uxrom_chr_addr(nes_mapper* nes_map, | |||
| uint16_t addr) { | |||
| return &((uxrom_mapper*)nes_map->data)->chr_ram[addr]; | |||
| static uint8_t* uxrom_chr_addr(void* data, uint16_t addr) { | |||
| return &((uxrom_mapper*)data)->chr_ram[addr]; | |||
| } | |||
| static uint8_t* uxrom_vram_addr(nes_mapper* nes_map, | |||
| uint16_t addr) { | |||
| uxrom_mapper* map = (uxrom_mapper*)nes_map->data; | |||
| static uint8_t* uxrom_vram_addr(void* data, uint16_t addr) { | |||
| uxrom_mapper* map = (uxrom_mapper*)data; | |||
| int page = addr >> 10U; | |||
| page >>= map->mirror; | |||
| addr = ((page & 1) << 10U) | (addr & 0x3FFU); | |||
| return &map->vram[addr]; | |||
| } | |||
| static void uxrom_chr_write(nes_mapper* nes_map, | |||
| static void uxrom_chr_write(void* data, | |||
| uint16_t addr, uint8_t val) { | |||
| ((uxrom_mapper*)nes_map->data)->chr_ram[addr] = val; | |||
| ((uxrom_mapper*)data)->chr_ram[addr] = val; | |||
| } | |||
| /* Save State */ | |||
| int uxrom_state_size(const nes_mapper* nes_map) { | |||
| uxrom_mapper* map = (uxrom_mapper*)nes_map->data; | |||
| int uxrom_state_size(const void* _map) { | |||
| uxrom_mapper* map = (uxrom_mapper*)_map; | |||
| return ( sizeof(uint32_t) + | |||
| sizeof(map->vram) + | |||
| sizeof(map->chr_ram)); | |||
| } | |||
| int uxrom_state_read(nes_mapper* nes_map, const void* data) { | |||
| uxrom_mapper* map = (uxrom_mapper*)nes_map->data; | |||
| int uxrom_state_read(void* _map, const void* data) { | |||
| uxrom_mapper* map = (uxrom_mapper*)_map; | |||
| const void* ptr = data; | |||
| map->bank = *(uint32_t*)ptr; | |||
| @@ -117,8 +113,8 @@ int uxrom_state_read(nes_mapper* nes_map, const void* data) { | |||
| return (ptr - data); | |||
| } | |||
| int uxrom_state_write(const nes_mapper* nes_map, void* data) { | |||
| uxrom_mapper* map = (uxrom_mapper*)nes_map->data; | |||
| int uxrom_state_write(const void* _map, void* data) { | |||
| uxrom_mapper* map = (uxrom_mapper*)_map; | |||
| void* ptr = data; | |||
| uint32_t bank = map->bank; | |||
| @@ -12,45 +12,42 @@ | |||
| struct nes_cart_t; | |||
| typedef struct nes_mapper_t { | |||
| void* data; | |||
| const char* name; | |||
| int (*init)(struct nes_mapper_t*, struct nes_cart_t* cart); | |||
| void (*reset)(struct nes_mapper_t*); | |||
| void (*done)(struct nes_mapper_t*); | |||
| void* (*init)(struct nes_mapper_t*, struct nes_cart_t* cart); | |||
| void (*reset)(void*); | |||
| void (*done)(void*); | |||
| uint8_t (*read)(struct nes_mapper_t*, uint16_t addr); | |||
| void (*write)(struct nes_mapper_t*, uint16_t addr, uint8_t val); | |||
| uint8_t (*read)(void*, uint16_t addr); | |||
| void (*write)(void*, 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); | |||
| uint8_t* (*chr_addr)(void*, uint16_t addr); | |||
| uint8_t* (*vram_addr)(void*, uint16_t addr); | |||
| void (*chr_write)(void*, uint16_t addr, uint8_t val); | |||
| void (*scanline)(struct nes_mapper_t*); | |||
| void (*irq_callback)(void*, int); | |||
| void (*scanline)(void*); | |||
| void (*irq_callback)(void* irq_arg, int); | |||
| void* irq_arg; | |||
| void* (*sram)(struct nes_mapper_t*); | |||
| int (*sram_size)(struct nes_mapper_t*); | |||
| int (*state_size)(const struct nes_mapper_t*); | |||
| int (*state_read)(struct nes_mapper_t*, const void*); | |||
| int (*state_write)(const struct nes_mapper_t*, void*); | |||
| void* (*sram)(void*); | |||
| int (*sram_size)(void*); | |||
| int (*state_size)(const void* map); | |||
| int (*state_read)(void* map, const void* data); | |||
| int (*state_write)(const void* map, void* data); | |||
| } nes_mapper; | |||
| static inline int nes_map_init(nes_mapper* map, | |||
| struct nes_cart_t* cart) { | |||
| static inline void* nes_map_init(nes_mapper* map, | |||
| struct nes_cart_t* cart) { | |||
| return map->init(map, cart); | |||
| } | |||
| static inline void nes_map_reset(nes_mapper* map) { | |||
| map->reset(map); | |||
| static inline void nes_map_reset(nes_mapper* map, void* data) { | |||
| map->reset(data); | |||
| } | |||
| static inline void nes_map_done(nes_mapper* map) { | |||
| map->done(map); | |||
| static inline void nes_map_done(nes_mapper* map, void* data) { | |||
| map->done(data); | |||
| } | |||
| static inline void nes_map_set_irq(nes_mapper* map, | |||
| @@ -66,44 +63,51 @@ static inline void nes_map_trigger_irq(nes_mapper* map, | |||
| } | |||
| static inline uint8_t nes_map_read(nes_mapper* map, | |||
| uint16_t addr) { | |||
| return map->read(map, addr); | |||
| void* data, | |||
| uint16_t addr) { | |||
| return map->read(data, addr); | |||
| } | |||
| static inline void nes_map_write(nes_mapper* map, | |||
| uint16_t addr, | |||
| uint8_t val) { | |||
| map->write(map, addr, val); | |||
| void* data, | |||
| uint16_t addr, | |||
| uint8_t val) { | |||
| map->write(data, addr, val); | |||
| } | |||
| static inline uint8_t* nes_map_chr_addr(nes_mapper* map, | |||
| uint16_t addr) { | |||
| return map->chr_addr(map, addr); | |||
| void* data, | |||
| uint16_t addr) { | |||
| return map->chr_addr(data, addr); | |||
| } | |||
| static inline uint8_t nes_chr_read(nes_mapper* map, | |||
| uint16_t addr) { | |||
| return *(nes_map_chr_addr(map, addr)); | |||
| void* data, | |||
| uint16_t addr) { | |||
| return *(nes_map_chr_addr(map, data, 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 void nes_chr_write(nes_mapper* map, void* data, | |||
| uint16_t addr, uint8_t val) { | |||
| return map->chr_write(data, addr, val); | |||
| } | |||
| static inline uint8_t* nes_map_vram_addr(nes_mapper* map, | |||
| void* data, | |||
| uint16_t addr) { | |||
| return map->vram_addr(map, addr & 0x1FFFU); | |||
| return map->vram_addr(data, addr & 0x1FFFU); | |||
| } | |||
| static inline uint8_t nes_vram_read(nes_mapper* map, | |||
| void* data, | |||
| uint16_t addr) { | |||
| return *(nes_map_vram_addr(map, addr)); | |||
| return *(nes_map_vram_addr(map, data, addr)); | |||
| } | |||
| static inline void nes_vram_write(nes_mapper* map, | |||
| void* data, | |||
| uint16_t addr, uint8_t val) { | |||
| *(nes_map_vram_addr(map, addr)) = val; | |||
| *(nes_map_vram_addr(map, data, addr)) = val; | |||
| } | |||
| @@ -23,7 +23,8 @@ uint8_t nes_mem_read(nes* sys, uint16_t addr) { | |||
| val = nes_apu_read(&sys->apu, addr); | |||
| } else { | |||
| val = nes_map_read(sys->cart.mapper, addr); | |||
| val = nes_map_read(sys->cart.mapper, | |||
| sys->cart.map_data, addr); | |||
| } | |||
| return val; | |||
| @@ -55,7 +56,8 @@ void nes_mem_write(nes* sys, uint16_t addr, uint8_t val) { | |||
| nes_apu_write(&sys->apu, addr, val); | |||
| } else { | |||
| nes_map_write(sys->cart.mapper, addr, val); | |||
| nes_map_write(sys->cart.mapper, sys->cart.map_data, | |||
| addr, val); | |||
| } | |||
| } | |||
| @@ -84,6 +86,7 @@ void nes_done(nes* sys) { | |||
| int nes_setup_cart(nes* sys) { | |||
| nes_map_set_irq(sys->cart.mapper, nes_irq, sys); | |||
| sys->ppu.mapper = sys->cart.mapper; | |||
| sys->ppu.map_data = sys->cart.map_data; | |||
| nes_reset(sys); | |||
| return 0; | |||
| } | |||
| @@ -43,12 +43,14 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) { | |||
| if (ppu->addr < nes_ppu_mem_vram_start) { | |||
| PPU_LOG("PPU: CHR MEM READ %04x > %02x\n", ppu->addr, val); | |||
| ppu->data = nes_chr_read(ppu->mapper, ppu->addr); | |||
| ppu->data = nes_chr_read(ppu->mapper, | |||
| ppu->map_data, | |||
| 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); | |||
| ppu->data = nes_vram_read( | |||
| ppu->mapper, | |||
| ppu->mapper, ppu->map_data, | |||
| ppu->addr - nes_ppu_mem_vram_start | |||
| ); | |||
| } else if (ppu->addr < nes_ppu_mem_pal_start) { | |||
| @@ -186,11 +188,13 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) { | |||
| } | |||
| #endif // DEBUG_VRAM | |||
| // printf("PPU: VRAM %04x < %02x\n", vram_addr, val); | |||
| nes_vram_write(ppu->mapper, vram_addr, val); | |||
| nes_vram_write(ppu->mapper, ppu->map_data, | |||
| vram_addr, val); | |||
| } else { | |||
| // PPU_LOG("PPU: CHR MEM WRITE %04x > %02x\n", ppu->addr, val); | |||
| nes_chr_write(ppu->mapper, ppu->addr, val); | |||
| nes_chr_write(ppu->mapper, ppu->map_data, | |||
| ppu->addr, val); | |||
| } | |||
| ppu->addr += (ppu->control & ppu_Control_VRAM_Inc) ? | |||
| @@ -212,6 +216,7 @@ void nes_ppu_reset(nes_ppu* ppu) { | |||
| int nes_ppu_init(nes_ppu* ppu, const nes_cart* cart) { | |||
| ppu->mapper = cart->mapper; | |||
| ppu->map_data = cart->map_data; | |||
| ppu->status = 0; | |||
| ppu->oam_addr = 0; | |||
| ppu->addr = 0; | |||
| @@ -237,7 +242,7 @@ nes_ppu_Result nes_ppu_run(nes_ppu* ppu, int cycles) { | |||
| ppu->scanline < nes_ppu_render && | |||
| (ppu->mask & (ppu_Mask_Back | ppu_Mask_Sprite)) && | |||
| ppu->cycle < 260 && next_cycle >= 260) { | |||
| ppu->mapper->scanline(ppu->mapper); | |||
| ppu->mapper->scanline(ppu->map_data); | |||
| } | |||
| ppu->cycle = next_cycle; | |||
| @@ -151,6 +151,7 @@ typedef struct { | |||
| // System Interface | |||
| struct nes_mapper_t* mapper; | |||
| void* map_data; | |||
| } nes_ppu; | |||
| uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr); | |||
| @@ -20,9 +20,9 @@ int load_sram(nes_cart* cart, const char* cart_filename) { | |||
| int status = -1; | |||
| int sram_size = cart->mapper->sram_size ? | |||
| cart->mapper->sram_size(cart->mapper) : 0; | |||
| cart->mapper->sram_size(cart->map_data) : 0; | |||
| void* sram = cart->mapper->sram ? | |||
| cart->mapper->sram(cart->mapper) : NULL; | |||
| cart->mapper->sram(cart->map_data) : NULL; | |||
| if (sram_size > 0 && NULL != sram) { | |||
| char sram_filename[FILENAME_MAX] = {0}; | |||
| @@ -39,9 +39,9 @@ int save_sram(const nes_cart* cart, const char* cart_filename) { | |||
| if (NULL != cart->mapper) { | |||
| int sram_size = cart->mapper->sram_size ? | |||
| cart->mapper->sram_size(cart->mapper) : 0; | |||
| cart->mapper->sram_size(cart->map_data) : 0; | |||
| const void* sram = cart->mapper->sram ? | |||
| cart->mapper->sram(cart->mapper) : NULL; | |||
| cart->mapper->sram(cart->map_data) : NULL; | |||
| if (sram_size > 0 && NULL != sram) { | |||
| char sram_filename[FILENAME_MAX] = {0}; | |||
| @@ -230,7 +230,7 @@ int state_size(const nes* sys) { | |||
| size += szChunkHeader + ram_state_size(sys); | |||
| // Cart should already be loaded | |||
| size += szChunkHeader + | |||
| sys->cart.mapper->state_size(sys->cart.mapper); | |||
| sys->cart.mapper->state_size(sys->cart.map_data); | |||
| return size; | |||
| } | |||
| @@ -273,8 +273,10 @@ int state_write(const nes* sys, void* mem, int size) { | |||
| ptr += ram_state_write(sys, ptr); | |||
| const nes_mapper* mapper = sys->cart.mapper; | |||
| ptr = write_header(ptr, tag_mapper, mapper->state_size(mapper)); | |||
| ptr += mapper->state_write(mapper, ptr); | |||
| const void* map_data = sys->cart.map_data; | |||
| ptr = write_header(ptr, tag_mapper, | |||
| mapper->state_size(map_data)); | |||
| ptr += mapper->state_write(map_data, ptr); | |||
| return (ptr - mem); | |||
| } | |||
| @@ -336,7 +338,7 @@ int state_read(nes* sys, const void* mem, int mem_size) { | |||
| } else if (tag_mapper == tag) { | |||
| n_read = sys->cart.mapper->state_read( | |||
| sys->cart.mapper, ptr | |||
| sys->cart.map_data, ptr | |||
| ); | |||
| loaded |= Component_Mapper; | |||
| @@ -33,7 +33,7 @@ static SDL_Color nes_palette[64] = { | |||
| static inline uint8_t* chr_mem(const nes_ppu* ppu, | |||
| uint16_t addr) { | |||
| return ppu->mapper->chr_addr(ppu->mapper, addr); | |||
| return ppu->mapper->chr_addr(ppu->map_data, addr); | |||
| } | |||
| @@ -243,6 +243,7 @@ static inline void render_bg_scanline_area( | |||
| y = y % 8; | |||
| int bank = (ppu->control & ppu_Control_Back_Bank) ? 0x100 : 0; | |||
| const uint8_t* indexes = nes_map_vram_addr(ppu->mapper, | |||
| ppu->map_data, | |||
| page << 10); | |||
| const uint8_t* attrs = indexes + 960U; | |||
| const uint8_t* index = indexes + | |||