/* internal defines */
typedef struct DisasContext {
CPUM68KState *env;
+ target_ulong insn_pc; /* Start of the current instruction. */
target_ulong pc;
int is_jmp;
int cc_op;
switch ((insn >> 3) & 7) {
case 0: /* Data register direct. */
case 1: /* Address register direct. */
- /* ??? generate bad addressing mode fault. */
- qemu_assert(0, "invalid addressing mode");
+ return -1;
case 2: /* Indirect register */
case 3: /* Indirect postincrement. */
reg += QREG_A0;
return gen_lea_indexed(s, opsize, -1);
case 4: /* Immediate. */
default:
- /* ??? generate bad addressing mode fault. */
- qemu_assert(0, "invalid addressing mode");
+ return -1;
}
}
/* Should never happen. */
tmp = *addrp;
} else {
tmp = gen_lea(s, insn, opsize);
+ if (tmp == -1)
+ return -1;
if (addrp)
*addrp = tmp;
}
tmp = *addrp;
} else {
tmp = gen_lea(s, insn, opsize);
+ if (tmp == -1)
+ return -1;
if (addrp)
*addrp = tmp;
}
}
return gen_im32(offset);
default:
- qemu_assert(0, "invalid addressing mode");
+ return -1;
}
}
/* Should never happen. */
gen_op_raise_exception(nr);
}
+static inline void gen_addr_fault(DisasContext *s)
+{
+ gen_exception(s, s->insn_pc, EXCP_ADDRESS);
+}
+
+#define SRC_EA(result, opsize, val, addrp) do { \
+ result = gen_ea(s, insn, opsize, val, addrp); \
+ if (result == -1) { \
+ gen_addr_fault(s); \
+ return; \
+ } \
+ } while (0)
+
+#define DEST_EA(insn, opsize, val, addrp) do { \
+ int ea_result = gen_ea(s, insn, opsize, val, addrp); \
+ if (ea_result == -1) { \
+ gen_addr_fault(s); \
+ return; \
+ } \
+ } while (0)
+
/* Generate a jump to an immediate address. */
static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
{
gen_op_ext16s32(tmp, reg);
else
gen_op_ext16u32(tmp, reg);
- src = gen_ea(s, insn, OS_WORD, sign ? -1 : 0, NULL);
+ SRC_EA(src, OS_WORD, sign ? -1 : 0, NULL);
gen_op_mul32(tmp, tmp, src);
gen_op_mov32(reg, tmp);
/* Unlike m68k, coldfire always clears the overflow bit. */
} else {
gen_op_ext16u32(QREG_DIV1, reg);
}
- src = gen_ea(s, insn, OS_WORD, sign ? -1 : 0, NULL);
+ SRC_EA(src, OS_WORD, sign ? -1 : 0, NULL);
gen_op_mov32(QREG_DIV2, src);
if (sign) {
gen_op_divs(1);
num = DREG(ext, 12);
reg = DREG(ext, 0);
gen_op_mov32(QREG_DIV1, num);
- den = gen_ea(s, insn, OS_LONG, 0, NULL);
+ SRC_EA(den, OS_LONG, 0, NULL);
gen_op_mov32(QREG_DIV2, den);
if (ext & 0x0800) {
gen_op_divs(2);
reg = DREG(insn, 9);
dest = gen_new_qreg(QMODE_I32);
if (insn & 0x100) {
- tmp = gen_ea(s, insn, OS_LONG, 0, &addr);
+ SRC_EA(tmp, OS_LONG, 0, &addr);
src = reg;
} else {
tmp = reg;
- src = gen_ea(s, insn, OS_LONG, 0, NULL);
+ SRC_EA(src, OS_LONG, 0, NULL);
}
if (add) {
gen_op_add32(dest, tmp, src);
}
gen_op_update_cc_add(dest, src);
if (insn & 0x100) {
- gen_ea(s, insn, OS_LONG, dest, &addr);
+ DEST_EA(insn, OS_LONG, dest, &addr);
} else {
gen_op_mov32(reg, dest);
}
else
opsize = OS_LONG;
op = (insn >> 6) & 3;
- src1 = gen_ea(s, insn, opsize, 0, op ? &addr: NULL);
+ SRC_EA(src1, opsize, 0, op ? &addr: NULL);
src2 = DREG(insn, 9);
dest = gen_new_qreg(QMODE_I32);
break;
}
if (op)
- gen_ea(s, insn, opsize, dest, &addr);
+ DEST_EA(insn, opsize, dest, &addr);
}
DISAS_INSN(sats)
mask = lduw_code(s->pc);
s->pc += 2;
tmp = gen_lea(s, insn, OS_LONG);
+ if (tmp == -1) {
+ gen_addr_fault(s);
+ return;
+ }
addr = gen_new_qreg(QMODE_I32);
gen_op_mov32(addr, tmp);
is_load = ((insn & 0x0400) != 0);
return;
}
- src1 = gen_ea(s, insn, opsize, 0, op ? &addr: NULL);
+ SRC_EA(src1, opsize, 0, op ? &addr: NULL);
gen_flush_flags(s);
tmp = gen_new_qreg(QMODE_I32);
break;
}
if (op)
- gen_ea(s, insn, opsize, dest, &addr);
+ DEST_EA(insn, opsize, dest, &addr);
}
DISAS_INSN(arith_im)
int addr;
op = (insn >> 9) & 7;
- src1 = gen_ea(s, insn, OS_LONG, 0, (op == 6) ? NULL : &addr);
+ SRC_EA(src1, OS_LONG, 0, (op == 6) ? NULL : &addr);
src2 = gen_im32(read_im32(s));
dest = gen_new_qreg(QMODE_I32);
switch (op) {
abort();
}
if (op != 6) {
- gen_ea(s, insn, OS_LONG, dest, &addr);
+ DEST_EA(insn, OS_LONG, dest, &addr);
}
}
default:
abort();
}
- src = gen_ea(s, insn, opsize, -1, NULL);
+ SRC_EA(src, opsize, -1, NULL);
op = (insn >> 6) & 7;
if (op == 1) {
/* movea */
/* normal move */
uint16_t dest_ea;
dest_ea = ((insn >> 9) & 7) | (op << 3);
- gen_ea(s, dest_ea, opsize, src, NULL);
+ DEST_EA(dest_ea, opsize, src, NULL);
/* This will be correct because loads sign extend. */
gen_logic_cc(s, src);
}
reg = AREG(insn, 9);
tmp = gen_lea(s, insn, OS_LONG);
+ if (tmp == -1) {
+ gen_addr_fault(s);
+ return;
+ }
gen_op_mov32(reg, tmp);
}
default:
abort();
}
- gen_ea (s, insn, opsize, gen_im32(0), NULL);
+ DEST_EA(insn, opsize, gen_im32(0), NULL);
gen_logic_cc(s, gen_im32(0));
}
int tmp;
tmp = gen_lea(s, insn, OS_LONG);
+ if (tmp == -1) {
+ gen_addr_fault(s);
+ return;
+ }
gen_push(s, tmp);
}
default:
abort();
}
- tmp = gen_ea(s, insn, opsize, -1, NULL);
+ SRC_EA(tmp, opsize, -1, NULL);
gen_logic_cc(s, tmp);
}
int addr;
dest = gen_new_qreg(QMODE_I32);
- src1 = gen_ea(s, insn, OS_BYTE, -1, &addr);
+ SRC_EA(src1, OS_BYTE, -1, &addr);
gen_logic_cc(s, src1);
gen_op_or32(dest, src1, gen_im32(0x80));
- gen_ea(s, insn, OS_BYTE, dest, &addr);
+ DEST_EA(insn, OS_BYTE, dest, &addr);
}
DISAS_INSN(mull)
return;
}
reg = DREG(ext, 12);
- src1 = gen_ea(s, insn, OS_LONG, 0, NULL);
+ SRC_EA(src1, OS_LONG, 0, NULL);
dest = gen_new_qreg(QMODE_I32);
gen_op_mul32(dest, src1, reg);
gen_op_mov32(reg, dest);
/* Load the target address first to ensure correct exception
behavior. */
tmp = gen_lea(s, insn, OS_LONG);
+ if (tmp == -1) {
+ gen_addr_fault(s);
+ return;
+ }
if ((insn & 0x40) == 0) {
/* jsr */
gen_push(s, gen_im32(s->pc));
int val;
int addr;
- src1 = gen_ea(s, insn, OS_LONG, 0, &addr);
+ SRC_EA(src1, OS_LONG, 0, &addr);
val = (insn >> 9) & 7;
if (val == 0)
val = 8;
}
gen_op_update_cc_add(dest, src2);
}
- gen_ea(s, insn, OS_LONG, dest, &addr);
+ DEST_EA(insn, OS_LONG, dest, &addr);
}
DISAS_INSN(tpf)
opsize = OS_WORD;
else
opsize = OS_BYTE;
- src = gen_ea(s, insn, opsize, (insn & 0x80) ? 0 : -1, NULL);
+ SRC_EA(src, opsize, (insn & 0x80) ? 0 : -1, NULL);
reg = DREG(insn, 9);
gen_op_mov32(reg, src);
gen_logic_cc(s, src);
reg = DREG(insn, 9);
dest = gen_new_qreg(QMODE_I32);
if (insn & 0x100) {
- src = gen_ea(s, insn, OS_LONG, 0, &addr);
+ SRC_EA(src, OS_LONG, 0, &addr);
gen_op_or32(dest, src, reg);
- gen_ea(s, insn, OS_LONG, dest, &addr);
+ DEST_EA(insn, OS_LONG, dest, &addr);
} else {
- src = gen_ea(s, insn, OS_LONG, 0, NULL);
+ SRC_EA(src, OS_LONG, 0, NULL);
gen_op_or32(dest, src, reg);
gen_op_mov32(reg, dest);
}
int src;
int reg;
- src = gen_ea(s, insn, OS_LONG, 0, NULL);
+ SRC_EA(src, OS_LONG, 0, NULL);
reg = AREG(insn, 9);
gen_op_sub32(reg, reg, src);
}
val = -1;
src = gen_im32(val);
gen_logic_cc(s, src);
- gen_ea(s, insn, OS_LONG, src, NULL);
+ DEST_EA(insn, OS_LONG, src, NULL);
}
DISAS_INSN(cmp)
default:
abort();
}
- src = gen_ea(s, insn, opsize, -1, NULL);
+ SRC_EA(src, opsize, -1, NULL);
reg = DREG(insn, 9);
dest = gen_new_qreg(QMODE_I32);
gen_op_sub32(dest, reg, src);
} else {
opsize = OS_WORD;
}
- src = gen_ea(s, insn, opsize, -1, NULL);
+ SRC_EA(src, opsize, -1, NULL);
reg = AREG(insn, 9);
dest = gen_new_qreg(QMODE_I32);
gen_op_sub32(dest, reg, src);
int dest;
int addr;
- src = gen_ea(s, insn, OS_LONG, 0, &addr);
+ SRC_EA(src, OS_LONG, 0, &addr);
reg = DREG(insn, 9);
dest = gen_new_qreg(QMODE_I32);
gen_op_xor32(dest, src, reg);
gen_logic_cc(s, dest);
- gen_ea(s, insn, OS_LONG, dest, &addr);
+ DEST_EA(insn, OS_LONG, dest, &addr);
}
DISAS_INSN(and)
reg = DREG(insn, 9);
dest = gen_new_qreg(QMODE_I32);
if (insn & 0x100) {
- src = gen_ea(s, insn, OS_LONG, 0, &addr);
+ SRC_EA(src, OS_LONG, 0, &addr);
gen_op_and32(dest, src, reg);
- gen_ea(s, insn, OS_LONG, dest, &addr);
+ DEST_EA(insn, OS_LONG, dest, &addr);
} else {
- src = gen_ea(s, insn, OS_LONG, 0, NULL);
+ SRC_EA(src, OS_LONG, 0, NULL);
gen_op_and32(dest, src, reg);
gen_op_mov32(reg, dest);
}
int src;
int reg;
- src = gen_ea(s, insn, OS_LONG, 0, NULL);
+ SRC_EA(src, OS_LONG, 0, NULL);
reg = AREG(insn, 9);
gen_op_add32(reg, reg, src);
}
default:
goto undef;
}
- gen_ea(s, insn, opsize, res, NULL);
+ DEST_EA(insn, opsize, res, NULL);
return;
case 4: /* fmove to control register. */
switch ((ext >> 10) & 7) {
(ext >> 10) & 7);
goto undef;
}
- gen_ea(s, insn, OS_LONG, res, NULL);
+ DEST_EA(insn, OS_LONG, res, NULL);
break;
case 6: /* fmovem */
case 7:
if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0)
goto undef;
src = gen_lea(s, insn, OS_LONG);
+ if (src == -1) {
+ gen_addr_fault(s);
+ return;
+ }
addr = gen_new_qreg(QMODE_I32);
gen_op_mov32(addr, src);
mask = 0x80;
default:
goto undef;
}
- tmp = gen_ea(s, insn, opsize, -1, NULL);
+ SRC_EA(tmp, opsize, -1, NULL);
if (opsize == OS_DOUBLE) {
src = tmp;
} else {
gen_opc_instr_start[lj] = 1;
}
last_cc_op = dc->cc_op;
+ dc->insn_pc = dc->pc;
disas_m68k_insn(env, dc);
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
!env->singlestep_enabled &&