changeset 1376:70d88d9bfe13

Implemented Z80 NMI
author Michael Pavone <pavone@retrodev.com>
date Sun, 28 May 2017 21:02:47 -0700
parents b68732dcbf00
children e587f16e7d3d
files z80_to_x86.c z80_to_x86.h
diffstat 2 files changed, 41 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/z80_to_x86.c	Fri May 26 19:18:19 2017 -0700
+++ b/z80_to_x86.c	Sun May 28 21:02:47 2017 -0700
@@ -3416,8 +3416,18 @@
 	neg_r(code, options->gen.cycles, SZ_D);
 	add_rr(code, options->gen.scratch2, options->gen.cycles, SZ_D);
 	//disable interrupts
+	cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B);
+	code_ptr is_nmi = code->cur + 1;
+	jcc(code, CC_NZ, is_nmi);
 	mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
 	mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
+	code_ptr after_int_disable = code->cur + 1;
+	jmp(code, after_int_disable);
+	*is_nmi = code->cur - (is_nmi + 1);
+	mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, iff1), options->gen.scratch2, SZ_B);
+	mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
+	mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
+	*after_int_disable = code->cur - (after_int_disable + 1);
 	cycles(&options->gen, 7);
 	//save return address (in scratch1) to Z80 stack
 	sub_ir(code, 2, options->regs[Z80_SP], SZ_W);
@@ -3441,8 +3451,18 @@
 	call(code, options->write_8_noinc);
 	//dispose of return address as we'll be jumping somewhere else
 	add_ir(code, 16, RSP, SZ_PTR);
+	cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B);
+	is_nmi = code->cur + 1;
+	jcc(code, CC_NZ, is_nmi);
 	//TODO: Support interrupt mode 0 and 2
 	mov_ir(code, 0x38, options->gen.scratch1, SZ_W);
+	code_ptr after_int_dest = code->cur + 1;
+	jmp(code, after_int_dest);
+	*is_nmi = code->cur - (is_nmi + 1);
+	mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B);
+	mov_irdisp(code, CYCLE_NEVER, options->gen.context_reg, offsetof(z80_context, nmi_start), SZ_D);
+	mov_ir(code, 0x66, options->gen.scratch1, SZ_W);
+	*after_int_dest = code->cur - (after_int_dest + 1);
 	call(code, options->native_addr);
 	mov_rrind(code, options->gen.scratch1, options->gen.context_reg, SZ_PTR);
 	tmp_stack_off = code->stack_off;
@@ -3571,10 +3591,19 @@
 	context->int_cycle = CYCLE_NEVER;
 	context->int_pulse_start = CYCLE_NEVER;
 	context->int_pulse_end = CYCLE_NEVER;
+	context->nmi_start = CYCLE_NEVER;
 	
 	return context;
 }
 
+static void check_nmi(z80_context *context)
+{
+	if (context->nmi_start < context->int_cycle) {
+		context->int_cycle = context->nmi_start;
+		context->int_is_nmi = 1;
+	}
+}
+
 void z80_run(z80_context * context, uint32_t target_cycle)
 {
 	if (context->reset || context->busack) {
@@ -3594,9 +3623,12 @@
 				}
 				if (context->iff1) {
 					context->int_cycle = context->int_pulse_start < context->int_enable_cycle ? context->int_enable_cycle : context->int_pulse_start;
+					context->int_is_nmi = 0;
 				} else {
 					context->int_cycle = CYCLE_NEVER;
 				}
+				check_nmi(context);
+				
 				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 (%d - %d)\n", context->current_cycle, context->sync_cycle, context->int_cycle, context->int_pulse_start, context->int_pulse_end);
 				context->options->run(context);
@@ -3668,6 +3700,12 @@
 	return context->busack;
 }
 
+void z80_assert_nmi(z80_context *context, uint32_t cycle)
+{
+	context->nmi_start = cycle;
+	check_nmi(context);
+}
+
 void z80_adjust_cycles(z80_context * context, uint32_t deduction)
 {
 	if (context->current_cycle < deduction) {
--- a/z80_to_x86.h	Fri May 26 19:18:19 2017 -0700
+++ b/z80_to_x86.h	Sun May 28 21:02:47 2017 -0700
@@ -76,6 +76,7 @@
 	uint16_t          pc;
 	uint32_t          int_pulse_start;
 	uint32_t          int_pulse_end;
+	uint32_t          nmi_start;
 	uint8_t           breakpoint_flags[(16 * 1024)/sizeof(uint8_t)];
 	uint8_t *         bp_handler;
 	uint8_t *         bp_stub;
@@ -84,6 +85,7 @@
 	uint8_t           reset;
 	uint8_t           busreq;
 	uint8_t           busack;
+	uint8_t           int_is_nmi;
 	uint8_t           ram_code_flags[];
 };
 
@@ -103,6 +105,7 @@
 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);
+void z80_assert_nmi(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);