From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MAAmL-0002Xw-39 for qemu-devel@nongnu.org; Fri, 29 May 2009 18:42:21 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MAAmD-0002Tm-4E for qemu-devel@nongnu.org; Fri, 29 May 2009 18:42:18 -0400 Received: from [199.232.76.173] (port=44639 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MAAmC-0002T0-HN for qemu-devel@nongnu.org; Fri, 29 May 2009 18:42:12 -0400 Received: from smtp5-g21.free.fr ([212.27.42.5]:52837) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MAAmA-0007Ks-Ci for qemu-devel@nongnu.org; Fri, 29 May 2009 18:42:11 -0400 From: Laurent Vivier Date: Sat, 30 May 2009 00:41:48 +0200 Message-Id: <1243636921-23054-5-git-send-email-laurent@vivier.eu> In-Reply-To: <1243636921-23054-4-git-send-email-laurent@vivier.eu> References: <1243636921-23054-1-git-send-email-laurent@vivier.eu> <1243636921-23054-2-git-send-email-laurent@vivier.eu> <1243636921-23054-3-git-send-email-laurent@vivier.eu> <1243636921-23054-4-git-send-email-laurent@vivier.eu> Subject: [Qemu-devel] [PATCH 04/17] m68k: add missing accessing modes for some instructions. List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Andreas Schwab , Laurent Vivier This patch modifies following instructions to allow them to manage data size other than "long", by adding "byte" and "word" data size: "addsub", "arith_im", "addsubq", "or", "eor", "and". This patch modifies following instructions to use EA to access data: "neg", "not". Signed-off-by: Andreas Schwab Signed-off-by: Laurent Vivier --- target-m68k/cpu.h | 10 ++- target-m68k/helper.c | 74 ++++++++++++----- target-m68k/translate.c | 202 +++++++++++++++++++++++++++-------------------- 3 files changed, 177 insertions(+), 109 deletions(-) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index eb18e9e..240d75f 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -131,11 +131,17 @@ enum { CC_OP_DYNAMIC, /* Use env->cc_op */ CC_OP_FLAGS, /* CC_DEST = CVZN, CC_SRC = unused */ CC_OP_LOGIC, /* CC_DEST = result, CC_SRC = unused */ + CC_OP_ADDB, /* CC_DEST = result, CC_SRC = source */ + CC_OP_ADDW, /* CC_DEST = result, CC_SRC = source */ CC_OP_ADD, /* CC_DEST = result, CC_SRC = source */ + CC_OP_SUBB, /* CC_DEST = result, CC_SRC = source */ + CC_OP_SUBW, /* CC_DEST = result, CC_SRC = source */ CC_OP_SUB, /* CC_DEST = result, CC_SRC = source */ - CC_OP_CMPB, /* CC_DEST = result, CC_SRC = source */ - CC_OP_CMPW, /* CC_DEST = result, CC_SRC = source */ + CC_OP_ADDXB, /* CC_DEST = result, CC_SRC = source */ + CC_OP_ADDXW, /* CC_DEST = result, CC_SRC = source */ CC_OP_ADDX, /* CC_DEST = result, CC_SRC = source */ + CC_OP_SUBXB, /* CC_DEST = result, CC_SRC = source */ + CC_OP_SUBXW, /* CC_DEST = result, CC_SRC = source */ CC_OP_SUBX, /* CC_DEST = result, CC_SRC = source */ CC_OP_SHIFT, /* CC_DEST = result, CC_SRC = carry */ }; diff --git a/target-m68k/helper.c b/target-m68k/helper.c index a22dc97..bcd73d5 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -256,6 +256,33 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) flags |= CCF_V; \ } while (0) +#define SET_FLAGS_ADD(type, utype) do { \ + SET_NZ((type)dest); \ + if ((utype) dest < (utype) src) \ + flags |= CCF_C; \ + tmp = dest - src; \ + if ((1u << (sizeof(type) * 8 - 1)) & (src ^ dest) & (tmp ^ src)) \ + flags |= CCF_V; \ + } while (0) + +#define SET_FLAGS_ADDX(type, utype) do { \ + SET_NZ((type)dest); \ + if ((utype) dest <= (utype) src) \ + flags |= CCF_C; \ + tmp = dest - src - 1; \ + if ((1u << (sizeof(type) * 8 - 1)) & (src ^ dest) & (tmp ^ src)) \ + flags |= CCF_V; \ + } while (0) + +#define SET_FLAGS_SUBX(type, utype) do { \ + SET_NZ((type)dest); \ + tmp = dest + src + 1; \ + if ((utype) dest <= (utype) src) \ + flags |= CCF_C; \ + if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \ + flags |= CCF_V; \ + } while (0) + flags = 0; src = env->cc_src; dest = env->cc_dest; @@ -266,38 +293,41 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) case CC_OP_LOGIC: SET_NZ(dest); break; + case CC_OP_ADDB: + SET_FLAGS_ADD(int8_t, uint8_t); + break; + case CC_OP_ADDW: + SET_FLAGS_ADD(int16_t, uint16_t); + break; case CC_OP_ADD: - SET_NZ(dest); - if (dest < src) - flags |= CCF_C; - tmp = dest - src; - if (HIGHBIT & (src ^ dest) & ~(tmp ^ src)) - flags |= CCF_V; + SET_FLAGS_ADD(int32_t, uint32_t); + break; + case CC_OP_SUBB: + SET_FLAGS_SUB(int8_t, uint8_t); + break; + case CC_OP_SUBW: + SET_FLAGS_SUB(int16_t, uint16_t); break; case CC_OP_SUB: SET_FLAGS_SUB(int32_t, uint32_t); break; - case CC_OP_CMPB: - SET_FLAGS_SUB(int8_t, uint8_t); + case CC_OP_ADDXB: + SET_FLAGS_ADDX(int8_t, uint8_t); break; - case CC_OP_CMPW: - SET_FLAGS_SUB(int16_t, uint16_t); + case CC_OP_ADDXW: + SET_FLAGS_ADDX(int16_t, uint16_t); break; case CC_OP_ADDX: - SET_NZ(dest); - if (dest <= src) - flags |= CCF_C; - tmp = dest - src - 1; - if (HIGHBIT & (src ^ dest) & ~(tmp ^ src)) - flags |= CCF_V; + SET_FLAGS_ADDX(int32_t, uint32_t); + break; + case CC_OP_SUBXB: + SET_FLAGS_SUBX(int8_t, uint8_t); + break; + case CC_OP_SUBXW: + SET_FLAGS_SUBX(int16_t, uint16_t); break; case CC_OP_SUBX: - SET_NZ(dest); - tmp = dest + src + 1; - if (tmp <= src) - flags |= CCF_C; - if (HIGHBIT & (tmp ^ dest) & (tmp ^ src)) - flags |= CCF_V; + SET_FLAGS_SUBX(int32_t, uint32_t); break; case CC_OP_SHIFT: SET_NZ(dest); diff --git a/target-m68k/translate.c b/target-m68k/translate.c index dc34a2a..1bf7169 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -264,6 +264,22 @@ static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val, } } +/* Read a 8-bit immediat constant */ +static inline uint32_t read_im8(DisasContext *s) +{ + uint32_t im; + im = ldsb_code(s->pc + 1); + s->pc += 2; + return im; +} +/* Read a 16-bit immediat constant */ +static inline uint32_t read_im16(DisasContext *s) +{ + uint32_t im; + im = ldsw_code(s->pc); + s->pc += 2; + return im; +} /* Read a 32-bit immediate constant. */ static inline uint32_t read_im32(DisasContext *s) { @@ -440,6 +456,25 @@ static inline int opsize_bytes(int opsize) } } +static inline int insn_opsize(int insn, int pos) +{ + switch ((insn >> pos) & 3) { + case 0: return OS_BYTE; + case 1: return OS_WORD; + case 2: return OS_LONG; + default: abort(); + } +} + +#define SET_CC_OP(opsize, op) do { \ + switch (opsize) { \ + case OS_BYTE: s->cc_op = CC_OP_##op##B; break; \ + case OS_WORD: s->cc_op = CC_OP_##op##W; break; \ + case OS_LONG: s->cc_op = CC_OP_##op; break; \ + default: abort(); \ + } \ +} while (0) + /* Assign value to a register. If the width is less than the register width only the low part of the register is set. */ static void gen_partset_reg(int opsize, TCGv reg, TCGv val) @@ -977,31 +1012,33 @@ DISAS_INSN(addsub) TCGv tmp; TCGv addr; int add; + int opsize; add = (insn & 0x4000) != 0; + opsize = insn_opsize(insn, 6); reg = DREG(insn, 9); dest = tcg_temp_new(); if (insn & 0x100) { - SRC_EA(tmp, OS_LONG, 0, &addr); + SRC_EA(tmp, opsize, -1, &addr); src = reg; } else { tmp = reg; - SRC_EA(src, OS_LONG, 0, NULL); + SRC_EA(src, opsize, -1, NULL); } if (add) { tcg_gen_add_i32(dest, tmp, src); gen_helper_xflag_lt(QREG_CC_X, dest, src); - s->cc_op = CC_OP_ADD; + SET_CC_OP(opsize, ADD); } else { gen_helper_xflag_lt(QREG_CC_X, tmp, src); tcg_gen_sub_i32(dest, tmp, src); - s->cc_op = CC_OP_SUB; + SET_CC_OP(opsize, SUB); } gen_update_cc_add(dest, src); if (insn & 0x100) { - DEST_EA(insn, OS_LONG, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } else { - tcg_gen_mov_i32(reg, dest); + gen_partset_reg(opsize, reg, dest); } } @@ -1192,10 +1229,24 @@ DISAS_INSN(arith_im) TCGv src1; TCGv dest; TCGv addr; + int opsize; op = (insn >> 9) & 7; - SRC_EA(src1, OS_LONG, 0, (op == 6) ? NULL : &addr); - im = read_im32(s); + opsize = insn_opsize(insn, 6); + switch (opsize) { + case OS_BYTE: + im = read_im8(s); + break; + case OS_WORD: + im = read_im16(s); + break; + case OS_LONG: + im = read_im32(s); + break; + default: + abort(); + } + SRC_EA(src1, opsize, -1, (op == 6) ? NULL : &addr); dest = tcg_temp_new(); switch (op) { case 0: /* ori */ @@ -1211,14 +1262,14 @@ DISAS_INSN(arith_im) gen_helper_xflag_lt(QREG_CC_X, dest, tcg_const_i32(im)); tcg_gen_subi_i32(dest, dest, im); gen_update_cc_add(dest, tcg_const_i32(im)); - s->cc_op = CC_OP_SUB; + SET_CC_OP(opsize, SUB); break; case 3: /* addi */ tcg_gen_mov_i32(dest, src1); tcg_gen_addi_i32(dest, dest, im); gen_update_cc_add(dest, tcg_const_i32(im)); gen_helper_xflag_lt(QREG_CC_X, dest, tcg_const_i32(im)); - s->cc_op = CC_OP_ADD; + SET_CC_OP(opsize, ADD); break; case 5: /* eori */ tcg_gen_xori_i32(dest, src1, im); @@ -1228,13 +1279,13 @@ DISAS_INSN(arith_im) tcg_gen_mov_i32(dest, src1); tcg_gen_subi_i32(dest, dest, im); gen_update_cc_add(dest, tcg_const_i32(im)); - s->cc_op = CC_OP_SUB; + SET_CC_OP(opsize, SUB); break; default: abort(); } if (op != 6) { - DEST_EA(insn, OS_LONG, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } } @@ -1310,19 +1361,7 @@ DISAS_INSN(clr) { int opsize; - switch ((insn >> 6) & 3) { - case 0: /* clr.b */ - opsize = OS_BYTE; - break; - case 1: /* clr.w */ - opsize = OS_WORD; - break; - case 2: /* clr.l */ - opsize = OS_LONG; - break; - default: - abort(); - } + opsize = insn_opsize(insn, 6); DEST_EA(insn, opsize, tcg_const_i32(0), NULL); gen_logic_cc(s, tcg_const_i32(0)); } @@ -1350,17 +1389,20 @@ DISAS_INSN(move_from_ccr) DISAS_INSN(neg) { - TCGv reg; TCGv src1; + TCGv dest; + TCGv addr; + int opsize; - reg = DREG(insn, 0); - src1 = tcg_temp_new(); - tcg_gen_mov_i32(src1, reg); - tcg_gen_neg_i32(reg, src1); - s->cc_op = CC_OP_SUB; - gen_update_cc_add(reg, src1); - gen_helper_xflag_lt(QREG_CC_X, tcg_const_i32(0), src1); - s->cc_op = CC_OP_SUB; + opsize = insn_opsize(insn, 6); + SRC_EA(src1, opsize, -1, &addr); + dest = tcg_temp_new(); + tcg_gen_neg_i32(dest, src1); + DEST_EA(insn, opsize, dest, &addr); + SET_CC_OP(opsize, SUB); + gen_update_cc_add(src1, dest); + gen_helper_xflag_lt(QREG_CC_X, tcg_const_i32(0), dest); + SET_CC_OP(opsize, SUB); } static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) @@ -1407,11 +1449,17 @@ DISAS_INSN(move_to_ccr) DISAS_INSN(not) { - TCGv reg; + TCGv src1; + TCGv dest; + TCGv addr; + int opsize; - reg = DREG(insn, 0); - tcg_gen_not_i32(reg, reg); - gen_logic_cc(s, reg); + opsize = insn_opsize(insn, 6); + SRC_EA(src1, opsize, -1, &addr); + dest = tcg_temp_new(); + tcg_gen_not_i32(dest, src1); + DEST_EA(insn, opsize, dest, &addr); + gen_logic_cc(s, dest); } DISAS_INSN(swap) @@ -1466,20 +1514,8 @@ DISAS_INSN(tst) int opsize; TCGv tmp; - switch ((insn >> 6) & 3) { - case 0: /* tst.b */ - opsize = OS_BYTE; - break; - case 1: /* tst.w */ - opsize = OS_WORD; - break; - case 2: /* tst.l */ - opsize = OS_LONG; - break; - default: - abort(); - } - SRC_EA(tmp, opsize, 1, NULL); + opsize = insn_opsize(insn, 6); + SRC_EA(tmp, opsize, -1, NULL); gen_logic_cc(s, tmp); } @@ -1600,8 +1636,14 @@ DISAS_INSN(addsubq) TCGv dest; int val; TCGv addr; + int opsize; - SRC_EA(src1, OS_LONG, 0, &addr); + if ((insn & 070) == 010) { + /* Operation on address register is always long. */ + opsize = OS_LONG; + } else + opsize = insn_opsize(insn, 6); + SRC_EA(src1, opsize, -1, &addr); val = (insn >> 9) & 7; if (val == 0) val = 8; @@ -1620,11 +1662,11 @@ DISAS_INSN(addsubq) if (insn & 0x0100) { gen_helper_xflag_lt(QREG_CC_X, dest, src2); tcg_gen_subi_i32(dest, dest, val); - s->cc_op = CC_OP_SUB; + SET_CC_OP(opsize, SUB); } else { tcg_gen_addi_i32(dest, dest, val); gen_helper_xflag_lt(QREG_CC_X, dest, src2); - s->cc_op = CC_OP_ADD; + SET_CC_OP(opsize, ADD); } gen_update_cc_add(dest, src2); } @@ -1712,17 +1754,19 @@ DISAS_INSN(or) TCGv dest; TCGv src; TCGv addr; + int opsize; + opsize = insn_opsize(insn, 6); reg = DREG(insn, 9); dest = tcg_temp_new(); if (insn & 0x100) { - SRC_EA(src, OS_LONG, 0, &addr); + SRC_EA(src, opsize, -1, &addr); tcg_gen_or_i32(dest, src, reg); - DEST_EA(insn, OS_LONG, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } else { - SRC_EA(src, OS_LONG, 0, NULL); + SRC_EA(src, opsize, -1, NULL); tcg_gen_or_i32(dest, src, reg); - tcg_gen_mov_i32(reg, dest); + gen_partset_reg(opsize, reg, dest); } gen_logic_cc(s, dest); } @@ -1763,34 +1807,18 @@ DISAS_INSN(mov3q) DISAS_INSN(cmp) { - int op; TCGv src; TCGv reg; TCGv dest; int opsize; - op = (insn >> 6) & 3; - switch (op) { - case 0: /* cmp.b */ - opsize = OS_BYTE; - s->cc_op = CC_OP_CMPB; - break; - case 1: /* cmp.w */ - opsize = OS_WORD; - s->cc_op = CC_OP_CMPW; - break; - case 2: /* cmp.l */ - opsize = OS_LONG; - s->cc_op = CC_OP_SUB; - break; - default: - abort(); - } - SRC_EA(src, opsize, 1, NULL); + opsize = insn_opsize(insn, 6); + SRC_EA(src, opsize, -1, NULL); reg = DREG(insn, 9); dest = tcg_temp_new(); tcg_gen_sub_i32(dest, reg, src); gen_update_cc_add(dest, src); + SET_CC_OP(opsize, SUB); } DISAS_INSN(cmpa) @@ -1810,7 +1838,7 @@ DISAS_INSN(cmpa) dest = tcg_temp_new(); tcg_gen_sub_i32(dest, reg, src); gen_update_cc_add(dest, src); - s->cc_op = CC_OP_SUB; + SET_CC_OP(opsize, SUB); } DISAS_INSN(eor) @@ -1819,13 +1847,15 @@ DISAS_INSN(eor) TCGv reg; TCGv dest; TCGv addr; + int opsize; - SRC_EA(src, OS_LONG, 0, &addr); + opsize = insn_opsize(insn, 6); + SRC_EA(src, opsize, -1, &addr); reg = DREG(insn, 9); dest = tcg_temp_new(); tcg_gen_xor_i32(dest, src, reg); gen_logic_cc(s, dest); - DEST_EA(insn, OS_LONG, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } DISAS_INSN(and) @@ -1834,17 +1864,19 @@ DISAS_INSN(and) TCGv reg; TCGv dest; TCGv addr; + int opsize; + opsize = insn_opsize(insn, 6); reg = DREG(insn, 9); dest = tcg_temp_new(); if (insn & 0x100) { - SRC_EA(src, OS_LONG, 0, &addr); + SRC_EA(src, opsize, -1, &addr); tcg_gen_and_i32(dest, src, reg); - DEST_EA(insn, OS_LONG, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } else { - SRC_EA(src, OS_LONG, 0, NULL); + SRC_EA(src, opsize, -1, NULL); tcg_gen_and_i32(dest, src, reg); - tcg_gen_mov_i32(reg, dest); + gen_partset_reg(opsize, reg, dest); } gen_logic_cc(s, dest); } -- 1.5.6.5