# HG changeset patch # User Mike Pavone # Date 1369199339 25200 # Node ID 2f264d2a60c2d073692d52f88ad20330f7708cb4 # Parent 91aa2aa05e68038faa9bbc152d3431bbec75fc38 Support for SRAM with SEGA mapper. Half-finished support for SRAM without SEGA mapper. diff -r 91aa2aa05e68 -r 2f264d2a60c2 blastem.c --- 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; diff -r 91aa2aa05e68 -r 2f264d2a60c2 blastem.h --- a/blastem.h Tue May 21 19:26:20 2013 -0700 +++ b/blastem.h Tue May 21 22:08:59 2013 -0700 @@ -15,11 +15,19 @@ uint8_t input[3]; } io_port; +#define RAM_FLAG_ODD 0x1800 +#define RAM_FLAG_EVEN 0x1000 +#define RAM_FLAG_BOTH 0x0000 + typedef struct { m68k_context *m68k; z80_context *z80; vdp_context *vdp; ym2612_context *ym; + uint8_t *save_ram; + uint32_t save_ram_mask; + uint32_t save_flags; + uint8_t bank_regs[8]; } genesis_context; #define GAMEPAD_TH0 0 diff -r 91aa2aa05e68 -r 2f264d2a60c2 m68k_to_x86.c --- a/m68k_to_x86.c Tue May 21 19:26:20 2013 -0700 +++ b/m68k_to_x86.c Tue May 21 22:08:59 2013 -0700 @@ -4192,7 +4192,78 @@ default: cfun = NULL; } - if (cfun) { + if(memmap[chunk].buffer && memmap[chunk].flags & access_flag) { + if (memmap[chunk].flags & MMAP_PTR_IDX) { + if (memmap[chunk].flags & MMAP_FUNC_NULL) { + dst = cmp_irdisp8(dst, 0, CONTEXT, offsetof(m68k_context, mem_pointers) + sizeof(void*) * memmap[chunk].ptr_index, SZ_Q); + uint8_t * not_null = dst+1; + dst = jcc(dst, CC_NZ, dst+2); + dst = call(dst, (uint8_t *)m68k_save_context); + if (is_write) { + //SCRATCH2 is RDI, so no need to move it there + dst = mov_rr(dst, SCRATCH1, RDX, size); + } else { + dst = push_r(dst, CONTEXT); + dst = mov_rr(dst, SCRATCH1, RDI, SZ_D); + } + dst = call(dst, cfun); + if (is_write) { + dst = mov_rr(dst, RAX, CONTEXT, SZ_Q); + } else { + dst = pop_r(dst, CONTEXT); + dst = mov_rr(dst, RAX, SCRATCH1, size); + } + dst = jmp(dst, (uint8_t *)m68k_load_context); + + *not_null = dst - (not_null + 1); + } + if (size == SZ_B) { + dst = xor_ir(dst, 1, adr_reg, SZ_D); + } + dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, mem_pointers) + sizeof(void*) * memmap[chunk].ptr_index, adr_reg, SZ_Q); + if (is_write) { + dst = mov_rrind(dst, SCRATCH1, SCRATCH2, size); + + } else { + dst = mov_rindr(dst, SCRATCH1, SCRATCH1, size); + } + } else { + if (size == SZ_B) { + dst = xor_ir(dst, 1, adr_reg, SZ_D); + } + if ((int64_t)memmap[chunk].buffer <= 0x7FFFFFFF && (int64_t)memmap[chunk].buffer >= -2147483648) { + if (is_write) { + dst = mov_rrdisp32(dst, SCRATCH1, SCRATCH2, (int64_t)memmap[chunk].buffer, size); + } else { + dst = mov_rdisp32r(dst, SCRATCH1, (int64_t)memmap[chunk].buffer, SCRATCH1, size); + } + } else { + if (is_write) { + dst = push_r(dst, SCRATCH1); + dst = mov_ir(dst, (int64_t)memmap[chunk].buffer, SCRATCH1, SZ_Q); + dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_Q); + dst = pop_r(dst, SCRATCH1); + dst = mov_rrind(dst, SCRATCH1, SCRATCH2, size); + } else { + dst = mov_ir(dst, (int64_t)memmap[chunk].buffer, SCRATCH2, SZ_Q); + dst = mov_rindexr(dst, SCRATCH2, SCRATCH1, 1, SCRATCH1, size); + } + } + } + if (is_write && (memmap[chunk].flags & MMAP_CODE)) { + dst = mov_rr(dst, SCRATCH2, SCRATCH1, SZ_D); + dst = shr_ir(dst, 11, SCRATCH1, SZ_D); + dst = bt_rrdisp32(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, ram_code_flags), SZ_D); + uint8_t * not_code = dst+1; + dst = jcc(dst, CC_NC, dst+2); + dst = call(dst, (uint8_t *)m68k_save_context); + dst = call(dst, (uint8_t *)m68k_handle_code_write); + dst = mov_rr(dst, RAX, CONTEXT, SZ_Q); + dst = call(dst, (uint8_t *)m68k_load_context); + *not_code = dst - (not_code+1); + } + dst = retn(dst); + } else if (cfun) { dst = call(dst, (uint8_t *)m68k_save_context); if (is_write) { //SCRATCH2 is RDI, so no need to move it there @@ -4209,41 +4280,6 @@ dst = mov_rr(dst, RAX, SCRATCH1, size); } dst = jmp(dst, (uint8_t *)m68k_load_context); - } else if(memmap[chunk].buffer && memmap[chunk].flags & access_flag) { - if (size == SZ_B) { - dst = xor_ir(dst, 1, adr_reg, SZ_D); - } - if ((int64_t)memmap[chunk].buffer <= 0x7FFFFFFF && (int64_t)memmap[chunk].buffer >= -2147483648) { - if (is_write) { - dst = mov_rrdisp32(dst, SCRATCH1, SCRATCH2, (int64_t)memmap[chunk].buffer, size); - } else { - dst = mov_rdisp32r(dst, SCRATCH1, (int64_t)memmap[chunk].buffer, SCRATCH1, size); - } - } else { - if (is_write) { - dst = push_r(dst, SCRATCH1); - dst = mov_ir(dst, (int64_t)memmap[chunk].buffer, SCRATCH1, SZ_Q); - dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_Q); - dst = pop_r(dst, SCRATCH1); - dst = mov_rrind(dst, SCRATCH1, SCRATCH2, size); - } else { - dst = mov_ir(dst, (int64_t)memmap[chunk].buffer, SCRATCH2, SZ_Q); - dst = mov_rindexr(dst, SCRATCH2, SCRATCH1, 1, SCRATCH1, size); - } - } - if (is_write && (memmap[chunk].flags & MMAP_CODE)) { - dst = mov_rr(dst, SCRATCH2, SCRATCH1, SZ_D); - dst = shr_ir(dst, 11, SCRATCH1, SZ_D); - dst = bt_rrdisp32(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, ram_code_flags), SZ_D); - uint8_t * not_code = dst+1; - dst = jcc(dst, CC_NC, dst+2); - dst = call(dst, (uint8_t *)m68k_save_context); - dst = call(dst, (uint8_t *)m68k_handle_code_write); - dst = mov_rr(dst, RAX, CONTEXT, SZ_Q); - dst = call(dst, (uint8_t *)m68k_load_context); - *not_code = dst - (not_code+1); - } - dst = retn(dst); } else { //Not sure the best course of action here if (!is_write) { diff -r 91aa2aa05e68 -r 2f264d2a60c2 x86_backend.h --- a/x86_backend.h Tue May 21 19:26:20 2013 -0700 +++ b/x86_backend.h Tue May 21 22:08:59 2013 -0700 @@ -26,10 +26,13 @@ } deferred_addr; -#define MMAP_READ 0x1 -#define MMAP_WRITE 0x2 -#define MMAP_CODE 0x4 -#define MMAP_PTR_IDX 0x8 +#define MMAP_READ 0x01 +#define MMAP_WRITE 0x02 +#define MMAP_CODE 0x04 +#define MMAP_PTR_IDX 0x08 +#define MMAP_ONLY_ODD 0x10 +#define MMAP_ONLY_EVEN 0x20 +#define MMAP_FUNC_NULL 0x40 typedef uint16_t (*read_16_fun)(uint32_t address, void * context); typedef uint8_t (*read_8_fun)(uint32_t address, void * context);