qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Laurent Vivier <laurent@vivier.eu>
To: qemu-devel@nongnu.org
Cc: Andreas Schwab <schwab@linux-m68k.org>,
	Laurent Vivier <laurent@vivier.eu>
Subject: [Qemu-devel] [PATCH 15/17] m68k: add bitfield_mem, bitfield_reg
Date: Sat, 30 May 2009 00:41:59 +0200	[thread overview]
Message-ID: <1243636921-23054-16-git-send-email-laurent@vivier.eu> (raw)
In-Reply-To: <1243636921-23054-15-git-send-email-laurent@vivier.eu>

This patch implements bitfields instructions: bftst, bfextu, bfexts,
bfffo, bfchg, bfclr, bfset, bfins and attach them to BITFIELD feature.

Signed-off-by: Andreas Schwab <schwab@linux-m68k.org>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target-m68k/helper.c    |   27 ++++
 target-m68k/helpers.h   |    3 +
 target-m68k/translate.c |  323 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 353 insertions(+), 0 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 92c7621..32ff8ca 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -514,6 +514,33 @@ uint32_t HELPER(ff1)(uint32_t x)
     return n;
 }
 
+uint32_t HELPER(bfffo)(uint32_t arg, uint32_t width)
+{
+    int n;
+    uint32_t mask;
+    mask = 0x80000000;
+    for (n = 0; n < width; n++) {
+       if (arg & mask)
+           break;
+       mask >>= 1;
+    }
+    return n;
+}
+
+uint32_t HELPER(rol32)(uint32_t val, uint32_t shift)
+{
+    uint32_t result;
+    result = (val << shift) | (val >> (32 - shift));
+    return result;
+}
+
+uint32_t HELPER(ror32)(uint32_t val, uint32_t shift)
+{
+    uint32_t result;
+    result = (val >> shift) | (val << (32 - shift));
+    return result;
+}
+
 uint32_t HELPER(sats)(uint32_t val, uint32_t ccr)
 {
     /* The result has the opposite sign to the original value.  */
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 07d1f82..949d5d5 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -2,6 +2,9 @@
 
 DEF_HELPER_1(bitrev, i32, i32)
 DEF_HELPER_1(ff1, i32, i32)
+DEF_HELPER_2(bfffo, i32, i32, i32)
+DEF_HELPER_2(rol32, i32, i32, i32)
+DEF_HELPER_2(ror32, i32, i32, i32)
 DEF_HELPER_2(sats, i32, i32, i32)
 DEF_HELPER_2(divu, void, env, i32)
 DEF_HELPER_2(divs, void, env, i32)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 17ab88c..289e3bb 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2390,6 +2390,327 @@ DISAS_INSN(rotate_mem)
     DEST_EA(insn, OS_WORD, dest, &addr);
 }
 
+DISAS_INSN(bitfield_reg)
+{
+    uint16_t ext;
+    TCGv tmp;
+    TCGv tmp1;
+    TCGv reg;
+    int offset;
+    int width;
+    int op;
+    TCGv reg2;
+    uint32_t mask;
+
+    reg = DREG(insn, 0);
+    op = (insn >> 8) & 7;
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+    if ((ext & 0x820) == 0) {
+       /* constant offset and width */
+       offset = (ext >> 6) & 31;
+       width = (ext & 31);
+       if (width == 0)
+           width = 32;
+       reg2 = DREG(ext, 12);
+       mask = 0xffffffff << (32 - width);
+       if (offset > 0)
+           mask = (mask >> offset) | (mask << (32 - offset));
+       tmp = tcg_temp_new_i32();
+       tcg_gen_andi_i32(tmp, reg, mask);
+       if (offset > 0) {
+           tmp1 = tcg_temp_new_i32();
+           gen_helper_rol32(tmp1, tmp, tcg_const_i32(offset));
+       } else
+           tmp1 = tmp;
+       gen_logic_cc(s, tmp1);
+       switch (op) {
+       case 0: /* bftst */
+           break;
+       case 1: /* bfextu */
+           if (offset + width != 32)
+               gen_helper_rol32(reg2, tmp, tcg_const_i32((offset + width) & 31));
+           else
+               tcg_gen_mov_i32(reg2, tmp);
+           break;
+       case 2: /* bfchg */
+           tcg_gen_xor_i32(reg, reg, tcg_const_i32(mask));
+           break;
+       case 3: /* bfexts */
+           if (offset > 0)
+               gen_helper_rol32(reg2, tmp, tcg_const_i32(offset));
+           if (width < 32)
+               tcg_gen_sari_i32(reg2, reg2, 32 - width);
+           break;
+       case 4: /* bfclr */
+	   tcg_gen_and_i32(reg, reg, tcg_const_i32(mask));
+           break;
+       case 5: /* bfffo */
+           if (offset > 0)
+               gen_helper_rol32(reg2, tmp, tcg_const_i32(offset));
+           gen_helper_bfffo(tmp, tmp, tcg_const_i32(width));
+           tcg_gen_addi_i32(reg2, tmp, offset);
+           break;
+       case 6: /* bfset */
+           tcg_gen_ori_i32(reg, reg, mask);
+           break;
+       case 7: /* bfins */
+           if (width == 32) {
+               if (offset > 0)
+                   gen_helper_ror32(reg, reg2, tcg_const_i32(offset));
+               else
+                   tcg_gen_mov_i32(reg, reg2);
+           } else {
+               tcg_gen_andi_i32(tmp, reg2, (1u << width) - 1);
+               if (offset + width != 32)
+                   gen_helper_ror32(tmp, tmp, tcg_const_i32((offset + width) & 31));
+               tcg_gen_andi_i32(reg, reg, ~mask);
+               tcg_gen_or_i32(reg, reg, tmp);
+           }
+           break;
+       }
+       return;
+    }
+    /* Not yet implemented */
+    gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
+}
+
+/* Generate a load from a bitfield.  */
+static void gen_bitfield_load(DisasContext *s, TCGv addr, int endpos,
+                             TCGv *val1, TCGv *val2)
+{   
+    TCGv tmp;
+    
+    if (endpos <= 8)
+       *val1 = gen_load(s, OS_BYTE, addr, 0);
+    else if (endpos <= 24) {
+       *val1 = gen_load(s, OS_WORD, addr, 0);
+       if (endpos > 16) {
+           tmp = tcg_temp_new_i32();
+           tcg_gen_addi_i32(tmp, addr, 2);
+           *val2 = gen_load(s, OS_BYTE, tmp, 0);
+       }
+    } else {
+       *val1 = gen_load(s, OS_LONG, addr, 0);
+       if (endpos > 32) {
+           tmp = tcg_temp_new_i32();
+           tcg_gen_addi_i32(tmp, addr, 4);
+           *val2 = gen_load(s, OS_BYTE, tmp, 0);
+       }
+    }
+}
+
+/* Generate a store to a bitfield.  */
+static void gen_bitfield_store(DisasContext *s, TCGv addr, int endpos,
+                              TCGv val1, TCGv val2)
+{
+    TCGv tmp;
+
+    if (endpos <= 8)
+       gen_store(s, OS_BYTE, addr, val1);
+    else if (endpos <= 24) {
+       gen_store(s, OS_WORD, addr, val1);
+       if (endpos > 16) {
+           tmp = tcg_temp_new_i32();
+           tcg_gen_addi_i32(tmp, addr, 2);
+           gen_store(s, OS_BYTE, tmp, val2);
+       }
+    } else {
+       gen_store(s, OS_LONG, addr, val1);
+       if (endpos > 32) {
+           tmp = tcg_temp_new_i32();
+           tcg_gen_addi_i32(tmp, addr, 4);
+           gen_store(s, OS_BYTE, tmp, val2);
+       }
+    }
+}
+
+static TCGv gen_bitfield_cc(DisasContext *s, int offset, int width,
+                          TCGv val1, TCGv val2)
+{
+    TCGv dest;
+    TCGv tmp;
+
+    dest = tcg_temp_new_i32();
+
+    if (offset + width <= 8)
+       tcg_gen_shli_i32(dest, val1, 24 + offset);
+    else if (offset + width <= 24) {
+       tcg_gen_shli_i32(dest, val1, 16 + offset);
+       if (offset + width > 16) {
+           tmp = tcg_temp_new_i32();
+           tcg_gen_shli_i32(tmp, val2, 8 + offset);
+           tcg_gen_or_i32(dest, dest, tmp);
+       }
+    } else {
+       tcg_gen_shli_i32(dest, val1, offset);
+       if (offset + width > 32) {
+           tmp = tcg_temp_new_i32();
+           tcg_gen_shri_i32(tmp, val2, offset);
+           tcg_gen_or_i32(dest, dest, tmp);
+       }
+    }
+    tcg_gen_andi_i32(dest, dest, 0xffffffff << (32 - width));
+    gen_logic_cc(s, dest);
+    return dest;
+}
+
+static void gen_bitfield_op(int offset, int width, int op, TCGv val1, TCGv val2)
+{
+    uint32_t mask1;
+    uint32_t mask2;
+    int endpos = offset + width;
+
+    if (endpos <= 8) {
+       mask1 = (0xff >> offset) & (0xff << (8 - endpos));
+       mask2 = 0;
+    } else if (endpos <= 16) {
+       mask1 = (0xffff >> offset) & (0xffff << (16 - endpos));
+       mask2 = 0;
+    } else if (endpos <= 24) {
+       mask1 = 0xffffff >> offset;
+       mask2 = 0xff & (0xff << (24 - endpos));
+    } else if (endpos <= 32) {
+       mask1 = (0xffffffff >> offset) & (0xffffffff << (32 - endpos));
+       mask2 = 0;
+    } else {
+       mask1 = 0xffffffff >> offset;
+       mask2 = 0xff & (0xff << (40 - endpos));
+    }
+    switch (op) {
+    case 2:                    /* bfchg */
+       tcg_gen_xori_i32(val1, val1, mask1);
+       if (mask2)
+           tcg_gen_xori_i32(val2, val2, mask2);
+       break;
+    case 4:                    /* bfclr */
+       tcg_gen_andi_i32(val1, val1, ~mask1);
+       if (mask2)
+           tcg_gen_andi_i32(val2, val2, ~mask2);
+       break;
+    case 6:                    /* bfset */
+       tcg_gen_ori_i32(val1, val1, mask1);
+       if (mask2)
+           tcg_gen_ori_i32(val2, val2, mask2);
+       break;
+    }
+}
+
+static void gen_bitfield_ins(int offset, int width, TCGv src,
+                            TCGv val1, TCGv val2)
+{
+    TCGv tmp;
+    int endpos = offset + width;
+
+    tmp = tcg_temp_new_i32();
+    if (width < 32) {
+       tcg_gen_andi_i32(tmp, src, (1u << width) - 1);
+    } else
+       tcg_gen_mov_i32(tmp, src);
+    if (endpos <= 8) {
+       if (endpos < 8)
+           tcg_gen_shli_i32(tmp, tmp, 8 - endpos);
+       tcg_gen_or_i32(val1, val1, tmp);
+    } else if (endpos <= 16) {
+       if (endpos < 16)
+           tcg_gen_shli_i32(tmp, tmp, 16 - endpos);
+       tcg_gen_or_i32(val1, val1, tmp);
+    } else if (endpos <= 24) {
+       tcg_gen_shri_i32(tmp, tmp, endpos - 16);
+       tcg_gen_or_i32(val1, val1, tmp);
+       tcg_gen_andi_i32(tmp, src, (1u << (endpos - 16)) - 1);
+       if (endpos < 24)
+           tcg_gen_shli_i32(tmp, tmp, 24 - endpos);
+       tcg_gen_or_i32(val2, val2, tmp);
+    } else if (endpos <= 32) {
+       if (endpos < 32)
+           tcg_gen_shli_i32(tmp, tmp, 32 - endpos);
+       tcg_gen_or_i32(val1, val1, tmp);
+    } else {
+       tcg_gen_shri_i32(tmp, tmp, endpos - 32);
+       tcg_gen_or_i32(val1, val1, tmp);
+       tcg_gen_andi_i32(tmp, src, (1u << (endpos - 32)) - 1);
+       tcg_gen_shri_i32(tmp, tmp, 32 - endpos);
+       tcg_gen_or_i32(val2, val2, tmp);
+    }
+}
+
+DISAS_INSN(bitfield_mem)
+{
+    uint16_t ext;
+    TCGv val;
+    TCGv val1, val2;
+    TCGv src;
+    int offset;
+    int width;
+    int op;
+    TCGv reg;
+    TCGv addr;
+    uint32_t mask;
+
+    op = (insn >> 8) & 7;
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+    src = gen_lea(s, insn, OS_LONG);
+    if (IS_NULL_QREG(src)) {
+       gen_addr_fault(s);
+       return;
+    }
+    if ((ext & 0x820) == 0) {
+       /* constant offset and width */
+       offset = (ext >> 6) & 31;
+       width = (ext & 31);
+       if (width == 0)
+           width = 32;
+       reg = DREG(ext, 12);
+       mask = 0xffffffff << (32 - width);
+       addr = tcg_temp_new_i32();
+       if (offset > 7) {
+           tcg_gen_addi_i32(addr, src, offset >> 3);
+           offset &= 7;
+       } else
+           tcg_gen_mov_i32(addr, src);
+       if (offset > 0)
+           mask <<= 32 - offset;
+       gen_bitfield_load(s, addr, offset + width, &val1, &val2);
+       val = gen_bitfield_cc(s, offset, width, val1, val2);
+       switch (op) {
+       case 0: /* bftst */
+           break;
+       case 1: /* bfextu */
+           if (width < 32)
+               tcg_gen_shri_i32(reg, val, 32 - width);
+           else
+               tcg_gen_mov_i32(reg, val);
+           break;
+       case 3: /* bfexts */
+           if (width < 32)
+               tcg_gen_sari_i32(reg, val, 32 - width);
+           else
+               tcg_gen_mov_i32(reg, val);
+           break;
+       case 5: /* bfffo */
+           gen_helper_bfffo(val, val, tcg_const_i32(width));
+           tcg_gen_addi_i32(reg, val, offset);
+           break;
+       case 2: /* bfchg */
+       case 4: /* bfclr */
+       case 6: /* bfset */
+           gen_bitfield_op(offset, width, op, val1, val2);
+           gen_bitfield_store(s, addr, offset + width, val1, val2);
+           break;
+       case 7: /* bfins */
+           gen_bitfield_op(offset, width, 4, val1, val2);
+           gen_bitfield_ins(offset, width, reg, val1, val2);
+           gen_bitfield_store(s, addr, offset + width, val1, val2);
+           break;
+       }
+       return;
+    }
+    /* Not yet implemented */
+    gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
+}
+
 DISAS_INSN(ff1)
 {
     TCGv reg;
@@ -3532,6 +3853,8 @@ void register_m68k_insns (CPUM68KState *env)
     INSN(rotate8_reg, e030, f0f0, M68000);
     INSN(rotate16_reg,e070, f0f0, M68000);
     INSN(rotate_mem, e4c0, fcc0, M68000);
+    INSN(bitfield_mem,e8c0, f8c0, BITFIELD);
+    INSN(bitfield_reg,e8c0, f8f8, BITFIELD);
     INSN(undef_fpu, f000, f000, CF_ISA_A);
     INSN(undef_fpu, f000, f000, M68000);
     INSN(fpu,       f200, ffc0, CF_FPU);
-- 
1.5.6.5

  reply	other threads:[~2009-05-29 22:42 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-05-29 22:41 [Qemu-devel] [PATCH 00/17] m68k: add partial Motorola 680x0 support Laurent Vivier
2009-05-29 22:41 ` [Qemu-devel] [PATCH 01/17] m68k: Replace gen_im32() by tcg_const_i32() Laurent Vivier
2009-05-29 22:41   ` [Qemu-devel] [PATCH 02/17] m68k: add tcg_gen_debug_insn_start() Laurent Vivier
2009-05-29 22:41     ` [Qemu-devel] [PATCH 03/17] m68k: define m680x0 CPUs and features Laurent Vivier
2009-05-29 22:41       ` [Qemu-devel] [PATCH 04/17] m68k: add missing accessing modes for some instructions Laurent Vivier
2009-05-29 22:41         ` [Qemu-devel] [PATCH 05/17] m68k: add Motorola 680x0 family common instructions Laurent Vivier
2009-05-29 22:41           ` [Qemu-devel] [PATCH 06/17] m68k: add Scc instruction with memory operand Laurent Vivier
2009-05-29 22:41             ` [Qemu-devel] [PATCH 07/17] m68k: add DBcc instruction Laurent Vivier
2009-05-29 22:41               ` [Qemu-devel] [PATCH 08/17] m68k: modify movem instruction to manage word Laurent Vivier
2009-05-29 22:41                 ` [Qemu-devel] [PATCH 09/17] m68k: add 64bit divide Laurent Vivier
2009-05-29 22:41                   ` [Qemu-devel] [PATCH 10/17] m68k: add 32bit and 64bit multiply Laurent Vivier
2009-05-29 22:41                     ` [Qemu-devel] [PATCH 11/17] m68k: add word data size for suba/adda Laurent Vivier
2009-05-29 22:41                       ` [Qemu-devel] [PATCH 12/17] m68k: add fpu Laurent Vivier
2009-05-29 22:41                         ` [Qemu-devel] [PATCH 13/17] m68k: add "byte", "word" and memory shift Laurent Vivier
2009-05-29 22:41                           ` [Qemu-devel] [PATCH 14/17] m68k: add "byte", "word" and memory rotate Laurent Vivier
2009-05-29 22:41                             ` Laurent Vivier [this message]
2009-05-29 22:42                               ` [Qemu-devel] [PATCH 16/17] m68k: add variable offset/width to bitfield_reg/bitfield_mem Laurent Vivier
2009-05-29 22:42                                 ` [Qemu-devel] [PATCH 17/17] m68k: add cas Laurent Vivier
2009-05-30 13:53                                   ` [Qemu-devel] " Andreas Schwab
2009-05-30 16:53                                     ` Laurent Vivier
2009-05-30 22:00               ` [Qemu-devel] Re: [PATCH 07/17] m68k: add DBcc instruction Andreas Schwab
2009-05-30 22:05                 ` Laurent Vivier
2009-05-31  2:06         ` [Qemu-devel] [PATCH 04/17] m68k: add missing accessing modes for some instructions Stuart Brady
2009-05-31  9:03           ` Laurent Vivier
2009-05-30 17:31 ` [Qemu-devel] [PATCH 00/17] m68k: add partial Motorola 680x0 support François Revol
2009-09-21  2:56 ` Rob Landley

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1243636921-23054-16-git-send-email-laurent@vivier.eu \
    --to=laurent@vivier.eu \
    --cc=qemu-devel@nongnu.org \
    --cc=schwab@linux-m68k.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).