# HG changeset patch # User Michael Pavone # Date 1628232521 25200 # Node ID 804954731e3f92fe36a71d9d741ac787a1f730f6 # Parent 3142602d21d81deb950b6c8c41c8505a6edbc877 Add cycle checks to deal with 68K core differences to the new refresh emulation blocks merged from default diff -r 3142602d21d8 -r 804954731e3f genesis.c --- a/genesis.c Thu Aug 05 09:43:29 2021 -0700 +++ b/genesis.c Thu Aug 05 23:48:41 2021 -0700 @@ -38,7 +38,7 @@ #ifdef IS_LIB #define MAX_SOUND_CYCLES (MCLKS_PER_YM*NUM_OPERATORS*6*4) #else -#define MAX_SOUND_CYCLES 100000 +#define MAX_SOUND_CYCLES 100000 #endif #ifdef NEW_CORE @@ -57,53 +57,53 @@ start_section(buf, SECTION_68000); m68k_serialize(gen->m68k, m68k_pc, buf); end_section(buf); - + start_section(buf, SECTION_Z80); z80_serialize(gen->z80, buf); end_section(buf); } - + start_section(buf, SECTION_VDP); vdp_serialize(gen->vdp, buf); end_section(buf); - + start_section(buf, SECTION_YM2612); ym_serialize(gen->ym, buf); end_section(buf); - + start_section(buf, SECTION_PSG); psg_serialize(gen->psg, buf); end_section(buf); - + if (all) { start_section(buf, SECTION_GEN_BUS_ARBITER); save_int8(buf, gen->z80->reset); save_int8(buf, gen->z80->busreq); save_int16(buf, gen->z80_bank_reg); end_section(buf); - + start_section(buf, SECTION_SEGA_IO_1); io_serialize(gen->io.ports, buf); end_section(buf); - + start_section(buf, SECTION_SEGA_IO_2); io_serialize(gen->io.ports + 1, buf); end_section(buf); - + start_section(buf, SECTION_SEGA_IO_EXT); io_serialize(gen->io.ports + 2, buf); end_section(buf); - + start_section(buf, SECTION_MAIN_RAM); save_int8(buf, RAM_WORDS * 2 / 1024); save_buffer16(buf, gen->work_ram, RAM_WORDS); end_section(buf); - + start_section(buf, SECTION_SOUND_RAM); save_int8(buf, Z80_RAM_BYTES / 1024); save_buffer8(buf, gen->zram, Z80_RAM_BYTES); end_section(buf); - + if (gen->version_reg & 0xF) { //only save TMSS info if it's present //that will allow a state saved on a model lacking TMSS @@ -113,7 +113,7 @@ save_buffer16(buf, gen->tmss_lock, 2); end_section(buf); } - + cart_serialize(&gen->header, buf); } } @@ -253,7 +253,7 @@ if ((address >= 0xA00000 && address < 0xB00000) || (address >= 0xC00000 && address <= 0xE00000)) { return 0; } - + //addresses here are word addresses (i.e. bit 0 corresponds to A1), so no need to do multiply by 2 return read_word(address * 2, (void **)genesis->m68k->mem_pointers, &genesis->m68k->options->gen, genesis->m68k); } @@ -298,7 +298,7 @@ uint32_t next_eint_port0 = io_next_interrupt(gen->io.ports, context->current_cycle); uint32_t next_eint_port1 = io_next_interrupt(gen->io.ports + 1, context->current_cycle); uint32_t next_eint_port2 = io_next_interrupt(gen->io.ports + 2, context->current_cycle); - uint32_t next_eint = next_eint_port0 < next_eint_port1 + uint32_t next_eint = next_eint_port0 < next_eint_port1 ? (next_eint_port0 < next_eint_port2 ? next_eint_port0 : next_eint_port2) : (next_eint_port1 < next_eint_port2 ? next_eint_port1 : next_eint_port2); if (next_eint != CYCLE_NEVER) { @@ -318,7 +318,7 @@ printf("int cycle changed to: %d, level: %d @ %d(%d), frame: %d, vcounter: %d, hslot: %d, mask: %d, hint_counter: %d\n", context->int_cycle, context->int_num, v_context->cycles, context->current_cycle, v_context->frame, v_context->vcounter, v_context->hslot, context->status & 0x7, v_context->hint_counter); old_int_cycle = context->int_cycle; }*/ - + if (context->status & M68K_STATUS_TRACE || context->trace_pending) { context->target_cycle = context->current_cycle; return; @@ -343,7 +343,7 @@ } else { context->target_cycle = context->sync_cycle = context->current_cycle; } - + } /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), @@ -628,7 +628,7 @@ gen->bus_busy = 0; } } - + if (blocked < 0) { blocked = vdp_control_port_write(v_context, value); } else { @@ -819,10 +819,12 @@ genesis_context * gen = context->system; #ifdef REFRESH_EMULATION //do refresh check here so we can avoid adding a penalty for a refresh that happens during an IO area access + if (context->current_cycle - 4*MCLKS_PER_68K > last_sync_cycle) { refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle; context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); last_sync_cycle = context->current_cycle - 4*MCLKS_PER_68K; + } #endif if (location < 0x10000) { //Access to Z80 memory incurs a one 68K cycle wait state @@ -979,10 +981,12 @@ genesis_context *gen = context->system; #ifdef REFRESH_EMULATION //do refresh check here so we can avoid adding a penalty for a refresh that happens during an IO area access + if (context->current_cycle - 4*MCLKS_PER_68K > last_sync_cycle) { refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle; context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); last_sync_cycle = context->current_cycle - 4*MCLKS_PER_68K; + } #endif if (location < 0x10000) { //Access to Z80 memory incurs a one 68K cycle wait state @@ -1328,7 +1332,7 @@ } else { gen->version_reg = NO_DISK | USA; } - + if (region & HZ50) { gen->normal_clock = MCLKS_PAL; gen->soft_flush_cycles = MCLKS_LINE * 262 / 3 + 2; @@ -1612,7 +1616,7 @@ render_audio_source_gaindb(gen->psg->audio, config_gain ? atof(config_gain) : 0.0f); config_gain = tern_find_path(config, "audio\0fm_gain\0", TVAL_PTR).ptrval; render_audio_source_gaindb(gen->ym->audio, config_gain ? atof(config_gain) : 0.0f); - + char *config_dac = tern_find_path_default(config, "audio\0fm_dac\0", (tern_val){.ptrval="zero_offset"}, TVAL_PTR).ptrval; ym_enable_zero_offset(gen->ym, !strcmp(config_dac, "zero_offset")); } @@ -1655,7 +1659,7 @@ if (gen->tmss) { return gen->tmss_write_16(address, context, value); } - + return context; } @@ -1666,7 +1670,7 @@ if (gen->tmss) { return gen->tmss_write_8(address, context, value); } - + return context; } @@ -1704,7 +1708,7 @@ *dest = value; m68k_handle_code_write(address, m68k); } - + return context; } @@ -1722,7 +1726,7 @@ #endif m68k_handle_code_write(address & ~1, m68k); } - + return context; } @@ -1831,10 +1835,10 @@ gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL; gen->int_latency_prev1 = MCLKS_PER_68K * 32; gen->int_latency_prev2 = MCLKS_PER_68K * 16; - + render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC); event_system_start(SYSTEM_GENESIS, (gen->version_reg & HZ50) ? VID_PAL : VID_NTSC, rom->name); - + gen->ym = malloc(sizeof(ym2612_context)); char *fm = tern_find_ptr_default(model, "fm", "discrete 2612"); if (!strcmp(fm + strlen(fm) -4, "3834")) { @@ -1844,7 +1848,7 @@ gen->psg = malloc(sizeof(psg_context)); psg_init(gen->psg, gen->master_clock, MCLKS_PER_PSG); - + set_audio_config(gen); z80_map[0].buffer = gen->zram = calloc(1, Z80_RAM_BYTES); @@ -1915,9 +1919,9 @@ } else { gen->save_storage = NULL; } - + gen->mapper_start_index = rom->mapper_start_index; - + //This must happen before we generate memory access functions in init_m68k_opts uint8_t next_ptr_index = 0; uint32_t tmss_min_alloc = 16 * 1024; @@ -2065,7 +2069,7 @@ gen->m68k = init_68k_context(opts, NULL); gen->m68k->system = gen; opts->address_log = (system_opts & OPT_ADDRESS_LOG) ? fopen("address.log", "w") : NULL; - + //This must happen after the 68K context has been allocated for (int i = 0; i < rom->map_chunks; i++) { @@ -2073,7 +2077,7 @@ gen->m68k->mem_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; } } - + if (gen->mapper_type == MAPPER_SEGA) { //initialize bank registers for (int i = 1; i < sizeof(gen->bank_regs); i++)