| @@ -30,7 +30,7 @@ PFLAGS += -g | |||
| #PFLAGS += -DDEBUG_APU | |||
| #PFLAGS += -DDEBUG_INPUT | |||
| #PFLAGS += -DE6502_DEBUG | |||
| #PFLAGS += -DE6502_ILLEGAL | |||
| PFLAGS += -DE6502_ILLEGAL | |||
| CFLAGS += $(PFLAGS) -Wall -Werror -Wshadow -Wunused -I../ -Isrc/ | |||
| CFLAGS += -Iinc/$(PLATFORM)/SDL2 | |||
| LDFLAGS += $(PFLAGS) | |||
| @@ -96,7 +96,7 @@ static int cnrom_state_size(const void* _map) { | |||
| return (sizeof(map->bank) + sizeof(map->vram)); | |||
| } | |||
| static int cnrom_state_read(void* _map, const void* data) { | |||
| static int cnrom_state_read(void* _map, const void* data, int len) { | |||
| cnrom_mapper* map = (cnrom_mapper*)_map; | |||
| const void* ptr = data; | |||
| @@ -111,7 +111,7 @@ static int cnrom_state_read(void* _map, const void* data) { | |||
| return (ptr - data); | |||
| } | |||
| static int cnrom_state_write(const void* _map, void* data) { | |||
| static int cnrom_state_write(const void* _map, void* data, int len) { | |||
| cnrom_mapper* map = (cnrom_mapper*)_map; | |||
| void* ptr = data; | |||
| @@ -15,9 +15,11 @@ typedef struct { | |||
| uint8_t* chr_bank[2]; | |||
| uint8_t* vram_bank[4]; | |||
| uint8_t* prg_bank[2]; | |||
| uint8_t* chr_ram; | |||
| uint8_t* chr; | |||
| int chr_bank_offset[2]; | |||
| int chr_ram_lim; | |||
| uint8_t reg_shift; | |||
| uint8_t reg_n_shift; | |||
| uint8_t reg_control; | |||
| @@ -27,6 +29,8 @@ typedef struct { | |||
| uint8_t vram[2][nes_vram_page_size]; | |||
| uint8_t wram[nes_mem_wram_size]; | |||
| uint8_t chr_ram[]; | |||
| } mmc1_mapper; | |||
| @@ -55,21 +59,22 @@ static void mmc1_update_vram(mmc1_mapper* map) { | |||
| } | |||
| static void mmc1_update_chr(mmc1_mapper* map) { | |||
| // CHR RAM selection | |||
| int banks[2] = {0}; | |||
| if (!(map->reg_control & 0b10000)) { | |||
| int bank = (map->reg_chr_0 & 0b11110); | |||
| MAP_LOG("CHR: 8 KB: %d + %d", bank, bank + 1); | |||
| map->chr_bank[0] = &map->chr[ bank * | |||
| nes_chr_page_size]; | |||
| map->chr_bank[1] = &map->chr[ (bank + 1) * | |||
| nes_chr_page_size]; | |||
| banks[0] = (map->reg_chr_0 & 0b11110); | |||
| banks[1] = banks[0] + 1; | |||
| } else { | |||
| MAP_LOG("CHR: %d + %d", map->reg_chr_0, map->reg_chr_1); | |||
| map->chr_bank[0] = &map->chr[ map->reg_chr_0 * | |||
| nes_chr_page_size]; | |||
| map->chr_bank[1] = &map->chr[ map->reg_chr_1 * | |||
| nes_chr_page_size]; | |||
| banks[0] = map->reg_chr_0; | |||
| banks[1] = map->reg_chr_1; | |||
| } | |||
| MAP_LOG("CHR: %d + %d", banks[0], banks[1]); | |||
| map->chr_bank_offset[0] = banks[0] * nes_chr_page_size; | |||
| map->chr_bank_offset[1] = banks[1] * nes_chr_page_size; | |||
| map->chr_bank[0] = &map->chr[map->chr_bank_offset[0]]; | |||
| map->chr_bank[1] = &map->chr[map->chr_bank_offset[1]]; | |||
| } | |||
| static void mmc1_update_prg(mmc1_mapper* map) { | |||
| @@ -103,20 +108,22 @@ static void mmc1_reset(void* data) { | |||
| } | |||
| static void* mmc1_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| mmc1_mapper* map = calloc(1, sizeof(mmc1_mapper)); | |||
| int chr_ram_size = ( cart->chr_rom_banks > 0 ? | |||
| 0 : 128 * 1024); | |||
| mmc1_mapper* map = calloc(1, sizeof(mmc1_mapper) + | |||
| chr_ram_size); | |||
| if (NULL != map) { | |||
| map->prg_rom = cart->prg_rom; | |||
| map->prg_rom_banks = cart->prg_rom_banks; | |||
| map->chr_rom_banks = cart->chr_rom_banks / 2; | |||
| if (map->chr_rom_banks > 0) { | |||
| map->chr_rom = cart->chr_rom; | |||
| map->chr_ram = NULL; | |||
| map->chr = map->chr_rom; | |||
| } else { | |||
| map->chr_rom = NULL; | |||
| map->chr_ram = calloc(32, nes_chr_page_size); | |||
| map->chr = map->chr_ram; | |||
| } | |||
| map->chr_ram_lim = 0; | |||
| map->battery = !!(cart->flags & Cart_Flag_Battery); | |||
| @@ -126,10 +133,7 @@ static void* mmc1_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| } | |||
| static void mmc1_done(void* data) { | |||
| if (NULL != data) { | |||
| free(((mmc1_mapper*)data)->chr_ram); | |||
| free(data); | |||
| } | |||
| free(data); | |||
| } | |||
| static inline uint8_t* mmc1_prg_addr(mmc1_mapper* map, | |||
| @@ -207,7 +211,11 @@ static uint8_t* mmc1_chr_addr(void* data, uint16_t addr) { | |||
| static void mmc1_chr_write(void* data, | |||
| uint16_t addr, uint8_t val) { | |||
| if (NULL != ((mmc1_mapper*)data)->chr_ram) { | |||
| mmc1_mapper* map = (mmc1_mapper*)data; | |||
| if (NULL == map->chr_rom) { | |||
| int pos = map->chr_bank_offset[(addr >> 12) & 1] + | |||
| (addr & 0xFFFU); | |||
| if (pos >= map->chr_ram_lim) map->chr_ram_lim = pos + 1; | |||
| *(mmc1_chr_addr(data, addr)) = val; | |||
| } | |||
| } | |||
| @@ -233,17 +241,27 @@ static int mmc1_sram_size(void* data) { | |||
| /* Save State */ | |||
| static inline int mmc1_chr_ram_size(const mmc1_mapper* map) { | |||
| return (map->chr_rom_banks <= 0 ? (128 * 1024) : 0); | |||
| } | |||
| static int mmc1_state_size(const void* _map) { | |||
| mmc1_mapper* map = (mmc1_mapper*)_map; | |||
| return ( (void*)map + | |||
| return ( map->chr_ram_lim + | |||
| (void*)map + | |||
| sizeof(*map) - | |||
| (void*)&(map->reg_shift)); | |||
| } | |||
| static int mmc1_state_read(void* _map, const void* data) { | |||
| static int mmc1_state_read(void* _map, const void* data, | |||
| int data_len) { | |||
| mmc1_mapper* map = (mmc1_mapper*)_map; | |||
| int size = mmc1_state_size(_map); | |||
| int base_size = mmc1_state_size(map) - map->chr_ram_lim; | |||
| int size = base_size + mmc1_chr_ram_size(map); | |||
| if (size > data_len) size = data_len; | |||
| map->chr_ram_lim = data_len - base_size; | |||
| memcpy(&(map->reg_shift), data, size); | |||
| mmc1_update_prg(map); | |||
| @@ -253,9 +271,11 @@ static int mmc1_state_read(void* _map, const void* data) { | |||
| return size; | |||
| } | |||
| static int mmc1_state_write(const void* _map, void* data) { | |||
| static int mmc1_state_write(const void* _map, void* data, | |||
| int data_len) { | |||
| mmc1_mapper* map = (mmc1_mapper*)_map; | |||
| int size = mmc1_state_size(_map); | |||
| if (size > data_len) size = data_len; | |||
| memcpy(data, &(map->reg_shift), size); | |||
| return size; | |||
| } | |||
| @@ -32,6 +32,9 @@ typedef struct { | |||
| uint8_t* chr_bank[8]; // 1 KB | |||
| uint8_t* vram_bank[4]; | |||
| int chr_bank_offset[8]; | |||
| int chr_ram_lim; | |||
| uint8_t r[8]; | |||
| uint8_t flags; | |||
| uint8_t bank_select; | |||
| @@ -40,6 +43,7 @@ typedef struct { | |||
| uint8_t wram[nes_mem_wram_size]; | |||
| uint8_t vram[2][nes_vram_page_size]; | |||
| uint8_t chr_ram[]; | |||
| } mmc3_mapper; | |||
| static inline uint8_t* mmc3_prg_bank(mmc3_mapper* map, int bank) { | |||
| @@ -79,6 +83,8 @@ static inline void mmc3_map_2k_chr(mmc3_mapper* map, | |||
| MAP_LOG("CHR ROM: 2k $%04x <- bank %d + %d", reg << 10, bank, bank | 1); | |||
| map->chr_bank[reg + 0] = mmc3_chr_bank(map, bank); | |||
| map->chr_bank[reg + 1] = mmc3_chr_bank(map, bank | 1); | |||
| map->chr_bank_offset[reg + 0] = map->chr_bank[reg + 0] - map->chr_rom; | |||
| map->chr_bank_offset[reg + 1] = map->chr_bank[reg + 1] - map->chr_rom; | |||
| } | |||
| static inline void mmc3_map_1k_chr(mmc3_mapper* map, | |||
| @@ -89,6 +95,7 @@ static inline void mmc3_map_1k_chr(mmc3_mapper* map, | |||
| } | |||
| MAP_LOG("CHR ROM: 1k $%04x <- bank %d", reg << 10, bank); | |||
| map->chr_bank[reg] = mmc3_chr_bank(map, bank); | |||
| map->chr_bank_offset[reg] = map->chr_bank[reg] - map->chr_rom; | |||
| } | |||
| static inline void mmc3_update_chr(mmc3_mapper* map, | |||
| @@ -159,7 +166,10 @@ static void mmc3_reset(void* data) { | |||
| } | |||
| static void* mmc3_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| mmc3_mapper* map = calloc(1, sizeof(mmc3_mapper)); | |||
| int chr_ram_size = ( cart->chr_rom_banks <= 0 ? | |||
| (256 * 1024) : 0); | |||
| mmc3_mapper* map = calloc(1, sizeof(mmc3_mapper) + | |||
| chr_ram_size); | |||
| if (NULL != map) { | |||
| map->mapper = nes_map; | |||
| map->flags = (cart->flags & Cart_Flag_Horizontal) ? | |||
| @@ -167,7 +177,7 @@ static void* mmc3_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| map->prg_rom = cart->prg_rom; | |||
| map->prg_rom_banks = cart->prg_rom_banks * 2; | |||
| if (cart->chr_rom_banks <= 0) { | |||
| map->chr_rom = calloc(1024, 256); | |||
| map->chr_rom = map->chr_ram; | |||
| map->chr_rom_banks = 256; | |||
| map->flags |= mmc3_Flag_CHR_RAM; | |||
| } else { | |||
| @@ -188,13 +198,7 @@ static void* mmc3_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| } | |||
| 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(map); | |||
| } | |||
| free(data); | |||
| } | |||
| static inline uint8_t* mmc3_prg_addr(mmc3_mapper* map, | |||
| @@ -328,7 +332,10 @@ static void mmc3_chr_write(void* data, | |||
| uint16_t addr, uint8_t val) { | |||
| mmc3_mapper* map = (mmc3_mapper*)data; | |||
| if (map->flags & mmc3_Flag_CHR_RAM) { | |||
| *(mmc3_chr_addr(data, addr)) = val; | |||
| uint8_t* ptr = mmc3_chr_addr(data, addr); | |||
| int pos = (ptr - map->chr_ram); | |||
| if (pos >= map->chr_ram_lim) map->chr_ram_lim = pos + 1; | |||
| *ptr = val; | |||
| } | |||
| // MAP_LOG("CHR ROM Write: $%04x < %02x\n", addr, val); | |||
| } | |||
| @@ -349,17 +356,27 @@ static int mmc3_sram_size(void* data) { | |||
| /* Save State */ | |||
| static inline int mmc3_chr_ram_size(const mmc3_mapper* map) { | |||
| return ( (map->flags & mmc3_Flag_CHR_RAM) ? | |||
| (256 * 1024) : 0); | |||
| } | |||
| 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)); | |||
| sizeof(map->vram) + | |||
| map->chr_ram_lim); | |||
| } | |||
| static int mmc3_state_read(void* _map, const void* data) { | |||
| static int mmc3_state_read(void* _map, const void* data, | |||
| int data_len) { | |||
| mmc3_mapper* map = (mmc3_mapper*)_map; | |||
| int size = mmc3_state_size(_map); | |||
| int base_size = mmc3_state_size(map) - map->chr_ram_lim; | |||
| int size = base_size + mmc3_chr_ram_size(map); | |||
| if (size > data_len) size = data_len; | |||
| map->chr_ram_lim = data_len - base_size; | |||
| memcpy(map->r, data, size); | |||
| uint8_t new_bank_select = map->bank_select; | |||
| @@ -371,9 +388,11 @@ static int mmc3_state_read(void* _map, const void* data) { | |||
| return size; | |||
| } | |||
| static int mmc3_state_write(const void* _map, void* data) { | |||
| static int mmc3_state_write(const void* _map, void* data, | |||
| int data_len) { | |||
| mmc3_mapper* map = (mmc3_mapper*)_map; | |||
| int size = mmc3_state_size(_map); | |||
| if (size > data_len) size = data_len; | |||
| memcpy(data, map->r, size); | |||
| return size; | |||
| } | |||
| @@ -10,20 +10,24 @@ typedef struct { | |||
| uint8_t* chr_rom; | |||
| int chr_rom_banks; | |||
| uint8_t mirror; | |||
| uint8_t vram[nes_vram_page_size * 2]; | |||
| uint8_t wram[nes_mem_wram_size]; | |||
| uint8_t chr_ram[]; | |||
| } nrom_mapper; | |||
| static void nrom_reset(void* data) {} | |||
| static void* nrom_init(nes_mapper* nes_map, nes_cart* cart) { | |||
| nrom_mapper* map = calloc(1, sizeof(nrom_mapper)); | |||
| int chr_ram_size = (cart->chr_rom_banks <= 0 ? 8192U : 0); | |||
| nrom_mapper* map = calloc(1, sizeof(nrom_mapper) + | |||
| chr_ram_size); | |||
| if (NULL != map) { | |||
| map->prg_rom = cart->prg_rom; | |||
| map->prg_rom_banks = cart->prg_rom_banks; | |||
| if (cart->chr_rom_banks <= 0) { | |||
| map->chr_rom = calloc(8, 1024); | |||
| map->chr_rom = map->chr_ram; | |||
| } else { | |||
| map->chr_rom = cart->chr_rom; | |||
| } | |||
| @@ -97,23 +101,29 @@ static void nrom_chr_write(void* data, | |||
| /* Save State */ | |||
| static inline int nrom_chr_ram_size(const nrom_mapper* map) { | |||
| return (map->chr_rom_banks <= 0 ? (8 * 1024) : 0); | |||
| } | |||
| static int nrom_state_size(const void* _map) { | |||
| nrom_mapper* map = (nrom_mapper*)_map; | |||
| return (sizeof(map->vram) + sizeof(map->wram)); | |||
| return ( sizeof(map->vram) + sizeof(map->wram) + | |||
| nrom_chr_ram_size(map)); | |||
| } | |||
| static int nrom_state_read(void* _map, const void* data) { | |||
| static int nrom_state_read(void* _map, const void* data, int len) { | |||
| 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 max_size = nrom_state_size(_map); | |||
| if (max_size > len) max_size = len; | |||
| memcpy(map->vram, data, max_size); | |||
| return max_size; | |||
| } | |||
| static int nrom_state_write(const void* _map, void* data) { | |||
| static int nrom_state_write(const void* _map, void* data, int len) { | |||
| 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)); | |||
| int size = nrom_state_size(_map); | |||
| memcpy(data, map->vram, size); | |||
| return size; | |||
| } | |||
| @@ -97,7 +97,7 @@ int uxrom_state_size(const void* _map) { | |||
| sizeof(map->chr_ram)); | |||
| } | |||
| int uxrom_state_read(void* _map, const void* data) { | |||
| int uxrom_state_read(void* _map, const void* data, int len) { | |||
| uxrom_mapper* map = (uxrom_mapper*)_map; | |||
| const void* ptr = data; | |||
| @@ -113,7 +113,7 @@ int uxrom_state_read(void* _map, const void* data) { | |||
| return (ptr - data); | |||
| } | |||
| int uxrom_state_write(const void* _map, void* data) { | |||
| int uxrom_state_write(const void* _map, void* data, int len) { | |||
| uxrom_mapper* map = (uxrom_mapper*)_map; | |||
| void* ptr = data; | |||
| @@ -33,8 +33,8 @@ typedef struct nes_mapper_t { | |||
| 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); | |||
| int (*state_read)(void* map, const void* data, int len); | |||
| int (*state_write)(const void* map, void* data, int len); | |||
| } nes_mapper; | |||
| static inline void* nes_map_init(nes_mapper* map, | |||
| @@ -76,7 +76,13 @@ int load_state(nes* sys, const char* cart_filename) { | |||
| FILE* file = fopen(state_filename, "rb"); | |||
| if (NULL != file) { | |||
| int file_size = state_size(sys); | |||
| // int expected_size = state_size(sys); | |||
| fseek(file, 0L, SEEK_END); | |||
| int file_size = ftell(file); | |||
| // rewind(file); | |||
| // if (max_size < size) size = max_size; | |||
| void* mem = map_file(file, file_size, Filemap_Mode_Read); | |||
| if (NULL != mem) { | |||
| @@ -278,9 +284,9 @@ int state_write(const nes* sys, void* mem, int size) { | |||
| const nes_mapper* mapper = sys->cart.mapper; | |||
| 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); | |||
| int state_size = mapper->state_size(map_data); | |||
| ptr = write_header(ptr, tag_mapper, state_size); | |||
| ptr += mapper->state_write(map_data, ptr, state_size); | |||
| return (ptr - mem); | |||
| } | |||
| @@ -342,7 +348,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.map_data, ptr | |||
| sys->cart.map_data, ptr, size | |||
| ); | |||
| loaded |= Component_Mapper; | |||
| @@ -395,3 +401,29 @@ int state_read(nes* sys, const void* mem, int mem_size) { | |||
| return result; | |||
| } | |||
| /* | |||
| // Chunking | |||
| int write_chunks(void* dst, int dst_len, const void* src, | |||
| const nese_io_chunk* chunks, int n_chunks) { | |||
| void* ptr = dst; | |||
| for ( void* end = dst + dst_len; | |||
| n_chunks > 0 && ptr < end; | |||
| ptr += chunks->size, --n_chunks, ++chunks) { | |||
| memcpy(ptr, src + chunks->offset, chunks->size); | |||
| } | |||
| return (ptr - dst); | |||
| } | |||
| int read_chunks(const void* src, int src_len, void* dst, | |||
| const nese_io_chunk* chunks, int n_chunks) { | |||
| const void* ptr = src; | |||
| for ( const void* end = src + src_len; | |||
| n_chunks > 0 && ptr < end; | |||
| ptr += chunks->size, --n_chunks, ++chunks) { | |||
| memcpy(dst + chunks->offset, ptr, chunks->size); | |||
| } | |||
| return (ptr - dst); | |||
| } | |||
| */ | |||
| @@ -14,5 +14,19 @@ int state_write(const nes*, void* mem, int size); | |||
| int load_state(nes*, const char* filename); | |||
| int save_state(const nes*, const char* filename); | |||
| /* | |||
| // Chunking | |||
| typedef struct { | |||
| int offset; | |||
| int size; | |||
| } nese_io_chunk; | |||
| int write_chunks(void* dst, int dst_len, const void* src, | |||
| const nese_io_chunk* chunks, int n_chunks); | |||
| int read_chunks(const void* src, int src_len, void* dst, | |||
| const nese_io_chunk* chunks, int n_chunks); | |||
| */ | |||
| #endif // NESE_SAVE_H_ | |||