All of lore.kernel.org
 help / color / mirror / Atom feed
From: Richard Henderson <rth@twiddle.net>
To: qemu-devel@nongnu.org
Cc: laurent@vivier.eu
Subject: [Qemu-devel] [PATCH v2 5/5] target-m68k: Implement bitfield ops for memory
Date: Wed,  9 Nov 2016 14:46:11 +0100	[thread overview]
Message-ID: <1478699171-10637-6-git-send-email-rth@twiddle.net> (raw)
In-Reply-To: <1478699171-10637-1-git-send-email-rth@twiddle.net>

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-m68k/cpu.h       |   1 +
 target-m68k/helper.h    |   7 ++
 target-m68k/op_helper.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++
 target-m68k/translate.c | 142 ++++++++++++++++++++++++++++++++++++-
 4 files changed, 333 insertions(+), 2 deletions(-)

diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index 7c119ba..0b63c0a 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -37,6 +37,7 @@
 #define OS_DOUBLE   4
 #define OS_EXTENDED 5
 #define OS_PACKED   6
+#define OS_UNSIZED  7
 
 #define MAX_QREGS 32
 
diff --git a/target-m68k/helper.h b/target-m68k/helper.h
index cae5bcb..301b7d1 100644
--- a/target-m68k/helper.h
+++ b/target-m68k/helper.h
@@ -77,3 +77,10 @@ DEF_HELPER_2(flush_flags, void, env, i32)
 DEF_HELPER_2(set_ccr, void, env, i32)
 DEF_HELPER_FLAGS_1(get_ccr, TCG_CALL_NO_WG_SE, i32, env)
 DEF_HELPER_2(raise_exception, void, env, i32)
+
+DEF_HELPER_FLAGS_4(bfexts_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32)
+DEF_HELPER_FLAGS_4(bfextu_mem, TCG_CALL_NO_WG, i64, env, i32, s32, i32)
+DEF_HELPER_FLAGS_5(bfins_mem, TCG_CALL_NO_WG, i32, env, i32, i32, s32, i32)
+DEF_HELPER_FLAGS_4(bfchg_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32)
+DEF_HELPER_FLAGS_4(bfclr_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32)
+DEF_HELPER_FLAGS_4(bfset_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32)
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index a4bfa4e..77d1f58 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -359,3 +359,188 @@ void HELPER(divsll)(CPUM68KState *env, int numr, int regr, int32_t den)
     env->dregs[regr] = rem;
     env->dregs[numr] = quot;
 }
+
+struct bf_data {
+    uint32_t addr;
+    uint32_t bofs;
+    uint32_t blen;
+    uint32_t len;
+};
+
+static struct bf_data bf_prep(uint32_t addr, int32_t ofs, uint32_t len)
+{
+    int bofs, blen;
+
+    /* Bound length; map 0 to 32.  */
+    len = ((len - 1) & 31) + 1;
+
+    /* Note that ofs is signed.  */
+    addr += ofs / 8;
+    bofs = ofs % 8;
+    if (bofs < 0) {
+        bofs += 8;
+        addr -= 1;
+    }
+
+    /* Compute the number of bytes required (minus one) to
+       satisfy the bitfield.  */
+    blen = (bofs + len - 1) / 8;
+
+    /* Canonicalize the bit offset for data loaded into a 64-bit big-endian
+       word.  For the cases where BLEN is not a power of 2, adjust ADDR so
+       that we can use the next power of two sized load without crossing a
+       page boundary, unless the field itself crosses the boundary.  */
+    switch (blen) {
+    case 0:
+        bofs += 56;
+        break;
+    case 1:
+        bofs += 48;
+        break;
+    case 2:
+        if (addr & 1) {
+            bofs += 8;
+            addr -= 1;
+        }
+        /* fallthru */
+    case 3:
+        bofs += 32;
+        break;
+    case 4:
+        if (addr & 3) {
+            bofs += 8 * (addr & 3);
+            addr &= -4;
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    return (struct bf_data){
+        .addr = addr,
+        .bofs = bofs,
+        .blen = blen,
+        .len = len,
+    };
+}
+
+static uint64_t bf_load(CPUM68KState *env, uint32_t addr, int blen,
+                        uintptr_t ra)
+{
+    switch (blen) {
+    case 0:
+        return cpu_ldub_data_ra(env, addr, ra);
+    case 1:
+        return cpu_lduw_data_ra(env, addr, ra);
+    case 2:
+    case 3:
+        return cpu_ldl_data_ra(env, addr, ra);
+    case 4:
+        return cpu_ldq_data_ra(env, addr, ra);
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void bf_store(CPUM68KState *env, uint32_t addr, int blen,
+                     uint64_t data, uintptr_t ra)
+{
+    switch (blen) {
+    case 0:
+        cpu_stb_data_ra(env, addr, data, ra);
+        break;
+    case 1:
+        cpu_stw_data_ra(env, addr, data, ra);
+        break;
+    case 2:
+    case 3:
+        cpu_stl_data_ra(env, addr, data, ra);
+        break;
+    case 4:
+        cpu_stq_data_ra(env, addr, data, ra);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+uint32_t HELPER(bfexts_mem)(CPUM68KState *env, uint32_t addr,
+                            int32_t ofs, uint32_t len)
+{
+    uintptr_t ra = GETPC();
+    struct bf_data d = bf_prep(addr, ofs, len);
+    uint64_t data = bf_load(env, d.addr, d.blen, ra);
+
+    return (int64_t)(data << d.bofs) >> (64 - len);
+}
+
+uint64_t HELPER(bfextu_mem)(CPUM68KState *env, uint32_t addr,
+                            int32_t ofs, uint32_t len)
+{
+    uintptr_t ra = GETPC();
+    struct bf_data d = bf_prep(addr, ofs, len);
+    uint64_t data = bf_load(env, d.addr, d.blen, ra);
+
+    /* Put CC_N at the top of the high word; put the zero-extended value
+       at the bottom of the low word.  */
+    data <<= d.bofs;
+    data >>= 64 - d.len;
+    data |= data << (64 - d.len);
+
+    return data;
+}
+
+uint32_t HELPER(bfins_mem)(CPUM68KState *env, uint32_t addr, uint32_t val,
+                           int32_t ofs, uint32_t len)
+{
+    uintptr_t ra = GETPC();
+    struct bf_data d = bf_prep(addr, ofs, len);
+    uint64_t data = bf_load(env, d.addr, d.blen, ra);
+    uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
+
+    data = (data & ~mask) | (((uint64_t)val << (64 - d.len)) >> d.bofs);
+
+    bf_store(env, d.addr, d.blen, data, ra);
+
+    /* The field at the top of the word is also CC_N for CC_OP_LOGIC.  */
+    return val << (32 - d.len);
+}
+
+uint32_t HELPER(bfchg_mem)(CPUM68KState *env, uint32_t addr,
+                           int32_t ofs, uint32_t len)
+{
+    uintptr_t ra = GETPC();
+    struct bf_data d = bf_prep(addr, ofs, len);
+    uint64_t data = bf_load(env, d.addr, d.blen, ra);
+    uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
+
+    bf_store(env, d.addr, d.blen, data ^ mask, ra);
+
+    return ((data & mask) << d.bofs) >> 32;
+}
+
+uint32_t HELPER(bfclr_mem)(CPUM68KState *env, uint32_t addr,
+                           int32_t ofs, uint32_t len)
+{
+    uintptr_t ra = GETPC();
+    struct bf_data d = bf_prep(addr, ofs, len);
+    uint64_t data = bf_load(env, d.addr, d.blen, ra);
+    uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
+
+    bf_store(env, d.addr, d.blen, data & ~mask, ra);
+
+    return ((data & mask) << d.bofs) >> 32;
+}
+
+uint32_t HELPER(bfset_mem)(CPUM68KState *env, uint32_t addr,
+                           int32_t ofs, uint32_t len)
+{
+    uintptr_t ra = GETPC();
+    struct bf_data d = bf_prep(addr, ofs, len);
+    uint64_t data = bf_load(env, d.addr, d.blen, ra);
+    uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
+
+    bf_store(env, d.addr, d.blen, data | mask, ra);
+
+    return ((data & mask) << d.bofs) >> 32;
+}
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index be59c37..61d9681 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -752,10 +752,17 @@ static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s,
     case 0: /* Data register direct.  */
     case 1: /* Address register direct.  */
         return NULL_QREG;
-    case 2: /* Indirect register */
     case 3: /* Indirect postincrement.  */
+        if (opsize == OS_UNSIZED) {
+            return NULL_QREG;
+        }
+        /* fallthru */
+    case 2: /* Indirect register */
         return get_areg(s, reg0);
     case 4: /* Indirect predecrememnt.  */
+        if (opsize == OS_UNSIZED) {
+            return NULL_QREG;
+        }
         reg = get_areg(s, reg0);
         tmp = tcg_temp_new();
         tcg_gen_subi_i32(tmp, reg, opsize_bytes(opsize));
@@ -3150,6 +3157,49 @@ DISAS_INSN(bfext_reg)
     set_cc_op(s, CC_OP_LOGIC);
 }
 
+DISAS_INSN(bfext_mem)
+{
+    int ext = read_im16(env, s);
+    int is_sign = insn & 0x200;
+    TCGv dest = DREG(ext, 12);
+    TCGv addr, len, ofs;
+
+    addr = gen_lea(env, s, insn, OS_UNSIZED);
+    if (IS_NULL_QREG(addr)) {
+        gen_addr_fault(s);
+        return;
+    }
+
+    if (ext & 0x20) {
+        len = DREG(ext, 0);
+    } else {
+        len = tcg_const_i32(extract32(ext, 0, 5));
+    }
+    if (ext & 0x800) {
+        ofs = DREG(ext, 6);
+    } else {
+        ofs = tcg_const_i32(extract32(ext, 6, 5));
+    }
+
+    if (is_sign) {
+        gen_helper_bfexts_mem(dest, cpu_env, addr, ofs, len);
+        tcg_gen_mov_i32(QREG_CC_N, dest);
+    } else {
+        TCGv_i64 tmp = tcg_temp_new_i64();
+        gen_helper_bfextu_mem(tmp, cpu_env, addr, ofs, len);
+        tcg_gen_extr_i64_i32(dest, QREG_CC_N, tmp);
+        tcg_temp_free_i64(tmp);
+    }
+    set_cc_op(s, CC_OP_LOGIC);
+
+    if (!(ext & 0x20)) {
+        tcg_temp_free(len);
+    }
+    if (!(ext & 0x800)) {
+        tcg_temp_free(ofs);
+    }
+}
+
 DISAS_INSN(bfop_reg)
 {
     int ext = read_im16(env, s);
@@ -3215,6 +3265,54 @@ DISAS_INSN(bfop_reg)
     tcg_temp_free(mask);
 }
 
+DISAS_INSN(bfop_mem)
+{
+    int ext = read_im16(env, s);
+    TCGv addr, len, ofs;
+
+    addr = gen_lea(env, s, insn, OS_UNSIZED);
+    if (IS_NULL_QREG(addr)) {
+        gen_addr_fault(s);
+        return;
+    }
+
+    if (ext & 0x20) {
+        len = DREG(ext, 0);
+    } else {
+        len = tcg_const_i32(extract32(ext, 0, 5));
+    }
+    if (ext & 0x800) {
+        ofs = DREG(ext, 6);
+    } else {
+        ofs = tcg_const_i32(extract32(ext, 6, 5));
+    }
+
+    switch (insn & 0x0f00) {
+    case 0x0a00: /* bfchg */
+        gen_helper_bfchg_mem(QREG_CC_N, cpu_env, addr, ofs, len);
+        break;
+    case 0x0c00: /* bfclr */
+        gen_helper_bfclr_mem(QREG_CC_N, cpu_env, addr, ofs, len);
+        break;
+    case 0x0e00: /* bfset */
+        gen_helper_bfset_mem(QREG_CC_N, cpu_env, addr, ofs, len);
+        break;
+    case 0x0800: /* bftst */
+        gen_helper_bfexts_mem(QREG_CC_N, cpu_env, addr, ofs, len);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    set_cc_op(s, CC_OP_LOGIC);
+
+    if (!(ext & 0x20)) {
+        tcg_temp_free(len);
+    }
+    if (!(ext & 0x800)) {
+        tcg_temp_free(ofs);
+    }
+}
+
 DISAS_INSN(bfins_reg)
 {
     int ext = read_im16(env, s);
@@ -3289,6 +3387,40 @@ DISAS_INSN(bfins_reg)
     tcg_temp_free(tmp);
 }
 
+DISAS_INSN(bfins_mem)
+{
+    int ext = read_im16(env, s);
+    TCGv src = DREG(ext, 12);
+    TCGv addr, len, ofs;
+
+    addr = gen_lea(env, s, insn, OS_UNSIZED);
+    if (IS_NULL_QREG(addr)) {
+        gen_addr_fault(s);
+        return;
+    }
+
+    if (ext & 0x20) {
+        len = DREG(ext, 0);
+    } else {
+        len = tcg_const_i32(extract32(ext, 0, 5));
+    }
+    if (ext & 0x800) {
+        ofs = DREG(ext, 6);
+    } else {
+        ofs = tcg_const_i32(extract32(ext, 6, 5));
+    }
+
+    gen_helper_bfins_mem(QREG_CC_N, cpu_env, addr, src, ofs, len);
+    set_cc_op(s, CC_OP_LOGIC);
+
+    if (!(ext & 0x20)) {
+        tcg_temp_free(len);
+    }
+    if (!(ext & 0x800)) {
+        tcg_temp_free(ofs);
+    }
+}
+
 DISAS_INSN(ff1)
 {
     TCGv reg;
@@ -4576,11 +4708,17 @@ void register_m68k_insns (CPUM68KState *env)
     INSN(shift16_reg, e060, f0f0, M68000);
     INSN(shift_reg, e0a0, f0f0, M68000);
     INSN(shift_mem, e0c0, fcc0, M68000);
-    INSN(bfext_reg, e9c0, fdf8, BITFIELD);  /* bfextu & bfexts */
+    INSN(bfext_mem, e9c0, fdc0, BITFIELD);  /* bfextu & bfexts */
+    INSN(bfext_reg, e9c0, fdf8, BITFIELD);
+    INSN(bfins_mem, efc0, ffc0, BITFIELD);
     INSN(bfins_reg, efc0, fff8, BITFIELD);
+    INSN(bfop_mem, eac0, ffc0, BITFIELD);   /* bfchg */
     INSN(bfop_reg, eac0, fff8, BITFIELD);   /* bfchg */
+    INSN(bfop_mem, ecc0, ffc0, BITFIELD);   /* bfclr */
     INSN(bfop_reg, ecc0, fff8, BITFIELD);   /* bfclr */
+    INSN(bfop_mem, eec0, ffc0, BITFIELD);   /* bfset */
     INSN(bfop_reg, eec0, fff8, BITFIELD);   /* bfset */
+    INSN(bfop_mem, e8c0, ffc0, BITFIELD);   /* bftst */
     INSN(bfop_reg, e8c0, fff8, BITFIELD);   /* bftst */
     INSN(undef_fpu, f000, f000, CF_ISA_A);
     INSN(fpu,       f200, ffc0, CF_FPU);
-- 
2.7.4

  parent reply	other threads:[~2016-11-09 13:46 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-11-09 13:46 [Qemu-devel] [PATCH v2 0/5] target-m68k-patches Richard Henderson
2016-11-09 13:46 ` [Qemu-devel] [PATCH v2 1/5] target-m68k: Implement 680x0 movem Richard Henderson
2016-11-09 13:46 ` [Qemu-devel] [PATCH v2 2/5] target-m68k: Do not cpu_abort on undefined insns Richard Henderson
2016-11-09 13:46 ` [Qemu-devel] [PATCH v2 3/5] target-m68k: Inline shifts Richard Henderson
2016-11-27 17:53   ` Laurent Vivier
2016-11-28 14:35     ` Richard Henderson
2016-11-27 19:30   ` Laurent Vivier
2016-11-28 14:47     ` Richard Henderson
2016-11-27 19:35   ` Laurent Vivier
2016-11-28 14:54     ` Richard Henderson
2016-11-29 23:52       ` Laurent Vivier
2016-11-30 20:42         ` Richard Henderson
2016-11-09 13:46 ` [Qemu-devel] [PATCH v2 4/5] target-m68k: Implement bitfield ops for registers Richard Henderson
2016-11-27 19:46   ` Laurent Vivier
2016-11-28 14:55     ` Richard Henderson
2016-11-09 13:46 ` Richard Henderson [this message]
2016-11-27 19:48   ` [Qemu-devel] [PATCH v2 5/5] target-m68k: Implement bitfield ops for memory Laurent Vivier
2016-11-28 16:26     ` Richard Henderson
2016-11-09 14:31 ` [Qemu-devel] [PATCH v2 0/5] target-m68k-patches Laurent Vivier

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=1478699171-10637-6-git-send-email-rth@twiddle.net \
    --to=rth@twiddle.net \
    --cc=laurent@vivier.eu \
    --cc=qemu-devel@nongnu.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.