diff options
author | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-05-26 22:11:13 +0000 |
---|---|---|
committer | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-05-26 22:11:13 +0000 |
commit | 510ff0b730d1ba25a382ac3f6f73571ea731b8e5 (patch) | |
tree | 865fc8f4cbb118a54d3cfe1f4be5d234759a73d1 | |
parent | e6dbd3b3f08318196cbdb1f0c23a7eefd9b38cb7 (diff) |
Generate m68k address faults.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2871 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | target-m68k/translate.c | 131 |
1 files changed, 88 insertions, 43 deletions
diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 93879c9301..6ee35f07bf 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -43,6 +43,7 @@ static inline void qemu_assert(int cond, const char *msg) /* 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; @@ -437,8 +438,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) 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; @@ -477,8 +477,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) 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. */ @@ -496,6 +495,8 @@ static inline int gen_ea_once(DisasContext *s, uint16_t insn, int opsize, tmp = *addrp; } else { tmp = gen_lea(s, insn, opsize); + if (tmp == -1) + return -1; if (addrp) *addrp = tmp; } @@ -548,6 +549,8 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, tmp = *addrp; } else { tmp = gen_lea(s, insn, opsize); + if (tmp == -1) + return -1; if (addrp) *addrp = tmp; } @@ -595,7 +598,7 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, } return gen_im32(offset); default: - qemu_assert(0, "invalid addressing mode"); + return -1; } } /* Should never happen. */ @@ -753,6 +756,27 @@ static void gen_exception(DisasContext *s, uint32_t where, int 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. */ static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest) { @@ -806,7 +830,7 @@ DISAS_INSN(mulw) 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. */ @@ -827,7 +851,7 @@ DISAS_INSN(divw) } 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); @@ -860,7 +884,7 @@ DISAS_INSN(divl) 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); @@ -891,11 +915,11 @@ DISAS_INSN(addsub) 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); @@ -908,7 +932,7 @@ DISAS_INSN(addsub) } 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); } @@ -966,7 +990,7 @@ DISAS_INSN(bitop_reg) 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); @@ -996,7 +1020,7 @@ DISAS_INSN(bitop_reg) break; } if (op) - gen_ea(s, insn, opsize, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } DISAS_INSN(sats) @@ -1041,6 +1065,10 @@ DISAS_INSN(movem) 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); @@ -1086,7 +1114,7 @@ DISAS_INSN(bitop_im) 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); @@ -1116,7 +1144,7 @@ DISAS_INSN(bitop_im) break; } if (op) - gen_ea(s, insn, opsize, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } DISAS_INSN(arith_im) @@ -1128,7 +1156,7 @@ 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) { @@ -1168,7 +1196,7 @@ DISAS_INSN(arith_im) abort(); } 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: abort(); } - src = gen_ea(s, insn, opsize, -1, NULL); + SRC_EA(src, opsize, -1, NULL); op = (insn >> 6) & 7; if (op == 1) { /* movea */ @@ -1211,7 +1239,7 @@ DISAS_INSN(move) /* 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); } @@ -1247,6 +1275,10 @@ DISAS_INSN(lea) reg = AREG(insn, 9); tmp = gen_lea(s, insn, OS_LONG); + if (tmp == -1) { + gen_addr_fault(s); + return; + } gen_op_mov32(reg, tmp); } @@ -1267,7 +1299,7 @@ DISAS_INSN(clr) 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)); } @@ -1384,6 +1416,10 @@ DISAS_INSN(pea) int tmp; tmp = gen_lea(s, insn, OS_LONG); + if (tmp == -1) { + gen_addr_fault(s); + return; + } gen_push(s, tmp); } @@ -1425,7 +1461,7 @@ DISAS_INSN(tst) default: abort(); } - tmp = gen_ea(s, insn, opsize, -1, NULL); + SRC_EA(tmp, opsize, -1, NULL); gen_logic_cc(s, tmp); } @@ -1447,10 +1483,10 @@ DISAS_INSN(tas) 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) @@ -1469,7 +1505,7 @@ 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); @@ -1528,6 +1564,10 @@ DISAS_INSN(jump) /* 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)); @@ -1543,7 +1583,7 @@ DISAS_INSN(addsubq) 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; @@ -1570,7 +1610,7 @@ DISAS_INSN(addsubq) } 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) @@ -1642,7 +1682,7 @@ DISAS_INSN(mvzs) 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); @@ -1658,11 +1698,11 @@ DISAS_INSN(or) 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); } @@ -1674,7 +1714,7 @@ DISAS_INSN(suba) 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); } @@ -1714,7 +1754,7 @@ DISAS_INSN(mov3q) 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) @@ -1742,7 +1782,7 @@ 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); @@ -1761,7 +1801,7 @@ DISAS_INSN(cmpa) } 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); @@ -1776,12 +1816,12 @@ DISAS_INSN(eor) 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) @@ -1794,11 +1834,11 @@ 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); } @@ -1810,7 +1850,7 @@ DISAS_INSN(adda) 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); } @@ -2114,7 +2154,7 @@ DISAS_INSN(fpu) 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) { @@ -2141,7 +2181,7 @@ DISAS_INSN(fpu) (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: @@ -2151,6 +2191,10 @@ DISAS_INSN(fpu) 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; @@ -2186,7 +2230,7 @@ DISAS_INSN(fpu) default: goto undef; } - tmp = gen_ea(s, insn, opsize, -1, NULL); + SRC_EA(tmp, opsize, -1, NULL); if (opsize == OS_DOUBLE) { src = tmp; } else { @@ -2846,6 +2890,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, 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 && |