# HG changeset patch # User Michael Pavone # Date 1420338184 28800 # Node ID 5439ae7946ca25881554a290fcecdb614bdc9182 # Parent 30ccf56842d66acd339fc290e205fb8dc0a51108 Made the Z80 core more contained by refactoring some code in blastem.c into z80_to_x86.c diff -r 30ccf56842d6 -r 5439ae7946ca backend.h --- a/backend.h Sat Jan 03 16:08:23 2015 -0800 +++ b/backend.h Sat Jan 03 18:23:04 2015 -0800 @@ -12,6 +12,7 @@ #define INVALID_OFFSET 0xFFFFFFFF #define EXTENSION_WORD 0xFFFFFFFE +#define CYCLE_NEVER 0xFFFFFFFF #if defined(X86_32) || defined(X86_64) typedef struct { diff -r 30ccf56842d6 -r 5439ae7946ca blastem.c --- a/blastem.c Sat Jan 03 16:08:23 2015 -0800 +++ b/blastem.c Sat Jan 03 18:23:04 2015 -0800 @@ -155,12 +155,6 @@ int break_on_sync = 0; int save_state = 0; -uint8_t reset = 1; -uint8_t need_reset = 0; -uint8_t busreq = 0; -uint8_t busack = 0; -uint32_t busack_cycle = CYCLE_NEVER; -uint8_t new_busack = 0; //#define DO_DEBUG_PRINT #ifdef DO_DEBUG_PRINT #define dprintf printf @@ -172,34 +166,18 @@ #define Z80_VINT_DURATION 128 +void z80_next_int_pulse(z80_context * z_context) +{ + genesis_context * gen = z_context->system; + z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp); + z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION; +} + void sync_z80(z80_context * z_context, uint32_t mclks) { #ifndef NO_Z80 - if (z80_enabled && !reset && !busreq) { - genesis_context * gen = z_context->system; - z_context->sync_cycle = mclks; - if (z_context->current_cycle < z_context->sync_cycle) { - if (need_reset) { - z80_reset(z_context); - need_reset = 0; - } - - while (z_context->current_cycle < z_context->sync_cycle) { - if (z_context->int_pulse_end < z_context->current_cycle || z_context->int_pulse_end == CYCLE_NEVER) { - z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp); - z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION; - } - if (z_context->iff1) { - z_context->int_cycle = z_context->int_pulse_start < z_context->int_enable_cycle ? z_context->int_enable_cycle : z_context->int_pulse_start; - } else { - z_context->int_cycle = CYCLE_NEVER; - } - z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle; - dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d\n", z_context->current_cycle, z_context->sync_cycle, z_context->int_cycle); - z_context->run(z_context); - dprintf("Z80 ran to cycle %d\n", z_context->current_cycle); - } - } + if (z80_enabled) { + z80_run(z_context, mclks); } else #endif { @@ -256,45 +234,8 @@ io_adjust_cycles(gen->ports, context->current_cycle, mclk_target); io_adjust_cycles(gen->ports+1, context->current_cycle, mclk_target); io_adjust_cycles(gen->ports+2, context->current_cycle, mclk_target); - if (busack_cycle != CYCLE_NEVER) { - if (busack_cycle > mclk_target) { - busack_cycle -= mclk_target; - } else { - busack_cycle = CYCLE_NEVER; - busack = new_busack; - } - } context->current_cycle -= mclk_target; - if (z_context->current_cycle >= mclk_target) { - z_context->current_cycle -= mclk_target; - } else { - z_context->current_cycle = 0; - } - if (z_context->int_cycle != CYCLE_NEVER) { - if (z_context->int_cycle >= mclk_target) { - z_context->int_cycle -= mclk_target; - } else { - z_context->int_cycle = 0; - } - } - if (z_context->int_pulse_start != CYCLE_NEVER) { - if (z_context->int_pulse_end >= mclk_target) { - z_context->int_pulse_end -= mclk_target; - if (z_context->int_pulse_start >= mclk_target) { - z_context->int_pulse_start -= mclk_target; - } else { - z_context->int_pulse_start = 0; - } - } - } else { - z_context->int_pulse_start = CYCLE_NEVER; - z_context->int_pulse_end = CYCLE_NEVER; - } - if (z_context->int_enable_cycle >= mclk_target) { - z_context->int_enable_cycle -= mclk_target; - } else { - z_context->int_enable_cycle = 0; - } + z80_adjust_cycles(z_context, mclk_target); if (mclks) { vdp_run_context(v_context, mclks); } @@ -458,7 +399,7 @@ value = vdp_hv_counter_read(v_context); //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles); } - } else if (vdp_port < 0x18){ + } else if (vdp_port < 0x18) { printf("Illegal read from PSG port %X\n", vdp_port); exit(1); } else { @@ -520,11 +461,7 @@ { genesis_context * gen = context->system; if (location < 0x10000) { - if (busack_cycle <= context->current_cycle) { - busack = new_busack; - busack_cycle = CYCLE_NEVER; - } - if (!(busack || reset)) { + if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) { location &= 0x7FFF; if (location < 0x4000) { z80_ram[location & 0x1FFF] = value; @@ -578,54 +515,40 @@ } } else { if (location == 0x1100) { - if (busack_cycle <= context->current_cycle) { - busack = new_busack; - busack_cycle = CYCLE_NEVER; - } if (value & 1) { dputs("bus requesting Z80"); - - if(!reset && !busreq) { - sync_z80(gen->z80, context->current_cycle + Z80_ACK_DELAY*MCLKS_PER_Z80); - busack_cycle = gen->z80->current_cycle;//context->current_cycle + Z80_ACK_DELAY; - new_busack = Z80_REQ_ACK; + if (z80_enabled) { + z80_assert_busreq(gen->z80, context->current_cycle); } - busreq = 1; } else { - sync_z80(gen->z80, context->current_cycle); - if (busreq) { + if (gen->z80->busreq) { dputs("releasing z80 bus"); - #ifdef DO_DEBUG_PRINT +#ifdef DO_DEBUG_PRINT char fname[20]; sprintf(fname, "zram-%d", zram_counter++); FILE * f = fopen(fname, "wb"); fwrite(z80_ram, 1, sizeof(z80_ram), f); fclose(f); - #endif - busack_cycle = gen->z80->current_cycle + Z80_BUSY_DELAY; - new_busack = Z80_REQ_BUSY; - busreq = 0; +#endif } - //busack_cycle = CYCLE_NEVER; - //busack = Z80_REQ_BUSY; - + if (z80_enabled) { + z80_clear_busreq(gen->z80, context->current_cycle); + } } } else if (location == 0x1200) { sync_z80(gen->z80, context->current_cycle); if (value & 1) { - if (reset && busreq) { - new_busack = 0; - busack_cycle = gen->z80->current_cycle + Z80_ACK_DELAY;//context->current_cycle + Z80_ACK_DELAY; + if (z80_enabled) { + z80_clear_reset(gen->z80, context->current_cycle); + } else { + gen->z80->reset = 0; } - //TODO: Deal with the scenario in which reset is not asserted long enough - if (reset) { - need_reset = 1; - //TODO: Add necessary delay between release of reset and start of execution - gen->z80->current_cycle = context->current_cycle + 16 * MCLKS_PER_Z80; + } else { + if (z80_enabled) { + z80_assert_reset(gen->z80, context->current_cycle); + } else { + gen->z80->reset = 1; } - reset = 0; - } else { - reset = 1; } } } @@ -653,11 +576,7 @@ uint8_t value; genesis_context *gen = context->system; if (location < 0x10000) { - if (busack_cycle <= context->current_cycle) { - busack = new_busack; - busack_cycle = CYCLE_NEVER; - } - if (!(busack==Z80_REQ_BUSY || reset)) { + if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) { location &= 0x7FFF; if (location < 0x4000) { value = z80_ram[location & 0x1FFF]; @@ -702,14 +621,10 @@ } } else { if (location == 0x1100) { - if (busack_cycle <= context->current_cycle) { - busack = new_busack; - busack_cycle = CYCLE_NEVER; - } - value = Z80_RES_BUSACK || busack; - dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d, busack: %d, busack_cycle %d)\n", value, context->current_cycle, reset, busack, busack_cycle); + value = z80_enabled ? !z80_get_busack(gen->z80, context->current_cycle) : 0; + dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d)\n", value, context->current_cycle, gen->z80->reset); } else if (location == 0x1200) { - value = !reset; + value = !gen->z80->reset; } else { value = 0xFF; printf("Byte read of unknown IO location: %X\n", location); @@ -1105,9 +1020,6 @@ insert_breakpoint(&context, pc, debugger); } adjust_int_cycle(gen->m68k, gen->vdp); -#ifndef NO_Z80 - gen->z80->native_pc = z80_get_native_address_trans(gen->z80, gen->z80->pc); -#endif start_68k_context(&context, pc); } else { if (debugger) { @@ -1364,6 +1276,7 @@ z80_options z_opts; init_z80_opts(&z_opts, z80_map, 5, MCLKS_PER_Z80); init_z80_context(&z_context, &z_opts); + z80_assert_reset(&z_context, 0); #endif z_context.system = &gen; diff -r 30ccf56842d6 -r 5439ae7946ca blastem.h --- a/blastem.h Sat Jan 03 16:08:23 2015 -0800 +++ b/blastem.h Sat Jan 03 18:23:04 2015 -0800 @@ -19,8 +19,6 @@ #define RAM_FLAG_EVEN 0x1000 #define RAM_FLAG_BOTH 0x0000 -#define CYCLE_NEVER 0xFFFFFFFF - typedef struct { m68k_context *m68k; z80_context *z80; @@ -42,8 +40,6 @@ extern int break_on_sync; extern int save_state; extern tern_node * config; -extern uint8_t busreq; -extern uint8_t reset; #define CARTRIDGE_WORDS 0x200000 #define RAM_WORDS 32 * 1024 diff -r 30ccf56842d6 -r 5439ae7946ca gst.c --- a/gst.c Sat Jan 03 16:08:23 2015 -0800 +++ b/gst.c Sat Jan 03 18:23:04 2015 -0800 @@ -1,6 +1,6 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #include "gst.h" @@ -207,8 +207,8 @@ curpos += 2; context->iff1 = context->iff2 = *curpos; curpos += 2; - reset = !*(curpos++); - busreq = *curpos; + context->reset = !*(curpos++); + context->busreq = *curpos; curpos += 3; uint32_t bank = read_le_32(curpos); if (bank < 0x400000) { @@ -350,8 +350,8 @@ curpos += 2; *curpos = context->iff1; curpos += 2; - *(curpos++) = !reset; - *curpos = busreq; + *(curpos++) = !context->reset; + *curpos = context->busreq; curpos += 3; uint32_t bank = context->bank_reg << 15; write_le_32(curpos, bank); diff -r 30ccf56842d6 -r 5439ae7946ca z80_to_x86.c --- a/z80_to_x86.c Sat Jan 03 16:08:23 2015 -0800 +++ b/z80_to_x86.c Sat Jan 03 18:23:04 2015 -0800 @@ -1777,7 +1777,7 @@ code_ptr dst = z80_get_native_address(context, inst_start); code_info code = {dst, dst+16}; z80_options * opts = context->options; - dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code, inst_start, address); + dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code.cur, inst_start, address); mov_ir(&code, inst_start, opts->gen.scratch1, SZ_D); call(&code, opts->retrans_stub); } @@ -2226,18 +2226,112 @@ context->banked_code_map = malloc(sizeof(native_map_slot)); memset(context->banked_code_map, 0, sizeof(native_map_slot)); context->options = options; - context->int_cycle = 0xFFFFFFFF; - context->int_pulse_start = 0xFFFFFFFF; - context->int_pulse_end = 0xFFFFFFFF; - context->run = options->run; + context->int_cycle = CYCLE_NEVER; + context->int_pulse_start = CYCLE_NEVER; + context->int_pulse_end = CYCLE_NEVER; +} + +void z80_run(z80_context * context, uint32_t target_cycle) +{ + if (context->reset || context->busack) { + context->current_cycle = target_cycle; + } else { + if (context->current_cycle < target_cycle) { + //busreq is sampled at the end of an m-cycle + //we can approximate that by running for a single m-cycle after a bus request + context->sync_cycle = context->busreq ? context->current_cycle + 3*context->options->gen.clock_divider : target_cycle; + if (!context->native_pc) { + context->native_pc = z80_get_native_address_trans(context, context->pc); + } + while (context->current_cycle < context->sync_cycle) + { + if (context->int_pulse_end < context->current_cycle || context->int_pulse_end == CYCLE_NEVER) { + z80_next_int_pulse(context); + } + if (context->iff1) { + context->int_cycle = context->int_pulse_start < context->int_enable_cycle ? context->int_enable_cycle : context->int_pulse_start; + } else { + context->int_cycle = CYCLE_NEVER; + } + context->target_cycle = context->sync_cycle < context->int_cycle ? context->sync_cycle : context->int_cycle; + dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d\n", context->current_cycle, context->sync_cycle, context->int_cycle); + context->options->run(context); + dprintf("Z80 ran to cycle %d\n", context->current_cycle); + } + if (context->busreq) { + context->busack = 1; + context->current_cycle = target_cycle; + } + } + } +} + +void z80_assert_reset(z80_context * context, uint32_t cycle) +{ + z80_run(context, cycle); + context->reset = 1; } -void z80_reset(z80_context * context) +void z80_clear_reset(z80_context * context, uint32_t cycle) +{ + z80_run(context, cycle); + if (context->reset) { + //TODO: Handle case where reset is not asserted long enough + context->im = 0; + context->iff1 = context->iff2 = 0; + context->native_pc = NULL; + context->extra_pc = NULL; + context->pc = 0; + context->reset = 0; + } +} + +void z80_assert_busreq(z80_context * context, uint32_t cycle) +{ + z80_run(context, cycle); + context->busreq = 1; +} + +void z80_clear_busreq(z80_context * context, uint32_t cycle) +{ + z80_run(context, cycle); + context->busreq = 0; + context->busack = 0; +} + +uint8_t z80_get_busack(z80_context * context, uint32_t cycle) { - context->im = 0; - context->iff1 = context->iff2 = 0; - context->native_pc = z80_get_native_address_trans(context, 0); - context->extra_pc = NULL; + z80_run(context, cycle); + return context->busack; +} + +void z80_adjust_cycles(z80_context * context, uint32_t deduction) +{ + if (context->current_cycle < deduction) { + fprintf(stderr, "WARNING: Deduction of %u cycles when Z80 cycle counter is only %u\n", deduction, context->current_cycle); + context->current_cycle = 0; + } else { + context->current_cycle -= deduction; + } + if (context->int_enable_cycle != CYCLE_NEVER) { + if (context->int_enable_cycle < deduction) { + context->int_enable_cycle = 0; + } else { + context->int_enable_cycle -= deduction; + } + } + if (context->int_pulse_start != CYCLE_NEVER) { + if (context->int_pulse_end < deduction) { + context->int_pulse_start = context->int_pulse_end = CYCLE_NEVER; + } else { + context->int_pulse_end -= deduction; + if (context->int_pulse_start < deduction) { + context->int_pulse_start = 0; + } else { + context->int_pulse_start -= deduction; + } + } + } } uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst) diff -r 30ccf56842d6 -r 5439ae7946ca z80_to_x86.h --- a/z80_to_x86.h Sat Jan 03 16:08:23 2015 -0800 +++ b/z80_to_x86.h Sat Jan 03 18:23:04 2015 -0800 @@ -70,15 +70,16 @@ void * system; uint8_t ram_code_flags[(8 * 1024)/128/8]; uint32_t int_enable_cycle; - z80_run_fun run; - uint16_t pc; + uint16_t pc; uint32_t int_pulse_start; uint32_t int_pulse_end; uint8_t breakpoint_flags[(16 * 1024)/sizeof(uint8_t)]; uint8_t * bp_handler; uint8_t * bp_stub; uint8_t * interp_code[256]; - + uint8_t reset; + uint8_t busreq; + uint8_t busack; } z80_context; void translate_z80_stream(z80_context * context, uint32_t address); @@ -87,10 +88,18 @@ code_ptr z80_get_native_address(z80_context * context, uint32_t address); code_ptr z80_get_native_address_trans(z80_context * context, uint32_t address); z80_context * z80_handle_code_write(uint32_t address, z80_context * context); -void z80_run(z80_context * context); void z80_reset(z80_context * context); void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler); void zremove_breakpoint(z80_context * context, uint16_t address); +void z80_run(z80_context * context, uint32_t target_cycle); +void z80_assert_reset(z80_context * context, uint32_t cycle); +void z80_clear_reset(z80_context * context, uint32_t cycle); +void z80_assert_busreq(z80_context * context, uint32_t cycle); +void z80_clear_busreq(z80_context * context, uint32_t cycle); +uint8_t z80_get_busack(z80_context * context, uint32_t cycle); +void z80_adjust_cycles(z80_context * context, uint32_t deduction); +//to be provided by system code +void z80_next_int_pulse(z80_context * z_context); #endif //Z80_TO_X86_H_