summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--m68k_core.c8
-rw-r--r--m68k_core.h1
-rw-r--r--m68k_core_x86.c50
-rw-r--r--m68k_internal.h3
4 files changed, 54 insertions, 8 deletions
diff --git a/m68k_core.c b/m68k_core.c
index 1faa3c0..3ed8185 100644
--- a/m68k_core.c
+++ b/m68k_core.c
@@ -969,11 +969,15 @@ static void translate_m68k(m68k_context *context, m68kinst * inst)
}
host_ea src_op, dst_op;
+ uint8_t needs_int_latch = 0;
if (inst->src.addr_mode != MODE_UNUSED) {
- translate_m68k_op(inst, &src_op, opts, 0);
+ needs_int_latch |= translate_m68k_op(inst, &src_op, opts, 0);
}
if (inst->dst.addr_mode != MODE_UNUSED) {
- translate_m68k_op(inst, &dst_op, opts, 1);
+ needs_int_latch |= translate_m68k_op(inst, &dst_op, opts, 1);
+ }
+ if (needs_int_latch) {
+ m68k_check_cycles_int_latch(opts);
}
if (info->itype == OP_FUNC) {
info->impl.op(opts, inst, &src_op, &dst_op);
diff --git a/m68k_core.h b/m68k_core.h
index 7773d64..a18d706 100644
--- a/m68k_core.h
+++ b/m68k_core.h
@@ -48,6 +48,7 @@ typedef struct {
code_ptr write_32_lowfirst;
code_ptr write_32_highfirst;
code_ptr do_sync;
+ code_ptr handle_int_latch;
code_ptr trap;
start_fun start_context;
code_ptr retrans_stub;
diff --git a/m68k_core_x86.c b/m68k_core_x86.c
index fede6ff..07eb1e2 100644
--- a/m68k_core_x86.c
+++ b/m68k_core_x86.c
@@ -350,12 +350,30 @@ void calc_areg_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_
calc_index_disp8(opts, op, native_reg);
}
-void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst)
+void m68k_check_cycles_int_latch(m68k_options *opts)
+{
+ code_info *code = &opts->gen.code;
+ uint8_t cc;
+ if (opts->gen.limit < 0) {
+ cmp_ir(code, 1, opts->gen.cycles, SZ_D);
+ cc = CC_NS;
+ } else {
+ cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D);
+ cc = CC_A;
+ }
+ code_ptr jmp_off = code->cur+1;
+ jcc(code, cc, jmp_off+1);
+ call(code, opts->handle_int_latch);
+ *jmp_off = code->cur - (jmp_off+1);
+}
+
+uint8_t translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst)
{
code_info *code = &opts->gen.code;
m68k_op_info *op = dst ? &inst->dst : &inst->src;
int8_t reg = native_reg(op, opts);
uint8_t sec_reg;
+ uint8_t ret = 1;
int32_t dec_amount, inc_amount;
if (reg >= 0) {
ea->mode = MODE_REG_DIRECT;
@@ -365,7 +383,7 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8
} else {
ea->base = reg;
}
- return;
+ return 0;
}
switch (op->addr_mode)
{
@@ -388,8 +406,9 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8
ea->mode = MODE_REG_DIRECT;
ea->base = opts->gen.scratch1;
//we're explicitly handling the areg dest here, so we exit immediately
- return;
+ return 0;
}
+ ret = 0;
break;
case MODE_AREG_PREDEC:
if (dst && inst->src.addr_mode == MODE_AREG_PREDEC) {
@@ -505,7 +524,7 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8
if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD && ea->disp & 0x8000) {
ea->disp |= 0xFFFF0000;
}
- return;
+ return inst->variant != VAR_QUICK;
default:
m68k_disasm(inst, disasm_buf);
fatal_error("%X: %s\naddress mode %d not implemented (%s)\n", inst->address, disasm_buf, op->addr_mode, dst ? "dst" : "src");
@@ -519,6 +538,7 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8
}
ea->base = opts->gen.scratch1;
}
+ return ret;
}
void check_user_mode_swap_ssp_usp(m68k_options *opts)
@@ -540,7 +560,9 @@ void translate_m68k_move(m68k_options * opts, m68kinst * inst)
int32_t offset;
int32_t inc_amount, dec_amount;
host_ea src;
- translate_m68k_op(inst, &src, opts, 0);
+ if (translate_m68k_op(inst, &src, opts, 0)) {
+ m68k_check_cycles_int_latch(opts);
+ }
reg = native_reg(&(inst->dst), opts);
if (inst->dst.addr_mode != MODE_AREG) {
@@ -3085,6 +3107,24 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu
add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
jmp_r(code, opts->gen.scratch1);
code->stack_off = tmp_stack_off;
+
+ opts->handle_int_latch = code->cur;
+ cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D);
+ code_ptr do_latch = code->cur + 1;
+ jcc(code, CC_NC, do_latch);
+ retn(code);
+ *do_latch = code->cur - (do_latch + 1);
+ cmp_irdisp(code, INT_PENDING_NONE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
+ do_latch = code->cur + 1;
+ jcc(code, CC_Z, do_latch);
+ retn(code);
+ *do_latch = code->cur - (do_latch + 1);
+ //store current interrupt number so it doesn't change before we start processing the vector
+ push_r(code, opts->gen.scratch1);
+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B);
+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
+ pop_r(code, opts->gen.scratch1);
+ retn(code);
opts->trap = code->cur;
push_r(code, opts->gen.scratch2);
diff --git a/m68k_internal.h b/m68k_internal.h
index fbe26ce..4533de1 100644
--- a/m68k_internal.h
+++ b/m68k_internal.h
@@ -36,13 +36,14 @@ void m68k_set_last_prefetch(m68k_options *opts, uint32_t address);
void translate_m68k_odd(m68k_options *opts, m68kinst *inst);
void m68k_trap_if_not_supervisor(m68k_options *opts, m68kinst *inst);
void m68k_breakpoint_patch(m68k_context *context, uint32_t address, m68k_debug_handler bp_handler, code_ptr native_addr);
+void m68k_check_cycles_int_latch(m68k_options *opts);
+uint8_t translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst);
//functions implemented in m68k_core.c
int8_t native_reg(m68k_op_info * op, m68k_options * opts);
size_t dreg_offset(uint8_t reg);
size_t areg_offset(uint8_t reg);
size_t reg_offset(m68k_op_info *op);
-void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst);
void m68k_read_size(m68k_options *opts, uint8_t size);
void m68k_write_size(m68k_options *opts, uint8_t size, uint8_t lowfirst);
void m68k_save_result(m68kinst * inst, m68k_options * opts);