Mercurial > repos > blastem
diff blastem.c @ 351:2f264d2a60c2
Support for SRAM with SEGA mapper. Half-finished support for SRAM without SEGA mapper.
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 21 May 2013 22:08:59 -0700 |
parents | aff29d50afd5 |
children | 15dd6418fe67 |
line wrap: on
line diff
--- a/blastem.c Tue May 21 19:26:20 2013 -0700 +++ b/blastem.c Tue May 21 22:08:59 2013 -0700 @@ -812,6 +812,127 @@ return ym_read_status(gen->ym); } +uint16_t read_sram_w(uint32_t address, m68k_context * context) +{ + genesis_context * gen = context->system; + address &= gen->save_ram_mask; + switch(gen->save_flags) + { + case RAM_FLAG_BOTH: + return gen->save_ram[address] << 8 | gen->save_ram[address+1]; + case RAM_FLAG_EVEN: + return gen->save_ram[address >> 1] << 8 | 0xFF; + case RAM_FLAG_ODD: + return gen->save_ram[address >> 1] | 0xFF00; + } + return 0xFFFF;//We should never get here +} + +uint8_t read_sram_b(uint32_t address, m68k_context * context) +{ + genesis_context * gen = context->system; + address &= gen->save_ram_mask; + switch(gen->save_flags) + { + case RAM_FLAG_BOTH: + return gen->save_ram[address]; + case RAM_FLAG_EVEN: + if (address & 1) { + return 0xFF; + } else { + return gen->save_ram[address >> 1]; + } + case RAM_FLAG_ODD: + if (address & 1) { + return gen->save_ram[address >> 1]; + } else { + return 0xFF; + } + } + return 0xFF;//We should never get here +} + +m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint16_t value) +{ + genesis_context * gen = context->system; + if ((gen->bank_regs[0] & 0x3) == 1) { + address &= gen->save_ram_mask; + switch(gen->save_flags) + { + case RAM_FLAG_BOTH: + gen->save_ram[address] = value >> 8; + gen->save_ram[address+1] = value; + break; + case RAM_FLAG_EVEN: + gen->save_ram[address >> 1] = value >> 8; + break; + case RAM_FLAG_ODD: + gen->save_ram[address >> 1] = value; + break; + } + } + return context; +} + +m68k_context * write_sram_area_b(uint32_t address, m68k_context * context, uint8_t value) +{ + genesis_context * gen = context->system; + if ((gen->bank_regs[0] & 0x3) == 1) { + address &= gen->save_ram_mask; + switch(gen->save_flags) + { + case RAM_FLAG_BOTH: + gen->save_ram[address] = value; + break; + case RAM_FLAG_EVEN: + if (!(address & 1)) { + gen->save_ram[address >> 1] = value; + } + break; + case RAM_FLAG_ODD: + if (address & 1) { + gen->save_ram[address >> 1] = value; + } + break; + } + } + return context; +} + +m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16_t value) +{ + genesis_context * gen = context->system; + address &= 0xE; + address >>= 1; + gen->bank_regs[address] = value; + if (!address) { + if (value & 1) { + context->mem_pointers[2] = NULL; + } else { + context->mem_pointers[2] = cart + 0x200000/2; + } + } + return context; +} + +m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_t value) +{ + if (address & 1) { + genesis_context * gen = context->system; + address &= 0xE; + address >>= 1; + gen->bank_regs[address] = value; + if (!address) { + if (value & 1) { + context->mem_pointers[2] = NULL; + } else { + context->mem_pointers[2] = cart + 0x200000/2; + } + } + } + return context; +} + typedef struct bp_def { struct bp_def * next; uint32_t address; @@ -1054,13 +1175,16 @@ return context; } -void init_run_cpu(genesis_context * gen, int debug, FILE * address_log) -{ - m68k_context context; - x86_68k_options opts; - gen->m68k = &context; - memmap_chunk memmap[] = { - {0, 0x400000, 0xFFFFFF, 0, MMAP_READ | MMAP_WRITE, cart, +#define ROM_END 0x1A4 +#define RAM_ID 0x1B0 +#define RAM_FLAGS 0x1B2 +#define RAM_START 0x1B4 +#define RAM_END 0x1B8 +#define MAX_MAP_CHUNKS (4+7+1) +#define RAM_FLAG_MASK 0x1800 + +const memmap_chunk static_map[] = { + {0, 0x400000, 0xFFFFFF, 0, MMAP_READ, cart, NULL, NULL, NULL, NULL}, {0xE00000, 0x1000000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, NULL, NULL, NULL, NULL}, @@ -1071,7 +1195,123 @@ (read_16_fun)io_read_w, (write_16_fun)io_write_w, (read_8_fun)io_read, (write_8_fun)io_write} }; - init_x86_68k_opts(&opts, memmap, sizeof(memmap)/sizeof(memmap_chunk)); + +char * sram_filename; +genesis_context * genesis; +void save_sram() +{ + FILE * f = fopen(sram_filename, "wb"); + if (!f) { + fprintf(stderr, "Failed to open SRAM file %s for writing\n", sram_filename); + return; + } + uint32_t size = genesis->save_ram_mask+1; + if (genesis->save_flags != RAM_FLAG_BOTH) { + size/= 2; + } + fwrite(genesis->save_ram, 1, size, f); + fclose(f); + printf("Saved SRAM to %s\n", sram_filename); +} + +void init_run_cpu(genesis_context * gen, int debug, FILE * address_log) +{ + m68k_context context; + x86_68k_options opts; + gen->m68k = &context; + memmap_chunk memmap[MAX_MAP_CHUNKS]; + uint32_t num_chunks; + void * initial_mapped = NULL; + gen->save_ram = NULL; + //TODO: Handle carts larger than 4MB + //TODO: Handle non-standard mappers + uint32_t size; + if ((cart[RAM_ID/2] & 0xFF) == 'A' && (cart[RAM_ID/2] >> 8) == 'R') { + //Cart has save RAM + uint32_t rom_end = ((cart[ROM_END/2] << 16) | cart[ROM_END/2+1]) + 1; + uint32_t ram_start = (cart[RAM_START/2] << 16) | cart[RAM_START/2+1]; + uint32_t ram_end = (cart[RAM_END/2] << 16) | cart[RAM_END/2+1]; + uint16_t ram_flags = cart[RAM_FLAGS/2]; + gen->save_flags = ram_flags & RAM_FLAG_MASK; + memset(memmap, 0, sizeof(memmap_chunk)*2); + if (ram_start >= rom_end) { + memmap[0].end = rom_end; + memmap[0].mask = 0xFFFFFF; + memmap[0].flags = MMAP_READ; + memmap[0].buffer = cart; + + ram_start &= 0xFFFFFE; + ram_end |= 1; + memmap[1].start = ram_start; + gen->save_ram_mask = memmap[1].mask = ram_end-ram_start; + ram_end += 1; + memmap[1].end = ram_end; + memmap[1].flags = MMAP_READ | MMAP_WRITE; + size = ram_end-ram_start; + if ((ram_flags & RAM_FLAG_MASK) == RAM_FLAG_ODD) { + memmap[1].flags |= MMAP_ONLY_ODD; + size /= 2; + } else if((ram_flags & RAM_FLAG_MASK) == RAM_FLAG_EVEN) { + memmap[1].flags |= MMAP_ONLY_EVEN; + size /= 2; + } + memmap[1].buffer = gen->save_ram = malloc(size); + + memcpy(memmap+2, static_map+1, sizeof(static_map)-sizeof(static_map[0])); + num_chunks = sizeof(static_map)/sizeof(memmap_chunk)+1; + } else { + //Assume the standard Sega mapper for now + memmap[0].end = 0x200000; + memmap[0].mask = 0xFFFFFF; + memmap[0].flags = MMAP_READ; + memmap[0].buffer = cart; + + memmap[1].start = 0x200000; + memmap[1].end = 0x400000; + memmap[1].mask = 0x1FFFFF; + ram_start &= 0xFFFFFE; + ram_end |= 1; + gen->save_ram_mask = ram_end-ram_start; + memmap[1].flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL; + memmap[1].ptr_index = 2; + memmap[1].read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL + memmap[1].read_8 = (read_8_fun)read_sram_b; + memmap[1].write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area + memmap[1].write_8 = (write_8_fun)write_sram_area_b; + memcpy(memmap+2, static_map+1, sizeof(static_map)-sizeof(static_map[0])); + num_chunks = sizeof(static_map)/sizeof(memmap_chunk)+1; + memset(memmap+num_chunks, 0, sizeof(memmap[num_chunks])); + memmap[num_chunks].start = 0xA13000; + memmap[num_chunks].end = 0xA13100; + memmap[num_chunks].mask = 0xFF; + memmap[num_chunks].write_16 = (write_16_fun)write_bank_reg_w; + memmap[num_chunks].write_8 = (write_8_fun)write_bank_reg_b; + num_chunks++; + ram_end++; + size = ram_end-ram_start; + if ((ram_flags & RAM_FLAG_MASK) != RAM_FLAG_BOTH) { + size /= 2; + } + gen->save_ram = malloc(size); + memmap[1].buffer = initial_mapped = cart + 0x200000/2; + } + } else { + memcpy(memmap, static_map, sizeof(static_map)); + num_chunks = sizeof(static_map)/sizeof(memmap_chunk); + } + if (gen->save_ram) { + memset(gen->save_ram, 0, size); + FILE * f = fopen(sram_filename, "rb"); + if (f) { + uint32_t read = fread(gen->save_ram, 1, size, f); + fclose(f); + if (read > 0) { + printf("Loaded SRAM from %s\n", sram_filename); + } + } + atexit(save_sram); + } + init_x86_68k_opts(&opts, memmap, num_chunks); opts.address_log = address_log; init_68k_context(&context, opts.native_code_map, &opts); @@ -1082,13 +1322,10 @@ context.target_cycle = context.sync_cycle = mclks_per_frame/MCLKS_PER_68K; //work RAM context.mem_pointers[1] = ram; + //save RAM/map + context.mem_pointers[2] = initial_mapped; + context.mem_pointers[3] = (uint16_t *)gen->save_ram; uint32_t address; - /*address = cart[0x68/2] << 16 | cart[0x6A/2]; - translate_m68k_stream(address, &context); - address = cart[0x70/2] << 16 | cart[0x72/2]; - translate_m68k_stream(address, &context); - address = cart[0x78/2] << 16 | cart[0x7A/2]; - translate_m68k_stream(address, &context);*/ address = cart[2] << 16 | cart[3]; translate_m68k_stream(address, &context); if (debug) { @@ -1249,6 +1486,21 @@ gen.z80 = &z_context; gen.vdp = &v_context; gen.ym = &y_context; + genesis = &gen; + + int fname_size = strlen(argv[1]); + sram_filename = malloc(fname_size+6); + memcpy(sram_filename, argv[1], fname_size); + int i; + for (i = fname_size-1; fname_size >= 0; --i) { + if (sram_filename[i] == '.') { + strcpy(sram_filename + i + 1, "sram"); + break; + } + } + if (i < 0) { + strcpy(sram_filename + fname_size, ".sram"); + } init_run_cpu(&gen, debug, address_log); return 0;