[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 022/111] m68k: add bitfield_mem, bitfield_reg
From: |
Bryce Lanham |
Subject: |
[Qemu-devel] [PATCH 022/111] m68k: add bitfield_mem, bitfield_reg |
Date: |
Wed, 17 Aug 2011 15:46:27 -0500 |
From: Laurent Vivier <address@hidden>
This patch implements bitfields instructions: bftst, bfextu, bfexts,
bfffo, bfchg, bfclr, bfset, bfins and attach them to BITFIELD feature.
Signed-off-by: Andreas Schwab <address@hidden>
Signed-off-by: Laurent Vivier <address@hidden>
---
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 7f83d20..d6c92bf 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -519,6 +519,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 cf59ffe..334681b 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2386,6 +2386,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;
@@ -3528,6 +3849,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.7.2.3
- [Qemu-devel] [PATCH 011/111] m68k: add missing accessing modes for some instructions., (continued)
- [Qemu-devel] [PATCH 011/111] m68k: add missing accessing modes for some instructions., Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 013/111] m68k: add Scc instruction with memory operand., Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 012/111] m68k: add Motorola 680x0 family common instructions., Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 015/111] m68k: modify movem instruction to manage word, Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 016/111] m68k: add 64bit divide., Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 014/111] m68k: add DBcc instruction., Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 018/111] m68k: add word data size for suba/adda, Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 017/111] m68k: add 32bit and 64bit multiply, Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 019/111] m68k: add fpu, Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 020/111] m68k: add "byte", "word" and memory shift, Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 022/111] m68k: add bitfield_mem, bitfield_reg,
Bryce Lanham <=
- [Qemu-devel] [PATCH 029/111] m68k: allow fpu to manage double data type with fmove to <ea>, Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 030/111] m68k: add FScc instruction, Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 031/111] m68k: add single data type to gen_ea, Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 039/111] m68k: add abcd instruction, Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 035/111] m68k: improve CC_OP_LOGIC, Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 037/111] Correct invalid use of "const void *" with "const uint8_t *", Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 041/111] mm68k: add nbcd instruction, Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 050/111] m68k: lsl/lsr, clear C flag if shift count is 0, Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 043/111] m68k: on 0 bit shift, don't update X flag, Bryce Lanham, 2011/08/17
- [Qemu-devel] [PATCH 075/111] m68k: better fpu traces, Bryce Lanham, 2011/08/17