summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend.h1
-rw-r--r--blastem.c155
-rw-r--r--blastem.h4
-rw-r--r--gst.c10
-rw-r--r--z80_to_x86.c114
-rw-r--r--z80_to_x86.h17
6 files changed, 157 insertions, 144 deletions
diff --git a/backend.h b/backend.h
index 7b255f1..c3ae875 100644
--- a/backend.h
+++ b/backend.h
@@ -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 --git a/blastem.c b/blastem.c
index bf82f3e..1ee89aa 100644
--- a/blastem.c
+++ b/blastem.c
@@ -155,12 +155,6 @@ void adjust_int_cycle(m68k_context * context, vdp_context * v_context)
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 @@ uint8_t new_busack = 0;
#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 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
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 @@ uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context)
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 @@ m68k_context * io_write(uint32_t location, m68k_context * context, 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 || 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 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value
}
} 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
+ }
+ if (z80_enabled) {
+ z80_clear_busreq(gen->z80, context->current_cycle);
}
- //busack_cycle = CYCLE_NEVER;
- //busack = Z80_REQ_BUSY;
-
}
} 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;
- }
- //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;
+ if (z80_enabled) {
+ z80_clear_reset(gen->z80, context->current_cycle);
+ } else {
+ gen->z80->reset = 0;
}
- reset = 0;
} else {
- reset = 1;
+ if (z80_enabled) {
+ z80_assert_reset(gen->z80, context->current_cycle);
+ } else {
+ gen->z80->reset = 1;
+ }
}
}
}
@@ -653,11 +576,7 @@ uint8_t io_read(uint32_t location, m68k_context * context)
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 @@ uint8_t io_read(uint32_t location, m68k_context * context)
}
} 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 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u
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 @@ int main(int argc, char ** argv)
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 --git a/blastem.h b/blastem.h
index 46d0b1b..cd75b64 100644
--- a/blastem.h
+++ b/blastem.h
@@ -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 headless;
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 --git a/gst.c b/gst.c
index adf034d..a901858 100644
--- a/gst.c
+++ b/gst.c
@@ -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 @@ uint8_t z80_load_gst(z80_context * context, FILE * gstfile)
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 @@ uint8_t z80_save_gst(z80_context * context, FILE * gstfile)
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 --git a/z80_to_x86.c b/z80_to_x86.c
index 13f952a..9ae1a7c 100644
--- a/z80_to_x86.c
+++ b/z80_to_x86.c
@@ -1777,7 +1777,7 @@ z80_context * z80_handle_code_write(uint32_t address, z80_context * context)
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 @@ void init_z80_context(z80_context * context, z80_options * options)
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_reset(z80_context * context)
+void z80_run(z80_context * context, uint32_t target_cycle)
{
- context->im = 0;
- context->iff1 = context->iff2 = 0;
- context->native_pc = z80_get_native_address_trans(context, 0);
- context->extra_pc = NULL;
+ 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_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)
+{
+ 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 --git a/z80_to_x86.h b/z80_to_x86.h
index 792d7b5..7a77636 100644
--- a/z80_to_x86.h
+++ b/z80_to_x86.h
@@ -70,15 +70,16 @@ typedef struct {
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 @@ void init_z80_context(z80_context * context, z80_options * options);
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_