Generate m68k address faults.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2871 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
pbrook 2007-05-26 22:11:13 +00:00
parent e6dbd3b3f0
commit 510ff0b730

View file

@ -43,6 +43,7 @@ static inline void qemu_assert(int cond, const char *msg)
/* internal defines */ /* internal defines */
typedef struct DisasContext { typedef struct DisasContext {
CPUM68KState *env; CPUM68KState *env;
target_ulong insn_pc; /* Start of the current instruction. */
target_ulong pc; target_ulong pc;
int is_jmp; int is_jmp;
int cc_op; int cc_op;
@ -437,8 +438,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize)
switch ((insn >> 3) & 7) { switch ((insn >> 3) & 7) {
case 0: /* Data register direct. */ case 0: /* Data register direct. */
case 1: /* Address register direct. */ case 1: /* Address register direct. */
/* ??? generate bad addressing mode fault. */ return -1;
qemu_assert(0, "invalid addressing mode");
case 2: /* Indirect register */ case 2: /* Indirect register */
case 3: /* Indirect postincrement. */ case 3: /* Indirect postincrement. */
reg += QREG_A0; reg += QREG_A0;
@ -477,8 +477,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize)
return gen_lea_indexed(s, opsize, -1); return gen_lea_indexed(s, opsize, -1);
case 4: /* Immediate. */ case 4: /* Immediate. */
default: default:
/* ??? generate bad addressing mode fault. */ return -1;
qemu_assert(0, "invalid addressing mode");
} }
} }
/* Should never happen. */ /* Should never happen. */
@ -496,6 +495,8 @@ static inline int gen_ea_once(DisasContext *s, uint16_t insn, int opsize,
tmp = *addrp; tmp = *addrp;
} else { } else {
tmp = gen_lea(s, insn, opsize); tmp = gen_lea(s, insn, opsize);
if (tmp == -1)
return -1;
if (addrp) if (addrp)
*addrp = tmp; *addrp = tmp;
} }
@ -548,6 +549,8 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val,
tmp = *addrp; tmp = *addrp;
} else { } else {
tmp = gen_lea(s, insn, opsize); tmp = gen_lea(s, insn, opsize);
if (tmp == -1)
return -1;
if (addrp) if (addrp)
*addrp = tmp; *addrp = tmp;
} }
@ -595,7 +598,7 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val,
} }
return gen_im32(offset); return gen_im32(offset);
default: default:
qemu_assert(0, "invalid addressing mode"); return -1;
} }
} }
/* Should never happen. */ /* Should never happen. */
@ -753,6 +756,27 @@ static void gen_exception(DisasContext *s, uint32_t where, int nr)
gen_op_raise_exception(nr); 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. */ /* Generate a jump to an immediate address. */
static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest) static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
{ {
@ -806,7 +830,7 @@ DISAS_INSN(mulw)
gen_op_ext16s32(tmp, reg); gen_op_ext16s32(tmp, reg);
else else
gen_op_ext16u32(tmp, reg); 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_mul32(tmp, tmp, src);
gen_op_mov32(reg, tmp); gen_op_mov32(reg, tmp);
/* Unlike m68k, coldfire always clears the overflow bit. */ /* Unlike m68k, coldfire always clears the overflow bit. */
@ -827,7 +851,7 @@ DISAS_INSN(divw)
} else { } else {
gen_op_ext16u32(QREG_DIV1, reg); 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); gen_op_mov32(QREG_DIV2, src);
if (sign) { if (sign) {
gen_op_divs(1); gen_op_divs(1);
@ -860,7 +884,7 @@ DISAS_INSN(divl)
num = DREG(ext, 12); num = DREG(ext, 12);
reg = DREG(ext, 0); reg = DREG(ext, 0);
gen_op_mov32(QREG_DIV1, num); 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); gen_op_mov32(QREG_DIV2, den);
if (ext & 0x0800) { if (ext & 0x0800) {
gen_op_divs(2); gen_op_divs(2);
@ -891,11 +915,11 @@ DISAS_INSN(addsub)
reg = DREG(insn, 9); reg = DREG(insn, 9);
dest = gen_new_qreg(QMODE_I32); dest = gen_new_qreg(QMODE_I32);
if (insn & 0x100) { if (insn & 0x100) {
tmp = gen_ea(s, insn, OS_LONG, 0, &addr); SRC_EA(tmp, OS_LONG, 0, &addr);
src = reg; src = reg;
} else { } else {
tmp = reg; tmp = reg;
src = gen_ea(s, insn, OS_LONG, 0, NULL); SRC_EA(src, OS_LONG, 0, NULL);
} }
if (add) { if (add) {
gen_op_add32(dest, tmp, src); gen_op_add32(dest, tmp, src);
@ -908,7 +932,7 @@ DISAS_INSN(addsub)
} }
gen_op_update_cc_add(dest, src); gen_op_update_cc_add(dest, src);
if (insn & 0x100) { if (insn & 0x100) {
gen_ea(s, insn, OS_LONG, dest, &addr); DEST_EA(insn, OS_LONG, dest, &addr);
} else { } else {
gen_op_mov32(reg, dest); gen_op_mov32(reg, dest);
} }
@ -966,7 +990,7 @@ DISAS_INSN(bitop_reg)
else else
opsize = OS_LONG; opsize = OS_LONG;
op = (insn >> 6) & 3; 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); src2 = DREG(insn, 9);
dest = gen_new_qreg(QMODE_I32); dest = gen_new_qreg(QMODE_I32);
@ -996,7 +1020,7 @@ DISAS_INSN(bitop_reg)
break; break;
} }
if (op) if (op)
gen_ea(s, insn, opsize, dest, &addr); DEST_EA(insn, opsize, dest, &addr);
} }
DISAS_INSN(sats) DISAS_INSN(sats)
@ -1041,6 +1065,10 @@ DISAS_INSN(movem)
mask = lduw_code(s->pc); mask = lduw_code(s->pc);
s->pc += 2; s->pc += 2;
tmp = gen_lea(s, insn, OS_LONG); tmp = gen_lea(s, insn, OS_LONG);
if (tmp == -1) {
gen_addr_fault(s);
return;
}
addr = gen_new_qreg(QMODE_I32); addr = gen_new_qreg(QMODE_I32);
gen_op_mov32(addr, tmp); gen_op_mov32(addr, tmp);
is_load = ((insn & 0x0400) != 0); is_load = ((insn & 0x0400) != 0);
@ -1086,7 +1114,7 @@ DISAS_INSN(bitop_im)
return; return;
} }
src1 = gen_ea(s, insn, opsize, 0, op ? &addr: NULL); SRC_EA(src1, opsize, 0, op ? &addr: NULL);
gen_flush_flags(s); gen_flush_flags(s);
tmp = gen_new_qreg(QMODE_I32); tmp = gen_new_qreg(QMODE_I32);
@ -1116,7 +1144,7 @@ DISAS_INSN(bitop_im)
break; break;
} }
if (op) if (op)
gen_ea(s, insn, opsize, dest, &addr); DEST_EA(insn, opsize, dest, &addr);
} }
DISAS_INSN(arith_im) DISAS_INSN(arith_im)
@ -1128,7 +1156,7 @@ DISAS_INSN(arith_im)
int addr; int addr;
op = (insn >> 9) & 7; 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)); src2 = gen_im32(read_im32(s));
dest = gen_new_qreg(QMODE_I32); dest = gen_new_qreg(QMODE_I32);
switch (op) { switch (op) {
@ -1168,7 +1196,7 @@ DISAS_INSN(arith_im)
abort(); abort();
} }
if (op != 6) { if (op != 6) {
gen_ea(s, insn, OS_LONG, dest, &addr); DEST_EA(insn, OS_LONG, dest, &addr);
} }
} }
@ -1200,7 +1228,7 @@ DISAS_INSN(move)
default: default:
abort(); abort();
} }
src = gen_ea(s, insn, opsize, -1, NULL); SRC_EA(src, opsize, -1, NULL);
op = (insn >> 6) & 7; op = (insn >> 6) & 7;
if (op == 1) { if (op == 1) {
/* movea */ /* movea */
@ -1211,7 +1239,7 @@ DISAS_INSN(move)
/* normal move */ /* normal move */
uint16_t dest_ea; uint16_t dest_ea;
dest_ea = ((insn >> 9) & 7) | (op << 3); 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. */ /* This will be correct because loads sign extend. */
gen_logic_cc(s, src); gen_logic_cc(s, src);
} }
@ -1247,6 +1275,10 @@ DISAS_INSN(lea)
reg = AREG(insn, 9); reg = AREG(insn, 9);
tmp = gen_lea(s, insn, OS_LONG); tmp = gen_lea(s, insn, OS_LONG);
if (tmp == -1) {
gen_addr_fault(s);
return;
}
gen_op_mov32(reg, tmp); gen_op_mov32(reg, tmp);
} }
@ -1267,7 +1299,7 @@ DISAS_INSN(clr)
default: default:
abort(); 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)); gen_logic_cc(s, gen_im32(0));
} }
@ -1384,6 +1416,10 @@ DISAS_INSN(pea)
int tmp; int tmp;
tmp = gen_lea(s, insn, OS_LONG); tmp = gen_lea(s, insn, OS_LONG);
if (tmp == -1) {
gen_addr_fault(s);
return;
}
gen_push(s, tmp); gen_push(s, tmp);
} }
@ -1425,7 +1461,7 @@ DISAS_INSN(tst)
default: default:
abort(); abort();
} }
tmp = gen_ea(s, insn, opsize, -1, NULL); SRC_EA(tmp, opsize, -1, NULL);
gen_logic_cc(s, tmp); gen_logic_cc(s, tmp);
} }
@ -1447,10 +1483,10 @@ DISAS_INSN(tas)
int addr; int addr;
dest = gen_new_qreg(QMODE_I32); 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_logic_cc(s, src1);
gen_op_or32(dest, src1, gen_im32(0x80)); 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) DISAS_INSN(mull)
@ -1469,7 +1505,7 @@ DISAS_INSN(mull)
return; return;
} }
reg = DREG(ext, 12); 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); dest = gen_new_qreg(QMODE_I32);
gen_op_mul32(dest, src1, reg); gen_op_mul32(dest, src1, reg);
gen_op_mov32(reg, dest); gen_op_mov32(reg, dest);
@ -1528,6 +1564,10 @@ DISAS_INSN(jump)
/* Load the target address first to ensure correct exception /* Load the target address first to ensure correct exception
behavior. */ behavior. */
tmp = gen_lea(s, insn, OS_LONG); tmp = gen_lea(s, insn, OS_LONG);
if (tmp == -1) {
gen_addr_fault(s);
return;
}
if ((insn & 0x40) == 0) { if ((insn & 0x40) == 0) {
/* jsr */ /* jsr */
gen_push(s, gen_im32(s->pc)); gen_push(s, gen_im32(s->pc));
@ -1543,7 +1583,7 @@ DISAS_INSN(addsubq)
int val; int val;
int addr; int addr;
src1 = gen_ea(s, insn, OS_LONG, 0, &addr); SRC_EA(src1, OS_LONG, 0, &addr);
val = (insn >> 9) & 7; val = (insn >> 9) & 7;
if (val == 0) if (val == 0)
val = 8; val = 8;
@ -1570,7 +1610,7 @@ DISAS_INSN(addsubq)
} }
gen_op_update_cc_add(dest, src2); 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) DISAS_INSN(tpf)
@ -1642,7 +1682,7 @@ DISAS_INSN(mvzs)
opsize = OS_WORD; opsize = OS_WORD;
else else
opsize = OS_BYTE; 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); reg = DREG(insn, 9);
gen_op_mov32(reg, src); gen_op_mov32(reg, src);
gen_logic_cc(s, src); gen_logic_cc(s, src);
@ -1658,11 +1698,11 @@ DISAS_INSN(or)
reg = DREG(insn, 9); reg = DREG(insn, 9);
dest = gen_new_qreg(QMODE_I32); dest = gen_new_qreg(QMODE_I32);
if (insn & 0x100) { 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_op_or32(dest, src, reg);
gen_ea(s, insn, OS_LONG, dest, &addr); DEST_EA(insn, OS_LONG, dest, &addr);
} else { } 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_or32(dest, src, reg);
gen_op_mov32(reg, dest); gen_op_mov32(reg, dest);
} }
@ -1674,7 +1714,7 @@ DISAS_INSN(suba)
int src; int src;
int reg; int reg;
src = gen_ea(s, insn, OS_LONG, 0, NULL); SRC_EA(src, OS_LONG, 0, NULL);
reg = AREG(insn, 9); reg = AREG(insn, 9);
gen_op_sub32(reg, reg, src); gen_op_sub32(reg, reg, src);
} }
@ -1714,7 +1754,7 @@ DISAS_INSN(mov3q)
val = -1; val = -1;
src = gen_im32(val); src = gen_im32(val);
gen_logic_cc(s, src); gen_logic_cc(s, src);
gen_ea(s, insn, OS_LONG, src, NULL); DEST_EA(insn, OS_LONG, src, NULL);
} }
DISAS_INSN(cmp) DISAS_INSN(cmp)
@ -1742,7 +1782,7 @@ DISAS_INSN(cmp)
default: default:
abort(); abort();
} }
src = gen_ea(s, insn, opsize, -1, NULL); SRC_EA(src, opsize, -1, NULL);
reg = DREG(insn, 9); reg = DREG(insn, 9);
dest = gen_new_qreg(QMODE_I32); dest = gen_new_qreg(QMODE_I32);
gen_op_sub32(dest, reg, src); gen_op_sub32(dest, reg, src);
@ -1761,7 +1801,7 @@ DISAS_INSN(cmpa)
} else { } else {
opsize = OS_WORD; opsize = OS_WORD;
} }
src = gen_ea(s, insn, opsize, -1, NULL); SRC_EA(src, opsize, -1, NULL);
reg = AREG(insn, 9); reg = AREG(insn, 9);
dest = gen_new_qreg(QMODE_I32); dest = gen_new_qreg(QMODE_I32);
gen_op_sub32(dest, reg, src); gen_op_sub32(dest, reg, src);
@ -1776,12 +1816,12 @@ DISAS_INSN(eor)
int dest; int dest;
int addr; int addr;
src = gen_ea(s, insn, OS_LONG, 0, &addr); SRC_EA(src, OS_LONG, 0, &addr);
reg = DREG(insn, 9); reg = DREG(insn, 9);
dest = gen_new_qreg(QMODE_I32); dest = gen_new_qreg(QMODE_I32);
gen_op_xor32(dest, src, reg); gen_op_xor32(dest, src, reg);
gen_logic_cc(s, dest); gen_logic_cc(s, dest);
gen_ea(s, insn, OS_LONG, dest, &addr); DEST_EA(insn, OS_LONG, dest, &addr);
} }
DISAS_INSN(and) DISAS_INSN(and)
@ -1794,11 +1834,11 @@ DISAS_INSN(and)
reg = DREG(insn, 9); reg = DREG(insn, 9);
dest = gen_new_qreg(QMODE_I32); dest = gen_new_qreg(QMODE_I32);
if (insn & 0x100) { 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_op_and32(dest, src, reg);
gen_ea(s, insn, OS_LONG, dest, &addr); DEST_EA(insn, OS_LONG, dest, &addr);
} else { } 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_and32(dest, src, reg);
gen_op_mov32(reg, dest); gen_op_mov32(reg, dest);
} }
@ -1810,7 +1850,7 @@ DISAS_INSN(adda)
int src; int src;
int reg; int reg;
src = gen_ea(s, insn, OS_LONG, 0, NULL); SRC_EA(src, OS_LONG, 0, NULL);
reg = AREG(insn, 9); reg = AREG(insn, 9);
gen_op_add32(reg, reg, src); gen_op_add32(reg, reg, src);
} }
@ -2114,7 +2154,7 @@ DISAS_INSN(fpu)
default: default:
goto undef; goto undef;
} }
gen_ea(s, insn, opsize, res, NULL); DEST_EA(insn, opsize, res, NULL);
return; return;
case 4: /* fmove to control register. */ case 4: /* fmove to control register. */
switch ((ext >> 10) & 7) { switch ((ext >> 10) & 7) {
@ -2141,7 +2181,7 @@ DISAS_INSN(fpu)
(ext >> 10) & 7); (ext >> 10) & 7);
goto undef; goto undef;
} }
gen_ea(s, insn, OS_LONG, res, NULL); DEST_EA(insn, OS_LONG, res, NULL);
break; break;
case 6: /* fmovem */ case 6: /* fmovem */
case 7: case 7:
@ -2151,6 +2191,10 @@ DISAS_INSN(fpu)
if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0) if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0)
goto undef; goto undef;
src = gen_lea(s, insn, OS_LONG); src = gen_lea(s, insn, OS_LONG);
if (src == -1) {
gen_addr_fault(s);
return;
}
addr = gen_new_qreg(QMODE_I32); addr = gen_new_qreg(QMODE_I32);
gen_op_mov32(addr, src); gen_op_mov32(addr, src);
mask = 0x80; mask = 0x80;
@ -2186,7 +2230,7 @@ DISAS_INSN(fpu)
default: default:
goto undef; goto undef;
} }
tmp = gen_ea(s, insn, opsize, -1, NULL); SRC_EA(tmp, opsize, -1, NULL);
if (opsize == OS_DOUBLE) { if (opsize == OS_DOUBLE) {
src = tmp; src = tmp;
} else { } else {
@ -2846,6 +2890,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
gen_opc_instr_start[lj] = 1; gen_opc_instr_start[lj] = 1;
} }
last_cc_op = dc->cc_op; last_cc_op = dc->cc_op;
dc->insn_pc = dc->pc;
disas_m68k_insn(env, dc); disas_m68k_insn(env, dc);
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
!env->singlestep_enabled && !env->singlestep_enabled &&