From patchwork Wed Aug 17 20:46:16 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bryce Lanham X-Patchwork-Id: 110402 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id B255CB6F18 for ; Thu, 18 Aug 2011 08:27:59 +1000 (EST) Received: from localhost ([::1]:49461 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Qtn3H-0007as-DW for incoming@patchwork.ozlabs.org; Wed, 17 Aug 2011 16:49:27 -0400 Received: from eggs.gnu.org ([140.186.70.92]:46879) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Qtn2S-0005Jl-Hz for qemu-devel@nongnu.org; Wed, 17 Aug 2011 16:48:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Qtn2Q-0006fO-BD for qemu-devel@nongnu.org; Wed, 17 Aug 2011 16:48:36 -0400 Received: from mail-gx0-f173.google.com ([209.85.161.173]:54221) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Qtn2Q-0006aR-5v for qemu-devel@nongnu.org; Wed, 17 Aug 2011 16:48:34 -0400 Received: by mail-gx0-f173.google.com with SMTP id 26so1230323gxk.4 for ; Wed, 17 Aug 2011 13:48:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=RGwGqYkcLGoNipnSxno7Wktb2zf0fF4/6kGRXUwN1EI=; b=s6gQe28/P5S8cUlVDi29Q2JCUC879ximEpyWa3m5OuRbk/FZKEkbKNs4nCVukBadLA uRua+9WkCcBL2YM6sqWAx9aZRirp3V6HLsr3DwOZm499pKCAq+qYUmCjtK1+XYo9c+Z9 3j//Su+BTBQ5foRMirZ+neQD6EqGjTQORDe6E= Received: by 10.236.143.100 with SMTP id k64mr4685196yhj.76.1313614113928; Wed, 17 Aug 2011 13:48:33 -0700 (PDT) Received: from localhost.localdomain (betelgeuse.cs.uchicago.edu [128.135.24.226]) by mx.google.com with ESMTPS id a29sm1237029yhj.59.2011.08.17.13.48.32 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 17 Aug 2011 13:48:33 -0700 (PDT) From: Bryce Lanham To: qemu-devel@nongnu.org Date: Wed, 17 Aug 2011 15:46:16 -0500 Message-Id: <1313614076-28878-12-git-send-email-blanham@gmail.com> X-Mailer: git-send-email 1.7.2.3 In-Reply-To: <1313614076-28878-1-git-send-email-blanham@gmail.com> References: <1313614076-28878-1-git-send-email-blanham@gmail.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.161.173 Cc: Andreas Schwab , Laurent Vivier Subject: [Qemu-devel] [PATCH 011/111] m68k: add missing accessing modes for some instructions. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: 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 | 78 +++++++++++++------ target-m68k/translate.c | 202 +++++++++++++++++++++++++++-------------------- 3 files changed, 179 insertions(+), 111 deletions(-) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 0f216c2..688642f 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -132,11 +132,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 f226e4a..dd9079f 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -242,7 +242,7 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) uint32_t dest; uint32_t tmp; -#define HIGHBIT 0x80000000u +#define HIGHBIT(type) (1u << (sizeof(type) * 8 - 1)) #define SET_NZ(x) do { \ if ((x) == 0) \ @@ -256,7 +256,34 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) tmp = dest + src; \ if ((utype) tmp < (utype) src) \ flags |= CCF_C; \ - if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \ + if (HIGHBIT(type) & (tmp ^ dest) & (tmp ^ src)) \ + 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 (HIGHBIT(type) & (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 (HIGHBIT(type) & (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) tmp <= (utype) src) \ + flags |= CCF_C; \ + if (HIGHBIT(type) & (tmp ^ dest) & (tmp ^ src)) \ flags |= CCF_V; \ } while (0) @@ -270,38 +297,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 b86588c..a537373 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -262,6 +262,22 @@ static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val, } } +/* Read an 8-bit immediate 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 immediate 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) { @@ -438,6 +454,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) @@ -974,31 +1009,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); } } @@ -1189,10 +1226,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 */ @@ -1208,14 +1259,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); @@ -1225,13 +1276,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); } } @@ -1307,19 +1358,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)); } @@ -1347,17 +1386,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) @@ -1404,11 +1446,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) @@ -1463,20 +1511,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); } @@ -1597,8 +1633,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; @@ -1617,11 +1659,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); } @@ -1709,17 +1751,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); } @@ -1760,34 +1804,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) @@ -1807,7 +1835,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) @@ -1816,13 +1844,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) @@ -1831,17 +1861,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); }