# HG changeset patch # User Michael Pavone # Date 1482182898 28800 # Node ID 2eb54e24914e50eef7675f976badd91e65147967 # Parent d1eed3b1121c4315753226bb42626cc35a10a1b7 Mostly working changes to allow support for multiple emulated system types in main blastem program diff -r d1eed3b1121c -r 2eb54e24914e Makefile --- a/Makefile Wed Dec 14 23:27:42 2016 -0800 +++ b/Makefile Mon Dec 19 13:28:18 2016 -0800 @@ -125,7 +125,7 @@ AUDIOOBJS=ym2612.o psg.o wave.o CONFIGOBJS=config.o tern.o util.o -MAINOBJS=blastem.o genesis.o debug.o gdb_remote.o vdp.o render_sdl.o io.o romdb.o menu.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) +MAINOBJS=blastem.o system.o genesis.o debug.o gdb_remote.o vdp.o render_sdl.o io.o romdb.o menu.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) ifeq ($(CPU),x86_64) CFLAGS+=-DX86_64 -m64 diff -r d1eed3b1121c -r 2eb54e24914e blastem.c --- a/blastem.c Wed Dec 14 23:27:42 2016 -0800 +++ b/blastem.c Mon Dec 19 13:28:18 2016 -0800 @@ -8,6 +8,7 @@ #include #include +#include "system.h" #include "68kinst.h" #include "m68k_core.h" #include "z80_to_x86.h" @@ -66,7 +67,7 @@ return rom_size; } -int load_rom(char * filename, uint16_t **dst) +int load_rom(char * filename, uint16_t **dst, system_type *stype) { uint8_t header[10]; FILE * f = fopen(filename, "rb"); @@ -90,6 +91,9 @@ if (header[2]) { fatal_error("%s is a split SMD ROM which is not currently supported", filename); } + if (stype) { + *stype = SYSTEM_GENESIS; + } return load_smd_rom(filesize, f, dst); } } @@ -98,6 +102,9 @@ fatal_error("Error reading from %s\n", filename); } fclose(f); + if (stype) { + *stype = detect_system_type((uint8_t *)*dst, filesize); + } return filesize; } @@ -111,26 +118,17 @@ char * save_filename; -genesis_context *genesis; -genesis_context *menu_context; -genesis_context *game_context; +system_header *current_system; +system_header *menu_context; +system_header *game_context; void persist_save() { if (!game_context) { return; } - FILE * f = fopen(save_filename, "wb"); - if (!f) { - fprintf(stderr, "Failed to open %s file %s for writing\n", game_context->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); - return; - } - fwrite(game_context->save_storage, 1, game_context->save_size, f); - fclose(f); - printf("Saved %s to %s\n", game_context->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); + game_context->persist_save(game_context); } - - char *title; void update_title(char *rom_name) { @@ -142,8 +140,9 @@ render_update_caption(title); } -void setup_saves(char *fname, rom_info *info, genesis_context *context) +void setup_saves(char *fname, rom_info *info, system_header *context) { + static uint8_t persist_save_registered; char * barename = basename_no_extension(fname); char const * parts[3] = {get_save_dir(), PATH_SEP, barename}; char *save_dir = alloc_concat_m(3, parts); @@ -154,21 +153,18 @@ parts[2] = info->save_type == SAVE_I2C ? "save.eeprom" : "save.sram"; free(save_filename); save_filename = alloc_concat_m(3, parts); + //TODO: make quick save filename dependent on system type parts[2] = "quicksave.gst"; free(save_state_path); save_state_path = alloc_concat_m(3, parts); context->save_dir = save_dir; free(barename); if (info->save_type != SAVE_NONE) { - FILE * f = fopen(save_filename, "rb"); - if (f) { - uint32_t read = fread(context->save_storage, 1, info->save_size, f); - fclose(f); - if (read > 0) { - printf("Loaded %s from %s\n", info->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); - } + context->load_save(context); + if (!persist_save_registered) { + atexit(persist_save); + persist_save_registered = 1; } - atexit(persist_save); } } @@ -181,13 +177,15 @@ int debug = 0; int ym_log = 0; int loaded = 0; + system_type stype; uint8_t force_region = 0; char * romfname = NULL; FILE *address_log = NULL; char * statefile = NULL; int rom_size, lock_on_size; uint16_t *cart = NULL, *lock_on = NULL; - uint8_t * debuggerfun = NULL; + debugger_type dtype = DEBUGGER_NATIVE; + uint8_t start_in_debugger = 0; uint8_t fullscreen = FULLSCREEN_DEFAULT, use_gl = 1; uint8_t debug_target = 0; for (int i = 1; i < argc; i++) { @@ -202,7 +200,7 @@ exit_after = atoi(argv[i]); break; case 'd': - debuggerfun = (uint8_t *)debugger; + start_in_debugger = 1; //allow debugging the menu if (argv[i][2] == 'm') { debug_target = 1; @@ -210,7 +208,7 @@ break; case 'D': gdb_remote_init(); - debuggerfun = (uint8_t *)gdb_debug_enter; + dtype = DEBUGGER_GDB; break; case 'f': fullscreen = !fullscreen; @@ -256,7 +254,7 @@ if (i >= argc) { fatal_error("-o must be followed by a lock on cartridge filename\n"); } - lock_on_size = load_rom(argv[i], &lock_on); + lock_on_size = load_rom(argv[i], &lock_on, NULL); if (!lock_on_size) { fatal_error("Failed to load lock on cartridge %s\n", argv[i]); } @@ -283,7 +281,7 @@ fatal_error("Unrecognized switch %s\n", argv[i]); } } else if (!loaded) { - if (!(rom_size = load_rom(argv[i], &cart))) { + if (!(rom_size = load_rom(argv[i], &cart, &stype))) { fatal_error("Failed to open %s for reading\n", argv[i]); } romfname = argv[i]; @@ -302,7 +300,7 @@ romfname = "menu.bin"; } if (is_absolute_path(romfname)) { - if (!(rom_size = load_rom(romfname, &cart))) { + if (!(rom_size = load_rom(romfname, &cart, &stype))) { fatal_error("Failed to open UI ROM %s for reading", romfname); } } else { @@ -311,6 +309,7 @@ if (!cart) { fatal_error("Failed to open UI ROM %s for reading", romfname); } + stype = detect_system_type((uint8_t *)cart, fsize); rom_size = nearest_pow2(fsize); if (rom_size > fsize) { cart = realloc(cart, rom_size); @@ -341,43 +340,41 @@ rom_info info; uint32_t ym_opts = (ym_log && !menu) ? YM_OPT_WAVE_LOG : 0; - genesis = alloc_config_genesis(cart, rom_size, lock_on, lock_on_size, ym_opts, force_region, &info); - setup_saves(romfname, &info, genesis); + current_system = alloc_config_system(stype, cart, rom_size, lock_on, lock_on_size, ym_opts, force_region, &info); + setup_saves(romfname, &info, current_system); update_title(info.name); if (menu) { - menu_context = genesis; + menu_context = current_system; } else { - genesis->m68k->options->address_log = address_log; - game_context = genesis; + //TODO: make this an option flag + //genesis->m68k->options->address_log = address_log; + game_context = current_system; } - set_keybindings(genesis->ports); - start_genesis(genesis, menu ? NULL : statefile, menu == debug_target ? debuggerfun : NULL); + current_system->debugger_type = dtype; + current_system->enter_debugger = start_in_debugger && menu == debug_target; + current_system->start_context(current_system, menu ? NULL : statefile); for(;;) { - if (genesis->should_exit) { + if (current_system->should_exit) { break; } if (menu && menu_context->next_rom) { if (game_context) { - if (game_context->save_type != SAVE_NONE) { - genesis = game_context; - persist_save(); - genesis = menu_context; - } + game_context->persist_save(game_context); //swap to game context arena and mark all allocated pages in it free - genesis->arena = set_current_arena(game_context->arena); + current_system->arena = set_current_arena(game_context->arena); mark_all_free(); - free_genesis(game_context); + game_context->free_context(game_context); } else { //start a new arena and save old one in suspended genesis context - genesis->arena = start_new_arena(); + current_system->arena = start_new_arena(); } - if (!(rom_size = load_rom(menu_context->next_rom, &cart))) { + if (!(rom_size = load_rom(menu_context->next_rom, &cart, &stype))) { fatal_error("Failed to open %s for reading\n", menu_context->next_rom); } //allocate new genesis context - game_context = alloc_config_genesis(cart, rom_size, lock_on, lock_on_size, ym_opts,force_region, &info); + game_context = alloc_config_system(stype, cart, rom_size, lock_on, lock_on_size, ym_opts,force_region, &info); menu_context->next_context = game_context; game_context->next_context = menu_context; setup_saves(menu_context->next_rom, &info, game_context); @@ -385,22 +382,22 @@ free(menu_context->next_rom); menu_context->next_rom = NULL; menu = 0; - genesis = game_context; - genesis->m68k->options->address_log = address_log; - map_all_bindings(genesis->ports); - start_genesis(genesis, statefile, menu == debug_target ? debuggerfun : NULL); + current_system = game_context; + //TODO: make this an option flag + //genesis->m68k->options->address_log = address_log; + current_system->debugger_type = dtype; + current_system->enter_debugger = start_in_debugger && menu == debug_target; + current_system->start_context(current_system, statefile); } else if (menu && game_context) { - genesis->arena = set_current_arena(game_context->arena); - genesis = game_context; + current_system->arena = set_current_arena(game_context->arena); + current_system = game_context; menu = 0; - map_all_bindings(genesis->ports); - resume_68k(genesis->m68k); + current_system->resume_context(current_system); } else if (!menu && menu_context) { - genesis->arena = set_current_arena(menu_context->arena); - genesis = menu_context; + current_system->arena = set_current_arena(menu_context->arena); + current_system = menu_context; menu = 1; - map_all_bindings(genesis->ports); - resume_68k(genesis->m68k); + current_system->resume_context(current_system); } else { break; } diff -r d1eed3b1121c -r 2eb54e24914e blastem.h --- a/blastem.h Wed Dec 14 23:27:42 2016 -0800 +++ b/blastem.h Mon Dec 19 13:28:18 2016 -0800 @@ -2,6 +2,7 @@ #define BLASTEM_H_ #include "tern.h" +#include "system.h" extern int headless; extern int exit_after; @@ -9,8 +10,10 @@ extern int frame_limit; extern tern_node * config; +extern system_header *current_system; extern char *save_state_path; +extern char *save_filename; #define QUICK_SAVE_SLOT 10 #endif //BLASTEM_H_ diff -r d1eed3b1121c -r 2eb54e24914e debug.c --- a/debug.c Wed Dec 14 23:27:42 2016 -0800 +++ b/debug.c Mon Dec 19 13:28:18 2016 -0800 @@ -603,7 +603,7 @@ break; } value = strtol(param, NULL, 16); - insert_breakpoint(context, value, (uint8_t *)debugger); + insert_breakpoint(context, value, debugger); new_bp = malloc(sizeof(bp_def)); new_bp->next = breakpoints; new_bp->address = value; @@ -620,7 +620,7 @@ break; } value = strtol(param, NULL, 16); - insert_breakpoint(context, value, (uint8_t *)debugger); + insert_breakpoint(context, value, debugger); return 0; case 'd': if (input_buf[1] == 'i') { @@ -682,7 +682,7 @@ if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) { branch_f = after; branch_t = m68k_branch_target(&inst, context->dregs, context->aregs); - insert_breakpoint(context, branch_t, (uint8_t *)debugger); + insert_breakpoint(context, branch_t, debugger); } else if(inst.op == M68K_DBCC) { if ( inst.extra.cond == COND_FALSE) { if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) { @@ -691,13 +691,13 @@ } else { branch_t = after; branch_f = m68k_branch_target(&inst, context->dregs, context->aregs); - insert_breakpoint(context, branch_f, (uint8_t *)debugger); + insert_breakpoint(context, branch_f, debugger); } } else { after = m68k_branch_target(&inst, context->dregs, context->aregs); } } - insert_breakpoint(context, after, (uint8_t *)debugger); + insert_breakpoint(context, after, debugger); return 0; case 'o': if (inst.op == M68K_RTS) { @@ -711,7 +711,7 @@ branch_t = 0; } else { branch_f = after; - insert_breakpoint(context, branch_t, (uint8_t *)debugger); + insert_breakpoint(context, branch_t, debugger); } } else if(inst.op == M68K_DBCC) { uint32_t target = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; @@ -721,14 +721,14 @@ } else { branch_f = target; branch_t = after; - insert_breakpoint(context, branch_f, (uint8_t *)debugger); + insert_breakpoint(context, branch_f, debugger); } } } else { after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; } } - insert_breakpoint(context, after, (uint8_t *)debugger); + insert_breakpoint(context, after, debugger); return 0; case 's': if (inst.op == M68K_RTS) { @@ -739,16 +739,16 @@ if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) { branch_f = after; branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; - insert_breakpoint(context, branch_t, (uint8_t *)debugger); + insert_breakpoint(context, branch_t, debugger); } else if(inst.op == M68K_DBCC && inst.extra.cond != COND_FALSE) { branch_t = after; branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; - insert_breakpoint(context, branch_f, (uint8_t *)debugger); + insert_breakpoint(context, branch_f, debugger); } else { after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; } } - insert_breakpoint(context, after, (uint8_t *)debugger); + insert_breakpoint(context, after, debugger); return 0; case 'v': { genesis_context * gen = context->system; diff -r d1eed3b1121c -r 2eb54e24914e gdb_remote.c --- a/gdb_remote.c Wed Dec 14 23:27:42 2016 -0800 +++ b/gdb_remote.c Mon Dec 19 13:28:18 2016 -0800 @@ -216,16 +216,16 @@ if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) { branch_f = after; branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; - insert_breakpoint(context, branch_t, (uint8_t *)gdb_debug_enter); + insert_breakpoint(context, branch_t, gdb_debug_enter); } else if(inst.op == M68K_DBCC && inst.extra.cond != COND_FALSE) { branch_t = after; branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; - insert_breakpoint(context, branch_f, (uint8_t *)gdb_debug_enter); + insert_breakpoint(context, branch_f, gdb_debug_enter); } else { after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; } } - insert_breakpoint(context, after, (uint8_t *)gdb_debug_enter); + insert_breakpoint(context, after, gdb_debug_enter); cont = 1; expect_break_response = 1; @@ -243,7 +243,7 @@ uint8_t type = command[1]; if (type < '2') { uint32_t address = strtoul(command+3, NULL, 16); - insert_breakpoint(context, address, (uint8_t *)gdb_debug_enter); + insert_breakpoint(context, address, gdb_debug_enter); bp_def *new_bp = malloc(sizeof(bp_def)); new_bp->next = breakpoints; new_bp->address = address; @@ -433,16 +433,16 @@ if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) { branch_f = after; branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; - insert_breakpoint(context, branch_t, (uint8_t *)gdb_debug_enter); + insert_breakpoint(context, branch_t, gdb_debug_enter); } else if(inst.op == M68K_DBCC && inst.extra.cond != COND_FALSE) { branch_t = after; branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; - insert_breakpoint(context, branch_f, (uint8_t *)gdb_debug_enter); + insert_breakpoint(context, branch_f, gdb_debug_enter); } else { after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; } } - insert_breakpoint(context, after, (uint8_t *)gdb_debug_enter); + insert_breakpoint(context, after, gdb_debug_enter); cont = 1; expect_break_response = 1; diff -r d1eed3b1121c -r 2eb54e24914e genesis.c --- a/genesis.c Wed Dec 14 23:27:42 2016 -0800 +++ b/genesis.c Mon Dec 19 13:28:18 2016 -0800 @@ -9,6 +9,8 @@ #include "render.h" #include "gst.h" #include "util.h" +#include "debug.h" +#include "gdb_remote.h" #define MCLKS_NTSC 53693175 #define MCLKS_PAL 53203395 @@ -27,6 +29,7 @@ uint16_t read_dma_value(uint32_t address) { + genesis_context *genesis = (genesis_context *)current_system; //addresses here are word addresses (i.e. bit 0 corresponds to A1), so no need to do multiply by 2 uint16_t *ptr = get_native_pointer(address*2, (void **)genesis->m68k->mem_pointers, &genesis->m68k->options->gen); if (ptr) { @@ -38,6 +41,7 @@ uint16_t get_open_bus_value() { + genesis_context *genesis = (genesis_context *)current_system; return read_dma_value(genesis->m68k->last_prefetch_address/2); } @@ -173,9 +177,9 @@ } vdp_adjust_cycles(v_context, mclks); - io_adjust_cycles(gen->ports, context->current_cycle, mclks); - io_adjust_cycles(gen->ports+1, context->current_cycle, mclks); - io_adjust_cycles(gen->ports+2, context->current_cycle, mclks); + io_adjust_cycles(gen->io.ports, context->current_cycle, mclks); + io_adjust_cycles(gen->io.ports+1, context->current_cycle, mclks); + io_adjust_cycles(gen->io.ports+2, context->current_cycle, mclks); context->current_cycle -= mclks; z80_adjust_cycles(z_context, mclks); gen->ym->current_cycle -= mclks; @@ -192,18 +196,18 @@ vdp_int_ack(v_context); context->int_ack = 0; } - if (!address && (break_on_sync || gen->save_state)) { + if (!address && (gen->header.enter_debugger || gen->header.save_state)) { context->sync_cycle = context->current_cycle + 1; } adjust_int_cycle(context, v_context); if (address) { - if (break_on_sync) { - break_on_sync = 0; + if (gen->header.enter_debugger) { + gen->header.enter_debugger = 0; debugger(context, address); } - if (gen->save_state && (z_context->pc || (!z_context->reset && !z_context->busreq))) { - uint8_t slot = gen->save_state - 1; - gen->save_state = 0; + if (gen->header.save_state && (z_context->pc || (!z_context->reset && !z_context->busreq))) { + uint8_t slot = gen->header.save_state - 1; + gen->header.save_state = 0; //advance Z80 core to the start of an instruction while (!z_context->pc) { @@ -215,7 +219,7 @@ } else { char slotname[] = "slot_0.gst"; slotname[5] = '0' + slot; - char const *parts[] = {gen->save_dir, PATH_SEP, slotname}; + char const *parts[] = {gen->header.save_dir, PATH_SEP, slotname}; save_path = alloc_concat_m(3, parts); } save_gst(gen, save_path, address); @@ -223,7 +227,7 @@ if (slot != QUICK_SAVE_SLOT) { free(save_path); } - } else if(gen->save_state) { + } else if(gen->header.save_state) { context->sync_cycle = context->current_cycle + 1; } } @@ -486,22 +490,22 @@ switch(location/2) { case 0x1: - io_data_write(gen->ports, value, context->current_cycle); + io_data_write(gen->io.ports, value, context->current_cycle); break; case 0x2: - io_data_write(gen->ports+1, value, context->current_cycle); + io_data_write(gen->io.ports+1, value, context->current_cycle); break; case 0x3: - io_data_write(gen->ports+2, value, context->current_cycle); + io_data_write(gen->io.ports+2, value, context->current_cycle); break; case 0x4: - gen->ports[0].control = value; + gen->io.ports[0].control = value; break; case 0x5: - gen->ports[1].control = value; + gen->io.ports[1].control = value; break; case 0x6: - gen->ports[2].control = value; + gen->io.ports[2].control = value; break; } } else { @@ -597,22 +601,22 @@ value = gen->version_reg; break; case 0x1: - value = io_data_read(gen->ports, context->current_cycle); + value = io_data_read(gen->io.ports, context->current_cycle); break; case 0x2: - value = io_data_read(gen->ports+1, context->current_cycle); + value = io_data_read(gen->io.ports+1, context->current_cycle); break; case 0x3: - value = io_data_read(gen->ports+2, context->current_cycle); + value = io_data_read(gen->io.ports+2, context->current_cycle); break; case 0x4: - value = gen->ports[0].control; + value = gen->io.ports[0].control; break; case 0x5: - value = gen->ports[1].control; + value = gen->io.ports[1].control; break; case 0x6: - value = gen->ports[2].control; + value = gen->io.ports[2].control; break; default: value = 0xFF; @@ -737,8 +741,9 @@ return context; } -void set_speed_percent(genesis_context * context, uint32_t percent) +static void set_speed_percent(system_header * system, uint32_t percent) { + genesis_context *context = (genesis_context *)system; uint32_t old_clock = context->master_clock; context->master_clock = ((uint64_t)context->normal_clock * (uint64_t)percent) / 100; while (context->ym->current_cycle != context->psg->cycles) { @@ -774,6 +779,109 @@ gen->master_clock = gen->normal_clock; } +static void start_genesis(system_header *system, char *statefile) +{ + genesis_context *gen = (genesis_context *)system; + set_keybindings(&gen->io); + if (statefile) { + uint32_t pc = load_gst(gen, statefile); + if (!pc) { + fatal_error("Failed to load save state %s\n", statefile); + } + printf("Loaded %s\n", statefile); + if (gen->header.enter_debugger) { + gen->header.enter_debugger = 0; + insert_breakpoint(gen->m68k, pc, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter); + } + adjust_int_cycle(gen->m68k, gen->vdp); + start_68k_context(gen->m68k, pc); + } else { + if (gen->header.enter_debugger) { + gen->header.enter_debugger = 0; + uint32_t address = gen->cart[2] << 16 | gen->cart[3]; + insert_breakpoint(gen->m68k, address, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter); + } + m68k_reset(gen->m68k); + } +} + +static void resume_genesis(system_header *system) +{ + genesis_context *gen = (genesis_context *)system; + map_all_bindings(&gen->io); + resume_68k(gen->m68k); +} + +static void inc_debug_mode(system_header *system) +{ + genesis_context *gen = (genesis_context *)system; + gen->vdp->debug++; + if (gen->vdp->debug == 7) { + gen->vdp->debug = 0; + } +} + +static void inc_debug_pal(system_header *system) +{ + genesis_context *gen = (genesis_context *)system; + gen->vdp->debug_pal++; + if (gen->vdp->debug_pal == 4) { + gen->vdp->debug_pal = 0; + } +} + +static void request_exit(system_header *system) +{ + genesis_context *gen = (genesis_context *)system; + gen->m68k->should_return = 1; +} + +static void persist_save(system_header *system) +{ + genesis_context *gen = (genesis_context *)system; + if (gen->save_type == SAVE_NONE) { + return; + } + FILE * f = fopen(save_filename, "wb"); + if (!f) { + fprintf(stderr, "Failed to open %s file %s for writing\n", gen->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); + return; + } + fwrite(gen->save_storage, 1, gen->save_size, f); + fclose(f); + printf("Saved %s to %s\n", gen->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); +} + +static void load_save(system_header *system) +{ + genesis_context *gen = (genesis_context *)system; + FILE * f = fopen(save_filename, "rb"); + if (f) { + uint32_t read = fread(gen->save_storage, 1, gen->save_size, f); + fclose(f); + if (read > 0) { + printf("Loaded %s from %s\n", gen->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); + } + } +} + +static void free_genesis(system_header *system) +{ + genesis_context *gen = (genesis_context *)system; + vdp_free(gen->vdp); + m68k_options_free(gen->m68k->options); + free(gen->m68k); + free(gen->work_ram); + z80_options_free(gen->z80->options); + free(gen->z80); + free(gen->zram); + ym_free(gen->ym); + psg_free(gen->psg); + free(gen->save_storage); + free(gen->header.save_dir); + free(gen->lock_on); +} + genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t ym_opts, uint8_t force_region) { static memmap_chunk z80_map[] = { @@ -784,6 +892,15 @@ { 0x7F00, 0x8000, 0x00FF, 0, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} }; genesis_context *gen = calloc(1, sizeof(genesis_context)); + gen->header.set_speed_percent = set_speed_percent; + gen->header.start_context = start_genesis; + gen->header.resume_context = resume_genesis; + gen->header.load_save = load_save; + gen->header.persist_save = persist_save; + gen->header.free_context = free_genesis; + gen->header.request_exit = request_exit; + gen->header.inc_debug_mode = inc_debug_mode; + gen->header.inc_debug_pal = inc_debug_pal; set_region(gen, rom, force_region); gen->vdp = malloc(sizeof(vdp_context)); @@ -855,47 +972,6 @@ return gen; } - - -void free_genesis(genesis_context *gen) -{ - vdp_free(gen->vdp); - m68k_options_free(gen->m68k->options); - free(gen->m68k); - free(gen->work_ram); - z80_options_free(gen->z80->options); - free(gen->z80); - free(gen->zram); - ym_free(gen->ym); - psg_free(gen->psg); - free(gen->save_storage); - free(gen->save_dir); - free(gen->lock_on); -} - -void start_genesis(genesis_context *gen, char *statefile, uint8_t *debugger) -{ - - if (statefile) { - uint32_t pc = load_gst(gen, statefile); - if (!pc) { - fatal_error("Failed to load save state %s\n", statefile); - } - printf("Loaded %s\n", statefile); - if (debugger) { - insert_breakpoint(gen->m68k, pc, debugger); - } - adjust_int_cycle(gen->m68k, gen->vdp); - start_68k_context(gen->m68k, pc); - } else { - if (debugger) { - uint32_t address = gen->cart[2] << 16 | gen->cart[3]; - insert_breakpoint(gen->m68k, address, debugger); - } - m68k_reset(gen->m68k); - } -} - genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t ym_opts, uint8_t force_region, rom_info *info_out) { static memmap_chunk base_map[] = { diff -r d1eed3b1121c -r 2eb54e24914e genesis.h --- a/genesis.h Wed Dec 14 23:27:42 2016 -0800 +++ b/genesis.h Mon Dec 19 13:28:18 2016 -0800 @@ -7,6 +7,7 @@ #define GENESIS_H_ #include +#include "system.h" #include "m68k_core.h" #include "z80_to_x86.h" #include "ym2612.h" @@ -19,20 +20,17 @@ typedef struct genesis_context genesis_context; struct genesis_context { + system_header header; m68k_context *m68k; z80_context *z80; vdp_context *vdp; ym2612_context *ym; psg_context *psg; - genesis_context *next_context; uint16_t *cart; uint16_t *lock_on; uint16_t *work_ram; uint8_t *zram; void *extra; - arena *arena; - char *next_rom; - char *save_dir; uint8_t *save_storage; eeprom_map *eeprom_map; uint32_t num_eeprom; @@ -45,30 +43,19 @@ uint8_t bank_regs[8]; uint16_t mapper_start_index; uint8_t save_type; - io_port ports[3]; + sega_io io; uint8_t version_reg; uint8_t bus_busy; - uint8_t should_exit; - uint8_t save_state; - uint8_t mouse_mode; - uint8_t mouse_captured; eeprom_state eeprom; }; -extern genesis_context * genesis; -extern int break_on_sync; - #define RAM_WORDS 32 * 1024 #define Z80_RAM_BYTES 8 * 1024 uint16_t read_dma_value(uint32_t address); uint16_t get_open_bus_value(); m68k_context * sync_components(m68k_context *context, uint32_t address); -m68k_context * debugger(m68k_context * context, uint32_t address); -void set_speed_percent(genesis_context * context, uint32_t percent); genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t ym_opts, uint8_t force_region, rom_info *info_out); -void start_genesis(genesis_context *gen, char *statefile, uint8_t *debugger); -void free_genesis(genesis_context *gen); #endif //GENESIS_H_ diff -r d1eed3b1121c -r 2eb54e24914e gst.c --- a/gst.c Wed Dec 14 23:27:42 2016 -0800 +++ b/gst.c Mon Dec 19 13:28:18 2016 -0800 @@ -434,8 +434,8 @@ if (!z80_load_gst(gen->z80, gstfile)) { goto error_close; } - gen->ports[0].control = 0x40; - gen->ports[1].control = 0x40; + gen->io.ports[0].control = 0x40; + gen->io.ports[1].control = 0x40; fseek(gstfile, GST_68K_RAM, SEEK_SET); for (int i = 0; i < (32*1024);) { diff -r d1eed3b1121c -r 2eb54e24914e io.c --- a/io.c Wed Dec 14 23:27:42 2016 -0800 +++ b/io.c Mon Dec 19 13:28:18 2016 -0800 @@ -107,7 +107,8 @@ #define DEFAULT_JOYBUTTON_ALLOC 12 -static keybinding * bindings[0x10000]; +static sega_io *current_io; +static keybinding *bindings[0x10000]; static joystick joysticks[MAX_JOYSTICKS]; static mousebinding mice[MAX_MICE]; static io_port *keyboard_port; @@ -294,8 +295,8 @@ void handle_mousedown(int mouse, int button) { - if (genesis->mouse_mode == MOUSE_CAPTURE && !genesis->mouse_captured) { - genesis->mouse_captured = 1; + if (current_io->mouse_mode == MOUSE_CAPTURE && !current_io->mouse_captured) { + current_io->mouse_captured = 1; render_relative_mouse(1); return; } @@ -348,24 +349,16 @@ switch (binding->subtype_a) { case UI_DEBUG_MODE_INC: - ui_debug_mode++; - if (ui_debug_mode == 7) { - ui_debug_mode = 0; - } - genesis->vdp->debug = ui_debug_mode; + current_system->inc_debug_mode(current_system); break; case UI_DEBUG_PAL_INC: - ui_debug_pal++; - if (ui_debug_pal == 4) { - ui_debug_pal = 0; - } - genesis->vdp->debug_pal = ui_debug_pal; + current_system->inc_debug_pal(current_system); break; case UI_ENTER_DEBUGGER: - break_on_sync = 1; + current_system->enter_debugger = 1; break; case UI_SAVE_STATE: - genesis->save_state = QUICK_SAVE_SLOT+1; + current_system->save_state = QUICK_SAVE_SLOT+1; break; case UI_NEXT_SPEED: current_speed++; @@ -373,7 +366,7 @@ current_speed = 0; } printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]); - set_speed_percent(genesis, speeds[current_speed]); + current_system->set_speed_percent(current_system, speeds[current_speed]); break; case UI_PREV_SPEED: current_speed--; @@ -381,26 +374,27 @@ current_speed = num_speeds - 1; } printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]); - set_speed_percent(genesis, speeds[current_speed]); + current_system->set_speed_percent(current_system, speeds[current_speed]); break; case UI_SET_SPEED: if (binding->value < num_speeds) { current_speed = binding->value; printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]); - set_speed_percent(genesis, speeds[current_speed]); + current_system->set_speed_percent(current_system, speeds[current_speed]); } else { printf("Setting speed to %d\n", speeds[current_speed]); - set_speed_percent(genesis, binding->value); + current_system->set_speed_percent(current_system, speeds[current_speed]); } break; case UI_RELEASE_MOUSE: - if (genesis->mouse_captured) { - genesis->mouse_captured = 0; + if (current_io->mouse_captured) { + current_io->mouse_captured = 0; render_relative_mouse(0); } break; case UI_EXIT: - genesis->m68k->should_return = 1; + current_system->request_exit(current_system); + break; } break; } @@ -460,7 +454,7 @@ return; } //TODO: relative mode - switch(genesis->mouse_mode) + switch(current_io->mouse_mode) { case MOUSE_ABSOLUTE: { float scale_x = 640.0 / ((float)render_width()); @@ -476,7 +470,7 @@ break; } case MOUSE_CAPTURE: { - if (genesis->mouse_captured) { + if (current_io->mouse_captured) { mice[mouse].motion_port->device.mouse.cur_x += deltax; mice[mouse].motion_port->device.mouse.cur_y += deltay; } @@ -721,7 +715,8 @@ void setup_io_devices(tern_node * config, rom_info *rom, genesis_context *gen) { - io_port * ports = gen->ports; + current_io = &gen->io; + io_port * ports = current_io->ports; tern_node *io_nodes = tern_get_node(tern_find_path(config, "io\0devices\0")); char * io_1 = rom->port1_override ? rom->port1_override : tern_find_ptr(io_nodes, "1"); char * io_2 = rom->port2_override ? rom->port2_override : tern_find_ptr(io_nodes, "2"); @@ -732,13 +727,13 @@ process_device(io_ext, ports+2); if (render_fullscreen()) { - gen->mouse_mode = MOUSE_RELATIVE; + current_io->mouse_mode = MOUSE_RELATIVE; render_relative_mouse(1); } else { if (rom->mouse_mode && !strcmp(rom->mouse_mode, "absolute")) { - gen->mouse_mode = MOUSE_ABSOLUTE; + current_io->mouse_mode = MOUSE_ABSOLUTE; } else { - gen->mouse_mode = MOUSE_CAPTURE; + current_io->mouse_mode = MOUSE_CAPTURE; } } @@ -926,8 +921,15 @@ } } -void set_keybindings(io_port *ports) +void set_keybindings(sega_io *io) { + static uint8_t already_done; + if (already_done) { + map_all_bindings(io); + return; + } + already_done = 1; + io_port *ports = io->ports; tern_node * special = tern_insert_int(NULL, "up", RENDERKEY_UP); special = tern_insert_int(special, "down", RENDERKEY_DOWN); special = tern_insert_int(special, "left", RENDERKEY_LEFT); @@ -1067,11 +1069,14 @@ speeds[i] = 100; } } - map_all_bindings(ports); + map_all_bindings(io); } -void map_all_bindings(io_port *ports) +void map_all_bindings(sega_io *io) { + current_io = io; + io_port *ports = io->ports; + for (int bucket = 0; bucket < 0x10000; bucket++) { if (bindings[bucket]) @@ -1117,7 +1122,7 @@ } //not really related to the intention of this function, but the best place to do this currently if (speeds[0] != 100) { - set_speed_percent(genesis, speeds[0]); + current_system->set_speed_percent(current_system, speeds[0]); } } @@ -1133,7 +1138,7 @@ if (port->device.mouse.tr_counter == 3) { port->device.mouse.latched_x = port->device.mouse.cur_x; port->device.mouse.latched_y = port->device.mouse.cur_y; - if (genesis->mouse_mode == MOUSE_ABSOLUTE) { + if (current_io->mouse_mode == MOUSE_ABSOLUTE) { //avoid overflow in absolute mode int deltax = port->device.mouse.latched_x - port->device.mouse.last_read_x; if (abs(deltax) > 255) { diff -r d1eed3b1121c -r 2eb54e24914e io.h --- a/io.h Wed Dec 14 23:27:42 2016 -0800 +++ b/io.h Mon Dec 19 13:28:18 2016 -0800 @@ -59,6 +59,12 @@ uint8_t device_type; } io_port; +typedef struct { + io_port ports[3]; + uint8_t mouse_mode; + uint8_t mouse_captured; +} sega_io; + #define GAMEPAD_TH0 0 #define GAMEPAD_TH1 1 #define GAMEPAD_EXTRA 2 @@ -77,8 +83,8 @@ typedef struct genesis_context genesis_context; -void set_keybindings(io_port *ports); -void map_all_bindings(io_port *ports); +void set_keybindings(sega_io *io); +void map_all_bindings(sega_io *io); void setup_io_devices(tern_node * config, rom_info *rom, genesis_context * gen); void io_adjust_cycles(io_port * pad, uint32_t current_cycle, uint32_t deduction); void io_data_write(io_port * pad, uint8_t value, uint32_t current_cycle); diff -r d1eed3b1121c -r 2eb54e24914e m68k_core.h --- a/m68k_core.h Wed Dec 14 23:27:42 2016 -0800 +++ b/m68k_core.h Mon Dec 19 13:28:18 2016 -0800 @@ -72,6 +72,7 @@ } m68k_context; typedef m68k_context *(*m68k_reset_handler)(m68k_context *context); +typedef m68k_context *(*m68k_debug_handler)(m68k_context *context, uint32_t pc); void translate_m68k_stream(uint32_t address, m68k_context * context); void start_68k_context(m68k_context * context, uint32_t address); @@ -80,7 +81,7 @@ m68k_context * init_68k_context(m68k_options * opts, m68k_reset_handler reset_handler); void m68k_reset(m68k_context * context); void m68k_options_free(m68k_options *opts); -void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_handler); +void insert_breakpoint(m68k_context * context, uint32_t address, m68k_debug_handler bp_handler); void remove_breakpoint(m68k_context * context, uint32_t address); m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context); uint32_t get_instruction_start(m68k_options *opts, native_map_slot * native_code_map, uint32_t address); diff -r d1eed3b1121c -r 2eb54e24914e m68k_core_x86.c --- a/m68k_core_x86.c Wed Dec 14 23:27:42 2016 -0800 +++ b/m68k_core_x86.c Mon Dec 19 13:28:18 2016 -0800 @@ -2289,7 +2289,7 @@ return context; } -void insert_breakpoint(m68k_context * context, uint32_t address, code_ptr bp_handler) +void insert_breakpoint(m68k_context * context, uint32_t address, m68k_debug_handler bp_handler) { static code_ptr bp_stub = NULL; m68k_options * opts = context->options; @@ -2315,7 +2315,7 @@ //Save context and call breakpoint handler call(code, opts->gen.save_context); push_r(code, opts->gen.scratch1); - call_args_abi(code, bp_handler, 2, opts->gen.context_reg, opts->gen.scratch1); + call_args_abi(code, (code_ptr)bp_handler, 2, opts->gen.context_reg, opts->gen.scratch1); mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); //Restore context call(code, opts->gen.load_context); diff -r d1eed3b1121c -r 2eb54e24914e menu.c --- a/menu.c Wed Dec 14 23:27:42 2016 -0800 +++ b/menu.c Mon Dec 19 13:28:18 2016 -0800 @@ -269,7 +269,7 @@ char buf[4096]; copy_string_from_guest(m68k, dst, buf, sizeof(buf)); char const *pieces[] = {menu->curpath, PATH_SEP, buf}; - gen->next_rom = alloc_concat_m(3, pieces); + gen->header.next_rom = alloc_concat_m(3, pieces); m68k->should_return = 1; break; } @@ -278,7 +278,7 @@ { case 1: m68k->should_return = 1; - gen->should_exit = 1; + gen->header.should_exit = 1; break; case 2: m68k->should_return = 1; @@ -290,10 +290,10 @@ case 4: { char *buffer = malloc(SAVE_INFO_BUFFER_SIZE); char *cur = buffer; - if (gen->next_context && gen->next_context->save_dir) { + if (gen->header.next_context && gen->header.next_context->save_dir) { char *end = buffer + SAVE_INFO_BUFFER_SIZE; char slotfile[] = "slot_0.gst"; - char const * parts[3] = {gen->next_context->save_dir, PATH_SEP, slotfile}; + char const * parts[3] = {gen->header.next_context->save_dir, PATH_SEP, slotfile}; struct tm ltime; char *fname; time_t modtime; @@ -338,14 +338,14 @@ break; case 5: //save state - if (gen->next_context) { - gen->next_context->save_state = dst + 1; + if (gen->header.next_context) { + gen->header.next_context->save_state = dst + 1; } m68k->should_return = 1; break; case 6: //load state - if (gen->next_context && gen->next_context->save_dir) { + if (gen->header.next_context && gen->header.next_context->save_dir) { char numslotname[] = "slot_0.gst"; char *slotname; if (dst == QUICK_SAVE_SLOT) { @@ -354,14 +354,15 @@ numslotname[5] = '0' + dst; slotname = numslotname; } - char const *parts[] = {gen->next_context->save_dir, PATH_SEP, slotname}; + char const *parts[] = {gen->header.next_context->save_dir, PATH_SEP, slotname}; char *gstpath = alloc_concat_m(3, parts); - uint32_t pc = load_gst(gen->next_context, gstpath); + genesis_context *next = (genesis_context *)gen->header.next_context; + uint32_t pc = load_gst(next, gstpath); free(gstpath); if (!pc) { break; } - gen->next_context->m68k->resume_pc = get_native_address_trans(gen->next_context->m68k, pc); + next->m68k->resume_pc = get_native_address_trans(next->m68k, pc); } m68k->should_return = 1; break; diff -r d1eed3b1121c -r 2eb54e24914e system.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/system.c Mon Dec 19 13:28:18 2016 -0800 @@ -0,0 +1,33 @@ +#include +#include "system.h" +#include "genesis.h" + +system_type detect_system_type(uint8_t *rom, long filesize) +{ + if (filesize >= 0x104 && !memcmp("SEGA", rom + 0x100, 4)) { + //TODO: Differentiate between vanilla Genesis and Sega CD/32X games + return SYSTEM_GENESIS; + } + //TODO: Detect SMS and Jaguar ROMs here + + //More certain checks failed, look for a valid 68K reset vector + if (filesize >= 8) { + uint32_t reset = rom[4] << 24 | rom[5] << 16 | rom[6] << 8 | rom[7]; + if (!(reset & 1) && reset < filesize) { + //we have a valid looking reset vector, assume it's a Genesis ROM + return SYSTEM_GENESIS; + } + } + return SYSTEM_UNKNOWN; +} + +system_header *alloc_config_system(system_type stype, void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t opts, uint8_t force_region, rom_info *info_out) +{ + switch (stype) + { + case SYSTEM_GENESIS: + return &(alloc_config_genesis(rom, rom_size, lock_on, lock_on_size, opts, force_region, info_out))->header; + default: + return NULL; + } +} diff -r d1eed3b1121c -r 2eb54e24914e system.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/system.h Mon Dec 19 13:28:18 2016 -0800 @@ -0,0 +1,49 @@ +#ifndef SYSTEM_H_ +#define SYSTEM_H_ +#include +#include "arena.h" +#include "romdb.h" + +typedef struct system_header system_header; + +typedef enum { + SYSTEM_UNKNOWN, + SYSTEM_GENESIS, + SYSTEM_SMS, + SYSTEM_JAGUAR +} system_type; + +typedef enum { + DEBUGGER_NATIVE, + DEBUGGER_GDB +} debugger_type; + +typedef void (*system_fun)(system_header *); +typedef void (*start_system_fun)(system_header *, char *); +typedef void (*speed_system_fun)(system_header *, uint32_t); + +struct system_header { + system_header *next_context; + start_system_fun start_context; + system_fun resume_context; + system_fun load_save; + system_fun persist_save; + system_fun request_exit; + system_fun free_context; + speed_system_fun set_speed_percent; + system_fun inc_debug_mode; + system_fun inc_debug_pal; + arena *arena; + char *next_rom; + char *save_dir; + uint8_t enter_debugger; + uint8_t should_exit; + uint8_t save_state; + debugger_type debugger_type; + system_type type; +}; + +system_type detect_system_type(uint8_t *rom, long filesize); +system_header *alloc_config_system(system_type stype, void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t opts, uint8_t force_region, rom_info *info_out); + +#endif //SYSTEM_H_