All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture
@ 2019-01-21 13:15 Yoshinori Sato
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 01/11] TCG translation Yoshinori Sato
                   ` (11 more replies)
  0 siblings, 12 replies; 17+ messages in thread
From: Yoshinori Sato @ 2019-01-21 13:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yoshinori Sato

Hello.
This patch series is added Renesas RX target emulation.

My git repository is bellow.
git://git.pf.osdn.net/gitroot/y/ys/ysato/qemu.git

Since my understanding is not enough,
I want many comments to make this a good one.

Thanks.

Yoshinori Sato (11):
  TCG translation
  RX CPU definition
  TCG helper functions
  Target miscellaneous functions.
  RX disassembler
  RX62N interrupt contoller.
  RX62N internal timer unit.
  RX62N internal  serical communication interface.
  RX Target hardware definition.
  Add rx-softmmu.
  MAINTAINERS: Add RX entry.

 MAINTAINERS                    |   20 +
 arch_init.c                    |    2 +
 configure                      |    8 +
 default-configs/rx-softmmu.mak |    7 +
 disas/Makefile.objs            |    1 +
 disas/rx.c                     | 1277 +++++++++++++++++
 hw/char/Makefile.objs          |    2 +-
 hw/char/renesas_sci.c          |  279 ++++
 hw/intc/Makefile.objs          |    1 +
 hw/intc/rx_icu.c               |  313 +++++
 hw/rx/Makefile.objs            |    1 +
 hw/rx/rx62n.c                  |  233 ++++
 hw/rx/rxqemu.c                 |  106 ++
 hw/timer/Makefile.objs         |    2 +
 hw/timer/renesas_cmt.c         |  226 +++
 hw/timer/renesas_tmr.c         |  401 ++++++
 include/disas/bfd.h            |    5 +
 include/hw/char/renesas_sci.h  |   42 +
 include/hw/intc/rx_icu.h       |   49 +
 include/hw/rx/rx.h             |    7 +
 include/hw/rx/rx62n.h          |   45 +
 include/hw/timer/renesas_cmt.h |   33 +
 include/hw/timer/renesas_tmr.h |   42 +
 include/sysemu/arch_init.h     |    1 +
 target/rx/Makefile.objs        |    2 +
 target/rx/cpu-qom.h            |   54 +
 target/rx/cpu.c                |  226 +++
 target/rx/cpu.h                |  212 +++
 target/rx/gdbstub.c            |  114 ++
 target/rx/helper.c             |  143 ++
 target/rx/helper.h             |   22 +
 target/rx/monitor.c            |   38 +
 target/rx/op_helper.c          |  548 ++++++++
 target/rx/translate.c          | 3003 ++++++++++++++++++++++++++++++++++++++++
 34 files changed, 7464 insertions(+), 1 deletion(-)
 create mode 100644 default-configs/rx-softmmu.mak
 create mode 100644 disas/rx.c
 create mode 100644 hw/char/renesas_sci.c
 create mode 100644 hw/intc/rx_icu.c
 create mode 100644 hw/rx/Makefile.objs
 create mode 100644 hw/rx/rx62n.c
 create mode 100644 hw/rx/rxqemu.c
 create mode 100644 hw/timer/renesas_cmt.c
 create mode 100644 hw/timer/renesas_tmr.c
 create mode 100644 include/hw/char/renesas_sci.h
 create mode 100644 include/hw/intc/rx_icu.h
 create mode 100644 include/hw/rx/rx.h
 create mode 100644 include/hw/rx/rx62n.h
 create mode 100644 include/hw/timer/renesas_cmt.h
 create mode 100644 include/hw/timer/renesas_tmr.h
 create mode 100644 target/rx/Makefile.objs
 create mode 100644 target/rx/cpu-qom.h
 create mode 100644 target/rx/cpu.c
 create mode 100644 target/rx/cpu.h
 create mode 100644 target/rx/gdbstub.c
 create mode 100644 target/rx/helper.c
 create mode 100644 target/rx/helper.h
 create mode 100644 target/rx/monitor.c
 create mode 100644 target/rx/op_helper.c
 create mode 100644 target/rx/translate.c

-- 
2.11.0

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH RFC 01/11] TCG translation
  2019-01-21 13:15 [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture Yoshinori Sato
@ 2019-01-21 13:15 ` Yoshinori Sato
  2019-01-21 13:35   ` Thomas Huth
  2019-01-23  3:17   ` Richard Henderson
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 02/11] RX CPU definition Yoshinori Sato
                   ` (10 subsequent siblings)
  11 siblings, 2 replies; 17+ messages in thread
From: Yoshinori Sato @ 2019-01-21 13:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yoshinori Sato

This part only supported RXv1 instructions.
Instruction manual.
https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01us0032ej0120_rxsm.pdf

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 target/rx/helper.h    |   22 +
 target/rx/op_helper.c |  548 +++++++++
 target/rx/translate.c | 3003 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 3573 insertions(+)
 create mode 100644 target/rx/helper.h
 create mode 100644 target/rx/op_helper.c
 create mode 100644 target/rx/translate.c

diff --git a/target/rx/helper.h b/target/rx/helper.h
new file mode 100644
index 0000000000..fe0bc838d3
--- /dev/null
+++ b/target/rx/helper.h
@@ -0,0 +1,22 @@
+DEF_HELPER_1(raise_illegal_instruction, noreturn, env)
+DEF_HELPER_1(raise_access_fault, noreturn, env)
+DEF_HELPER_1(raise_privilege_violation, noreturn, env)
+DEF_HELPER_1(wait, noreturn, env)
+DEF_HELPER_1(debug, noreturn, env)
+DEF_HELPER_2(rxint, noreturn, env, i32)
+DEF_HELPER_1(rxbrk, noreturn, env)
+DEF_HELPER_FLAGS_4(floatop, TCG_CALL_NO_WG, f32, env, i32, f32, f32)
+DEF_HELPER_2(to_fpsw, void, env, i32)
+DEF_HELPER_FLAGS_2(ftoi, TCG_CALL_NO_WG, i32, env, f32)
+DEF_HELPER_FLAGS_2(round, TCG_CALL_NO_WG, i32, env, f32)
+DEF_HELPER_FLAGS_2(itof, TCG_CALL_NO_WG, f32, env, i32)
+DEF_HELPER_2(racw, void, env, i32)
+DEF_HELPER_1(update_psw, void, env)
+DEF_HELPER_1(psw_c, i32, env)
+DEF_HELPER_1(psw_s, i32, env)
+DEF_HELPER_1(psw_o, i32, env)
+DEF_HELPER_3(mvtc, void, env, i32, i32)
+DEF_HELPER_2(mvfc, i32, env, i32)
+DEF_HELPER_2(cond, i32, env, i32)
+DEF_HELPER_1(unpack_psw, void, env)
+
diff --git a/target/rx/op_helper.c b/target/rx/op_helper.c
new file mode 100644
index 0000000000..c9c87dc308
--- /dev/null
+++ b/target/rx/op_helper.c
@@ -0,0 +1,548 @@
+/*
+ *  RX helper functions
+ *
+ *  Copyright (c) 2018 Yoshinori Sato
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+#include "fpu/softfloat.h"
+
+static uint32_t psw_c(CPURXState *env)
+{
+    int m = env->op_mode & 0x000f;
+    int c;
+    switch (m) {
+    case RX_PSW_OP_NONE:
+        return env->psw_c;
+    case RX_PSW_OP_ADD:
+        c = (env->op_r[m - 1] < env->op_a1[m - 1]);
+        break;
+    case RX_PSW_OP_SUB:
+    case RX_PSW_OP_STRING:
+        c = (env->op_r[m - 1] <= env->op_a1[m - 1]);
+        break;
+    case RX_PSW_OP_BTST:
+    case RX_PSW_OP_ROT:
+        c = (env->op_r[m - 1] != 0);
+        break;
+    case RX_PSW_OP_SHLL:
+    case RX_PSW_OP_SHAR:
+    case RX_PSW_OP_SHLR:
+        c = (env->op_a1[m - 1] != 0);
+        break;
+    case RX_PSW_OP_ABS:
+        c = (env->op_r[m - 1] == 0);
+        break;
+    default:
+        g_assert_not_reached();
+        return -1;
+    }
+    env->psw_c = c;
+    env->op_mode &= ~0x000f;
+    return c;
+}
+
+uint32_t helper_psw_c(CPURXState *env)
+{
+    return psw_c(env);
+}
+
+static uint32_t psw_z(CPURXState *env)
+{
+    int m = (env->op_mode >> 4) & 0x000f;
+    if (m == RX_PSW_OP_NONE)
+        return env->psw_z;
+    else {
+        env->psw_z = (env->op_r[m - 1] == 0);
+        env->op_mode &= ~0x00f0;
+        return env->psw_z;
+    }
+}
+
+static uint32_t psw_s(CPURXState *env)
+{
+    int m = (env->op_mode >> 8) & 0x000f;
+    int s;
+    switch (m) {
+    case RX_PSW_OP_NONE:
+        return env->psw_s;
+    case RX_PSW_OP_FCMP:
+        s = (env->op_r[m - 1] == 2);
+        break;
+    default:
+        s = ((env->op_r[m - 1] & 0x80000000UL) != 0);
+        break;
+    }
+    env->psw_s = s;
+    env->op_mode &= ~0x0f00;
+    return s;
+}
+
+uint32_t helper_psw_s(CPURXState *env)
+{
+    return psw_s(env);
+}
+
+static uint32_t psw_o(CPURXState *env)
+{
+    int m = (env->op_mode >> 12) & 0x000f;
+    int o;
+
+    switch (m) {
+    case RX_PSW_OP_NONE:
+        return env->psw_o;
+    case RX_PSW_OP_ABS:
+        o = (env->op_a1[m - 1] == 0x80000000UL);
+        break;
+    case RX_PSW_OP_ADD: {
+            uint32_t r1, r2;
+            r1 = ~(env->op_a1[m - 1] ^ env->op_a2[m - 1]);
+            r2 = (env->op_a1[m - 1] ^ env->op_r[m - 1]);
+            o = (r1 & r2) >> 31;
+            break;
+        }
+    case RX_PSW_OP_SUB: {
+            uint32_t r1, r2;
+            r1 = (env->op_a1[m - 1] ^ env->op_a2[m - 1]);
+            r2 = (env->op_a1[m - 1] ^ env->op_r[m - 1]);
+            o = (r1 & r2) >> 31;
+            break;
+    }
+    case RX_PSW_OP_DIV:
+        o = (env->op_a1[m - 1] == 0) ||
+            ((env->op_a1[m - 1] == -1) &&
+             (env->op_a2[m - 1] == 0x80000000UL));
+        break;
+    case RX_PSW_OP_SHLL:
+        o = ((env->op_a2[m - 1] & 0x80000000UL) ^
+             (env->op_r[m - 1] & 0x80000000UL)) != 0;
+        break;
+    case RX_PSW_OP_SHAR:
+        o = 0;
+        break;
+    default:
+        g_assert_not_reached();
+        return -1;
+    }
+    env->psw_o = o;
+    env->op_mode &= ~0xf000;
+    return o;
+}
+
+uint32_t helper_psw_o(CPURXState *env)
+{
+    return psw_o(env);
+}
+
+static uint32_t cond_psw_z(CPURXState *env, int set)
+{
+    return psw_z(env) ^ set;
+}
+
+static uint32_t cond_psw_c(CPURXState *env, int set)
+{
+    return psw_c(env) ^ set;
+}
+
+static uint32_t cond_psw_s(CPURXState *env, int set)
+{
+    return psw_s(env) ^ set;
+}
+
+static uint32_t cond_psw_o(CPURXState *env, int set)
+{
+    return psw_o(env) ^ set;
+}
+
+uint32_t helper_cond(CPURXState *env, uint32_t cond)
+{
+    uint32_t c, z, s, o;
+
+    switch (cond) {
+    case 0: /* z */
+    case 1: /* nz */
+        return cond_psw_z(env, cond);
+    case 2: /* c */
+    case 3: /* nc */
+        return cond_psw_c(env, cond - 2);
+    case 4: /* gtu (C&^Z) == 1 */
+    case 5: /* leu (C&^Z) == 0 */
+        c = psw_c(env);
+        z = psw_z(env);
+        return (c && !z) == (5 - cond);
+    case 6: /* pz (S == 0) */
+    case 7: /* n (S == 1) */
+        return cond_psw_s(env, 7 - cond);
+    case 8: /* ge (S^O)==0 */
+    case 9: /* lt (S^O)==1 */
+        s = psw_s(env);
+        o = psw_o(env);
+        return (s | o) == (cond - 8);
+    case 10: /* gt ((S^O)|Z)==0 */
+    case 11: /* le ((S^O)|Z)==1 */
+        s = psw_s(env);
+        o = psw_o(env);
+        z = psw_z(env);
+        return ((s ^ o) | z) == (cond - 10);
+    case 12: /* o */
+    case 13: /* no */
+        return cond_psw_o(env, 13 - cond);
+    case 14: /* always true */
+        return 1;
+    case 15:
+        return 0;
+    default:
+        g_assert_not_reached();
+        return -1;
+    }
+}
+
+uint32_t rx_get_psw_low(CPURXState *env)
+{
+    return (psw_o(env) << 3) |
+        (psw_s(env) << 2) |
+        (psw_z(env) << 1) |
+        (psw_c(env) << 0);
+}
+
+void helper_update_psw(CPURXState *env)
+{
+    struct {
+        uint32_t *p;
+        uint32_t (*fn)(CPURXState *);
+    } const update_proc[] = {
+        {&env->psw_c, psw_c},
+        {&env->psw_z, psw_z},
+        {&env->psw_s, psw_s},
+        {&env->psw_o, psw_o},
+    };
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        *(update_proc[i].p) = update_proc[i].fn(env);
+    }
+    g_assert((env->op_mode & 0xffff) == 0);
+}
+
+static inline void QEMU_NORETURN raise_exception(CPURXState *env, int index,
+                                                 uintptr_t retaddr)
+{
+    CPUState *cs = CPU(rx_env_get_cpu(env));
+
+    cs->exception_index = index;
+    cpu_loop_exit_restore(cs, retaddr);
+}
+
+void QEMU_NORETURN helper_raise_privilege_violation(CPURXState *env)
+{
+    raise_exception(env, 20, GETPC());
+}
+
+void QEMU_NORETURN helper_raise_access_fault(CPURXState *env)
+{
+    raise_exception(env, 21, GETPC());
+}
+
+void QEMU_NORETURN helper_raise_illegal_instruction(CPURXState *env)
+{
+    raise_exception(env, 23, GETPC());
+}
+
+void QEMU_NORETURN helper_wait(CPURXState *env)
+{
+    CPUState *cs = CPU(rx_env_get_cpu(env));
+
+    cs->halted = 1;
+    env->in_sleep = 1;
+    raise_exception(env, EXCP_HLT, 0);
+}
+
+void QEMU_NORETURN helper_debug(CPURXState *env)
+{
+    CPUState *cs = CPU(rx_env_get_cpu(env));
+
+    cs->exception_index = EXCP_DEBUG;
+    cpu_loop_exit(cs);
+}
+
+void QEMU_NORETURN helper_rxint(CPURXState *env, uint32_t vec)
+{
+    CPUState *cs = CPU(rx_env_get_cpu(env));
+
+    cs->interrupt_request |= CPU_INTERRUPT_SOFT;
+    env->sirq = vec;
+    raise_exception(env, 0x100, 0);
+}
+
+void QEMU_NORETURN helper_rxbrk(CPURXState *env)
+{
+    CPUState *cs = CPU(rx_env_get_cpu(env));
+
+    cs->interrupt_request |= CPU_INTERRUPT_SOFT;
+    env->sirq = 0;
+    raise_exception(env, 0x100, 0);
+}
+
+static void update_fpsw(CPURXState *env, uintptr_t retaddr)
+{
+    int xcpt, cause, enable;
+
+    xcpt = get_float_exception_flags(&env->fp_status);
+
+    /* Clear the cause entries */
+    env->fpsw &= ~FPSW_CAUSE_MASK;
+
+    if (unlikely(xcpt)) {
+        if (xcpt & float_flag_invalid) {
+            env->fpsw |= FPSW_CAUSE_V;
+        }
+        if (xcpt & float_flag_divbyzero) {
+            env->fpsw |= FPSW_CAUSE_Z;
+        }
+        if (xcpt & float_flag_overflow) {
+            env->fpsw |= FPSW_CAUSE_O;
+        }
+        if (xcpt & float_flag_underflow) {
+            env->fpsw |= FPSW_CAUSE_U;
+        }
+        if (xcpt & float_flag_inexact) {
+            env->fpsw |= FPSW_CAUSE_X;
+        }
+
+        /* Accumulate in flag entries */
+        env->fpsw |= (env->fpsw & FPSW_CAUSE_MASK)
+                      << (FPSW_FLAG_SHIFT - FPSW_CAUSE_SHIFT);
+        env->fpsw |= ((env->fpsw >> FPSW_FLAG_V) |
+                      (env->fpsw >> FPSW_FLAG_O) |
+                      (env->fpsw >> FPSW_FLAG_Z) |
+                      (env->fpsw >> FPSW_FLAG_U) |
+                      (env->fpsw >> FPSW_FLAG_X)) << FPSW_FLAG_S;
+
+        /* Generate an exception if enabled */
+        cause = (env->fpsw & FPSW_CAUSE_MASK) >> FPSW_CAUSE_SHIFT;
+        enable = (env->fpsw & FPSW_ENABLE_MASK) >> FPSW_ENABLE_SHIFT;
+        if (cause & enable) {
+            raise_exception(env, 21, retaddr);
+        }
+    }
+}
+
+void helper_to_fpsw(CPURXState *env, uint32_t val)
+{
+    static const int roundmode[] = {
+        float_round_nearest_even,
+        float_round_to_zero,
+        float_round_up,
+        float_round_down,
+    };
+    env->fpsw = val & FPSW_MASK;
+    set_float_rounding_mode(roundmode[val & FPSW_RM_MASK],
+                            &env->fp_status);
+    set_flush_to_zero((val & FPSW_DN) != 0, &env->fp_status);
+}
+
+typedef float32 (*floatfunc)(float32 f1, float32 f2, float_status *st);
+float32 helper_floatop(CPURXState *env, uint32_t op,
+                       float32 t0, float32 t1)
+{
+    static const floatfunc fop[] = {
+        float32_sub,
+        NULL,
+        float32_add,
+        float32_mul,
+        float32_div,
+    };
+    int st, xcpt;
+    if (op != 1) {
+        t0 = fop[op](t0, t1, &env->fp_status);
+        update_fpsw(env, GETPC());
+    } else {
+        st = float32_compare(t0, t1, &env->fp_status);
+        xcpt = get_float_exception_flags(&env->fp_status);
+        env->fpsw &= ~FPSW_CAUSE_MASK;
+
+        if (xcpt & float_flag_invalid) {
+            env->fpsw |= FPSW_CAUSE_V;
+            if (env->fpsw & FPSW_ENABLE_V) {
+                raise_exception(env, 21, GETPC());
+            }
+        }
+        switch (st) {
+        case float_relation_unordered:
+            return (float32)0;
+        case float_relation_equal:
+            return (float32)1;
+        case float_relation_less:
+            return (float32)2;
+        }
+    }
+    return t0;
+}
+
+uint32_t helper_ftoi(CPURXState *env, float32 t0)
+{
+    uint32_t ret;
+    ret = float32_to_int32_round_to_zero(t0, &env->fp_status);
+    update_fpsw(env, GETPC());
+    return ret;
+}
+
+uint32_t helper_round(CPURXState *env, float32 t0)
+{
+    uint32_t ret;
+    ret = float32_to_int32(t0, &env->fp_status);
+    update_fpsw(env, GETPC());
+    return ret;
+}
+
+float32 helper_itof(CPURXState *env, uint32_t t0)
+{
+    float32 ret;
+    ret = int32_to_float32(t0, &env->fp_status);
+    update_fpsw(env, GETPC());
+    return ret;
+}
+
+static uint32_t *cr_ptr(CPURXState *env, uint32_t cr)
+{
+    switch (cr) {
+    case 0:
+        return &env->psw;
+    case 2:
+        return &env->usp;
+    case 3:
+        return &env->fpsw;
+    case 8:
+        return &env->bpsw;
+    case 9:
+        return &env->bpc;
+    case 10:
+        return &env->isp;
+    case 11:
+        return &env->fintv;
+    case 12:
+        return &env->intb;
+    default:
+        return NULL;
+    }
+}
+
+void rx_cpu_pack_psw(CPURXState *env)
+{
+    helper_update_psw(env);
+    env->psw = (
+        (env->psw_ipl << 24) | (env->psw_pm << 20) |
+        (env->psw_u << 17) | (env->psw_i << 16) |
+        (env->psw_o << 3) | (env->psw_s << 2) |
+        (env->psw_z << 1) | (env->psw_c << 0));
+}
+
+void rx_cpu_unpack_psw(CPURXState *env, int all)
+{
+    if (env->psw_pm == 0) {
+        env->psw_ipl = (env->psw >> 24) & 15;
+        if (all) {
+            env->psw_pm = (env->psw >> 20) & 1;
+        }
+        env->psw_u =  (env->psw >> 17) & 1;
+        env->psw_i =  (env->psw >> 16) & 1;
+    }
+    env->psw_o =  (env->psw >> 3) & 1;
+    env->psw_s =  (env->psw >> 2) & 1;
+    env->psw_z =  (env->psw >> 1) & 1;
+    env->psw_c =  (env->psw >> 0) & 1;
+    env->op_mode = 0;
+}
+
+uint32_t helper_mvfc(CPURXState *env, uint32_t cr)
+{
+    uint32_t *crp = cr_ptr(env, cr);
+    if (crp != NULL) {
+        if (cr == 0) {
+            rx_cpu_pack_psw(env);
+        }
+        if ((cr == 2 && env->psw_u) || (cr == 10 && !env->psw_u)) {
+            return env->regs[0];
+        } else {
+            return *crp;
+        }
+    }
+    return 0;
+}
+
+void helper_mvtc(CPURXState *env, uint32_t cr, uint32_t val)
+{
+    uint32_t *crp = cr_ptr(env, cr);
+    if (crp != NULL) {
+        *crp = val;
+        if ((cr == 2 && env->psw_u) ||
+            (cr == 10 && !env->psw_u)) {
+            env->regs[0] = val;
+        }
+        if (cr == 0) {
+            rx_cpu_unpack_psw(env, 0);
+        }
+    }
+}
+
+void helper_unpack_psw(CPURXState *env)
+{
+    uint32_t prev_u;
+    prev_u = env->psw_u;
+    rx_cpu_unpack_psw(env, 1);
+    if (prev_u != env->psw_u) {
+        if (env->psw_u) {
+            env->isp = env->regs[0];
+            env->regs[0] = env->usp;
+        } else {
+            env->usp = env->regs[0];
+            env->regs[0] = env->isp;
+        }
+    }
+}
+
+void helper_racw(CPURXState *env, uint32_t shift)
+{
+    int64_t acc;
+    acc = env->acc_m;
+    acc = (acc << 32) | env->acc_l;
+    acc <<= shift;
+    acc += 0x0000000080000000LL;
+    if (acc > 0x00007FFF00000000LL) {
+        acc = 0x00007FFF00000000LL;
+    } else if (acc < 0xFFFF800000000000LL) {
+        acc = 0xFFFF800000000000LL;
+    } else {
+        acc &= 0xffffffff00000000;
+    }
+    env->acc_m = (acc >> 32);
+    env->acc_l = (acc & 0xffffffff);
+}
+
+void tlb_fill(CPUState *cs, target_ulong addr, int size,
+              MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
+{
+    uint32_t address, physical, prot;
+
+    /* Linear mapping */
+    address = physical = addr & TARGET_PAGE_MASK;
+    prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+    tlb_set_page(cs, address, physical, prot, mmu_idx, TARGET_PAGE_SIZE);
+}
diff --git a/target/rx/translate.c b/target/rx/translate.c
new file mode 100644
index 0000000000..d3cc0389f2
--- /dev/null
+++ b/target/rx/translate.c
@@ -0,0 +1,3003 @@
+/*
+ *  RX translation
+ *
+ *  Copyright (c) 2019 Yoshinori Sato
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "disas/disas.h"
+#include "exec/exec-all.h"
+#include "tcg-op.h"
+#include "exec/cpu_ldst.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
+#include "exec/translator.h"
+#include "trace-tcg.h"
+#include "exec/log.h"
+
+typedef struct DisasContext {
+    DisasContextBase base;
+    uint32_t pc;
+} DisasContext;
+
+/* PSW condition operation */
+typedef struct {
+    TCGv op_mode;
+    TCGv op_a1[13];
+    TCGv op_a2[13];
+    TCGv op_r[13];
+} CCOP;
+CCOP ccop;
+
+/* Target-specific values for dc->base.is_jmp.  */
+#define DISAS_JUMP    DISAS_TARGET_0
+
+/* global register indexes */
+static TCGv cpu_regs[16];
+static TCGv cpu_psw, cpu_psw_o, cpu_psw_s, cpu_psw_z, cpu_psw_c;
+static TCGv cpu_psw_i, cpu_psw_pm, cpu_psw_u, cpu_psw_ipl;
+static TCGv cpu_usp, cpu_fpsw, cpu_bpsw, cpu_bpc, cpu_isp;
+static TCGv cpu_fintv, cpu_intb, cpu_pc, cpu_acc_m, cpu_acc_l;
+
+
+#include "exec/gen-icount.h"
+
+void rx_cpu_dump_state(CPUState *cs, FILE *f,
+                           fprintf_function cpu_fprintf, int flags)
+{
+    RXCPU *cpu = RXCPU(cs);
+    CPURXState *env = &cpu->env;
+    int i;
+    uint32_t psw;
+
+    psw = rx_get_psw_low(env);
+    psw |= (env->psw_ipl << 24) | (env->psw_pm << 20) |
+        (env->psw_u << 17) | (env->psw_i << 16);
+    cpu_fprintf(f, "pc=0x%08x psw=0x%08x\n",
+                env->pc, psw);
+    for (i = 0; i < 16; i += 4) {
+        cpu_fprintf(f, "r%d=0x%08x r%d=0x%08x r%d=0x%08x r%d=0x%08x\n",
+                    i, env->regs[i], i + 1, env->regs[i + 1],
+                    i + 2, env->regs[i + 2], i + 3, env->regs[i + 3]);
+    }
+}
+
+static inline void gen_save_cpu_state(DisasContext *dc, bool save_pc)
+{
+    if (save_pc) {
+        tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
+    }
+}
+
+static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
+{
+    if (unlikely(dc->base.singlestep_enabled)) {
+        return false;
+    } else {
+        return true;
+    }
+}
+
+static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
+{
+    if (use_goto_tb(dc, dest)) {
+        tcg_gen_goto_tb(n);
+        tcg_gen_movi_i32(cpu_pc, dest);
+        tcg_gen_exit_tb(dc->base.tb, n);
+    } else {
+        tcg_gen_movi_i32(cpu_pc, dest);
+        if (dc->base.singlestep_enabled) {
+            gen_helper_debug(cpu_env);
+        } else {
+            tcg_gen_lookup_and_goto_ptr();
+        }
+    }
+    dc->base.is_jmp = DISAS_NORETURN;
+}
+
+typedef void (*disas_proc)(CPURXState *env, DisasContext *dc,
+                           uint32_t insn);
+
+static uint32_t rx_load_simm(CPURXState *env, uint32_t addr,
+                             int sz, uint32_t *ret)
+{
+    int32_t tmp;
+    switch (sz) {
+    case 1:
+        *ret = cpu_ldsb_code(env, addr);
+        return addr + 1;
+    case 2:
+        *ret = cpu_ldsw_code(env, addr);
+        return addr + 2;
+    case 3:
+        tmp = cpu_ldsb_code(env, addr + 2) << 16;
+        tmp |= cpu_lduw_code(env, addr) & 0xffff;
+        *ret = tmp;
+        return addr + 3;
+    case 0:
+        *ret = cpu_ldl_code(env, addr);
+        return addr + 4;
+    default:
+        return addr;
+    }
+}
+
+#define SET_MODE_O(mode)                                                \
+    do {                                                                \
+        tcg_gen_andi_i32(ccop.op_mode, ccop.op_mode, ~0xf000);          \
+        tcg_gen_ori_i32(ccop.op_mode, ccop.op_mode, mode << 12);        \
+    } while (0)
+
+#define SET_MODE_ZS(mode)                                               \
+    do {                                                                \
+        tcg_gen_andi_i32(ccop.op_mode, ccop.op_mode, ~0x0ff0);          \
+        tcg_gen_ori_i32(ccop.op_mode, ccop.op_mode,                     \
+                        (mode << 8) | (mode << 4));                     \
+    } while (0)
+
+#define SET_MODE_ZSO(mode)                                              \
+    do {                                                                \
+        tcg_gen_andi_i32(ccop.op_mode, ccop.op_mode, ~0xfff0);          \
+        tcg_gen_ori_i32(ccop.op_mode, ccop.op_mode,                     \
+                        (mode << 12) | (mode << 8) | (mode << 4));      \
+    } while (0)
+
+#define SET_MODE_CZ(mode)                                               \
+    do {                                                                \
+        tcg_gen_andi_i32(ccop.op_mode, ccop.op_mode, ~0x00ff);          \
+        tcg_gen_ori_i32(ccop.op_mode, ccop.op_mode,                     \
+                        (mode << 4) | mode);                            \
+    } while (0)
+
+#define SET_MODE_CZSO(mode)                                             \
+    do {                                                                \
+        tcg_gen_movi_i32(ccop.op_mode,                                  \
+                         (mode << 12) | (mode << 8) |                   \
+                         (mode << 4) | mode);                           \
+    } while (0)
+
+#define SET_MODE_CZS(mode)                                              \
+    do {                                                                \
+        tcg_gen_andi_i32(ccop.op_mode, ccop.op_mode, ~0x0fff);          \
+        tcg_gen_ori_i32(ccop.op_mode, ccop.op_mode,                     \
+                        (mode << 8) | (mode << 4) | mode);              \
+    } while (0)
+
+#define DEFINE_INSN(name) \
+    static void name(CPURXState *env, DisasContext *dc, uint32_t insn)
+
+#define RX_MEMORY_ST 0
+#define RX_MEMORY_LD 1
+#define RX_MEMORY_BYTE 0
+#define RX_MEMORY_WORD 1
+#define RX_MEMORY_LONG 2
+
+#define RX_OP_SUB 0
+#define RX_OP_CMP 1
+#define RX_OP_ADD 2
+#define RX_OP_SBB 3
+#define RX_OP_ADC 4
+#define RX_OP_MUL 3
+
+static void rx_gen_ldst(int size, int dir, TCGv reg, TCGv mem)
+{
+    static void (* const rw[])(TCGv ret, TCGv addr, int idx) = {
+        tcg_gen_qemu_st8, tcg_gen_qemu_ld8s,
+        tcg_gen_qemu_st16, tcg_gen_qemu_ld16s,
+        tcg_gen_qemu_st32, tcg_gen_qemu_ld32s,
+    };
+    rw[size * 2 + dir](reg, mem, 0);
+}
+
+/* mov.[bwl] rs,dsp:[rd] / mov.[bwl] dsp:[rs],rd */
+DEFINE_INSN(mov1_2)
+{
+    TCGv mem;
+    int r1, r2, dsp, dir, sz;
+
+    insn >>= 16;
+    sz = (insn >> 12) & 3;
+    dsp = ((insn >> 6) & 0x1e) | ((insn >> 3) & 1);
+    dsp <<= sz;
+    r2 = insn & 7;
+    r1 = (insn >> 4) & 7;
+    dir = (insn >> 11) & 1;
+
+    mem = tcg_temp_local_new();
+    tcg_gen_addi_i32(mem, cpu_regs[r1], dsp);
+    rx_gen_ldst(sz, dir, cpu_regs[r2], mem);
+    tcg_temp_free(mem);
+    dc->pc += 2;
+}
+
+/* mov.l #uimm:4,rd */
+DEFINE_INSN(mov3)
+{
+    uint32_t imm;
+    int rd;
+
+    imm = (insn >> 20) & 0x0f;
+    rd = (insn >> 16) & 15;
+    tcg_gen_movi_i32(cpu_regs[rd], imm);
+    dc->pc += 2;
+}
+
+/* mov.[bwl] #imm8,dsp:[rd] */
+DEFINE_INSN(mov4)
+{
+    uint32_t imm8;
+    TCGv src, dst;
+    int rd, sz, dsp;
+
+    sz = (insn >> 24) & 3;
+    rd = (insn >> 20) & 7;
+    dsp = ((insn >> 19) & 0x10) | ((insn >> 16) & 0x0f);
+    dsp <<= sz;
+    imm8 = (insn >> 8) & 0xff;
+
+    src = tcg_const_local_i32(imm8);
+    dst = tcg_temp_local_new();
+    tcg_gen_addi_i32(dst, cpu_regs[rd], dsp);
+    rx_gen_ldst(sz, RX_MEMORY_ST, src, dst);
+    tcg_temp_free(src);
+    tcg_temp_free(dst);
+    dc->pc += 3;
+}
+
+/* mov.l #uimm8,rd */
+DEFINE_INSN(mov5)
+{
+    uint32_t imm8;
+    int rd;
+
+    imm8 = (insn >> 8) & 0xff;
+    rd = (insn >> 16) & 15;
+    tcg_gen_movi_i32(cpu_regs[rd], imm8);
+    dc->pc += 3;
+}
+
+/* mov.l #imm,rd */
+DEFINE_INSN(mov6)
+{
+    uint32_t imm;
+    int rd, li;
+
+    rd = (insn >> 20) & 15;
+    li = (insn >> 18) & 3;
+
+    dc->pc = rx_load_simm(env, dc->pc + 2, li, &imm);
+    tcg_gen_movi_i32(cpu_regs[rd], imm);
+}
+
+/* mov.[bwl] rs,rd */
+DEFINE_INSN(mov7)
+{
+    int sz, rs, rd;
+
+    sz = (insn >> 28) & 3;
+    rs = (insn >> 20) & 15;
+    rd = (insn >> 16) & 15;
+
+    switch (sz) {
+    case 0:
+        tcg_gen_ext8s_i32(cpu_regs[rd], cpu_regs[rs]);
+        break;
+    case 1:
+        tcg_gen_ext16s_i32(cpu_regs[rd], cpu_regs[rs]);
+        break;
+    case 2:
+        tcg_gen_mov_i32(cpu_regs[rd], cpu_regs[rs]);
+        break;
+    }
+    dc->pc += 2;
+}
+
+static TCGv rx_index_addr(int id, int size, int offset, int reg,
+                          DisasContext *dc, CPURXState *env)
+{
+    TCGv addr;
+    uint32_t dsp;
+
+    addr = tcg_temp_local_new();
+    switch (id) {
+    case 0:
+        tcg_gen_mov_i32(addr, cpu_regs[reg]);
+        break;
+    case 1:
+        dsp = cpu_ldub_code(env, dc->base.pc_next + offset) << size;
+        tcg_gen_addi_i32(addr, cpu_regs[reg], dsp);
+        break;
+    case 2:
+        dsp = cpu_lduw_code(env, dc->base.pc_next + offset) << size;
+        tcg_gen_addi_i32(addr, cpu_regs[reg], dsp);
+        break;
+    }
+    return addr;
+}
+
+/* mov #imm, dsp:[rd] */
+DEFINE_INSN(mov8)
+{
+    uint32_t imm;
+    TCGv _imm, dst;
+    int id, rd, li, sz;
+
+    id = (insn >> 24) & 3;
+    rd = (insn >> 20) & 15;
+    li = (insn >> 18) & 3;
+    sz = (insn >> 16) & 3;
+
+    dst = rx_index_addr(id, sz, 2, rd, dc, env);
+    dc->pc = rx_load_simm(env, dc->pc + 2 + id, li, &imm);
+    _imm = tcg_const_local_i32(imm);
+    rx_gen_ldst(sz, RX_MEMORY_ST, _imm, dst);
+    tcg_temp_free(_imm);
+    tcg_temp_free(dst);
+}
+
+/* mov.[bwl] dsp:[rs],rd */
+DEFINE_INSN(mov9)
+{
+    int sz, id, rs, rd;
+    TCGv src;
+
+    sz = (insn >> 28) & 3;
+    id = (insn >> 24) & 3;
+    rs = (insn >> 20) & 15;
+    rd = (insn >> 16) & 15;
+
+    src = rx_index_addr(id, sz, 2, rs, dc, env);
+    rx_gen_ldst(sz, RX_MEMORY_LD, cpu_regs[rd], src);
+    tcg_temp_free(src);
+    dc->pc += 2 + id;
+}
+
+static TCGv rx_gen_regindex(int size, int ri, int rb)
+{
+    TCGv ret;
+
+    ret = tcg_temp_local_new();
+    tcg_gen_shli_i32(ret, cpu_regs[ri], size);
+    tcg_gen_add_i32(ret, ret, cpu_regs[rb]);
+    return ret;
+}
+
+/* mov.[bwl] [ri,rb],rd / mov.[bwl] rd,[ri,rb] */
+DEFINE_INSN(mov10_12)
+{
+    TCGv mem;
+    int sz, ri, rb, rn, dir;
+
+    dir = (insn >> 22) & 1;
+    sz = (insn >> 20) & 3;
+    ri = (insn >> 16) & 15;
+    rb = (insn >> 12) & 15;
+    rn = (insn >> 8) & 15;
+
+    mem = rx_gen_regindex(sz, ri, rb);
+    rx_gen_ldst(sz, dir, cpu_regs[rn], mem);
+    tcg_temp_free(mem);
+    dc->pc += 3;
+}
+
+/* mov.[bwl] rs,dsp:[rd] */
+DEFINE_INSN(mov11)
+{
+    int sz, id, rs, rd;
+    TCGv mem;
+
+    sz = (insn >> 28) & 3;
+    id = (insn >> 26) & 3;
+    rd = (insn >> 20) & 15;
+    rs = (insn >> 16) & 15;
+
+    mem = rx_index_addr(id, sz, 2, rd, dc, env);
+    rx_gen_ldst(sz, RX_MEMORY_ST, cpu_regs[rs], mem);
+    tcg_temp_free(mem);
+    dc->pc += 2 + id;
+}
+
+/* mov.[bwl] dsp:[rs],dsp:[rd] */
+DEFINE_INSN(mov13)
+{
+    int sz, rs, rd, ids, idd;
+    TCGv src, dst, val;
+
+    sz = (insn >> 28) & 3;
+    idd = (insn >> 26) & 3;
+    ids = (insn >> 24) & 3;
+    rs = (insn >> 20) & 15;
+    rd = (insn >> 16) & 15;
+
+    src = rx_index_addr(ids, sz, 2, rs, dc, env);
+    dst = rx_index_addr(idd, sz, 2 + ids, rd, dc, env);
+    val = tcg_temp_local_new();
+    rx_gen_ldst(sz, RX_MEMORY_LD, val, src);
+    rx_gen_ldst(sz, RX_MEMORY_ST, val, dst);
+    tcg_temp_free(src);
+    tcg_temp_free(dst);
+    tcg_temp_free(val);
+    dc->pc += 2 + ids + idd;
+}
+
+/* mov.[bwl] rs,[rd+] / mov.[bwl] rs,[-rd] */
+DEFINE_INSN(mov14)
+{
+    int rs, rd, ad, sz;
+    TCGv dst;
+
+    ad = (insn >> 18) & 3;
+    sz = (insn >> 16) & 3;
+    rd = (insn >> 12) & 15;
+    rs = (insn >> 8) & 15;
+
+    dst = tcg_temp_local_new();
+    tcg_gen_mov_i32(dst, cpu_regs[rd]);
+    if (ad == 1) {
+        tcg_gen_subi_i32(dst, dst, 1 << sz);
+    }
+    rx_gen_ldst(sz, RX_MEMORY_ST, cpu_regs[rs], dst);
+    if (ad == 0) {
+        tcg_gen_addi_i32(cpu_regs[rd], cpu_regs[rd], 1 << sz);
+    } else {
+        tcg_gen_mov_i32(cpu_regs[rd], dst);
+    }
+    tcg_temp_free(dst);
+    dc->pc += 3;
+}
+
+/* mov.[bwl] [rs+],rd / mov.[bwl] [-rs],rd */
+DEFINE_INSN(mov15)
+{
+    int rs, rd, ad, sz;
+
+    ad = (insn >> 18) & 3;
+    sz = (insn >> 16) & 3;
+    rs = (insn >> 12) & 15;
+    rd = (insn >> 8) & 15;
+
+    if (ad == 3) {
+        tcg_gen_subi_i32(cpu_regs[rs], cpu_regs[rs], 1 << sz);
+    }
+    rx_gen_ldst(sz, RX_MEMORY_LD, cpu_regs[rd], cpu_regs[rs]);
+    if (ad == 2) {
+        tcg_gen_addi_i32(cpu_regs[rs], cpu_regs[rs], 1 << sz);
+    }
+    dc->pc += 3;
+}
+
+static void rx_gen_ldu(unsigned int sz, TCGv reg, TCGv addr)
+{
+    static void (* const rd[])(TCGv ret, TCGv addr, int idx) = {
+        tcg_gen_qemu_ld8u, tcg_gen_qemu_ld16u, tcg_gen_qemu_ld32u,
+    };
+    g_assert(sz < 3);
+    rd[sz](reg, addr, 0);
+}
+
+/* movu.[bw] dsp5:[rs],rd */
+DEFINE_INSN(movu1)
+{
+    int sz, dsp, rs, rd;
+    TCGv mem;
+
+    mem = tcg_temp_local_new();
+    sz = (insn >> 27) & 1;
+    dsp = ((insn >> 22) & 0x1e) | ((insn >> 19) & 1);
+    rs = (insn >> 20) & 7;
+    rd = (insn >> 16) & 7;
+
+    tcg_gen_addi_i32(mem, cpu_regs[rs], dsp << sz);
+    rx_gen_ldu(sz, cpu_regs[rd], mem);
+    tcg_temp_free(mem);
+    dc->pc += 2;
+}
+
+/* movu.[bw] rs,rd / movu.[bw] dsp:[rs],rd */
+DEFINE_INSN(movu2)
+{
+    int sz, id, rs, rd;
+    TCGv mem;
+    static void (* const ext[])(TCGv ret, TCGv arg) = {
+        tcg_gen_ext8u_i32, tcg_gen_ext16u_i32,
+    };
+
+    sz = (insn >> 26) & 1;
+    id = (insn >> 24) & 3;
+    rs = (insn >> 20) & 15;
+    rd = (insn >> 16) & 15;
+
+    if (id < 3) {
+        mem = rx_index_addr(id, sz, 2, rs, dc, env);
+        rx_gen_ldu(sz, cpu_regs[rd], mem);
+        tcg_temp_free(mem);
+        dc->pc += 2 + id;
+    } else {
+        ext[sz](cpu_regs[rd], cpu_regs[rs]);
+        dc->pc += 2;
+    }
+}
+
+/* movu.[bw] [ri,rb],rd */
+DEFINE_INSN(movu3)
+{
+    TCGv mem;
+    int sz, ri, rb, rd;
+
+    sz = (insn >> 20) & 1;
+    ri = (insn >> 16) & 15;
+    rb = (insn >> 12) & 15;
+    rd = (insn >> 8) & 15;
+
+    mem = rx_gen_regindex(sz, ri, rb);
+    rx_gen_ldu(sz, cpu_regs[rd], mem);
+    tcg_temp_free(mem);
+    dc->pc += 3;
+}
+
+/* movu.[bw] [rs+],rd / movu.[bw] [-rs],rd */
+DEFINE_INSN(movu4)
+{
+    int rs, rd, ad, sz;
+
+    ad = (insn >> 18) & 3;
+    sz = (insn >> 16) & 1;
+    rs = (insn >> 12) & 15;
+    rd = (insn >> 8) & 15;
+
+    if (ad == 3) {
+        tcg_gen_subi_i32(cpu_regs[rs], cpu_regs[rs], 1 << sz);
+    }
+    rx_gen_ldu(sz, cpu_regs[rd], cpu_regs[rs]);
+    if (ad == 2) {
+        tcg_gen_addi_i32(cpu_regs[rs], cpu_regs[rs], 1 << sz);
+    }
+    dc->pc += 3;
+}
+
+/* pop rd */
+DEFINE_INSN(pop)
+{
+    int rd;
+
+    rd = (insn >> 16) & 15;
+    tcg_gen_qemu_ld32u(cpu_regs[rd], cpu_regs[0], 0);
+    if (rd != 0) {
+        tcg_gen_addi_i32(cpu_regs[0], cpu_regs[0], 4);
+    }
+    dc->pc += 2;
+}
+
+/* popc rx */
+DEFINE_INSN(popc)
+{
+    TCGv cr, val;
+
+    cr = tcg_const_i32((insn >> 16) & 15);
+    val = tcg_temp_local_new();
+    tcg_gen_qemu_ld32u(val, cpu_regs[0], 0);
+    tcg_gen_addi_i32(cpu_regs[0], cpu_regs[0], 4);
+    gen_helper_mvtc(cpu_env, cr, val);
+    tcg_temp_free(cr);
+    tcg_temp_free(val);
+    dc->pc += 2;
+}
+
+/* popm rd-rd2 */
+DEFINE_INSN(popm)
+{
+    int rd, rd2, r;
+
+    rd = (insn >> 20) & 15;
+    rd2 = (insn >> 16) & 15;
+
+    for (r = rd; r <= rd2; r++) {
+        tcg_gen_qemu_ld32u(cpu_regs[r], cpu_regs[0], 0);
+        tcg_gen_addi_i32(cpu_regs[0], cpu_regs[0], 4);
+    }
+    dc->pc += 2;
+}
+
+/* push rs */
+DEFINE_INSN(push1)
+{
+    TCGv tmp;
+    int rs;
+
+    rs = (insn >> 16) & 15;
+    tmp = tcg_temp_local_new();
+    tcg_gen_mov_i32(tmp, cpu_regs[rs]);
+    tcg_gen_subi_i32(cpu_regs[0], cpu_regs[0], 4);
+    tcg_gen_qemu_st32(tmp, cpu_regs[0], 0);
+    tcg_temp_free(tmp);
+    dc->pc += 2;
+}
+
+/* push rs */
+DEFINE_INSN(push2)
+{
+    TCGv tmp, mem;
+    int id, sz, rs;
+
+    id = (insn >> 24) & 3;
+    rs = (insn >> 20) & 15;
+    sz = (insn >> 16) & 3;
+    tmp = tcg_temp_local_new();
+    mem = rx_index_addr(id, sz, 2, rs, dc, env);
+    rx_gen_ldst(sz, RX_MEMORY_LD, tmp, mem);
+    tcg_gen_subi_i32(cpu_regs[0], cpu_regs[0], 4);
+    tcg_gen_qemu_st32(tmp, cpu_regs[0], 0);
+    tcg_temp_free(tmp);
+    tcg_temp_free(mem);
+    dc->pc += 2 + id;
+}
+
+/* pushc rx */
+DEFINE_INSN(pushc)
+{
+    TCGv cr, val;
+
+    cr = tcg_const_i32((insn >> 16) & 15);
+    val = tcg_temp_local_new();
+    gen_helper_mvfc(val, cpu_env, cr);
+    tcg_gen_subi_i32(cpu_regs[0], cpu_regs[0], 4);
+    tcg_gen_qemu_st32(val, cpu_regs[0], 0);
+    tcg_temp_free(cr);
+    tcg_temp_free(val);
+    dc->pc += 2;
+}
+
+    /* pushm */
+DEFINE_INSN(pushm)
+{
+    int rs, rs2, r;
+
+    rs = (insn >> 20) & 15;
+    rs2 = (insn >> 16) & 15;
+
+    for (r = rs2; r >= rs; r--) {
+        tcg_gen_subi_i32(cpu_regs[0], cpu_regs[0], 4);
+        tcg_gen_qemu_st32(cpu_regs[r], cpu_regs[0], 0);
+    }
+    dc->pc += 2;
+}
+
+/* revl rs, rd */
+DEFINE_INSN(revl)
+{
+    int rs, rd;
+    TCGv t0, t1;
+
+    rs = (insn >> 12) & 15;
+    rd = (insn >> 8) & 15;
+
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+    tcg_gen_rotri_i32(t0, cpu_regs[rs], 8);
+    tcg_gen_andi_i32(t1, t0, 0xff000000);
+    tcg_gen_shli_i32(t0, cpu_regs[rs], 8);
+    tcg_gen_andi_i32(t0, t0, 0x00ff0000);
+    tcg_gen_or_i32(t1, t1, t0);
+    tcg_gen_shri_i32(t0, cpu_regs[rs], 8);
+    tcg_gen_andi_i32(t0, t0, 0x0000ff00);
+    tcg_gen_or_i32(t1, t1, t0);
+    tcg_gen_rotli_i32(t0, cpu_regs[rs], 8);
+    tcg_gen_ext8u_i32(t0, t0);
+    tcg_gen_or_i32(cpu_regs[rd], t1, t0);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    dc->pc += 3;
+}
+
+/* revw rs, rd */
+DEFINE_INSN(revw)
+{
+    int rs, rd;
+    TCGv t0, t1, t2;
+
+    rs = (insn >> 12) & 15;
+    rd = (insn >> 8) & 15;
+
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+    t2 = tcg_temp_local_new();
+    tcg_gen_ext8u_i32(t0, cpu_regs[rs]);
+    tcg_gen_shli_i32(t0, t0, 8);
+    tcg_gen_shri_i32(t1, cpu_regs[rs], 8);
+    tcg_gen_andi_i32(t1, t1, 0x000000ff);
+    tcg_gen_or_i32(t2, t0, t1);
+    tcg_gen_shli_i32(t0, cpu_regs[rs], 8);
+    tcg_gen_andi_i32(t0, t0, 0xff000000);
+    tcg_gen_shri_i32(t1, cpu_regs[rs], 8);
+    tcg_gen_andi_i32(t1, t1, 0x00ff0000);
+    tcg_gen_or_i32(t0, t0, t1);
+    tcg_gen_or_i32(cpu_regs[rd], t2, t0);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+    dc->pc += 3;
+}
+
+DEFINE_INSN(sccnd)
+{
+    int sz, id, rd;
+    TCGv result, cd;
+    TCGv mem;
+    sz = (insn >> 18) & 3;
+    id = (insn >> 16) & 3;
+    rd = (insn >> 12) & 15;
+    cd = tcg_const_local_i32((insn >> 8) & 15);
+    result = tcg_temp_local_new();
+
+    gen_helper_cond(result, cpu_env, cd);
+    if (id < 3) {
+        mem = rx_index_addr(sz, id, 3, rd, dc, env);
+        rx_gen_ldst(sz, RX_MEMORY_ST, result, mem);
+        tcg_temp_free(mem);
+        dc->pc += 3 + id;
+    } else {
+        tcg_gen_mov_i32(cpu_regs[rd], result);
+        dc->pc += 3;
+    }
+    tcg_temp_free(result);
+    tcg_temp_free(cd);
+}
+
+/* stz #imm,rd / stnz #imm,rd */
+DEFINE_INSN(stz)
+{
+    int rd, li;
+    uint32_t imm;
+    TCGv zero, _imm, cond, result;
+    li = (insn >> 18) & 3;
+    cond = tcg_const_local_i32((insn >> 12) & 1);
+    rd = (insn >> 8) & 15;
+    result = tcg_temp_local_new();
+    dc->pc = rx_load_simm(env, dc->pc + 3, li, &imm);
+    _imm = tcg_const_local_i32(imm);
+    gen_helper_cond(result, cpu_env, cond);
+    zero = tcg_const_local_i32(0);
+    tcg_gen_movcond_i32(TCG_COND_NE, cpu_regs[rd],
+                        result, zero, _imm, cpu_regs[rd]);
+    tcg_temp_free(zero);
+    tcg_temp_free(_imm);
+    tcg_temp_free(cond);
+    tcg_temp_free(result);
+}
+
+DEFINE_INSN(xchg1)
+{
+    int id, rs, rd;
+    TCGv tmp, mem;
+
+    id = (insn >> 16) & 3;
+    rs = (insn >> 12) & 15;
+    rd = (insn >> 8) & 15;
+
+    tmp = tcg_temp_local_new();
+    if (id == 3) {
+        tcg_gen_mov_i32(tmp, cpu_regs[rs]);
+        tcg_gen_mov_i32(cpu_regs[rs], cpu_regs[rd]);
+        tcg_gen_mov_i32(cpu_regs[rd], tmp);
+        dc->pc += 3;
+    } else {
+        mem = rx_index_addr(id, RX_MEMORY_BYTE, 3, rs, dc, env);
+        rx_gen_ldu(RX_MEMORY_BYTE, tmp, mem);
+        rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_ST, cpu_regs[rd], mem);
+        tcg_gen_mov_i32(cpu_regs[rd], tmp);
+        dc->pc += 3 + id;
+        tcg_temp_free(mem);
+    }
+    tcg_temp_free(tmp);
+}
+
+DEFINE_INSN(xchg2)
+{
+    int id, rs, rd, sz, mi;
+    TCGv tmp, mem;
+
+    mi = (insn >> 22) & 3;
+    id = (insn >> 16) & 3;
+    rs = (insn >> 4) & 15;
+    rd = insn & 15;
+    sz = (mi < 3) ? mi : RX_MEMORY_WORD;
+
+    tmp = tcg_temp_local_new();
+    mem = rx_index_addr(id, sz, 4, rs, dc, env);
+    if (mi == 3) {
+        rx_gen_ldu(RX_MEMORY_WORD, tmp, mem);
+    } else {
+        rx_gen_ldst(sz, RX_MEMORY_LD, tmp, mem);
+    }
+    rx_gen_ldst(sz, RX_MEMORY_ST, cpu_regs[rd], mem);
+    tcg_gen_mov_i32(cpu_regs[rd], tmp);
+    dc->pc += 4 + id;
+    tcg_temp_free(mem);
+    tcg_temp_free(tmp);
+}
+
+static void rx_gen_logic(int opr, TCGv ret, TCGv r1, TCGv r2)
+{
+    static void (*fn[])(TCGv ret, TCGv arg1, TCGv arg2) = {
+        tcg_gen_and_i32,
+        tcg_gen_or_i32,
+        tcg_gen_xor_i32,
+        tcg_gen_and_i32,
+    };
+    fn[opr](ccop.op_r[RX_PSW_OP_LOGIC], r1, r2);
+    SET_MODE_ZS(RX_PSW_OP_LOGIC);
+    if (opr < 3) {
+        tcg_gen_mov_i32(ret, ccop.op_r[RX_PSW_OP_LOGIC]);
+    }
+}
+
+DEFINE_INSN(nop)
+{
+    dc->pc += 1;
+}
+
+static void rx_gen_logici(int opr, TCGv ret, TCGv r1, uint32_t imm)
+{
+    static void (*fn[])(TCGv ret, TCGv arg1, int arg2) = {
+        tcg_gen_andi_i32,
+        tcg_gen_ori_i32,
+        tcg_gen_xori_i32,
+        tcg_gen_andi_i32,
+    };
+    fn[opr](ccop.op_r[RX_PSW_OP_LOGIC], r1, imm);
+    SET_MODE_ZS(RX_PSW_OP_LOGIC);
+    if (opr < 3) {
+        tcg_gen_mov_i32(ret, ccop.op_r[RX_PSW_OP_LOGIC]);
+    }
+}
+
+#define UIMM4OP(opmask,  operation_fn)                          \
+    do {                                                        \
+        int op, rd;                                             \
+        uint32_t imm;                                           \
+        op = (insn >> 24) & opmask;                             \
+        imm = (insn >> 20) & 15;                                \
+        rd = (insn >> 16) & 15;                                 \
+        operation_fn(op, cpu_regs[rd], cpu_regs[rd], imm);      \
+        dc->pc += 2;                                            \
+    } while (0)
+
+
+/* and #uimm:4,rd / or #uimm:4,rd */
+DEFINE_INSN(logic_op1)
+{
+    UIMM4OP(1, rx_gen_logici);
+}
+
+#define SIMMOP_S(operation_fn)                                          \
+    do {                                                                \
+        int op, rd, li;                                                 \
+        uint32_t imm;                                                   \
+        li = (insn >> 24) & 3;                                          \
+        op = (insn >> 20) & 1;                                          \
+        rd = (insn >> 16) & 15;                                         \
+        dc->pc = rx_load_simm(env, dc->pc + 2, li, &imm);     \
+        operation_fn;                                                   \
+    } while (0)
+
+#define SIMMOP_L(operation_fn)                                          \
+    do {                                                                \
+        int op, rd, li;                                                 \
+        uint32_t imm;                                                   \
+        li = (insn >> 18) & 3;                                          \
+        op = (insn >> 12) & 1;                                          \
+        rd = (insn >> 8) & 15;                                          \
+        dc->pc = rx_load_simm(env, dc->pc + 3, li, &imm);               \
+        operation_fn;                                                   \
+    } while (0)
+
+/* and #imm, rd / or #imm,rd / xor #imm,rd / tst #imm,rd */
+DEFINE_INSN(logic_op2)
+{
+    if ((insn & 0xfc000000) == 0x74000000) {
+        /* and / or */
+        SIMMOP_S(rx_gen_logici(op, cpu_regs[rd], cpu_regs[rd], imm));
+    } else if ((insn & 0x0000e000) == 0x0000c000) {
+        /* xor / tst */
+        SIMMOP_L(rx_gen_logici(3 - op, cpu_regs[rd], cpu_regs[rd], imm));
+    } else
+        g_assert_not_reached();
+
+}
+
+#define MEMOP1_S(opmask, operation_fn)                                  \
+    do {                                                                \
+        int op, id, rs, rd;                                             \
+        TCGv mem, val;                                                  \
+        op = (insn >> 26) & opmask;                                     \
+        id = (insn >> 24) & 3;                                          \
+        rs = (insn >> 20) & 15;                                         \
+        rd = (insn >> 16) & 15;                                         \
+        if (id == 3) {                                                  \
+            operation_fn(op, cpu_regs[rd], cpu_regs[rd], cpu_regs[rs]); \
+            dc->pc += 2;                                                \
+        } else {                                                        \
+            mem = rx_index_addr(id, RX_MEMORY_BYTE, 2, rs, dc, env);    \
+            val = tcg_temp_local_new();                                 \
+            rx_gen_ldu(RX_MEMORY_BYTE, val, mem);                       \
+            operation_fn(op, cpu_regs[rd], cpu_regs[rd], val);          \
+            tcg_temp_free(mem);                                         \
+            tcg_temp_free(val);                                         \
+            dc->pc += 2 + id;                                           \
+        }                                                               \
+    } while (0)
+
+#define MEMOP1_L(operation_fn_reg, operation_fn_mem)                    \
+    do {                                                                \
+        int op, id, rs, rd;                                             \
+        TCGv mem, val;                                                  \
+        op = (insn >> 18) & 1;                                          \
+        id = (insn >> 16) & 3;                                          \
+        rs = (insn >> 12) & 15;                                         \
+        rd = (insn >> 8) & 15;                                          \
+        if (id == 3) {                                                  \
+            operation_fn_reg;                                           \
+            dc->pc += 3;                                                \
+        } else {                                                        \
+            mem = rx_index_addr(id, 1, 3, rs, dc, env);                 \
+            val = tcg_temp_local_new();                                 \
+            rx_gen_ldu(RX_MEMORY_BYTE, val, mem);                       \
+            operation_fn_mem;                                           \
+            tcg_temp_free(mem);                                         \
+            tcg_temp_free(val);                                         \
+            dc->pc += 3 + id;                                           \
+        }                                                               \
+    } while (0)
+
+#define MEMOP2_S(opmask, operation_fn)                          \
+    do {                                                        \
+        int op, mi, id, rs, rd, size;                           \
+        TCGv mem, val;                                          \
+        mi = (insn >> 22) & 3;                                  \
+        op = (insn >> 18) & opmask;                             \
+        id = (insn >> 16) & 3;                                  \
+        rs = (insn >> 12) & 15;                                 \
+        rd = (insn >> 8) & 15;                                  \
+        size = (mi == 3) ? RX_MEMORY_WORD : mi;                 \
+        mem = rx_index_addr(id, size, 3, rs, dc, env);          \
+        val = tcg_temp_local_new();                             \
+        if (mi != 3)                                            \
+            rx_gen_ldst(size, RX_MEMORY_LD, val, mem);          \
+        else                                                    \
+            rx_gen_ldu(RX_MEMORY_WORD, val, mem);               \
+        operation_fn(op, cpu_regs[rd], cpu_regs[rd], val);      \
+        tcg_temp_free(mem);                                     \
+        tcg_temp_free(val);                                     \
+        dc->pc += 3 + id;                                       \
+    } while (0)
+
+#define MEMOP2_L(operation_fn)                                  \
+    do {                                                        \
+        int op, mi, id, rs, rd, size;                           \
+        TCGv mem, val;                                          \
+        mi = (insn >> 22) & 3;                                  \
+        id = (insn >> 16) & 3;                                  \
+        op = (insn >> 8) & 1;                                   \
+        rs = (insn >> 4) & 15;                                  \
+        rd = insn & 15;                                         \
+        size = (mi == 3) ? RX_MEMORY_WORD : mi;                 \
+        mem = rx_index_addr(id, size, 4, rs, dc, env);          \
+        val = tcg_temp_local_new();                             \
+        if (mi != 3)                                            \
+            rx_gen_ldst(size, RX_MEMORY_LD, val, mem);          \
+        else                                                    \
+            rx_gen_ldu(RX_MEMORY_WORD, val, mem);               \
+        operation_fn;                                           \
+        tcg_temp_free(mem);                                     \
+        tcg_temp_free(val);                                     \
+        dc->pc += 4 + id;                                       \
+    } while (0)
+
+/* and rs, rd / or rs,rd / xor rs,rd / tst rs,rd */
+/* and [rs].ub, rd / or [rs].ub,rd / xor [rs].ub,rd / tst [rs].ub,rd */
+DEFINE_INSN(logic_op3)
+{
+
+    if ((insn & 0xff000000) == 0xfc000000) {
+        /* xor / tst */
+        MEMOP1_L(rx_gen_logic(3 - op, cpu_regs[rd], cpu_regs[rd], cpu_regs[rs]),
+                 rx_gen_logic(3 - op, cpu_regs[rd], cpu_regs[rd], mem));
+    } else if ((insn & 0xf0000000) == 0x50000000) {
+        /* and / or */
+        MEMOP1_S(1, rx_gen_logic);
+    } else
+        g_assert_not_reached();
+}
+
+/* and [rs],rd / or [rs],rd / xor [rs],rd / tst [rs],rd */
+DEFINE_INSN(logic_op4)
+{
+    if ((insn & 0x00300000) == 0x00200000) {
+        /* xor / tst */
+        MEMOP2_L(rx_gen_logic(3 - op, cpu_regs[rd], cpu_regs[rd], val));
+    } else if ((insn & 0x00300000) == 0x00100000) {
+        MEMOP2_S(3, rx_gen_logic);
+    } else
+        g_assert_not_reached();
+}
+
+#define OP3(opmask, operation_fn)                                       \
+    do {                                                                \
+        int op, rs, rs2, rd;                                            \
+        op = (insn >> 20) & opmask;                                     \
+        rd = (insn >> 16) & 15;                                         \
+        rs = (insn >> 12) & 15;                                         \
+        rs2 = (insn >> 8) & 15;                                         \
+        operation_fn(op, cpu_regs[rd], cpu_regs[rs2], cpu_regs[rs]);    \
+        dc->pc += 3;                                                    \
+    } while (0)
+
+/* and rs,rs2,rd / or rs,rs2,rd */
+DEFINE_INSN(logic_op5)
+{
+    OP3(1, rx_gen_logic);
+}
+
+#define UPDATE_ALITH_CCOP(mode, arg1, arg2, ret)                   \
+    do {                                                                \
+        tcg_gen_mov_i32(ccop.op_a1[mode], arg1);                   \
+        tcg_gen_mov_i32(ccop.op_a2[mode], arg2);                   \
+        tcg_gen_mov_i32(ccop.op_r[mode], ret);                     \
+        SET_MODE_CZSO(mode);                                   \
+    } while (0)
+
+#define UPDATE_ALITHIMM_CCOP(mode, arg1, arg2, ret)                 \
+    do {                                                                \
+        tcg_gen_mov_i32(ccop.op_a1[mode], arg1);                   \
+        tcg_gen_movi_i32(ccop.op_a2[mode], arg2);                  \
+        tcg_gen_mov_i32(ccop.op_r[mode], ret);                     \
+        SET_MODE_CZSO(mode);                                   \
+    } while (0)
+
+static void rx_gen_sbb_i32(TCGv ret, TCGv arg1, TCGv arg2)
+{
+    TCGv invc;
+
+    invc = tcg_temp_local_new();
+    gen_helper_psw_c(invc, cpu_env);
+    tcg_gen_xori_i32(invc, invc, 1);
+    tcg_gen_sub_i32(ret, arg1, arg2);
+    tcg_gen_sub_i32(ret, ret, invc);
+    UPDATE_ALITH_CCOP(RX_PSW_OP_SUB, arg1, arg2, ret);
+    tcg_temp_free(invc);
+}
+
+static void rx_gen_adc_i32(TCGv ret, TCGv arg1, TCGv arg2)
+{
+    TCGv c;
+    c = tcg_temp_local_new();
+    gen_helper_psw_c(c, cpu_env);
+    tcg_gen_add_i32(ret, arg1, arg2);
+    tcg_gen_add_i32(ret, ret, c);
+    UPDATE_ALITH_CCOP(RX_PSW_OP_ADD, arg1, arg2, ret);
+    tcg_temp_free(c);
+}
+
+static void rx_gen_sbbi_i32(TCGv ret, TCGv arg1, int arg2)
+{
+    TCGv invc;
+
+    invc = tcg_temp_local_new();
+    gen_helper_psw_c(invc, cpu_env);
+    tcg_gen_xori_i32(invc, invc, 1);
+    tcg_gen_subi_i32(ret, arg1, arg2);
+    tcg_gen_sub_i32(ret, ret, invc);
+    UPDATE_ALITHIMM_CCOP(RX_PSW_OP_SUB, arg1, arg2, ret);
+    tcg_temp_free(invc);
+}
+
+static void rx_gen_adci_i32(TCGv ret, TCGv arg1, int arg2)
+{
+    TCGv c;
+    c = tcg_temp_local_new();
+    gen_helper_psw_c(c, cpu_env);
+    tcg_gen_addi_i32(ret, arg1, arg2);
+    tcg_gen_add_i32(ret, ret, c);
+    UPDATE_ALITHIMM_CCOP(RX_PSW_OP_ADD, arg1, arg2, ret);
+    tcg_temp_free(c);
+}
+
+static void rx_alith_op(int opr, TCGv ret, TCGv r1, TCGv r2)
+{
+    static void (* const fn[])(TCGv ret, TCGv arg1, TCGv arg2) = {
+        tcg_gen_sub_i32,
+        tcg_gen_sub_i32,
+        tcg_gen_add_i32,
+        rx_gen_sbb_i32,
+        rx_gen_adc_i32,
+    };
+    static const int opmodes[] = {RX_PSW_OP_SUB, RX_PSW_OP_SUB, RX_PSW_OP_ADD,
+                                  RX_PSW_OP_SUB, RX_PSW_OP_ADD};
+    int opmode = opmodes[opr];
+    fn[opr](ccop.op_r[opmode], r1, r2);
+    if (opr != RX_OP_CMP) {
+        tcg_gen_mov_i32(ret, ccop.op_r[opmode]);
+    }
+    tcg_gen_mov_i32(ccop.op_a1[opmode], r1);
+    tcg_gen_mov_i32(ccop.op_a2[opmode], r2);
+    SET_MODE_CZSO(opmode);
+}
+
+static void rx_alith_imm_op(int opr, TCGv ret, TCGv r1, uint32_t imm)
+{
+    static void (* const fn[])(TCGv ret, TCGv arg1, int arg2) = {
+        tcg_gen_subi_i32,
+        tcg_gen_subi_i32,
+        tcg_gen_addi_i32,
+        rx_gen_sbbi_i32,
+        rx_gen_adci_i32,
+    };
+    static const int opmodes[] = {RX_PSW_OP_SUB, RX_PSW_OP_SUB, RX_PSW_OP_ADD,
+                                  RX_PSW_OP_SUB, RX_PSW_OP_ADD};
+    int opmode = opmodes[opr];
+    fn[opr](ccop.op_r[opmode], r1, imm);
+    if (opr != RX_OP_CMP) {
+        tcg_gen_mov_i32(ret, ccop.op_r[opmode]);
+    }
+    tcg_gen_mov_i32(ccop.op_a1[opmode], r1);
+    tcg_gen_movi_i32(ccop.op_a2[opmode], imm);
+    SET_MODE_CZSO(opmode);
+}
+
+DEFINE_INSN(addsub1)
+{
+    UIMM4OP(3, rx_alith_imm_op);
+}
+
+DEFINE_INSN(addsub2)
+{
+    MEMOP1_S(3, rx_alith_op);
+}
+
+DEFINE_INSN(addsub3)
+{
+    MEMOP2_S(3, rx_alith_op);
+}
+
+DEFINE_INSN(add4)
+{
+    /* Can't use UIMM4OP */
+    int rs, rd, li;
+    uint32_t imm;
+    li = (insn >> 24) & 3;
+    rs = (insn >> 20) & 15;
+    rd = (insn >> 16) & 15;
+    dc->pc = rx_load_simm(env, dc->pc + 2, li, &imm);
+    rx_alith_imm_op(RX_OP_ADD, cpu_regs[rd], cpu_regs[rs], imm);
+}
+
+DEFINE_INSN(addsub5)
+{
+    OP3(3, rx_alith_op);
+}
+
+DEFINE_INSN(cmp2)
+{
+    int rd;
+    uint32_t imm;
+
+    rd = (insn >> 16) & 15;
+    imm = (insn >> 8) & 0xff;
+
+    rx_alith_imm_op(RX_OP_CMP, cpu_regs[rd], cpu_regs[rd], imm);
+    dc->pc += 3;
+}
+
+DEFINE_INSN(cmp3)
+{
+    int li, rd;
+    uint32_t imm;
+
+    li = (insn >> 24) & 3;
+    rd = (insn >> 16) & 15;
+
+    dc->pc = rx_load_simm(env, dc->pc + 2, li, &imm);
+    rx_alith_imm_op(RX_OP_CMP, cpu_regs[rd], cpu_regs[rd], imm);
+}
+
+DEFINE_INSN(cmp4)
+{
+    MEMOP1_S(3, rx_alith_op);
+}
+
+DEFINE_INSN(cmp5)
+{
+    MEMOP2_S(3, rx_alith_op);
+}
+
+DEFINE_INSN(adc1)
+{
+    SIMMOP_L(rx_alith_imm_op(op = RX_OP_ADC, cpu_regs[rd], cpu_regs[rd], imm));
+}
+
+DEFINE_INSN(adc2sbb1)
+{
+    int op, rs, rd;
+
+    op = (insn >> 19) & 1;
+    rs = (insn >> 12) & 15;
+    rd = (insn >> 8) & 15;
+
+    rx_alith_op(RX_OP_SBB + op, cpu_regs[rd], cpu_regs[rs], cpu_regs[rd]);
+    dc->pc += 3;
+}
+
+DEFINE_INSN(adc3sbb2)
+{
+    int op, id, rs, rd;
+    TCGv mem;
+    TCGv val;
+
+    val = tcg_temp_local_new();
+    id = (insn >> 16) & 3;
+    op = (insn >> 9) & 1;
+    rs = (insn >> 4) & 15;
+    rd = insn & 15;
+
+    mem = rx_index_addr(id, RX_MEMORY_LONG, 4, rs, dc, env);
+    rx_gen_ldst(RX_MEMORY_LONG, RX_MEMORY_LD, val, mem);
+
+    rx_alith_op(RX_OP_SBB + op, cpu_regs[rd], val, cpu_regs[rd]);
+    tcg_temp_free(mem);
+    tcg_temp_free(val);
+    dc->pc += 4 + id;
+}
+
+static void rx_gen_abs(TCGv ret, TCGv arg1)
+{
+    TCGLabel *l1 = gen_new_label();
+    TCGLabel *l2 = gen_new_label();
+
+    tcg_gen_brcondi_i32(TCG_COND_GE, arg1, 0, l1);
+    tcg_gen_neg_i32(ret, arg1);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_mov_i32(ret, arg1);
+    gen_set_label(l2);
+    tcg_gen_mov_i32(ccop.op_a1[RX_PSW_OP_ABS], arg1);
+    tcg_gen_mov_i32(ccop.op_r[RX_PSW_OP_ABS], ret);
+    SET_MODE_ZSO(RX_PSW_OP_ABS);
+}
+
+static void rx_gen_neg(TCGv ret, TCGv arg1)
+{
+    tcg_gen_neg_i32(ret, arg1);
+    tcg_gen_mov_i32(ccop.op_a1[RX_PSW_OP_ABS], arg1);
+    tcg_gen_mov_i32(ccop.op_r[RX_PSW_OP_ABS], ret);
+    SET_MODE_ZSO(RX_PSW_OP_ABS);
+}
+
+static void rx_gen_not(TCGv ret, TCGv arg1)
+{
+    tcg_gen_not_i32(ret, arg1);
+    tcg_gen_mov_i32(ccop.op_a1[RX_PSW_OP_LOGIC], arg1);
+    tcg_gen_mov_i32(ccop.op_r[RX_PSW_OP_LOGIC], ret);
+    SET_MODE_ZS(RX_PSW_OP_LOGIC);
+}
+
+DEFINE_INSN(absnegnot1)
+{
+    static void (* const fn[])(TCGv ret, TCGv arg1) = {
+        rx_gen_not,
+        rx_gen_neg,
+        rx_gen_abs,
+    };
+    int op, rd;
+    op = (insn >> 20) & 3;
+    rd = (insn >> 16) & 15;
+    fn[op](cpu_regs[rd], cpu_regs[rd]);
+    dc->pc += 2;
+}
+
+DEFINE_INSN(absnegnot2)
+{
+    static void (* const fn[])(TCGv ret, TCGv arg1) = {
+        rx_gen_neg,
+        rx_gen_not,
+        rx_gen_abs,
+    };
+    int op, rs, rd;
+    op = ((insn >> 18) & 3) - 1;
+    rs = (insn >> 12) & 15;
+    rd = (insn >> 8) & 15;
+    if (op == -1) {
+        rx_alith_op(RX_OP_SBB, cpu_regs[rd], cpu_regs[rs], cpu_regs[rd]);
+    } else {
+        fn[op](cpu_regs[rd], cpu_regs[rs]);
+    }
+    dc->pc += 3;
+}
+
+static void rx_mul_imm_op(int op, TCGv ret, TCGv arg1, int arg2)
+{
+    tcg_gen_muli_i32(ret, arg1, arg2);
+}
+
+static void rx_mul_op(int op, TCGv ret, TCGv arg1, TCGv arg2)
+{
+    tcg_gen_mul_i32(ret, arg1, arg2);
+}
+
+DEFINE_INSN(mul1)
+{
+    UIMM4OP(3, rx_mul_imm_op);
+}
+
+DEFINE_INSN(mul2)
+{
+    SIMMOP_S(rx_mul_imm_op(op = RX_OP_MUL, cpu_regs[rd], cpu_regs[rd], imm));
+}
+
+DEFINE_INSN(mul3)
+{
+    MEMOP1_S(3, rx_mul_op);
+}
+
+DEFINE_INSN(mul4)
+{
+    MEMOP2_S(3, rx_mul_op);
+}
+
+DEFINE_INSN(mul5)
+{
+    OP3(3, rx_mul_op);
+}
+
+static void rx_div_imm_op(int op, TCGv ret, TCGv arg1, int arg2)
+{
+    static void (*fn[])(TCGv ret, TCGv arg1, TCGv arg2) = {
+        tcg_gen_div_i32, tcg_gen_divu_i32,
+    };
+    TCGv _arg2 = tcg_const_local_i32(arg2);
+    if (arg2) {
+        fn[op](ret, arg1, _arg2);
+        tcg_gen_mov_i32(ccop.op_a1[RX_PSW_OP_DIV], arg1);
+        tcg_gen_movi_i32(ccop.op_a2[RX_PSW_OP_DIV], arg2);
+        tcg_gen_mov_i32(ccop.op_r[RX_PSW_OP_DIV], ret);
+        SET_MODE_O(RX_PSW_OP_DIV);
+    }
+    tcg_temp_free(_arg2);
+}
+
+static void rx_div_op(int op, TCGv ret, TCGv arg1, TCGv arg2)
+{
+    static void (*fn[])(TCGv ret, TCGv arg1, TCGv arg2) = {
+        tcg_gen_div_i32, tcg_gen_divu_i32,
+    };
+    TCGLabel *l1 = gen_new_label();
+    tcg_gen_brcondi_i32(TCG_COND_EQ, arg2, 0, l1);
+    fn[op](ret, arg1, arg2);
+    tcg_gen_mov_i32(ccop.op_a1[RX_PSW_OP_DIV], arg1);
+    tcg_gen_mov_i32(ccop.op_a2[RX_PSW_OP_DIV], arg2);
+    tcg_gen_mov_i32(ccop.op_r[RX_PSW_OP_DIV], ret);
+    SET_MODE_O(RX_PSW_OP_DIV);
+    gen_set_label(l1);
+}
+
+DEFINE_INSN(div1)
+{
+    int divop = (insn >> 12) & 1;
+    SIMMOP_L(rx_div_imm_op(op = divop, cpu_regs[rd], cpu_regs[rd], imm));
+}
+
+DEFINE_INSN(div2)
+{
+    MEMOP1_L(rx_div_op(op, cpu_regs[rd], cpu_regs[rd], cpu_regs[rs]),
+             rx_div_op(op, cpu_regs[rd], cpu_regs[rd], val));
+}
+
+DEFINE_INSN(div3)
+{
+    MEMOP2_L(rx_div_op(op, cpu_regs[rd], cpu_regs[rd], val));
+}
+
+static void rx_emul_imm_op(int op, TCGv rl, TCGv rh, TCGv arg1, int arg2)
+{
+    static void (*fn[])(TCGv rl, TCGv rh, TCGv arg1, TCGv arg2) = {
+        tcg_gen_muls2_i32, tcg_gen_mulu2_i32,
+    };
+    TCGv _arg2 = tcg_const_local_i32(arg2);
+    fn[op](rl, rh, arg1, _arg2);
+    tcg_temp_free(_arg2);
+}
+
+static void rx_emul_op(int op, TCGv rl, TCGv rh, TCGv arg1, TCGv
+                       arg2)
+{
+    static void (* const fn[])(TCGv rl, TCGv rh, TCGv arg1, TCGv arg2) = {
+        tcg_gen_muls2_i32, tcg_gen_mulu2_i32,
+    };
+    fn[op](rl, rh, arg1, arg2);
+}
+
+DEFINE_INSN(emul1)
+{
+    SIMMOP_L(rx_emul_imm_op(op, cpu_regs[rd], cpu_regs[rd + 1],
+                            cpu_regs[rd], imm));
+}
+
+DEFINE_INSN(emul2)
+{
+    MEMOP1_L(rx_emul_op(op, cpu_regs[rd], cpu_regs[rd + 1],
+                        cpu_regs[rd], cpu_regs[rs]),
+             rx_emul_op(op, cpu_regs[rd], cpu_regs[rd + 1],
+                        cpu_regs[rd], val));
+}
+
+DEFINE_INSN(emul3)
+{
+    MEMOP2_L(rx_emul_op(op, cpu_regs[rd], cpu_regs[rd + 1],
+                        cpu_regs[rd], val));
+}
+
+static void rx_minmax_imm_op(int op, TCGv ret, TCGv arg1, int arg2)
+{
+    static const TCGCond cond[] = {TCG_COND_GT, TCG_COND_LT};
+    TCGv _arg2 = tcg_const_local_i32(arg2);
+    tcg_gen_movcond_i32(cond[op], ret, arg1, _arg2, arg1, _arg2);
+    tcg_temp_free(_arg2);
+}
+
+static void rx_minmax_op(int op, TCGv ret, TCGv arg1, TCGv arg2)
+{
+    static const TCGCond cond[] = {TCG_COND_GT, TCG_COND_LT};
+    tcg_gen_movcond_i32(cond[op], ret, arg1, arg2, arg1, arg2);
+}
+
+DEFINE_INSN(minmax1)
+{
+    SIMMOP_L(rx_minmax_imm_op(op, cpu_regs[rd], cpu_regs[rd], imm));
+}
+
+DEFINE_INSN(minmax2)
+{
+    MEMOP1_L(rx_minmax_op(op, cpu_regs[rd], cpu_regs[rd], cpu_regs[rs]),
+             rx_minmax_op(op, cpu_regs[rd], cpu_regs[rd], mem));
+}
+
+DEFINE_INSN(minmax3)
+{
+    MEMOP2_L(rx_minmax_op(op, cpu_regs[rd], cpu_regs[rd], mem));
+}
+
+static void rx_shlri(TCGv ret, TCGv arg1, int arg2)
+{
+    if (arg2) {
+        tcg_gen_shri_i32(ccop.op_r[RX_PSW_OP_SHLR], arg1, arg2 - 1);
+        tcg_gen_andi_i32(ccop.op_a1[RX_PSW_OP_SHLR],
+                         ccop.op_r[RX_PSW_OP_SHLR], 0x00000001);
+        tcg_gen_shri_i32(ccop.op_r[RX_PSW_OP_SHLR],
+                         ccop.op_r[RX_PSW_OP_SHLR], 1);
+        tcg_gen_mov_i32(ret, ccop.op_r[RX_PSW_OP_SHLR]);
+        SET_MODE_CZS(RX_PSW_OP_SHLR);
+    }
+}
+
+static void rx_shari(TCGv ret, TCGv arg1, int arg2)
+{
+    if (arg2) {
+        tcg_gen_sari_i32(ccop.op_r[RX_PSW_OP_SHAR], arg1, arg2 - 1);
+        tcg_gen_andi_i32(ccop.op_a1[RX_PSW_OP_SHAR],
+                         ccop.op_r[RX_PSW_OP_SHAR], 0x00000001);
+        tcg_gen_sari_i32(ccop.op_r[RX_PSW_OP_SHAR],
+                         ccop.op_r[RX_PSW_OP_SHAR], 1);
+        tcg_gen_mov_i32(ret, ccop.op_r[RX_PSW_OP_SHAR]);
+        SET_MODE_CZSO(RX_PSW_OP_SHAR);
+    }
+}
+
+static void rx_shlli(TCGv ret, TCGv arg1, int arg2)
+{
+    if (arg2) {
+        tcg_gen_shri_i32(ccop.op_a1[RX_PSW_OP_SHLL], arg1, 32 - arg2);
+        tcg_gen_mov_i32(ccop.op_a2[RX_PSW_OP_SHLL], arg1);
+        tcg_gen_shli_i32(ret, arg1, arg2);
+        tcg_gen_mov_i32(ccop.op_r[RX_PSW_OP_SHLL], ret);
+        SET_MODE_CZSO(RX_PSW_OP_SHLL);
+    }
+}
+
+static void rx_shlr(TCGv ret, TCGv arg1, TCGv arg2)
+{
+    TCGv t0;
+    TCGLabel *l1;
+    t0 = tcg_temp_local_new();
+    l1 = gen_new_label();
+    tcg_gen_brcondi_i32(TCG_COND_EQ, arg2, 0, l1);
+    tcg_gen_subi_i32(t0, arg2, 1);
+    tcg_gen_shr_i32(ccop.op_r[RX_PSW_OP_SHLR], arg1, t0);
+    tcg_gen_andi_i32(ccop.op_a1[RX_PSW_OP_SHLR],
+                     ccop.op_r[RX_PSW_OP_SHLR], 0x00000001);
+    tcg_gen_shri_i32(ccop.op_r[RX_PSW_OP_SHLR],
+                     ccop.op_r[RX_PSW_OP_SHLR], 1);
+    tcg_gen_mov_i32(ret, ccop.op_r[RX_PSW_OP_SHLR]);
+    gen_set_label(l1);
+    tcg_temp_free(t0);
+}
+
+static void rx_shar(TCGv ret, TCGv arg1, TCGv arg2)
+{
+    TCGv t0;
+    TCGLabel *l1;
+    t0 = tcg_temp_local_new();
+    l1 = gen_new_label();
+    tcg_gen_brcondi_i32(TCG_COND_EQ, arg2, 0, l1);
+    tcg_gen_subi_i32(t0, arg2, 1);
+    tcg_gen_sar_i32(ccop.op_r[RX_PSW_OP_SHAR], arg1, t0);
+    tcg_gen_andi_i32(ccop.op_a1[RX_PSW_OP_SHAR],
+                     ccop.op_r[RX_PSW_OP_SHAR], 0x00000001);
+    tcg_gen_sari_i32(ccop.op_r[RX_PSW_OP_SHAR],
+                     ccop.op_r[RX_PSW_OP_SHAR], 1);
+    tcg_gen_mov_i32(ret, ccop.op_r[RX_PSW_OP_SHAR]);
+    gen_set_label(l1);
+    tcg_temp_free(t0);
+}
+
+static void rx_shll(TCGv ret, TCGv arg1, TCGv arg2)
+{
+    TCGv t0;
+    TCGLabel *l1;
+    t0 = tcg_temp_local_new();
+    l1 = gen_new_label();
+    tcg_gen_brcondi_i32(TCG_COND_EQ, arg2, 0, l1);
+    tcg_gen_movi_i32(t0, 32);
+    tcg_gen_sub_i32(t0, t0, arg2);
+    tcg_gen_shr_i32(ccop.op_a1[RX_PSW_OP_SHLL], arg1, t0);
+    tcg_gen_mov_i32(ccop.op_a2[RX_PSW_OP_SHLL], arg1);
+    tcg_gen_shl_i32(ret, arg1, arg2);
+    tcg_gen_mov_i32(ccop.op_r[RX_PSW_OP_SHLL], ret);
+    SET_MODE_CZSO(RX_PSW_OP_SHLL);
+    gen_set_label(l1);
+    tcg_temp_free(t0);
+}
+
+DEFINE_INSN(shift1)
+{
+    static void (* const fn[])(TCGv ret, TCGv arg1, int arg2) = {
+        rx_shlri, rx_shari, rx_shlli,
+    };
+    int op, imm, rd;
+    op = (insn >> 25) & 7;
+    imm = (insn >> 20) & 0x1f;
+    rd = (insn >> 16) & 15;
+    if (imm != 0) {
+        fn[op - 4](cpu_regs[rd], cpu_regs[rd], imm);
+    }
+    dc->pc += 2;
+}
+
+DEFINE_INSN(shift2)
+{
+    static void (* const fn[])(TCGv ret, TCGv arg1, TCGv arg2) = {
+        rx_shlr, rx_shar, rx_shll,
+    };
+    int op, rs, rd;
+    op = (insn >> 16) & 3;
+    rs = (insn >> 12) & 15;
+    rd = (insn >> 8) & 15;
+    fn[op](cpu_regs[rd], cpu_regs[rd], cpu_regs[rs]);
+    dc->pc += 3;
+}
+
+DEFINE_INSN(shift3)
+{
+    static void (* const fn[])(TCGv ret, TCGv arg1, int arg2) = {
+        rx_shlri, rx_shari, rx_shlli,
+    };
+    int op, imm, rs, rd;
+    op = (insn >> 21) & 3;
+    imm = (insn >> 16) & 0x1f;
+    rs = (insn >> 12) & 15;
+    rd = (insn >> 8) & 15;
+    if (imm != 0) {
+        fn[op](cpu_regs[rd], cpu_regs[rs], imm);
+    }
+    dc->pc += 3;
+}
+
+DEFINE_INSN(roc)
+{
+    int dir, rd;
+    TCGv cin;
+
+    dir = (insn >> 20) & 1;
+    rd = (insn >> 16) & 15;
+    cin = tcg_temp_local_new();
+    gen_helper_psw_c(cin, cpu_env);
+    if (dir) {
+        tcg_gen_shri_i32(ccop.op_a1[RX_PSW_OP_SHLR], cpu_regs[rd], 31);
+        tcg_gen_shli_i32(cpu_regs[rd], cpu_regs[rd], 1);
+        tcg_gen_or_i32(cpu_regs[rd], cpu_regs[rd], cin);
+    } else {
+        tcg_gen_andi_i32(ccop.op_a1[RX_PSW_OP_SHLR], cpu_regs[rd], 0x00000001);
+        tcg_gen_shri_i32(cpu_regs[rd], cpu_regs[rd], 1);
+        tcg_gen_shli_i32(cin, cin, 31);
+        tcg_gen_or_i32(cpu_regs[rd], cpu_regs[rd], cin);
+    }
+    tcg_gen_mov_i32(ccop.op_r[RX_PSW_OP_SHLR], cpu_regs[rd]);
+    SET_MODE_CZS(RX_PSW_OP_SHLR);
+    tcg_temp_free(cin);
+    dc->pc += 2;
+}
+
+DEFINE_INSN(rot1)
+{
+    int dir, imm, rd;
+    dir = (insn >> 17) & 1;
+    imm = (insn >> 12) & 31;
+    rd = (insn >> 8) & 15;
+    tcg_gen_movi_i32(ccop.op_a1[RX_PSW_OP_ROT], dir);
+    if (dir) {
+        tcg_gen_rotli_i32(cpu_regs[rd], cpu_regs[rd], imm);
+    } else {
+        tcg_gen_rotri_i32(cpu_regs[rd], cpu_regs[rd], imm);
+    }
+    tcg_gen_andi_i32(ccop.op_r[RX_PSW_OP_ROT], cpu_regs[rd], 0x00000001);
+    SET_MODE_CZS(RX_PSW_OP_ROT);
+    dc->pc += 3;
+}
+
+DEFINE_INSN(rot2)
+{
+    int dir, rs, rd;
+    dir = (insn >> 17) & 1;
+    rs = (insn >> 12) & 15;
+    rd = (insn >> 8) & 15;
+    tcg_gen_movi_i32(ccop.op_a1[RX_PSW_OP_ROT], dir);
+    if (dir) {
+        tcg_gen_rotl_i32(cpu_regs[rd], cpu_regs[rd], cpu_regs[rs]);
+    } else {
+        tcg_gen_rotr_i32(cpu_regs[rd], cpu_regs[rd], cpu_regs[rs]);
+    }
+    tcg_gen_andi_i32(ccop.op_r[RX_PSW_OP_ROT], cpu_regs[rd], 0x00000001);
+    SET_MODE_CZS(RX_PSW_OP_ROT);
+    dc->pc += 3;
+}
+
+DEFINE_INSN(sat)
+{
+    int rd;
+    TCGv s, o, plus, minus, one;
+    TCGLabel *l1;
+
+    l1 = gen_new_label();
+    rd = (insn >> 16) & 15;
+    s = tcg_temp_local_new();
+    o = tcg_temp_local_new();
+    plus = tcg_const_local_i32(0x7fffffff);
+    minus = tcg_const_local_i32(0x80000000);
+    one = tcg_const_local_i32(1);
+    gen_helper_psw_s(s, cpu_env);
+    gen_helper_psw_o(o, cpu_env);
+    tcg_gen_brcondi_i32(TCG_COND_NE, o, 1, l1);
+    tcg_gen_movcond_i32(TCG_COND_EQ, cpu_regs[rd], s, one, plus, minus);
+    gen_set_label(l1);
+    tcg_temp_free(s);
+    tcg_temp_free(o);
+    tcg_temp_free(plus);
+    tcg_temp_free(minus);
+    tcg_temp_free(one);
+    dc->pc += 2;
+}
+
+DEFINE_INSN(satr)
+{
+    TCGv s, o;
+    TCGLabel *l1, *l2;
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+
+    s = tcg_temp_local_new();
+    o = tcg_temp_local_new();
+    gen_helper_psw_s(s, cpu_env);
+    gen_helper_psw_o(o, cpu_env);
+    tcg_gen_brcondi_i32(TCG_COND_NE, o, 1, l2);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, s, 1, l1);
+    tcg_gen_movi_i32(cpu_regs[6], 0x7fffffff);
+    tcg_gen_movi_i32(cpu_regs[5], 0xffffffff);
+    tcg_gen_movi_i32(cpu_regs[4], 0xffffffff);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_movi_i32(cpu_regs[6], 0x80000000);
+    tcg_gen_movi_i32(cpu_regs[5], 0x00000000);
+    tcg_gen_movi_i32(cpu_regs[4], 0x00000000);
+    gen_set_label(l2);
+    tcg_temp_free(s);
+    tcg_temp_free(o);
+    dc->pc += 2;
+}
+
+DEFINE_INSN(rmpa)
+{
+    int sz;
+    TCGLabel *l0, *l1, *l2, *l3;
+    TCGv t0, t1, t2, t3;
+
+    sz = (insn >> 16) & 3;
+    l0 = gen_new_label();
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+    l3 = gen_new_label();
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+    t2 = tcg_temp_local_new();
+    t3 = tcg_temp_local_new();
+    gen_set_label(l0);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_regs[3], 0, l2);
+    rx_gen_ldst(sz, RX_MEMORY_LD, t0, cpu_regs[1]);
+    tcg_gen_addi_i32(cpu_regs[1], cpu_regs[1], 1 << sz);
+    tcg_gen_addi_i32(cpu_regs[2], cpu_regs[2], 1 << sz);
+    rx_gen_ldst(sz, RX_MEMORY_LD, t1, cpu_regs[2]);
+    tcg_gen_muls2_i32(t2, t3, t0, t1);
+    tcg_gen_add2_i32(t0, t1, cpu_regs[4], cpu_regs[5], t2, t3);
+    tcg_gen_brcond_i32(TCG_COND_GT, t1, cpu_regs[5], l1);
+    tcg_gen_brcond_i32(TCG_COND_GT, t0, cpu_regs[4], l1);
+    tcg_gen_addi_i32(cpu_regs[6], cpu_regs[6], 1);
+    gen_set_label(l1);
+    tcg_gen_subi_i32(cpu_regs[3], cpu_regs[3], 1);
+    tcg_gen_br(l0);
+    gen_set_label(l2);
+    tcg_gen_ext16s_i32(cpu_regs[6], cpu_regs[6]);
+    tcg_gen_shri_i32(cpu_psw_s, cpu_regs[6], 31);
+    tcg_gen_movi_i32(cpu_psw_o, 0);
+    tcg_gen_andi_i32(ccop.op_mode, ccop.op_mode, 0x00ff);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_regs[6], 0, l3);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_regs[6], -1, l3);
+    tcg_gen_movi_i32(cpu_psw_o, 1);
+    gen_set_label(l3);
+    tcg_temp_free(t3);
+    tcg_temp_free(t2);
+    tcg_temp_free(t1);
+    tcg_temp_free(t0);
+    dc->pc += 2;
+}
+
+static void bsetmem(TCGv mem, TCGv mask)
+{
+    TCGv val;
+    val = tcg_temp_local_new();
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_LD, val, mem);
+    tcg_gen_or_i32(val, val, mask);
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_ST, val, mem);
+    tcg_temp_free(val);
+}
+
+static void bclrmem(TCGv mem, TCGv mask)
+{
+    TCGv val;
+    val = tcg_temp_local_new();
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_LD, val, mem);
+    tcg_gen_not_i32(mask, mask);
+    tcg_gen_and_i32(val, val, mask);
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_ST, val, mem);
+    tcg_temp_free(val);
+}
+
+static void btstmem(TCGv mem, TCGv mask)
+{
+    TCGv val;
+    val = tcg_temp_local_new();
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_LD, val, mem);
+    tcg_gen_and_i32(val, val, mask);
+    tcg_gen_setcondi_i32(TCG_COND_NE, ccop.op_r[RX_PSW_OP_BTST], val, 0);
+    SET_MODE_CZ(RX_PSW_OP_BTST);
+    tcg_temp_free(val);
+}
+
+static void bnotmem(TCGv mem, TCGv mask)
+{
+    TCGv val;
+    val = tcg_temp_local_new();
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_LD, val, mem);
+    tcg_gen_xor_i32(val, val, mask);
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_ST, val, mem);
+    tcg_temp_free(val);
+}
+
+static void bsetreg(TCGv reg, TCGv mask)
+{
+    tcg_gen_or_i32(reg, reg, mask);
+}
+
+static void bclrreg(TCGv reg, TCGv mask)
+{
+    tcg_gen_not_i32(mask, mask);
+    tcg_gen_and_i32(reg, reg, mask);
+}
+
+static void btstreg(TCGv reg, TCGv mask)
+{
+    TCGv t0;
+    t0 = tcg_temp_local_new();
+    tcg_gen_and_i32(t0, reg, mask);
+    tcg_gen_setcondi_i32(TCG_COND_NE, ccop.op_r[RX_PSW_OP_BTST], t0, 0);
+    SET_MODE_CZ(RX_PSW_OP_BTST);
+    tcg_temp_free(t0);
+}
+
+static void bnotreg(TCGv reg, TCGv mask)
+{
+    tcg_gen_xor_i32(reg, reg, mask);
+}
+
+DEFINE_INSN(bop1)
+{
+    static void (* const fn[])(TCGv mem, TCGv mask) = {
+        bsetmem, bclrmem, btstmem,
+    };
+    int op, id, rd, imm;
+    TCGv mem, mask;
+    op = ((insn >> 25) & 6) | ((insn >> 19) & 1);
+    id = (insn >> 24) & 3;
+    rd = (insn >> 20) & 15;
+    imm = (insn >> 16) & 7;
+    mem = rx_index_addr(id, RX_MEMORY_BYTE, 2, rd, dc, env);
+    mask = tcg_const_local_i32(1 << imm);
+    fn[op](mem, mask);
+    tcg_temp_free(mem);
+    tcg_temp_free(mask);
+    dc->pc += 2 + id;
+}
+
+DEFINE_INSN(bop2)
+{
+    static void (*bmem[])(TCGv mem, TCGv mask) = {
+        bsetmem, bclrmem, btstmem, bnotmem,
+    };
+    static void (*breg[])(TCGv reg, TCGv mask) = {
+        bsetreg, bclrreg, btstreg, bnotreg,
+    };
+    int op, id, rd, rs;
+    TCGv mem, mask;
+    op = (insn >> 18) & 3;
+    id = (insn >> 16) & 3;
+    rd = (insn >> 12) & 15;
+    rs = (insn >> 8) & 15;
+
+    mask = tcg_temp_local_new();
+    tcg_gen_movi_i32(mask, 1);
+    tcg_gen_shl_i32(mask, mask, cpu_regs[rs]);
+    if (id < 3) {
+        mem = rx_index_addr(id, RX_MEMORY_BYTE, 2, rd, dc, env);
+        bmem[op](mem, mask);
+        tcg_temp_free(mem);
+        dc->pc += 3 + id;
+    } else {
+        breg[op](cpu_regs[rd], mask);
+        dc->pc += 3;
+    }
+    tcg_temp_free(mask);
+}
+
+DEFINE_INSN(bop3)
+{
+    static void (*fn[])(TCGv reg, TCGv mask) = {
+        bsetreg, bclrreg, btstreg,
+    };
+    int op, imm, rd;
+    TCGv mask;
+    op = (insn >> 25) & 3;
+    imm = (insn >> 20) & 31;
+    rd = (insn >> 16) & 15;
+    mask = tcg_const_local_i32(1 << imm);
+    fn[op](cpu_regs[rd], mask);
+    tcg_temp_free(mask);
+    dc->pc += 2;
+}
+
+DEFINE_INSN(bnot1)
+{
+    int imm, id, rd;
+    TCGv mem, val;
+    imm = (insn >> 18) & 7;
+    id = (insn >> 16) & 3;
+    rd = (insn >> 12) & 15;
+    mem = rx_index_addr(id, RX_MEMORY_BYTE, 2, rd, dc, env);
+    val = tcg_temp_local_new();
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_LD, val, mem);
+    tcg_gen_xori_i32(val, val, 1 << imm);
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_ST, val, mem);
+    dc->pc += 3;
+}
+
+DEFINE_INSN(bmcnd1)
+{
+    int imm, id, rd;
+    TCGv mem, val, cd, result;
+    TCGLabel *l1, *l2;
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+    imm = (insn >> 18) & 7;
+    id = (insn >> 16) & 3;
+    rd = (insn >> 12) & 15;
+    cd = tcg_const_local_i32((insn >> 8) & 15);
+    val = tcg_temp_local_new();
+    result = tcg_temp_local_new();
+    mem = rx_index_addr(id, RX_MEMORY_BYTE, 2, rd, dc, env);
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_LD, val, mem);
+    if (((insn >> 8) & 15) == 15) {
+        /* special case bnot #imm, mem */
+        tcg_gen_xori_i32(val, val, 1 << imm);
+    } else {
+        gen_helper_cond(result, cpu_env, cd);
+        tcg_gen_brcondi_i32(TCG_COND_NE, result, 0, l1);
+        tcg_gen_andi_i32(val, val, ~(1 << imm));
+        tcg_gen_br(l2);
+        gen_set_label(l1);
+        tcg_gen_ori_i32(val, val, 1 << imm);
+        gen_set_label(l2);
+    }
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_ST, val, mem);
+    tcg_temp_free(mem);
+    tcg_temp_free(val);
+    tcg_temp_free(cd);
+    tcg_temp_free(result);
+    dc->pc += 3 + id;
+}
+
+DEFINE_INSN(bmcnd2)
+{
+    int imm, rd;
+    TCGv cd, result;
+    TCGLabel *l1, *l2;
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+    imm = (insn >> 16) & 31;
+    cd = tcg_const_local_i32((insn >> 12) & 15);
+    rd = (insn >> 8) & 15;
+    if (((insn >> 12) & 15) == 15) {
+        /* special case bnot #imm, reg */
+        tcg_gen_xori_i32(cpu_regs[rd], cpu_regs[rd], 1 << imm);
+    } else {
+        result = tcg_temp_local_new();
+        gen_helper_cond(result, cpu_env, cd);
+        tcg_gen_brcondi_i32(TCG_COND_NE, result, 0, l1);
+        tcg_gen_andi_i32(cpu_regs[rd], cpu_regs[rd], ~(1 << imm));
+        tcg_gen_br(l2);
+        gen_set_label(l1);
+        tcg_gen_ori_i32(cpu_regs[rd], cpu_regs[rd], 1 << imm);
+        gen_set_label(l2);
+        tcg_temp_free(result);
+    }
+    tcg_temp_free(cd);
+    dc->pc += 3;
+}
+
+DEFINE_INSN(scmpu)
+{
+    TCGLabel *l1, *l2;
+    TCGv t0, t1;
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+    tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_regs[3], 0, l2);
+    gen_set_label(l1);
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_LD, t1, cpu_regs[2]);
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_LD, t0, cpu_regs[1]);
+    tcg_gen_addi_i32(cpu_regs[1], cpu_regs[1], 1);
+    tcg_gen_addi_i32(cpu_regs[2], cpu_regs[2], 1);
+    tcg_gen_subi_i32(cpu_regs[3], cpu_regs[3], 1);
+    tcg_gen_brcond_i32(TCG_COND_NE, t0, t1, l2);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l2);
+    tcg_gen_brcondi_i32(TCG_COND_GTU, cpu_regs[3], 0, l1);
+    gen_set_label(l2);
+    tcg_gen_sub_i32(ccop.op_r[RX_PSW_OP_STRING], t0, t1);
+    SET_MODE_CZ(RX_PSW_OP_STRING);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    dc->pc += 2;
+}
+
+DEFINE_INSN(smovbfu)
+{
+    TCGLabel *l1, *l2;
+    TCGv t0;
+    int dir, term;
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+    t0 = tcg_temp_local_new();
+    term = (insn >> 19) & 1;
+    dir = (insn >> 18) & 1;
+    gen_set_label(l1);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_regs[3], 0, l2);
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_LD, t0, cpu_regs[2]);
+    rx_gen_ldst(RX_MEMORY_BYTE, RX_MEMORY_ST, t0, cpu_regs[1]);
+    if (dir) {
+        tcg_gen_addi_i32(cpu_regs[1], cpu_regs[1], 1);
+        tcg_gen_addi_i32(cpu_regs[2], cpu_regs[2], 1);
+    } else {
+        tcg_gen_subi_i32(cpu_regs[1], cpu_regs[1], 1);
+        tcg_gen_subi_i32(cpu_regs[2], cpu_regs[2], 1);
+    }
+    tcg_gen_subi_i32(cpu_regs[3], cpu_regs[3], 1);
+    if (term == 0) {
+        tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l2);
+    }
+    tcg_gen_br(l1);
+    gen_set_label(l2);
+    tcg_temp_free(t0);
+    dc->pc += 2;
+}
+
+DEFINE_INSN(sstr)
+{
+    int size;
+    TCGLabel *l1, *l2;
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+
+    size = (insn >> 16) & 3;
+    gen_set_label(l1);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_regs[3], 0, l2);
+    rx_gen_ldst(size, RX_MEMORY_ST, cpu_regs[2], cpu_regs[1]);
+    tcg_gen_addi_i32(cpu_regs[1], cpu_regs[1], 1 << size);
+    tcg_gen_subi_i32(cpu_regs[3], cpu_regs[3], 1);
+    tcg_gen_br(l1);
+    gen_set_label(l2);
+    dc->pc += 2;
+}
+
+DEFINE_INSN(ssearch)
+{
+    int match, size;
+    TCGv t0;
+    TCGLabel *l1, *l2;
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+    t0 = tcg_temp_local_new();
+    match = (insn >> 18) & 1;
+    size = (insn >> 16) & 3;
+    gen_set_label(l1);
+    rx_gen_ldu(size, t0, cpu_regs[1]);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_regs[3], 0, l2);
+    tcg_gen_addi_i32(cpu_regs[1], cpu_regs[1], 1 << size);
+    tcg_gen_subi_i32(cpu_regs[3], cpu_regs[3], 1);
+    tcg_gen_brcond_i32(match ? TCG_COND_EQ : TCG_COND_NE,
+                       t0, cpu_regs[2], l2);
+    tcg_gen_br(l1);
+    gen_set_label(l2);
+    tcg_gen_sub_i32(ccop.op_r[RX_PSW_OP_STRING], t0, cpu_regs[2]);
+    SET_MODE_CZ(RX_PSW_OP_STRING);
+    tcg_temp_free(t0);
+    dc->pc += 2;
+}
+
+static void bra_main(int dst, DisasContext *dc)
+{
+    tcg_gen_movi_i32(cpu_pc, dc->pc += dst);
+    dc->base.is_jmp = DISAS_JUMP;
+}
+
+DEFINE_INSN(bra1)
+{
+    unsigned int dst;
+    dst = (insn >> 24) & 7;
+    if (dst < 3) {
+        dst += 8;
+    }
+    bra_main(dst, dc);
+    dc->pc += 1;
+}
+
+DEFINE_INSN(bra2)
+{
+    char dst;
+    dst = (insn >> 16) & 255;
+    bra_main(dst, dc);
+    dc->pc += 2;
+}
+
+DEFINE_INSN(bra3)
+{
+    short dst;
+    dst = (insn & 0xff00) | ((insn >> 16) & 0xff);
+    bra_main(dst, dc);
+    dc->pc += 3;
+}
+
+DEFINE_INSN(bra4)
+{
+    unsigned short dstl;
+    char dsth;
+    dstl = (insn & 0xff00) | ((insn >> 16) & 0xff);
+    dsth = insn & 255;
+    bra_main((dsth << 16) | dstl, dc);
+    dc->pc += 4;
+}
+
+DEFINE_INSN(bra5)
+{
+    int rd;
+    rd = (insn >> 16) & 15;
+    tcg_gen_addi_i32(cpu_pc, cpu_regs[rd], dc->pc);
+    dc->base.is_jmp = DISAS_JUMP;
+}
+
+static void bcnd_main(int cd, int dst, int len, DisasContext *dc)
+{
+    TCGv zero, cond, result, t, f;
+    t = tcg_const_local_i32(dc->pc + dst);
+    f = tcg_const_local_i32(dc->pc + len);
+    result = tcg_temp_local_new();
+    cond = tcg_const_local_i32(cd);
+    zero = tcg_const_local_i32(0);
+    gen_helper_cond(result, cpu_env, cond);
+
+    tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc,
+                        result, zero, t, f);
+    dc->base.is_jmp = DISAS_JUMP;
+    tcg_temp_free(t);
+    tcg_temp_free(f);
+    tcg_temp_free(zero);
+    tcg_temp_free(cond);
+    tcg_temp_free(result);
+    dc->pc += len;
+}
+
+DEFINE_INSN(bcnd1)
+{
+    int cd, dst;
+    cd = (insn >> 27) & 1;
+    dst = (insn >> 24) & 7;
+    if (dst < 3) {
+        dst += 8;
+    }
+    bcnd_main(cd, dst, 1, dc);
+}
+
+DEFINE_INSN(bcnd2)
+{
+    int cd;
+    char dst;
+    cd = (insn >> 24) & 15;
+    dst = (insn >> 16) & 255;
+    bcnd_main(cd, dst, 2, dc);
+}
+
+DEFINE_INSN(bcnd3)
+{
+    int cd;
+    short dst;
+    cd = (insn >> 24) & 1;
+    dst = (insn & 0xff00) | ((insn >> 16) & 0xff);
+    bcnd_main(cd, dst, 3, dc);
+}
+
+static void pc_save_stack(int len, DisasContext *dc)
+{
+    TCGv save_pc;
+    save_pc = tcg_const_local_i32(dc->pc + len);
+    tcg_gen_subi_i32(cpu_regs[0], cpu_regs[0], 4);
+    tcg_gen_qemu_st32(save_pc, cpu_regs[0], 0);
+    tcg_temp_free(save_pc);
+}
+
+DEFINE_INSN(bsr1)
+{
+    short dst;
+    pc_save_stack(3, dc);
+    dst = (insn & 0xff00) | ((insn >> 16) & 0xff);
+    bra_main(dst, dc);
+}
+
+DEFINE_INSN(bsr2)
+{
+    unsigned short dstl;
+    char dsth;
+    pc_save_stack(4, dc);
+    dstl = (insn & 0xff00) | ((insn >> 16) & 0xff);
+    dsth = insn & 255;
+    bra_main((dsth << 16) | dstl, dc);
+}
+
+DEFINE_INSN(bsr3)
+{
+    int rd;
+    rd = (insn >> 16) & 15;
+    pc_save_stack(2, dc);
+    tcg_gen_addi_i32(cpu_pc, cpu_regs[rd], dc->pc);
+    dc->base.is_jmp = DISAS_JUMP;
+}
+
+DEFINE_INSN(jmpjsr)
+{
+    int is_jsr, rd;
+    is_jsr = (insn >> 20) & 1;
+    rd = (insn >> 16) & 15;
+    if (is_jsr) {
+        pc_save_stack(2, dc);
+    }
+    tcg_gen_mov_i32(cpu_pc, cpu_regs[rd]);
+    dc->base.is_jmp = DISAS_JUMP;
+    dc->pc += 2;
+}
+
+DEFINE_INSN(rts)
+{
+    tcg_gen_qemu_ld32u(cpu_pc, cpu_regs[0], 0);
+    tcg_gen_addi_i32(cpu_regs[0], cpu_regs[0], 4);
+    dc->base.is_jmp = DISAS_JUMP;
+    dc->pc += 1;
+}
+
+DEFINE_INSN(rtsd1)
+{
+    int src;
+    src = (insn >> 16) & 255;
+    tcg_gen_addi_i32(cpu_regs[0], cpu_regs[0], src << 2);
+    tcg_gen_qemu_ld32u(cpu_pc, cpu_regs[0], 0);
+    tcg_gen_addi_i32(cpu_regs[0], cpu_regs[0], 4);
+    dc->base.is_jmp = DISAS_JUMP;
+    dc->pc += 2;
+}
+
+DEFINE_INSN(rtsd2)
+{
+    int src, dst, dst2;
+    dst = (insn >> 20) & 15;
+    dst2 = (insn >> 16) & 15;
+    src = (insn >> 8) & 255;
+    src -= (dst2 - dst + 1);
+    tcg_gen_addi_i32(cpu_regs[0], cpu_regs[0], src << 2);
+    for (; dst <= dst2; dst++) {
+        tcg_gen_qemu_ld32u(cpu_regs[dst], cpu_regs[0], 0);
+        tcg_gen_addi_i32(cpu_regs[0], cpu_regs[0], 4);
+    }
+    tcg_gen_qemu_ld32u(cpu_pc, cpu_regs[0], 0);
+    tcg_gen_addi_i32(cpu_regs[0], cpu_regs[0], 4);
+    dc->base.is_jmp = DISAS_JUMP;
+    dc->pc += 3;
+}
+
+DEFINE_INSN(rxbrk)
+{
+    tcg_gen_movi_i32(cpu_pc, dc->pc + 1);
+    gen_helper_rxbrk(cpu_env);
+    dc->base.is_jmp = DISAS_NORETURN;
+    dc->pc += 1;
+}
+
+DEFINE_INSN(rxint)
+{
+    int imm;
+    TCGv vec;
+    imm = (insn >> 8) & 0xff;
+    vec = tcg_const_local_i32(imm);
+    tcg_gen_movi_i32(cpu_pc, dc->pc + 3);
+    gen_helper_rxint(cpu_env, vec);
+    tcg_temp_free(vec);
+    dc->base.is_jmp = DISAS_NORETURN;
+    dc->pc += 3;
+}
+
+DEFINE_INSN(clrsetpsw)
+{
+    TCGv psw[] = {
+        cpu_psw_c, cpu_psw_z, cpu_psw_s, cpu_psw_o,
+        NULL, NULL, NULL, NULL,
+        cpu_psw_i, cpu_psw_u, NULL, NULL,
+        NULL, NULL, NULL, NULL
+    };
+    static const uint32_t opmask[] = {~0x000f, ~0x00f0, ~0x0f00, ~0xf000};
+    int mode, dst;
+    TCGLabel *l;
+
+    mode = (insn >> 20 & 1);
+    dst = (insn >> 16) & 15;
+    l = gen_new_label();
+    if (dst >= 8) {
+        tcg_gen_brcondi_i32(TCG_COND_NE, cpu_psw_pm, 0, l);
+    }
+    tcg_gen_movi_i32(psw[dst], (mode ? 0 : 1));
+    gen_set_label(l);
+    if (dst < 4) {
+        tcg_gen_andi_i32(ccop.op_mode, ccop.op_mode, opmask[dst]);
+    }
+    dc->pc += 2;
+}
+
+DEFINE_INSN(mvfc)
+{
+    int rd, cr;
+    TCGv _cr;
+    cr = (insn >> 12) & 15;
+    _cr = tcg_const_i32(cr);
+    rd = (insn >> 8) & 15;
+    if (cr == 1) {
+        tcg_gen_movi_i32(cpu_regs[rd], dc->pc);
+    } else {
+        gen_helper_mvfc(cpu_regs[rd], cpu_env, _cr);
+    }
+    tcg_temp_free(_cr);
+    dc->pc += 3;
+}
+
+DEFINE_INSN(mvtc1)
+{
+    int li;
+    uint32_t imm;
+    TCGv cr, _imm;
+
+    li = (insn >> 18) & 3;
+    cr = tcg_const_i32((insn >> 8) & 15);
+    dc->pc = rx_load_simm(env, dc->pc + 3, li, &imm);
+    _imm = tcg_const_i32(imm);
+    gen_helper_mvtc(cpu_env, cr, _imm);
+    tcg_temp_free(cr);
+    tcg_temp_free(_imm);
+}
+
+DEFINE_INSN(mvtc2)
+{
+    int rs;
+    TCGv cr;
+    rs = (insn >> 12) & 15;
+    cr = tcg_const_i32((insn >> 8) & 15);
+    gen_helper_mvtc(cpu_env, cr, cpu_regs[rs]);
+    dc->pc += 3;
+    tcg_temp_free(cr);
+}
+
+static void check_previleged(void)
+{
+    TCGLabel *good;
+    good = gen_new_label();
+    tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_psw_pm, 0, good);
+    gen_helper_raise_privilege_violation(cpu_env);
+    gen_set_label(good);
+}
+
+DEFINE_INSN(mvtipl)
+{
+    int ipl;
+    check_previleged();
+    ipl = (insn >> 8) & 15;
+    tcg_gen_movi_i32(cpu_psw_ipl, ipl);
+    dc->pc += 3;
+}
+
+DEFINE_INSN(rte)
+{
+    check_previleged();
+    tcg_gen_qemu_ld32u(cpu_pc, cpu_regs[0], 0);
+    tcg_gen_addi_i32(cpu_regs[0], cpu_regs[0], 4);
+    tcg_gen_qemu_ld32u(cpu_psw, cpu_regs[0], 0);
+    tcg_gen_addi_i32(cpu_regs[0], cpu_regs[0], 4);
+    gen_helper_unpack_psw(cpu_env);
+    dc->base.is_jmp = DISAS_JUMP;
+    dc->pc += 2;
+}
+
+DEFINE_INSN(rtfi)
+{
+    check_previleged();
+    tcg_gen_mov_i32(cpu_pc, cpu_bpc);
+    tcg_gen_mov_i32(cpu_psw, cpu_bpsw);
+    gen_helper_unpack_psw(cpu_env);
+    dc->base.is_jmp = DISAS_JUMP;
+    dc->pc += 2;
+}
+
+DEFINE_INSN(rxwait)
+{
+    check_previleged();
+    tcg_gen_addi_i32(cpu_pc, cpu_pc, 2);
+    gen_helper_wait(cpu_env);
+    dc->pc += 2;
+}
+
+DEFINE_INSN(fimm)
+{
+    int op, rd, fop;
+    uint32_t imm;
+    TCGv _op, t0;
+
+    op = (insn >> 12) & 7;
+    rd = (insn >> 8) & 15;
+    dc->pc = rx_load_simm(env, dc->pc + 4, 3, &imm);
+    t0 = tcg_const_i32(imm);
+    _op = tcg_const_i32(op);
+    fop = (op != 1) ? RX_PSW_OP_FLOAT : RX_PSW_OP_FCMP;
+    gen_helper_floatop(ccop.op_r[fop], cpu_env, _op, cpu_regs[rd], t0);
+    if (op != 1) {
+        tcg_gen_mov_i32(cpu_regs[rd], ccop.op_r[RX_PSW_OP_FLOAT]);
+        SET_MODE_ZS(RX_PSW_OP_FLOAT);
+    } else
+        SET_MODE_ZSO(RX_PSW_OP_FCMP);
+    tcg_temp_free(t0);
+    tcg_temp_free(_op);
+}
+
+DEFINE_INSN(fmem)
+{
+    int op, id, rs, rd, fop;
+    TCGv _op, t1;
+
+    op = (insn >> 18) & 7;
+    id = (insn >> 16) & 3;
+    rs = (insn >> 8) & 15;
+    rd = (insn >> 8) & 15;
+
+    t1 = tcg_temp_local_new();
+    if (id < 3) {
+        TCGv t0;
+        t0 = rx_index_addr(id, 2, 3, rs, dc, env);
+        tcg_gen_qemu_ld32u(t1, t0, 0);
+        dc->pc += 3 + id;
+        tcg_temp_free(t0);
+    } else {
+        tcg_gen_mov_i32(t1, cpu_regs[rs]);
+        dc->pc += 3;
+    }
+    switch (op) {
+    case 0 ... 4:
+        _op = tcg_const_i32(op);
+        fop = (op != 1) ? RX_PSW_OP_FLOAT : RX_PSW_OP_FCMP;
+        gen_helper_floatop(ccop.op_r[fop], cpu_env,
+                           _op, cpu_regs[rd], t1);
+        if (op != 1) {
+            tcg_gen_mov_i32(cpu_regs[rd], ccop.op_r[RX_PSW_OP_FLOAT]);
+            SET_MODE_ZS(RX_PSW_OP_FLOAT);
+        } else
+            SET_MODE_ZSO(RX_PSW_OP_FCMP);
+        tcg_temp_free(_op);
+        break;
+    case 5:
+        gen_helper_ftoi(cpu_regs[rd], cpu_env, t1);
+        tcg_gen_mov_i32(ccop.op_r[RX_PSW_OP_FLOAT], cpu_regs[rd]);
+        SET_MODE_ZS(RX_PSW_OP_FLOAT);
+        break;
+    case 6:
+        gen_helper_round(cpu_regs[rd], cpu_env, t1);
+        tcg_gen_mov_i32(ccop.op_r[RX_PSW_OP_FLOAT], cpu_regs[rd]);
+        SET_MODE_ZS(RX_PSW_OP_FLOAT);
+        break;
+    }
+    tcg_temp_free(t1);
+}
+
+DEFINE_INSN(itof1)
+{
+    int id, rs, rd;
+    TCGv mem, t0;
+
+    id = (insn >> 16) & 3;
+    rs = (insn >> 12) & 15;
+    rd = (insn >> 8) & 15;
+    t0 = tcg_temp_local_new();
+    if (id < 3) {
+        mem = rx_index_addr(id, 2, 3, rs, dc, env);
+        rx_gen_ldu(RX_MEMORY_BYTE, t0, mem);
+        tcg_temp_free(mem);
+        dc->pc += 3 + id;
+    } else {
+        tcg_gen_mov_i32(t0, cpu_regs[rs]);
+        dc->pc += 3;
+    }
+    gen_helper_itof(cpu_regs[rd], cpu_env, t0);
+    tcg_gen_mov_i32(ccop.op_r[RX_PSW_OP_FLOAT], cpu_regs[rd]);
+    SET_MODE_ZS(RX_PSW_OP_FLOAT);
+}
+
+DEFINE_INSN(itof2)
+{
+    int id, rs, rd, sz, mi;
+    TCGv tmp, mem;
+
+    mi = (insn >> 22) & 3;
+    id = (insn >> 16) & 3;
+    rs = (insn >> 4) & 15;
+    rd = insn & 15;
+    sz = (mi < 3) ? mi : RX_MEMORY_WORD;
+
+    tmp = tcg_temp_local_new();
+    mem = rx_index_addr(id, sz, 4, rs, dc, env);
+    if (mi == 3) {
+        rx_gen_ldu(RX_MEMORY_WORD, tmp, mem);
+    } else {
+        rx_gen_ldst(sz, RX_MEMORY_LD, tmp, mem);
+    }
+    rx_gen_ldst(sz, RX_MEMORY_ST, cpu_regs[rd], mem);
+    gen_helper_itof(cpu_regs[rd], cpu_env, tmp);
+    tcg_gen_mov_i32(ccop.op_r[RX_PSW_OP_FLOAT], cpu_regs[rd]);
+    SET_MODE_ZS(RX_PSW_OP_FLOAT);
+    dc->pc += 4 + id;
+    tcg_temp_free(mem);
+    tcg_temp_free(tmp);
+}
+
+DEFINE_INSN(mulmacXX)
+{
+    int add, lo, rs, rs2;
+    TCGv t0, t1;
+
+    add = (insn >> 18) & 1;
+    lo = (insn >> 16) & 1;
+    rs = (insn >> 12) & 15;
+    rs2 = (insn >> 8) & 15;
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+    if (lo) {
+        tcg_gen_ext16s_i32(t0, cpu_regs[rs]);
+        tcg_gen_ext16s_i32(t1, cpu_regs[rs2]);
+    } else {
+        tcg_gen_sari_i32(t0, cpu_regs[rs], 16);
+        tcg_gen_sari_i32(t1, cpu_regs[rs2], 16);
+    }
+    tcg_gen_mul_i32(t0, t0, t1);
+    tcg_gen_mov_i32(t1, t0);
+    tcg_gen_shli_i32(t0, t0, 16);
+    tcg_gen_sari_i32(t0, t1, 16);
+    if (add)
+        tcg_gen_add2_i32(cpu_acc_l, cpu_acc_m, cpu_acc_l, cpu_acc_m, t1, t0);
+    else {
+        tcg_gen_mov_i32(cpu_acc_l, t0);
+        tcg_gen_mov_i32(cpu_acc_m, t1);
+    }
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    dc->pc += 3;
+}
+
+DEFINE_INSN(mvfacXX)
+{
+    int md, rd;
+    TCGv t0;
+    md = (insn >> 12) & 3;
+    rd = (insn >> 8) & 15;
+    if (md == 0) {
+        tcg_gen_mov_i32(cpu_regs[rd], cpu_acc_m);
+    } else {
+        t0 = tcg_temp_local_new();
+        tcg_gen_shli_i32(cpu_regs[rd], cpu_acc_m, 16);
+        tcg_gen_shri_i32(t0, cpu_acc_l, 16);
+        tcg_gen_or_i32(cpu_regs[rd], cpu_regs[rd], t0);
+        tcg_temp_free(t0);
+    }
+    dc->pc += 3;
+}
+
+DEFINE_INSN(mvtacXX)
+{
+    int md, rs;
+    md = (insn >> 12) & 3;
+    rs = (insn >> 8) & 15;
+    if (md == 0) {
+        tcg_gen_mov_i32(cpu_acc_m, cpu_regs[rs]);
+    } else {
+        tcg_gen_mov_i32(cpu_acc_l, cpu_regs[rs]);
+    }
+    dc->pc += 3;
+}
+
+DEFINE_INSN(racw)
+{
+    TCGv shift;
+    shift = tcg_const_local_i32(((insn >> 12) & 1) + 1);
+    gen_helper_racw(cpu_env, shift);
+    dc->pc += 3;
+}
+
+DEFINE_INSN(op0620)
+{
+    static const disas_proc op[] = {
+        adc3sbb2, NULL, adc3sbb2, NULL,
+        minmax3, minmax3, emul3, emul3,
+        div3, div3, NULL, NULL,
+        logic_op4, logic_op4, NULL, NULL,
+        xchg2, itof2, NULL, NULL,
+        NULL, NULL, NULL, NULL,
+        NULL, NULL, NULL, NULL,
+        NULL, NULL, NULL, NULL,
+    };
+    if (op[(insn & 0x00001f00) >> 8]) {
+        op[(insn & 0x00001f00) >> 8](env, dc, insn);
+    } else {
+        gen_helper_raise_illegal_instruction(cpu_env);
+    }
+}
+
+DEFINE_INSN(opfd70)
+{
+    static const disas_proc op[] = {
+        NULL, NULL, adc1, NULL,
+        minmax1, minmax1, emul1, emul1,
+        div1, div1, NULL, NULL,
+        logic_op2, logic_op2, stz, stz,
+    };
+    if (op[(insn & 0x0000f000) >> 12]) {
+        op[(insn & 0x0000f000) >> 12](env, dc, insn);
+    } else {
+        gen_helper_raise_illegal_instruction(cpu_env);
+    }
+}
+
+static disas_proc optable[65536];
+
+#define OPTABLE(code, mask, proc) {code, mask, proc},
+static struct op {
+    uint16_t code;
+    uint16_t mask;
+    disas_proc proc;
+} oplist[] = {
+    OPTABLE(0x0620, 0xff3c, op0620)
+    OPTABLE(0xfd70, 0xfff3, opfd70)
+
+    OPTABLE(0x8000, 0xc800, mov1_2)
+    OPTABLE(0x8800, 0xc800, mov1_2)
+    OPTABLE(0x6600, 0xff00, mov3)
+    OPTABLE(0x3c00, 0xfc00, mov4)
+    OPTABLE(0x7540, 0xfff0, mov5)
+    OPTABLE(0xfb02, 0xff03, mov6)
+    OPTABLE(0xcf00, 0xcf00, mov7)
+    OPTABLE(0xf800, 0xfc00, mov8)
+    OPTABLE(0xcc00, 0xcc00, mov9)
+    OPTABLE(0xfe40, 0xffc0, mov10_12)
+    OPTABLE(0xc300, 0xc300, mov11)
+    OPTABLE(0xfe00, 0xffc0, mov10_12)
+    OPTABLE(0xc000, 0xc000, mov13)
+    OPTABLE(0xfd20, 0xfff8, mov14)
+    OPTABLE(0xfd28, 0xfff8, mov15)
+
+    OPTABLE(0xb000, 0xf000, movu1)
+    OPTABLE(0x5800, 0xf800, movu2)
+    OPTABLE(0xfec0, 0xffe0, movu3)
+    OPTABLE(0xfd30, 0xfff2, movu4)
+
+    OPTABLE(0x7eb0, 0xfff0, pop)
+    OPTABLE(0x7ee0, 0xfff0, popc)
+    OPTABLE(0x6f00, 0xff00, popm)
+
+    OPTABLE(0x7e80, 0xffc0, push1)
+    OPTABLE(0xf408, 0xfc0c, push2)
+    OPTABLE(0x7ec0, 0xfff0, pushc)
+    OPTABLE(0x6e00, 0xff00, pushm)
+
+    OPTABLE(0xfd67, 0xffff, revl)
+    OPTABLE(0xfd65, 0xffff, revw)
+
+    OPTABLE(0xfcd0, 0xfff0, sccnd)
+
+    OPTABLE(0xfc40, 0xffc0, xchg1)
+
+    OPTABLE(0x0300, 0xff00, nop)
+
+    /* and */
+    OPTABLE(0x6400, 0xff00, logic_op1)
+    OPTABLE(0x7420, 0xfcf0, logic_op2)
+    OPTABLE(0x5000, 0xfc00, logic_op3)
+    OPTABLE(0x0610, 0xff3c, logic_op4)
+    OPTABLE(0xff40, 0xfff0, logic_op5)
+    /* or */
+    OPTABLE(0x6500, 0xff00, logic_op1)
+    OPTABLE(0x7430, 0xfcf0, logic_op2)
+    OPTABLE(0x5400, 0xfc00, logic_op3)
+    OPTABLE(0x0614, 0xff3c, logic_op4)
+    OPTABLE(0xff50, 0xfff0, logic_op5)
+    /* xor */
+    OPTABLE(0xfc34, 0xfffc, logic_op3)
+    /* tst */
+    OPTABLE(0xfc30, 0xfffc, logic_op3)
+
+    OPTABLE(0x6200, 0xff00, addsub1)
+    OPTABLE(0x4800, 0xfc00, addsub2)
+    OPTABLE(0x0608, 0xff3c, addsub3)
+    OPTABLE(0x7000, 0xfc00, add4)
+    OPTABLE(0xff20, 0xfff0, addsub5)
+
+    OPTABLE(0x6000, 0xff00, addsub1)
+    OPTABLE(0x4000, 0xfc00, addsub2)
+    OPTABLE(0x0600, 0xff3c, addsub3)
+    OPTABLE(0xff00, 0xfff0, addsub5)
+
+    OPTABLE(0x6100, 0xff00, addsub1)
+    OPTABLE(0x7550, 0xfff0, cmp2)
+    OPTABLE(0x7400, 0xfcf0, cmp3)
+    OPTABLE(0x4400, 0xfc00, cmp4)
+    OPTABLE(0x0604, 0xff3c, cmp5)
+
+    OPTABLE(0xfc00, 0xfff4, adc2sbb1)
+
+    OPTABLE(0x7e00, 0xffc0, absnegnot1)
+    OPTABLE(0xfc03, 0xffc3, absnegnot2)
+
+    OPTABLE(0x6300, 0xff00, mul1)
+    OPTABLE(0x7410, 0xfcf0, mul2)
+    OPTABLE(0x4c00, 0xfc00, mul3)
+    OPTABLE(0x060c, 0xff3c, mul4)
+    OPTABLE(0xff30, 0xfff0, mul5)
+
+    OPTABLE(0xfc20, 0xfff8, div2)
+
+    OPTABLE(0xfc18, 0xfff8, emul2)
+
+    OPTABLE(0xfc10, 0xfff8, minmax2)
+
+    OPTABLE(0x6a00, 0xfe00, shift1)
+    OPTABLE(0xfd61, 0xffff, shift2)
+    OPTABLE(0xfda0, 0xffe0, shift3)
+    OPTABLE(0x6c00, 0xfe00, shift1)
+    OPTABLE(0xfd62, 0xffff, shift2)
+    OPTABLE(0xfdc0, 0xffe0, shift3)
+    OPTABLE(0x6800, 0xfe00, shift1)
+    OPTABLE(0xfd60, 0xffff, shift2)
+    OPTABLE(0xfd80, 0xffe0, shift3)
+
+    OPTABLE(0x7e40, 0xffe0, roc)
+    OPTABLE(0xfd6e, 0xfffe, rot1)
+    OPTABLE(0xfd66, 0xffff, rot2)
+    OPTABLE(0xfd6c, 0xfffe, rot1)
+    OPTABLE(0xfd64, 0xffff, rot2)
+
+    OPTABLE(0x7e30, 0xfff0, sat)
+    OPTABLE(0x7f93, 0xffff, satr)
+    OPTABLE(0x7f8c, 0xfffc, rmpa)
+
+    OPTABLE(0xf008, 0xfc08, bop1)
+    OPTABLE(0xfc64, 0xfffc, bop2)
+    OPTABLE(0x7a00, 0xfe00, bop3)
+    OPTABLE(0xfce0, 0xffe0, bnot1)
+    OPTABLE(0xfc6c, 0xfffc, bop2)
+    OPTABLE(0xf000, 0xfc08, bop1)
+    OPTABLE(0xfc60, 0xfffc, bop2)
+    OPTABLE(0x7800, 0xfe00, bop3)
+    OPTABLE(0xf400, 0xfc08, bop1)
+    OPTABLE(0xfc68, 0xfffc, bop2)
+    OPTABLE(0x7c00, 0xfe00, bop3)
+
+    OPTABLE(0xfce0, 0xffe0, bmcnd1)
+    OPTABLE(0xfde0, 0xffe0, bmcnd2)
+
+    OPTABLE(0x7f83, 0xffff, scmpu)
+    OPTABLE(0x7f8b, 0xffff, smovbfu)
+    OPTABLE(0x7f8f, 0xffff, smovbfu)
+    OPTABLE(0x7f87, 0xffff, smovbfu)
+    OPTABLE(0x7f88, 0xfffc, sstr)
+    OPTABLE(0x7f80, 0xfffc, ssearch)
+    OPTABLE(0x7f84, 0xfffc, ssearch)
+
+    OPTABLE(0x0800, 0xf800, bra1)
+    OPTABLE(0x2e00, 0xff00, bra2)
+    OPTABLE(0x3800, 0xff00, bra3)
+    OPTABLE(0x0400, 0xff00, bra4)
+    OPTABLE(0x7f40, 0xfff0, bra5)
+
+    OPTABLE(0x1000, 0xf000, bcnd1)
+    OPTABLE(0x2000, 0xf000, bcnd2)
+    OPTABLE(0x3a00, 0xfe00, bcnd3)
+
+    OPTABLE(0x3900, 0xff00, bsr1)
+    OPTABLE(0x0500, 0xff00, bsr2)
+    OPTABLE(0x7f50, 0xfff0, bsr3)
+
+    OPTABLE(0x7f00, 0xfff0, jmpjsr)
+    OPTABLE(0x7f10, 0xfff0, jmpjsr)
+
+    OPTABLE(0x0200, 0xff00, rts)
+    OPTABLE(0x6700, 0xff00, rtsd1)
+    OPTABLE(0x3f00, 0xff00, rtsd2)
+
+    OPTABLE(0x7fb0, 0xfff0, clrsetpsw)
+    OPTABLE(0x7fa0, 0xfff0, clrsetpsw)
+
+    OPTABLE(0xfd6a, 0xffff, mvfc)
+    OPTABLE(0xfd73, 0xfff3, mvtc1)
+    OPTABLE(0xfd68, 0xfff8, mvtc2)
+    OPTABLE(0x7570, 0xffff, mvtipl)
+
+    OPTABLE(0x0000, 0xff00, rxbrk)
+    OPTABLE(0x7560, 0xffff, rxint)
+
+    OPTABLE(0x7f95, 0xffff, rte)
+    OPTABLE(0x7f94, 0xffff, rtfi)
+    OPTABLE(0x7f96, 0xffff, rxwait)
+
+    OPTABLE(0xfd72, 0xffff, fimm)
+    OPTABLE(0xfc88, 0xfffc, fmem)
+    OPTABLE(0xfc84, 0xfffc, fmem)
+    OPTABLE(0xfc90, 0xfffc, fmem)
+    OPTABLE(0xfc8c, 0xfffc, fmem)
+    OPTABLE(0xfc80, 0xfffc, fmem)
+    OPTABLE(0xfc94, 0xfffc, fmem)
+    OPTABLE(0xfc98, 0xfffc, fmem)
+    OPTABLE(0xfc44, 0xfffc, itof1)
+
+    OPTABLE(0xfd04, 0xffff, mulmacXX)
+    OPTABLE(0xfd05, 0xffff, mulmacXX)
+    OPTABLE(0xfd00, 0xffff, mulmacXX)
+    OPTABLE(0xfd01, 0xffff, mulmacXX)
+    OPTABLE(0xfd1f, 0xffff, mvfacXX)
+    OPTABLE(0xfd17, 0xffff, mvtacXX)
+    OPTABLE(0xfd18, 0xffff, racw)
+};
+
+static int comp_mask(const void *p1, const void *p2)
+{
+    return ctpop32(((struct op *)p1)->mask)
+        - ctpop32(((struct op *)p2)->mask);
+}
+
+static void rx_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
+{
+}
+
+static void rx_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
+{
+}
+
+static void rx_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    tcg_gen_insn_start(dc->base.pc_next);
+}
+
+static bool rx_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
+                                    const CPUBreakpoint *bp)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    /* We have hit a breakpoint - make sure PC is up-to-date */
+    gen_save_cpu_state(dc, true);
+    gen_helper_debug(cpu_env);
+    dc->base.is_jmp = DISAS_NORETURN;
+    dc->base.pc_next += 1;
+    return true;
+}
+
+static void rx_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
+{
+    CPURXState *env = cs->env_ptr;
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+    uint32_t insn = 0;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        insn <<= 8;
+        insn |= cpu_ldub_code(env, dc->base.pc_next + i);
+    }
+    dc->pc = dc->base.pc_next;
+    if (optable[insn >> 16]) {
+        optable[insn >> 16](env, dc, insn);
+        dc->base.pc_next = dc->pc;
+    } else {
+        gen_helper_raise_illegal_instruction(cpu_env);
+    }
+}
+
+static void rx_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    switch (dc->base.is_jmp) {
+    case DISAS_NEXT:
+    case DISAS_TOO_MANY:
+        gen_save_cpu_state(dc, false);
+        gen_goto_tb(dc, 0, dc->base.pc_next);
+        break;
+    case DISAS_JUMP:
+        if (dc->base.singlestep_enabled) {
+            gen_helper_update_psw(cpu_env);
+            gen_helper_debug(cpu_env);
+        } else
+            tcg_gen_lookup_and_goto_ptr();
+        break;
+    case DISAS_NORETURN:
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void rx_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs)
+{
+    qemu_log("IN:\n");  /* , lookup_symbol(dcbase->pc_first)); */
+    log_target_disas(cs, dcbase->pc_first, dcbase->tb->size);
+}
+
+static const TranslatorOps rx_tr_ops = {
+    .init_disas_context = rx_tr_init_disas_context,
+    .tb_start           = rx_tr_tb_start,
+    .insn_start         = rx_tr_insn_start,
+    .breakpoint_check   = rx_tr_breakpoint_check,
+    .translate_insn     = rx_tr_translate_insn,
+    .tb_stop            = rx_tr_tb_stop,
+    .disas_log          = rx_tr_disas_log,
+};
+
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
+{
+    DisasContext dc;
+
+    translator_loop(&rx_tr_ops, &dc.base, cs, tb);
+}
+
+void restore_state_to_opc(CPURXState *env, TranslationBlock *tb,
+                          target_ulong *data)
+{
+    env->pc = data[0];
+    env->psw = data[1];
+    rx_cpu_unpack_psw(env, 1);
+}
+
+#define ALLOC_REGISTER(sym, name) \
+    cpu_##sym = tcg_global_mem_new_i32(cpu_env, \
+                                       offsetof(CPURXState, sym), name)
+
+void rx_translate_init(void)
+{
+    int i, j;
+    struct op *p;
+    static const char * const regnames[16] = {
+        "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+        "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"
+    };
+
+    for (i = 0; i < 16; i++) {
+        cpu_regs[i] = tcg_global_mem_new_i32(cpu_env,
+                                              offsetof(CPURXState, regs[i]),
+                                              regnames[i]);
+    }
+    for (i = 0; i < 12; i++) {
+        ccop.op_a1[i + 1] = tcg_global_mem_new_i32(cpu_env,
+                                               offsetof(CPURXState, op_a1[i]),
+                                               "");
+        ccop.op_a2[i + 1] = tcg_global_mem_new_i32(cpu_env,
+                                               offsetof(CPURXState, op_a2[i]),
+                                               "");
+        ccop.op_r[i + 1] = tcg_global_mem_new_i32(cpu_env,
+                                               offsetof(CPURXState, op_r[i]),
+                                               "");
+    }
+    ccop.op_mode = tcg_global_mem_new_i32(cpu_env,
+                                          offsetof(CPURXState, op_mode),
+                                          "");
+    ALLOC_REGISTER(pc, "PC");
+    ALLOC_REGISTER(psw, "PSW");
+    ALLOC_REGISTER(psw_o, "PSW(O)");
+    ALLOC_REGISTER(psw_s, "PSW(S)");
+    ALLOC_REGISTER(psw_z, "PSW(Z)");
+    ALLOC_REGISTER(psw_c, "PSW(C)");
+    ALLOC_REGISTER(psw_u, "PSW(U)");
+    ALLOC_REGISTER(psw_i, "PSW(I)");
+    ALLOC_REGISTER(psw_pm, "PSW(PM)");
+    ALLOC_REGISTER(psw_ipl, "PSW(IPL)");
+    ALLOC_REGISTER(usp, "USP");
+    ALLOC_REGISTER(fpsw, "FPSW");
+    ALLOC_REGISTER(bpsw, "BPSW");
+    ALLOC_REGISTER(bpc, "BPC");
+    ALLOC_REGISTER(isp, "ISP");
+    ALLOC_REGISTER(fintv, "FINTV");
+    ALLOC_REGISTER(intb, "INTB");
+    ALLOC_REGISTER(acc_m, "ACC-M");
+    ALLOC_REGISTER(acc_l, "ACC-L");
+
+    qsort(oplist, ARRAY_SIZE(oplist), sizeof(struct op), comp_mask);
+    for (p = oplist, i = 0; i < ARRAY_SIZE(oplist); p++, i++) {
+        for (j = 0; j < 0x10000; j++) {
+            if (p->code == (j & p->mask)) {
+                optable[j] = p->proc;
+            }
+        }
+    }
+}
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH RFC 02/11] RX CPU definition
  2019-01-21 13:15 [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture Yoshinori Sato
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 01/11] TCG translation Yoshinori Sato
@ 2019-01-21 13:15 ` Yoshinori Sato
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 03/11] TCG helper functions Yoshinori Sato
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2019-01-21 13:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yoshinori Sato

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 target/rx/cpu-qom.h |  54 +++++++++++++
 target/rx/cpu.c     | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 target/rx/cpu.h     | 212 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 492 insertions(+)
 create mode 100644 target/rx/cpu-qom.h
 create mode 100644 target/rx/cpu.c
 create mode 100644 target/rx/cpu.h

diff --git a/target/rx/cpu-qom.h b/target/rx/cpu-qom.h
new file mode 100644
index 0000000000..7215e17ce8
--- /dev/null
+++ b/target/rx/cpu-qom.h
@@ -0,0 +1,54 @@
+/*
+ * QEMU RX CPU
+ *
+ * Copyright (c) 2019 Yoshinori Sato
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#ifndef QEMU_RX_CPU_QOM_H
+#define QEMU_RX_CPU_QOM_H
+
+#include "qom/cpu.h"
+
+#define TYPE_RXCPU "rxcpu"
+
+#define RXCPU_CLASS(klass)                                     \
+    OBJECT_CLASS_CHECK(RXCPUClass, (klass), TYPE_RXCPU)
+#define RXCPU(obj) \
+    OBJECT_CHECK(RXCPU, (obj), TYPE_RXCPU)
+#define RXCPU_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(RXCPUClass, (obj), TYPE_RXCPU)
+
+/*
+ * RXCPUClass:
+ * @parent_realize: The parent class' realize handler.
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A RX CPU model.
+ */
+typedef struct RXCPUClass {
+    /*< private >*/
+    CPUClass parent_class;
+    /*< public >*/
+
+    DeviceRealize parent_realize;
+    void (*parent_reset)(CPUState *cpu);
+
+} RXCPUClass;
+
+typedef struct RXCPU RXCPU;
+
+#endif
diff --git a/target/rx/cpu.c b/target/rx/cpu.c
new file mode 100644
index 0000000000..990620e353
--- /dev/null
+++ b/target/rx/cpu.c
@@ -0,0 +1,226 @@
+/*
+ * QEMU RX CPU
+ *
+ * Copyright (c) 2018 Yoshinori Sato
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "qemu-common.h"
+#include "migration/vmstate.h"
+#include "exec/exec-all.h"
+#include "hw/loader.h"
+
+static void rx_cpu_set_pc(CPUState *cs, vaddr value)
+{
+    RXCPU *cpu = RXCPU(cs);
+
+    cpu->env.pc = value;
+}
+
+static void rx_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
+{
+    RXCPU *cpu = RXCPU(cs);
+
+    cpu->env.pc = tb->pc;
+}
+
+static bool rx_cpu_has_work(CPUState *cs)
+{
+    return cs->interrupt_request & CPU_INTERRUPT_HARD;
+}
+
+static void rx_cpu_reset(CPUState *s)
+{
+    RXCPU *cpu = RXCPU(s);
+    RXCPUClass *rcc = RXCPU_GET_CLASS(cpu);
+    CPURXState *env = &cpu->env;
+    uint32_t *resetvec;
+
+    rcc->parent_reset(s);
+
+    memset(env, 0, offsetof(CPURXState, end_reset_fields));
+
+    resetvec = rom_ptr(0xfffffffc, 4);
+    if (resetvec) {
+        /* In the case of kernel, it is ignored because it is not set. */
+        env->pc = ldl_p(resetvec);
+    }
+    env->psw = 0x00000000;
+}
+
+typedef struct RXCPUListState {
+    fprintf_function cpu_fprintf;
+    FILE *file;
+} RXCPUListState;
+
+static void rx_cpu_list_entry(gpointer data, gpointer user_data)
+{
+    RXCPUListState *s = user_data;
+    const char *typename = object_class_get_name(OBJECT_CLASS(data));
+    int len = strlen(typename) - strlen(RX_CPU_TYPE_SUFFIX);
+
+    (*s->cpu_fprintf)(s->file, "%.*s\n", len, typename);
+}
+
+void rx_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    RXCPUListState s = {
+        .cpu_fprintf = cpu_fprintf,
+        .file = f,
+    };
+    GSList *list;
+
+    list = object_class_get_list_sorted(TYPE_RXCPU, false);
+    g_slist_foreach(list, rx_cpu_list_entry, &s);
+    g_slist_free(list);
+}
+
+static ObjectClass *rx_cpu_class_by_name(const char *cpu_model)
+{
+    ObjectClass *oc;
+    char *typename = NULL;
+
+    typename = g_strdup_printf(RX_CPU_TYPE_NAME(""));
+    oc = object_class_by_name(typename);
+    if (oc != NULL && object_class_is_abstract(oc)) {
+        oc = NULL;
+    }
+
+    g_free(typename);
+    return oc;
+}
+
+static void rx_cpu_realize(DeviceState *dev, Error **errp)
+{
+    CPUState *cs = CPU(dev);
+    RXCPUClass *rcc = RXCPU_GET_CLASS(dev);
+    Error *local_err = NULL;
+
+    cpu_exec_realizefn(cs, &local_err);
+    if (local_err != NULL) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    cpu_reset(cs);
+    qemu_init_vcpu(cs);
+
+    rcc->parent_realize(dev, errp);
+}
+
+static void rxcpu_set_irq(void *opaque, int no, int request)
+{
+    RXCPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
+    int irq = request & 0xff;
+
+    static const int mask[] = {
+        [RX_CPU_IRQ] = CPU_INTERRUPT_HARD,
+        [RX_CPU_FIR] = CPU_INTERRUPT_FIR,
+    };
+    if (request & 0x1000) {
+        cpu->env.irq = irq;
+        cpu->env.intlevel = (request >> 8) & 0x0f;
+        cpu_interrupt(cs, mask[no]);
+    } else
+        cpu_reset_interrupt(cs, mask[no]);
+}
+
+static void rx_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
+{
+    info->mach = bfd_mach_rx;
+    info->print_insn = print_insn_rx;
+}
+
+static void rx_cpu_init(Object *obj)
+{
+    CPUState *cs = CPU(obj);
+    RXCPU *cpu = RXCPU(obj);
+    CPURXState *env = &cpu->env;
+
+    cs->env_ptr = env;
+    qdev_init_gpio_in(DEVICE(cpu), rxcpu_set_irq, 2);
+}
+
+static void rxcpu_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    CPUClass *cc = CPU_CLASS(klass);
+    RXCPUClass *rcc = RXCPU_CLASS(klass);
+
+    device_class_set_parent_realize(dc, rx_cpu_realize,
+                                    &rcc->parent_realize);
+
+    rcc->parent_reset = cc->reset;
+    cc->reset = rx_cpu_reset;
+
+    cc->class_by_name = rx_cpu_class_by_name;
+    cc->has_work = rx_cpu_has_work;
+    cc->do_interrupt = rx_cpu_do_interrupt;
+    cc->cpu_exec_interrupt = rx_cpu_exec_interrupt;
+    cc->dump_state = rx_cpu_dump_state;
+    cc->set_pc = rx_cpu_set_pc;
+    cc->synchronize_from_tb = rx_cpu_synchronize_from_tb;
+    cc->gdb_read_register = rx_cpu_gdb_read_register;
+    cc->gdb_write_register = rx_cpu_gdb_write_register;
+    cc->get_phys_page_debug = rx_cpu_get_phys_page_debug;
+    cc->disas_set_info = rx_cpu_disas_set_info;
+    cc->tcg_initialize = rx_translate_init;
+
+    cc->gdb_num_core_regs = 26;
+}
+
+static const TypeInfo rxcpu_info = {
+    .name = TYPE_RXCPU,
+    .parent = TYPE_CPU,
+    .instance_size = sizeof(RXCPU),
+    .instance_init = rx_cpu_init,
+    .abstract = false,
+    .class_size = sizeof(RXCPUClass),
+    .class_init = rxcpu_class_init,
+};
+
+static void rxcpu_register_types(void)
+{
+    type_register_static(&rxcpu_info);
+}
+
+type_init(rxcpu_register_types)
+
+static uint32_t extable[32];
+
+void rx_load_image(RXCPU *cpu, const char *filename,
+                   uint32_t start, uint32_t size)
+{
+    long kernel_size;
+    int i;
+
+    kernel_size = load_image_targphys(filename, start, size);
+    if (kernel_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n", filename);
+        exit(1);
+    }
+    cpu->env.pc = start;
+
+    /* setup exception trap trampoline */
+    for (i = 0; i < 32; i++) {
+        extable[i] = 0x10 + i * 4;
+    }
+    rom_add_blob_fixed("extable", extable, sizeof(extable), 0xffffff80);
+}
diff --git a/target/rx/cpu.h b/target/rx/cpu.h
new file mode 100644
index 0000000000..70c0cbe928
--- /dev/null
+++ b/target/rx/cpu.h
@@ -0,0 +1,212 @@
+/*
+ *  RX emulation
+ *
+ *  Copyright (c) 2019 Yoshinori Sato
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef RX_CPU_H
+#define RX_CPU_H
+
+#include "qemu-common.h"
+#include "cpu-qom.h"
+
+#define TARGET_LONG_BITS 32
+#define TARGET_PAGE_BITS 12
+
+#define CPUArchState struct CPURXState
+
+#include "exec/cpu-defs.h"
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+
+#define PSW_I3 27
+#define PSW_I2 26
+#define PSW_I1 25
+#define PSW_I0 24
+#define PSW_IPL PSW_I0
+#define PSW_PM 20
+#define PSW_U  17
+#define PSW_I  16
+#define PSW_O  3
+#define PSW_S  2
+#define PSW_Z  1
+#define PSW_C  0
+
+#define FPSW_MASK 0xfc007cff
+#define FPSW_RM_MASK 0x00000003
+#define FPSW_DN (1 << 8)
+#define FPSW_CAUSE_MASK 0x000000fc
+#define FPSW_CAUSE_SHIFT 2
+#define FPSW_CAUSE_V (1 << 2)
+#define FPSW_CAUSE_O (1 << 3)
+#define FPSW_CAUSE_Z (1 << 4)
+#define FPSW_CAUSE_U (1 << 5)
+#define FPSW_CAUSE_X (1 << 6)
+#define FPSW_CAUSE_E (1 << 7)
+#define FPSW_ENABLE_MASK 0x00007c00
+#define FPSW_ENABLE_SHIFT 10
+#define FPSW_ENABLE_V (1 << 10)
+#define FPSW_ENABLE_O (1 << 11)
+#define FPSW_ENABLE_Z (1 << 12)
+#define FPSW_ENABLE_U (1 << 13)
+#define FPSW_ENABLE_X (1 << 14)
+#define FPSW_FLAG_SHIFT 26
+#define FPSW_FLAG_V 26
+#define FPSW_FLAG_O 27
+#define FPSW_FLAG_Z 28
+#define FPSW_FLAG_U 29
+#define FPSW_FLAG_X 30
+#define FPSW_FLAG_S 31
+
+#define NB_MMU_MODES 1
+#define MMU_MODE0_SUFFIX _all
+
+#define RX_PSW_OP_NONE 0
+#define RX_PSW_OP_SUB 1
+#define RX_PSW_OP_ADD 2
+#define RX_PSW_OP_ABS 3
+#define RX_PSW_OP_DIV 4
+#define RX_PSW_OP_STRING 5
+#define RX_PSW_OP_BTST 6
+#define RX_PSW_OP_LOGIC 7
+#define RX_PSW_OP_ROT 8
+#define RX_PSW_OP_SHLL 9
+#define RX_PSW_OP_SHAR 10
+#define RX_PSW_OP_SHLR 11
+#define RX_PSW_OP_FLOAT 12
+#define RX_PSW_OP_FCMP 13
+
+typedef struct memory_content {
+    uint32_t address;
+    struct memory_content *next;
+} memory_content;
+
+struct CCop;
+
+typedef struct CPURXState {
+    /* CPU registers */
+    uint32_t regs[16];          /* general registers */
+    uint32_t psw;               /* processor status */
+    uint32_t psw_o;             /* O bit of status register */
+    uint32_t psw_s;             /* S bit of status register */
+    uint32_t psw_z;             /* Z bit of status register */
+    uint32_t psw_c;             /* C bit of status register */
+    uint32_t psw_u;
+    uint32_t psw_i;
+    uint32_t psw_pm;
+    uint32_t psw_ipl;
+    uint32_t bpsw;              /* backup status */
+    uint32_t bpc;               /* backup pc */
+    uint32_t isp;               /* global base register */
+    uint32_t usp;               /* vector base register */
+    uint32_t pc;                /* program counter */
+    uint32_t intb;              /* interrupt vector */
+    uint32_t fintv;
+    uint32_t fpsw;
+    uint32_t acc_m;
+    uint32_t acc_l;
+
+    /* Internal use */
+    uint32_t in_sleep;
+    uint32_t intlevel;          /* Requested interrupt level */
+    uint32_t irq;               /* Requested interrupt no (hard) */
+    uint32_t sirq;              /* Requested interrupt no (soft) */
+    float_status fp_status;
+
+    /* Flag operation */
+    uint32_t op_a1[12];
+    uint32_t op_a2[12];
+    uint32_t op_r[12];
+    uint32_t op_mode;
+    /* Fields up to this point are cleared by a CPU reset */
+    struct {} end_reset_fields;
+
+    CPU_COMMON
+
+    void *ack;
+} CPURXState;
+
+/*
+ * RXCPU:
+ * @env: #CPURXState
+ *
+ * A RX CPU
+ */
+struct RXCPU {
+    /*< private >*/
+    CPUState parent_obj;
+    /*< public >*/
+
+    CPURXState env;
+};
+
+static inline RXCPU *rx_env_get_cpu(CPURXState *env)
+{
+    return container_of(env, RXCPU, env);
+}
+
+#define ENV_GET_CPU(e) CPU(rx_env_get_cpu(e))
+
+#define ENV_OFFSET offsetof(RXCPU, env)
+
+#define RX_CPU_TYPE_SUFFIX "-" TYPE_RXCPU
+#define RX_CPU_TYPE_NAME(model) model RX_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_RXCPU
+
+void rx_cpu_do_interrupt(CPUState *cpu);
+bool rx_cpu_exec_interrupt(CPUState *cpu, int int_req);
+void rx_cpu_dump_state(CPUState *cpu, FILE *f,
+                           fprintf_function cpu_fprintf, int flags);
+int rx_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int rx_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+hwaddr rx_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+
+void rx_translate_init(void);
+int cpu_rx_signal_handler(int host_signum, void *pinfo,
+                           void *puc);
+
+void rx_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+void rx_load_image(RXCPU *cpu, const char *filename,
+                   uint32_t start, uint32_t size);
+void rx_cpu_pack_psw(CPURXState *env);
+void rx_cpu_unpack_psw(CPURXState *env, int all);
+uint32_t rx_get_psw_low(CPURXState *env);
+
+#define cpu_signal_handler cpu_rx_signal_handler
+#define cpu_list rx_cpu_list
+
+#include "exec/cpu-all.h"
+
+#define CPU_INTERRUPT_SOFT CPU_INTERRUPT_TGT_INT_0
+#define CPU_INTERRUPT_FIR  CPU_INTERRUPT_TGT_INT_1
+
+#define RX_CPU_IRQ 0
+#define RX_CPU_FIR 1
+
+static inline void cpu_get_tb_cpu_state(CPURXState *env, target_ulong *pc,
+                                        target_ulong *cs_base, uint32_t *flags)
+{
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = 0;
+}
+
+static inline int cpu_mmu_index(CPURXState *env, bool ifetch)
+{
+    return 0;
+}
+
+#endif /* RX_CPU_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH RFC 03/11] TCG helper functions
  2019-01-21 13:15 [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture Yoshinori Sato
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 01/11] TCG translation Yoshinori Sato
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 02/11] RX CPU definition Yoshinori Sato
@ 2019-01-21 13:15 ` Yoshinori Sato
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 04/11] Target miscellaneous functions Yoshinori Sato
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2019-01-21 13:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yoshinori Sato

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 target/rx/helper.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 143 insertions(+)
 create mode 100644 target/rx/helper.c

diff --git a/target/rx/helper.c b/target/rx/helper.c
new file mode 100644
index 0000000000..1d00732c0c
--- /dev/null
+++ b/target/rx/helper.c
@@ -0,0 +1,143 @@
+/*
+ *  RX emulation
+ *
+ *  Copyright (c) 2019 Yoshinori Sato
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+
+#include "cpu.h"
+#include "exec/log.h"
+#include "exec/cpu_ldst.h"
+#include "sysemu/sysemu.h"
+
+void rx_cpu_do_interrupt(CPUState *cs)
+{
+    RXCPU *cpu = RXCPU(cs);
+    CPURXState *env = &cpu->env;
+    int do_irq = cs->interrupt_request &
+        (CPU_INTERRUPT_HARD | CPU_INTERRUPT_SOFT | CPU_INTERRUPT_FIR);
+    int irq_vector = -1;
+
+    env->in_sleep = 0;
+
+    if (do_irq & CPU_INTERRUPT_HARD) {
+        irq_vector = env->irq;
+        cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
+    }
+    if (irq_vector == -1 && do_irq & CPU_INTERRUPT_SOFT) {
+        irq_vector = env->sirq;
+        cs->interrupt_request &= ~CPU_INTERRUPT_SOFT;
+    }
+
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
+        if (cs->exception_index < 0x100) {
+            const char *expname;
+            switch (cs->exception_index) {
+            case 20:
+                expname = "previlage_violation";
+                break;
+            case 21:
+                expname = "access_exception";
+                break;
+            case 23:
+                expname = "illegal_instruction";
+                break;
+            case 25:
+                expname = "fpu_exception";
+                break;
+            case 30:
+                expname = "NMI_interrupt";
+                break;
+            }
+            qemu_log("exception 0x%02x [%s] raised\n",
+                     cs->exception_index, expname);
+        } else {
+            if (do_irq & CPU_INTERRUPT_FIR)
+                qemu_log("fast interrupt raised\n");
+            else
+                qemu_log("interrupt 0x%02x raised\n",
+                         irq_vector);
+        }
+        log_cpu_state(cs, 0);
+    }
+    if (env->psw_u) {
+        env->usp = env->regs[0];
+    } else {
+        env->isp = env->regs[0];
+    }
+    rx_cpu_pack_psw(env);
+    if ((do_irq & CPU_INTERRUPT_FIR) == 0) {
+        env->isp -= 4;
+        cpu_stl_all(env, env->isp, env->psw);
+        env->isp -= 4;
+        cpu_stl_all(env, env->isp, env->pc);
+    } else {
+        env->bpc = env->pc;
+        env->bpsw = env->psw;
+    }
+    env->psw_pm = env->psw_i = env->psw_u = 0;
+    env->regs[0] = env->isp;
+    if (do_irq) {
+        if (do_irq & CPU_INTERRUPT_FIR) {
+            env->pc = env->fintv;
+            env->psw_ipl = 15;
+            cs->interrupt_request &= ~CPU_INTERRUPT_FIR;
+            qemu_set_irq(env->ack, 0);
+            return;
+        } else if (do_irq & CPU_INTERRUPT_HARD) {
+            env->psw_ipl = env->intlevel;
+            qemu_set_irq(env->ack, 0);
+        }
+        env->pc = cpu_ldl_all(env, env->intb + irq_vector * 4);
+        return;
+    } else {
+        uint32_t vec = cs->exception_index;
+        env->pc = cpu_ldl_all(env, 0xffffffc0 + vec * 4);
+        return;
+    }
+}
+
+bool rx_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
+{
+    RXCPU *cpu = RXCPU(cs);
+    CPURXState *env = &cpu->env;
+    int accept = 0;
+    /* software interrupt */
+    if (interrupt_request & CPU_INTERRUPT_SOFT) {
+        accept = 1;
+    }
+    /* hardware interrupt (Normal) */
+    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
+        env->psw_i && (env->psw_ipl < env->intlevel)) {
+        accept = 1;
+    }
+    /* hardware interrupt (FIR) */
+    if ((interrupt_request & CPU_INTERRUPT_FIR) &&
+        env->psw_i && (env->psw_ipl < 15)) {
+        accept = 1;
+    }
+    if (accept) {
+        rx_cpu_do_interrupt(cs);
+        return true;
+    }
+    return false;
+}
+
+hwaddr rx_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
+{
+    return addr;
+}
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH RFC 04/11] Target miscellaneous functions.
  2019-01-21 13:15 [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture Yoshinori Sato
                   ` (2 preceding siblings ...)
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 03/11] TCG helper functions Yoshinori Sato
@ 2019-01-21 13:15 ` Yoshinori Sato
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 05/11] RX disassembler Yoshinori Sato
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2019-01-21 13:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yoshinori Sato

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 target/rx/gdbstub.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 target/rx/monitor.c |  38 ++++++++++++++++++
 2 files changed, 152 insertions(+)
 create mode 100644 target/rx/gdbstub.c
 create mode 100644 target/rx/monitor.c

diff --git a/target/rx/gdbstub.c b/target/rx/gdbstub.c
new file mode 100644
index 0000000000..cd29302f59
--- /dev/null
+++ b/target/rx/gdbstub.c
@@ -0,0 +1,114 @@
+/*
+ * RX gdb server stub
+ *
+ * Copyright (c) 2019 Yoshinori Sato
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "exec/gdbstub.h"
+
+int rx_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    RXCPU *cpu = RXCPU(cs);
+    CPURXState *env = &cpu->env;
+
+    switch (n) {
+    case 0 ... 15:
+        return gdb_get_regl(mem_buf, env->regs[n]);
+    case 16:
+        return gdb_get_regl(mem_buf, (env->psw_u) ? env->regs[0] : env->usp);
+    case 17:
+        return gdb_get_regl(mem_buf, (!env->psw_u) ? env->regs[0] : env->isp);
+    case 18:
+        rx_cpu_pack_psw(env);
+        return gdb_get_regl(mem_buf, env->psw);
+    case 19:
+        return gdb_get_regl(mem_buf, env->pc);
+    case 20:
+        return gdb_get_regl(mem_buf, env->intb);
+    case 21:
+        return gdb_get_regl(mem_buf, env->bpsw);
+    case 22:
+        return gdb_get_regl(mem_buf, env->bpc);
+    case 23:
+        return gdb_get_regl(mem_buf, env->fintv);
+    case 24:
+        return gdb_get_regl(mem_buf, env->fpsw);
+    case 25:
+        return 0;
+    }
+    return 0;
+}
+
+int rx_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    RXCPU *cpu = RXCPU(cs);
+    CPURXState *env = &cpu->env;
+
+    switch (n) {
+    case 0 ... 15:
+        env->regs[n] = ldl_p(mem_buf);
+        if (n == 0) {
+            if (env->psw_u) {
+                env->usp = env->regs[0];
+            } else {
+                env->isp = env->regs[0];
+            }
+        }
+        break;
+    case 16:
+        env->usp = ldl_p(mem_buf);
+        if (env->psw_u) {
+            env->regs[0] = ldl_p(mem_buf);
+        }
+        break;
+    case 17:
+        env->isp = ldl_p(mem_buf);
+        if (!env->psw_u) {
+            env->regs[0] = ldl_p(mem_buf);
+        }
+        break;
+    case 18:
+        env->psw = ldl_p(mem_buf);
+        rx_cpu_unpack_psw(env, 1);
+        break;
+    case 19:
+        env->pc = ldl_p(mem_buf);
+        break;
+    case 20:
+        env->intb = ldl_p(mem_buf);
+        break;
+    case 21:
+        env->bpsw = ldl_p(mem_buf);
+        break;
+    case 22:
+        env->bpc = ldl_p(mem_buf);
+        break;
+    case 23:
+        env->fintv = ldl_p(mem_buf);
+        break;
+    case 24:
+        env->fpsw = ldl_p(mem_buf);
+        break;
+    case 25:
+        return 8;
+    default:
+        return 0;
+    }
+
+    return 4;
+}
diff --git a/target/rx/monitor.c b/target/rx/monitor.c
new file mode 100644
index 0000000000..5d7a1e58b5
--- /dev/null
+++ b/target/rx/monitor.c
@@ -0,0 +1,38 @@
+/*
+ * QEMU monitor
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "monitor/monitor.h"
+#include "monitor/hmp-target.h"
+#include "hmp.h"
+
+void hmp_info_tlb(Monitor *mon, const QDict *qdict)
+{
+    CPUArchState *env = mon_get_cpu_env();
+
+    if (!env) {
+        monitor_printf(mon, "No CPU available\n");
+        return;
+    }
+}
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH RFC 05/11] RX disassembler
  2019-01-21 13:15 [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture Yoshinori Sato
                   ` (3 preceding siblings ...)
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 04/11] Target miscellaneous functions Yoshinori Sato
@ 2019-01-21 13:15 ` Yoshinori Sato
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 06/11] RX62N interrupt contoller Yoshinori Sato
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2019-01-21 13:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yoshinori Sato

It only supported RXv1 instructions.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 disas/Makefile.objs |    1 +
 disas/rx.c          | 1277 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/disas/bfd.h |    5 +
 3 files changed, 1283 insertions(+)
 create mode 100644 disas/rx.c

diff --git a/disas/Makefile.objs b/disas/Makefile.objs
index 3c1cdce026..a74cc9d945 100644
--- a/disas/Makefile.objs
+++ b/disas/Makefile.objs
@@ -24,6 +24,7 @@ common-obj-$(CONFIG_SH4_DIS) += sh4.o
 common-obj-$(CONFIG_SPARC_DIS) += sparc.o
 common-obj-$(CONFIG_LM32_DIS) += lm32.o
 common-obj-$(CONFIG_XTENSA_DIS) += xtensa.o
+common-obj-$(CONFIG_RX_DIS) += rx.o
 
 # TODO: As long as the TCG interpreter and its generated code depend
 # on the QEMU target, we cannot compile the disassembler here.
diff --git a/disas/rx.c b/disas/rx.c
new file mode 100644
index 0000000000..7ebd50b319
--- /dev/null
+++ b/disas/rx.c
@@ -0,0 +1,1277 @@
+/*
+ * Renesas RX Disassembler
+ *
+ * Copyright (c) 2019 Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "disas/bfd.h"
+
+struct opcode {
+    const char *nim;
+    int size;
+    int szwid;
+    int cond;
+    int len;
+};
+
+enum operand_type {
+    none,
+    imm135,
+    imm8,
+    uimm48,
+    uimm8_4,
+    imm,
+    float32,
+    incdec,
+    ind,
+    creg,
+    pcdsp,
+    memory,
+    dsp5,
+    regub,
+    psw,
+    reg,
+    reg8,
+    range,
+};
+
+struct operand {
+    enum operand_type type;
+    union {
+        struct {
+            int pos;
+            int sz;
+        } imm135;
+        struct {
+            int pos;
+        } imm8;
+        struct {
+            int pos;
+            int sz;
+        } uimm48;
+        struct {
+            int pos;
+        } uimm8_4;
+        struct {
+            int pos;
+            int li;
+        } imm;
+        struct {
+            int pos;
+        } float32;
+        struct {
+            int reg;
+            int incdec;
+        } incdec;
+        struct {
+            int base;
+            int offset;
+        } ind;
+        struct {
+            int creg;
+        } creg;
+        struct {
+            int pos;
+            int sz;
+        } pcdsp;
+        struct {
+            int reg;
+            int id;
+            int mi;
+        } memory;
+        struct {
+            int reg;
+            int id;
+        } regub;
+        struct {
+            int reg;
+            int offset1;
+            int offset1w;
+            int offset2;
+        } dsp5;
+        struct {
+            int b;
+        } psw;
+        struct {
+            int r;
+        } reg;
+        struct {
+            int r;
+        } reg8;
+        struct {
+            int start;
+            int end;
+        } range;
+    };
+};
+
+#define opcode(_code, _mask, _nim, _size, _szwid, _cond, _len)  \
+    .code = _code,                                              \
+    .mask = _mask,                                              \
+    .opcode = {                                                 \
+        .nim = _nim, .size = _size, .szwid = _szwid,            \
+        .cond = _cond, .len = _len,                             \
+    },
+#define operand(no, _type, ...)                 \
+    .operand[no] = { .type = _type, ._type = {__VA_ARGS__}, },
+#define NONE (-1)
+#define PCRELB (-2)
+
+/* Instruction Tables */
+static struct instruction {
+    unsigned int code;
+    unsigned int mask;
+    struct opcode opcode;
+    struct operand operand[3];
+} const instructions[] = {
+    {
+        opcode(0xfd180000, 0xffffef00, "racw", NONE, NONE, NONE, 3)
+        operand(0, imm135, 19, 1)
+    },
+    {
+        opcode(0xfd170000, 0xfffff000, "mvtachi", NONE, NONE, NONE, 3)
+        operand(0, reg, 20)
+    },
+    {
+        opcode(0xfd171000, 0xfffff000, "mvtaclo", NONE, NONE, NONE, 3)
+        operand(0, reg, 20)
+    },
+    {
+        opcode(0xfd722000, 0xfffff000, "fadd", NONE, NONE, NONE, 3)
+        operand(0, float32, 24)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd720000, 0xfffff000, "fsub", NONE, NONE, NONE, 3)
+        operand(0, float32, 24)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd723000, 0xfffff000, "fmul", NONE, NONE, NONE, 3)
+        operand(0, float32, 24)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd724000, 0xfffff000, "fdiv", NONE, NONE, NONE, 3)
+        operand(0, float32, 24)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd721000, 0xfffff000, "fcmp", NONE, NONE, NONE, 3)
+        operand(0, float32, 24)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0x06200000, 0xff3cff00, "sbb", NONE, NONE, NONE, 4)
+        operand(0, memory, 24, 14, 8)
+        operand(1, reg, 28)
+    },
+    {
+        opcode(0x06200200, 0xff3cff00, "adc", NONE, NONE, NONE, 4)
+        operand(0, memory, 24, 14, 8)
+        operand(1, reg, 28)
+    },
+    {
+        opcode(0x06200400, 0xff3cff00, "max", NONE, NONE, NONE, 4)
+        operand(0, memory, 24, 14, 8)
+        operand(1, reg, 28)
+    },
+    {
+        opcode(0x06200500, 0xff3cff00, "min", NONE, NONE, NONE, 4)
+        operand(0, memory, 24, 14, 8)
+        operand(1, reg, 28)
+    },
+    {
+        opcode(0x06200600, 0xff3cff00, "emul", NONE, NONE, NONE, 4)
+        operand(0, memory, 24, 14, 8)
+        operand(1, reg, 28)
+    },
+    {
+        opcode(0x06200700, 0xff3cff00, "emulu", NONE, NONE, NONE, 4)
+        operand(0, memory, 24, 14, 8)
+        operand(1, reg, 28)
+    },
+    {
+        opcode(0x06200800, 0xff3cff00, "div", NONE, NONE, NONE, 4)
+        operand(0, memory, 24, 14, 8)
+        operand(1, reg, 28)
+    },
+    {
+        opcode(0x06200900, 0xff3cff00, "divu", NONE, NONE, NONE, 4)
+        operand(0, memory, 24, 14, 8)
+        operand(1, reg, 28)
+    },
+    {
+        opcode(0x06200c00, 0xff3cff00, "tst", NONE, NONE, NONE, 4)
+        operand(0, memory, 24, 14, 8)
+        operand(1, reg, 28)
+    },
+    {
+        opcode(0x06200d00, 0xff3cff00, "xor", NONE, NONE, NONE, 4)
+        operand(0, memory, 24, 14, 8)
+        operand(1, reg, 28)
+    },
+    {
+        opcode(0x06201000, 0xff3cff00, "xchg", NONE, NONE, NONE, 4)
+        operand(0, memory, 24, 14, 8)
+        operand(1, reg, 28)
+    },
+    {
+        opcode(0x06201100, 0xff3cff00, "itof", NONE, NONE, NONE, 4)
+        operand(0, memory, 24, 14, 8)
+        operand(1, reg, 28)
+    },
+    {
+        opcode(0xfd702000, 0xfff3f000, "adc", NONE, NONE, NONE, 3)
+        operand(0, imm, 24, 12)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd704000, 0xfff3f000, "max", NONE, NONE, NONE, 3)
+        operand(0, imm, 24, 12)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd705000, 0xfff3f000, "min", NONE, NONE, NONE, 3)
+        operand(0, imm, 24, 12)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd706000, 0xfff3f000, "emul", NONE, NONE, NONE, 3)
+        operand(0, imm, 24, 12)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd707000, 0xfff3f000, "emulu", NONE, NONE, NONE, 3)
+        operand(0, imm, 24, 12)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd708000, 0xfff3f000, "div", NONE, NONE, NONE, 3)
+        operand(0, imm, 24, 12)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd709000, 0xfff3f000, "divu", NONE, NONE, NONE, 3)
+        operand(0, imm, 24, 12)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd70c000, 0xfff3f000, "tst", NONE, NONE, NONE, 3)
+        operand(0, imm, 24, 12)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd70d000, 0xfff3f000, "xor", NONE, NONE, NONE, 3)
+        operand(0, imm, 24, 12)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd70e000, 0xfff3f000, "stz", NONE, NONE, NONE, 3)
+        operand(0, imm, 24, 12)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd70f000, 0xfff3f000, "stnz", NONE, NONE, NONE, 3)
+        operand(0, imm, 24, 12)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd6a0000, 0xffff0000, "mvfc", NONE, NONE, NONE, 3)
+        operand(0, creg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd670000, 0xffff0000, "revl", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd660000, 0xffff0000, "rotl", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd650000, 0xffff0000, "revl", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd640000, 0xffff0000, "rotr", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd620000, 0xffff0000, "shll", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd610000, 0xffff0000, "shar", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd600000, 0xffff0000, "shlr", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd1f0000, 0xffff0000, "mvfachi", NONE, NONE, NONE, 3)
+        operand(0, reg, 20)
+    },
+    {
+        opcode(0xfd1f2000, 0xffff0000, "mvfacmi", NONE, NONE, NONE, 3)
+        operand(0, reg, 20)
+    },
+    {
+        opcode(0xfd050000, 0xffff0000, "maclo", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd040000, 0xffff0000, "machi", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd010000, 0xffff0000, "mullo", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd000000, 0xffff0000, "mulhi", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0x7f960000, 0xffff0000, "wait", NONE, NONE, NONE, 2)
+    },
+    {
+        opcode(0x7f950000, 0xffff0000, "rte", NONE, NONE, NONE, 2)
+    },
+    {
+        opcode(0x7f940000, 0xffff0000, "rtfi", NONE, NONE, NONE, 2)
+    },
+    {
+        opcode(0x7f930000, 0xffff0000, "satr", NONE, NONE, NONE, 2)
+    },
+    {
+        opcode(0x7f8f0000, 0xffff0000, "smovf", NONE, NONE, NONE, 2)
+    },
+    {
+        opcode(0x7f8b0000, 0xffff0000, "smovb", NONE, NONE, NONE, 2)
+    },
+    {
+        opcode(0x7f870000, 0xffff0000, "smovu", NONE, NONE, NONE, 2)
+    },
+    {
+        opcode(0x7f830000, 0xffff0000, "scmpu", NONE, NONE, NONE, 2)
+    },
+    {
+        opcode(0x75700000, 0xffff0000, "mvtipl", NONE, NONE, NONE, 3)
+        operand(0, uimm48, 20, 4)
+    },
+    {
+        opcode(0x75600000, 0xffff0000, "int", NONE, NONE, NONE, 3)
+        operand(0, uimm48, 16, 8)
+    },
+    {
+        opcode(0xfc0f0000, 0xffff0000, "abs", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc070000, 0xffff0000, "neg", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc000000, 0xffff0000, "sbb", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd6e0000, 0xfffe0000, "rotl", NONE, NONE, NONE, 3)
+        operand(0, imm135, 15, 5)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd6c0000, 0xfffe0000, "rotl", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc980000, 0xfffc0000, "round", NONE, NONE, NONE, 3)
+        operand(0, regub, 16, 14)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc940000, 0xfffc0000, "ftoi", NONE, NONE, NONE, 3)
+        operand(0, regub, 16, 14)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc900000, 0xfffc0000, "fdiv", NONE, NONE, NONE, 3)
+        operand(0, regub, 16, 14)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc8c0000, 0xfffc0000, "fmul", NONE, NONE, NONE, 3)
+        operand(0, memory, 16, 14, NONE)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc880000, 0xfffc0000, "fadd", NONE, NONE, NONE, 3)
+        operand(0, memory, 16, 14, NONE)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc840000, 0xfffc0000, "fcmp", NONE, NONE, NONE, 3)
+        operand(0, memory, 16, 14, NONE)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc800000, 0xfffc0000, "fsub", NONE, NONE, NONE, 3)
+        operand(0, memory, 16, 14, NONE)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc6c0000, 0xfffc0000, "bnot", NONE, NONE, NONE, 3)
+        operand(0, reg, 20)
+        operand(1, memory, 16, 14, NONE)
+    },
+    {
+        opcode(0xfc640000, 0xfffc0000, "btst", NONE, NONE, NONE, 3)
+        operand(0, reg, 20)
+        operand(1, memory, 16, 14, NONE)
+    },
+    {
+        opcode(0xfc680000, 0xfffc0000, "bclr", NONE, NONE, NONE, 3)
+        operand(0, reg, 20)
+        operand(1, memory, 16, 14, NONE)
+    },
+    {
+        opcode(0xfc600000, 0xfffc0000, "bset", NONE, NONE, NONE, 3)
+        operand(0, reg, 20)
+        operand(1, memory, 16, 14, NONE)
+    },
+    {
+        opcode(0xfc440000, 0xfffc0000, "itof", NONE, NONE, NONE, 3)
+        operand(0, regub, 16, 14)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc340000, 0xfffc0000, "xor", NONE, NONE, NONE, 3)
+        operand(0, regub, 16, 14)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc300000, 0xfffc0000, "tst", NONE, NONE, NONE, 3)
+        operand(0, regub, 16, 14)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc380000, 0xfffc0000, "not", NONE, NONE, NONE, 3)
+        operand(0, regub, 16, 14)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0x7f8c0000, 0xfffc0000, "rmpa", 14, 2, NONE, 2)
+    },
+    {
+        opcode(0x7f880000, 0xfffc0000, "sstr", 14, 2, NONE, 2)
+    },
+    {
+        opcode(0x7f840000, 0xfffc0000, "swhile", 14, 2, NONE, 2)
+    },
+    {
+        opcode(0x7f800000, 0xfffc0000, "suntil", 14, 2, NONE, 2)
+    },
+    {
+        opcode(0xfd680000, 0xfff80000, "mvtc", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, creg, 20)
+    },
+    {
+        opcode(0xfd280000, 0xfff80000, "mov", 14, 2, NONE, 3)
+        operand(0, incdec, 16, 13)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd200000, 0xfff80000, "mov", 14, 2, NONE, 3)
+        operand(0, reg, 20)
+        operand(1, incdec, 16, 13)
+    },
+    {
+        opcode(0xfc200000, 0xfff80000, "div", NONE, NONE, NONE, 3)
+        operand(0, regub, 16, 14)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc180000, 0xfff80000, "emul", NONE, NONE, NONE, 3)
+        operand(0, regub, 16, 14)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc100000, 0xfff80000, "max", NONE, NONE, NONE, 3)
+        operand(0, regub, 16, 14)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc000000, 0xfff80000, "sbb", NONE, NONE, NONE, 3)
+        operand(0, regub, 16, 14)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfc080000, 0xfff80000, "adb", NONE, NONE, NONE, 3)
+        operand(0, regub, 16, 14)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfd730000, 0xfff30000, "mvtc", NONE, NONE, NONE, 3)
+        operand(0, imm, 24, 12)
+        operand(1, creg, 20)
+    },
+    {
+        opcode(0xfd300000, 0xfff20000, "movu", 15, 1, NONE, 3)
+        operand(0, incdec, 16, 13)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xff500000, 0xfff00000, "or", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+        operand(2, reg, 12)
+    },
+    {
+        opcode(0xff400000, 0xfff00000, "or", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+        operand(2, reg, 12)
+    },
+    {
+        opcode(0xff300000, 0xfff00000, "mul", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+        operand(2, reg, 12)
+    },
+    {
+        opcode(0xff200000, 0xfff00000, "add", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+        operand(2, reg, 12)
+    },
+    {
+        opcode(0xff000000, 0xfff00000, "sub", NONE, NONE, NONE, 3)
+        operand(0, reg, 16)
+        operand(1, reg, 20)
+        operand(2, reg, 12)
+    },
+    {
+        opcode(0xfcd00000, 0xfff00000, "sc", 12, 2, 20, 3)
+        operand(0, memory, 16, 14, NONE)
+    },
+    {
+        opcode(0x7fb00000, 0xfff00000, "clrpsw", NONE, NONE, NONE, 2)
+        operand(0, psw, 12)
+    },
+    {
+        opcode(0x7fa00000, 0xfff00000, "setpsw", NONE, NONE, NONE, 2)
+        operand(0, psw, 12)
+    },
+    {
+        opcode(0x7f500000, 0xfff00000, "bsr.l", NONE, NONE, NONE, 2)
+        operand(0, reg, 12)
+    },
+    {
+        opcode(0x7f400000, 0xfff00000, "bra.l", NONE, NONE, NONE, 2)
+        operand(0, reg, 12)
+    },
+    {
+        opcode(0x7f100000, 0xfff00000, "jsr", NONE, NONE, NONE, 2)
+        operand(0, reg, 12)
+    },
+    {
+        opcode(0x7f000000, 0xfff00000, "jmp", NONE, NONE, NONE, 2)
+        operand(0, reg, 12)
+    },
+    {
+        opcode(0x7ee00000, 0xfff00000, "popc", NONE, NONE, NONE, 2)
+        operand(0, creg, 12)
+    },
+    {
+        opcode(0x7ec00000, 0xfff00000, "pushc", NONE, NONE, NONE, 2)
+        operand(0, creg, 12)
+    },
+    {
+        opcode(0x7eb00000, 0xfff00000, "pop", NONE, NONE, NONE, 2)
+        operand(0, reg, 12)
+    },
+    {
+        opcode(0x7e300000, 0xfff00000, "sat", NONE, NONE, NONE, 2)
+        operand(0, reg, 12)
+    },
+    {
+        opcode(0x75500000, 0xfff00000, "cmp", NONE, NONE, NONE, 3)
+        operand(0, uimm48, 16, 8)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x75400000, 0xfff00000, "mov.l", NONE, NONE, NONE, 3)
+        operand(0, uimm48, 16, 8)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x7e500000, 0xfff00000, "rolc", NONE, NONE, NONE, 2)
+        operand(0, reg, 12)
+    },
+    {
+        opcode(0x7e400000, 0xfff00000, "rorc", NONE, NONE, NONE, 2)
+        operand(0, reg, 12)
+    },
+    {
+        opcode(0x7e000000, 0xfff00000, "not", NONE, NONE, NONE, 2)
+        operand(0, reg, 12)
+    },
+    {
+        opcode(0x7e100000, 0xfff00000, "neg", NONE, NONE, NONE, 2)
+        operand(0, reg, 12)
+    },
+    {
+        opcode(0x7e200000, 0xfff00000, "abs", NONE, NONE, NONE, 2)
+        operand(0, reg, 12)
+    },
+    {
+        opcode(0x06140000, 0xff3c0000, "or", NONE, NONE, NONE, 3)
+        operand(0, memory, 16, 14, 8)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0x06100000, 0xff3c0000, "and", NONE, NONE, NONE, 3)
+        operand(0, memory, 16, 14, 8)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0x060c0000, 0xff3c0000, "mul", NONE, NONE, NONE, 3)
+        operand(0, memory, 16, 14, 8)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0x06080000, 0xff3c0000, "add", NONE, NONE, NONE, 3)
+        operand(0, memory, 16, 14, 8)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0x06040000, 0xff3c0000, "cmp", NONE, NONE, NONE, 3)
+        operand(0, memory, 16, 14, 8)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0x06000000, 0xff3c0000, "sub", NONE, NONE, NONE, 3)
+        operand(0, memory, 16, 14, 8)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfde0f000, 0xffe0f000, "bnot", NONE, NONE, NONE, 3)
+        operand(0, imm135, 11, 5)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfce00f00, 0xffe00f00, "bnot", NONE, NONE, NONE, 3)
+        operand(0, imm135, 11, 3)
+        operand(1, memory, 16, 14, NONE)
+    },
+    {
+        opcode(0xfec00000, 0xffe00000, "movu.l", NONE, NONE, NONE, 3)
+        operand(0, uimm48, 16, 8)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0xfde00000, 0xffe00000, "bm", NONE, NONE, 16, 3)
+        operand(0, imm135, 11, 5)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfdc00000, 0xffe00000, "shll", NONE, NONE, NONE, 3)
+        operand(0, imm135, 11, 5)
+        operand(1, reg, 16)
+        operand(2, reg, 20)
+    },
+    {
+        opcode(0xfda00000, 0xffe00000, "shar", NONE, NONE, NONE, 3)
+        operand(0, imm135, 11, 5)
+        operand(1, reg, 16)
+        operand(2, reg, 20)
+    },
+    {
+        opcode(0xfd800000, 0xffe00000, "shlr", NONE, NONE, NONE, 3)
+        operand(0, imm135, 11, 5)
+        operand(1, reg, 16)
+        operand(2, reg, 20)
+    },
+    {
+        opcode(0xfce00000, 0xffe00000, "bm", NONE, NONE, 20, 3)
+        operand(0, imm135, 11, 3)
+        operand(1, memory, 16, 14, NONE)
+    },
+    {
+        opcode(0x7e800000, 0xffc00000, "push", 10, 2, NONE, 2)
+        operand(0, reg, 12)
+    },
+    {
+        opcode(0xfe400000, 0xffc00000, "mov", 10, 2, NONE, 3)
+        operand(0, ind, 16, 12)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfe000000, 0xffc00000, "mov", 10, 2, NONE, 3)
+        operand(0, reg, 20)
+        operand(1, ind, 16, 12)
+    },
+    {
+        opcode(0xfc400000, 0xffc00000, "xchg", NONE, NONE, NONE, 3)
+        operand(0, regub, 16, 14)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0x74300000, 0xfcf00000, "or", NONE, NONE, NONE, 2)
+        operand(0, imm, 16, 6)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0x74200000, 0xfcf00000, "and", NONE, NONE, NONE, 2)
+        operand(0, imm, 16, 6)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0x74100000, 0xfcf00000, "mul", NONE, NONE, NONE, 2)
+        operand(0, imm, 16, 6)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0x74000000, 0xfcf00000, "cmp", NONE, NONE, NONE, 2)
+        operand(0, imm, 16, 6)
+        operand(1, reg, 20)
+    },
+    {
+        opcode(0xfb020000, 0xff030000, "mov.l", NONE, NONE, NONE, 2)
+        operand(0, imm, 16, 12)
+        operand(1, reg, 8)
+    },
+    {
+        opcode(0xf4080000, 0xfc0c0000, "push", NONE, NONE, NONE, 2)
+        operand(0, memory, 8, 6, NONE)
+    },
+    {
+        opcode(0x6f000000, 0xff000000, "popm", NONE, NONE, NONE, 2)
+        operand(0, range, 8, 12)
+    },
+    {
+        opcode(0x6e000000, 0xff000000, "pushm", NONE, NONE, NONE, 2)
+        operand(0, range, 8, 12)
+    },
+    {
+        opcode(0x67000000, 0xff000000, "rtsd", NONE, NONE, NONE, 2)
+        operand(0, uimm8_4, 8)
+    },
+    {
+        opcode(0x66000000, 0xff000000, "mov.l", NONE, NONE, NONE, 2)
+        operand(0, uimm48, 8, 4)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x65000000, 0xff000000, "or", NONE, NONE, NONE, 2)
+        operand(0, uimm48, 8, 4)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x64000000, 0xff000000, "and", NONE, NONE, NONE, 2)
+        operand(0, uimm48, 8, 4)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x63000000, 0xff000000, "mul", NONE, NONE, NONE, 2)
+        operand(0, uimm48, 8, 4)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x62000000, 0xff000000, "add", NONE, NONE, NONE, 2)
+        operand(0, uimm48, 8, 4)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x61000000, 0xff000000, "cmp", NONE, NONE, NONE, 2)
+        operand(0, uimm48, 8, 4)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x60000000, 0xff000000, "sub", NONE, NONE, NONE, 2)
+        operand(0, uimm48, 8, 4)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x3f000000, 0xff000000, "rtsd", NONE, NONE, NONE, 3)
+        operand(0, uimm8_4, 16)
+        operand(1, range, 8, 12)
+    },
+    {
+        opcode(0x39000000, 0xff000000, "bsr.w", NONE, NONE, NONE, 3)
+        operand(0, pcdsp, 8, 16)
+    },
+    {
+        opcode(0x38000000, 0xff000000, "bra.w", NONE, NONE, NONE, 3)
+        operand(0, pcdsp, 8, 16)
+    },
+    {
+        opcode(0x2e000000, 0xff000000, "bra.b", NONE, NONE, NONE, 2)
+        operand(0, pcdsp, 8, 8)
+    },
+    {
+        opcode(0x05000000, 0xff000000, "bsr.a", NONE, NONE, NONE, 4)
+        operand(0, pcdsp, 8, 24)
+    },
+    {
+        opcode(0x04000000, 0xff000000, "bra.a", NONE, NONE, NONE, 4)
+        operand(0, pcdsp, 8, 24)
+    },
+    {
+        opcode(0x03000000, 0xff000000, "nop", NONE, NONE, NONE, 1)
+    },
+    {
+        opcode(0x02000000, 0xff000000, "rts", NONE, NONE, NONE, 1)
+    },
+    {
+        opcode(0x00000000, 0xff000000, "brk", NONE, NONE, NONE, 1)
+    },
+    {
+        opcode(0x3a000000, 0xff000000, "beq.w", NONE, NONE, NONE, 3)
+        operand(0, pcdsp, 8, 16)
+    },
+    {
+        opcode(0x3b000000, 0xff000000, "bne.w", NONE, NONE, NONE, 3)
+        operand(0, pcdsp, 8, 16)
+    },
+    {
+        opcode(0x7c000000, 0xfe000000, "btst", NONE, NONE, NONE, 2)
+        operand(0, imm135, 7, 5)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x7a000000, 0xfe000000, "bclr", NONE, NONE, NONE, 2)
+        operand(0, imm135, 7, 5)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x78000000, 0xfe000000, "bset", NONE, NONE, NONE, 2)
+        operand(0, imm135, 7, 5)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x6c000000, 0xfe000000, "shll", NONE, NONE, NONE, 2)
+        operand(0, imm135, 7, 5)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x6a000000, 0xfe000000, "shar", NONE, NONE, NONE, 2)
+        operand(0, imm135, 7, 5)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x68000000, 0xfe000000, "shlr", NONE, NONE, NONE, 2)
+        operand(0, imm135, 7, 5)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0xf4000000, 0xfc000000, "btst", NONE, NONE, NONE, 2)
+        operand(0, imm135, 13, 3)
+        operand(1, memory, 8, 6, NONE)
+    },
+    {
+        opcode(0xf0080000, 0xfc080000, "bclr", NONE, NONE, NONE, 2)
+        operand(0, imm135, 13, 3)
+        operand(1, memory, 8, 6, NONE)
+    },
+    {
+        opcode(0xf0000000, 0xfc080000, "bset", NONE, NONE, NONE, 2)
+        operand(0, imm135, 13, 3)
+        operand(1, memory, 8, 6, NONE)
+    },
+    {
+        opcode(0xf8000000, 0xfc000000, "mov", 14, 2, NONE, 2)
+        operand(0, imm, NONE, 12)
+        operand(1, memory, 8, 6, NONE)
+    },
+    {
+        opcode(0x70000000, 0xfc000000, "add", NONE, NONE, NONE, 2)
+        operand(0, imm, NONE, 6)
+        operand(1, reg, 8)
+        operand(2, reg, 12)
+    },
+    {
+        opcode(0x54000000, 0xfc000000, "or", NONE, NONE, NONE, 2)
+        operand(0, regub, 8, 6)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x50000000, 0xfc000000, "and", NONE, NONE, NONE, 2)
+        operand(0, regub, 8, 6)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x4c000000, 0xfc000000, "mul", NONE, NONE, NONE, 2)
+        operand(0, regub, 8, 6)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x48000000, 0xfc000000, "add", NONE, NONE, NONE, 2)
+        operand(0, regub, 8, 6)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x44000000, 0xfc000000, "cmp", NONE, NONE, NONE, 2)
+        operand(0, regub, 8, 6)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x40000000, 0xfc000000, "sub", NONE, NONE, NONE, 2)
+        operand(0, regub, 8, 6)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x3c000000, 0xfc000000, "mov", 6, 2, NONE, 3)
+        operand(0, uimm48, 16, 8)
+        operand(1, dsp5, 9, 8, 1, 12)
+    },
+    {
+        opcode(0xcf000000, 0xcf000000, "mov", 2, 2, NONE, 2)
+        operand(0, reg, 8)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x58000000, 0xf8000000, "movu", 5, 1, NONE, 2)
+        operand(0, memory, 8, 6, NONE)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x08000000, 0xf8000000, "bra.s", NONE, NONE, NONE, 1)
+        operand(0, pcdsp, 5, 3)
+    },
+    {
+        opcode(0x10000000, 0xf8000000, "beq.s", NONE, NONE, NONE, 1)
+        operand(0, pcdsp, 5, 3)
+    },
+    {
+        opcode(0x18000000, 0xf8000000, "bne.s", NONE, NONE, NONE, 1)
+        operand(0, pcdsp, 5, 3)
+    },
+    {
+        opcode(0xb0000000, 0xf0000000, "movu", 4, 1, NONE, 2)
+        operand(0, dsp5, 9, 8, 4, 12)
+        operand(1, reg8, 13)
+    },
+    {
+        opcode(0x20000000, 0xf0000000, "b", PCRELB, NONE, 4, 2)
+        operand(0, pcdsp, 8, 8)
+    },
+    {
+        opcode(0xcc000000, 0xcc000000, "mov", 2, 2, NONE, 2)
+        operand(0, memory, 8, 6, NONE)
+        operand(1, reg, 12)
+    },
+    {
+        opcode(0x88000000, 0xc8000000, "mov", 2, 2, NONE, 2)
+        operand(0, dsp5, 9, 8, 4, 12)
+        operand(1, reg8, 13)
+    },
+    {
+        opcode(0x80000000, 0xc8000000, "mov", 2, 2, NONE, 2)
+        operand(0, reg8, 13)
+        operand(1, dsp5, 9, 8, 4, 12)
+    },
+    {
+        opcode(0xc3000000, 0xc3000000, "mov", 2, 2, NONE, 2)
+        operand(0, reg, 12)
+        operand(1, memory, 8, 4, NONE)
+    },
+    {
+        opcode(0xc0000000, 0xc0000000, "mov", 2, 2, NONE, 2)
+        operand(0, memory, 8, 6, NONE)
+        operand(1, memory, 12, 4, NONE)
+    },
+};
+
+static const char *cond[] = {
+    "eq", "ne", "c", "nc", "gtu", "leu", "pz", "n",
+    "ge", "lt", "gt", "le", "o", "no", "<inv>", "<inv>",
+};
+
+static const char size[] = { 'b', 'w', 'l', '?' };
+
+static const char *creg_name[] = {
+    "psw", "pc", "usp", "fpsw", "<inv>", "<inv>", "<inv>", "<inv>",
+    "bpsw", "bpc", "isp", "fintv", "intb", "<inv>", "<inv>", "<inv>",
+};
+
+static const char *psw_bit[] = {
+    "c", "s", "z", "o", "<inv>", "<inv>", "<inv>", "<inv>",
+    "i", "u", "<inv>", "<inv>", "<inv>", "<inv>", "<inv>", "<inv>",
+};
+
+static const char *memex[] = {
+    "b", "w", "l", "uw",
+};
+
+#define prt(...) dis->fprintf_func(dis->stream, __VA_ARGS__)
+#define opcval(pos, wid) (op >> (32 - insn->opcode.pos - (wid)) \
+                                & ((1 << (wid)) - 1))
+#define oprval(pos, wid) (op >> (32 - insn->operand[i].pos - (wid))     \
+                                & ((1 << (wid)) - 1))
+#define oplen() (insn->opcode.len)
+#define opr(type, field) (insn->operand[i].type.field)
+
+#define memdisp(offset, reg)                                            \
+    do {                                                                \
+        bfd_byte dbuf[2];                                               \
+        uint16_t dsp;                                                   \
+        dis->read_memory_func(addr + oplen() + offset,                 \
+                              dbuf, id, dis);                           \
+        dsp = (id == 1) ? dbuf[0] : (dbuf[0] | dbuf[1] << 8);               \
+        prt("%d[r%d]", dsp << scale, reg);                              \
+        append += id;                                                   \
+    } while (0)
+
+int print_insn_rx(bfd_vma addr, disassemble_info *dis)
+{
+    bfd_byte buf;
+    uint32_t op;
+    unsigned int i;
+    int append = 0;
+    int32_t val;
+    int scale = 0;
+    struct instruction const *insn = NULL;
+
+    op = 0;
+    for (i = 0; i < 4; i++) {
+        op <<= 8;
+        if (!dis->read_memory_func(addr + i, &buf, 1, dis)) {
+            op |= buf;
+        }
+    }
+
+    for (i = 0; i < sizeof(instructions) / sizeof(instructions[0]); i++) {
+        if ((op & instructions[i].mask) == instructions[i].code) {
+            insn = &instructions[i];
+            break;
+        }
+    }
+
+    if (insn == NULL) {
+        prt(".byte\t0x%02x", op >> 24);
+        return 1;
+    }
+
+    prt("%s", insn->opcode.nim);
+    if (insn->opcode.cond > 0) {
+        prt("%s", cond[opcval(cond, 4)]);
+        if (insn->opcode.size == PCRELB) {
+            prt(".b");
+        }
+    }
+    if (insn->opcode.size > 0) {
+        scale = opcval(size, insn->opcode.szwid);
+        prt(".%c", size[scale]);
+    }
+
+    for (i = 0; i < 3; i++) {
+        if (insn->operand[i].type) {
+            prt((i > 0) ? ", " : "\t");
+        }
+        switch (insn->operand[i].type) {
+        case none:
+            break;
+        case imm135:
+            prt("#%d", oprval(imm135.pos, opr(imm135, sz)));
+            break;
+        case imm8:
+            val = (op >> (32 - opr(imm8, pos) - 8)) << 24;
+            val >>= 24;
+            prt("#%d", val);
+            break;
+        case uimm48:
+            prt("#%d", oprval(uimm48.pos, opr(uimm48, sz)));
+            break;
+        case uimm8_4:
+            prt("#%d", oprval(uimm8_4.pos, 8) << 2);
+            break;
+        case imm: {
+            int li = oprval(imm.li, 2);
+            bfd_byte ibuf[4];
+            int offset = append;
+
+            /* "mov #imm, dsp[rd]" is destination first */
+            if ((op & 0xfc000000) == 0xf8000000) {
+                offset = oprval(memory.id, 2);
+            }
+            if (li == 0) {
+                li = 4;
+            }
+            dis->read_memory_func(addr + oplen() + offset,
+                                  ibuf, li, dis);
+            switch (li) {
+            case 1:
+                val = (signed char)ibuf[0];
+                break;
+            case 2:
+                val = (signed short)(ibuf[0] | ibuf[1] << 8);
+                break;
+            case 3:
+                val = ibuf[0] | ibuf[1] << 8 | ibuf[2] << 16;
+                /* sign extended */
+                val <<= 8;
+                val >>= 8;
+                break;
+            case 4:
+                val = ibuf[0] | ibuf[1] << 8 | ibuf[2] << 16 | ibuf[3] << 24;
+                break;
+            }
+            append += li;
+            if (abs(val) < 256) {
+                prt("#%d", val);
+            } else {
+                prt("#0x%08x", val);
+            }
+            break;
+        }
+        case float32: {
+            float f;
+            dis->read_memory_func(addr + oplen() + append,
+                                  (bfd_byte *)&f, 4, dis);
+            append += 4;
+            prt("#%f", f);
+            break;
+        }
+        case incdec:
+            if (oprval(incdec.incdec, 1) & 1) {
+                prt("[-r%d]", oprval(incdec.reg, 4));
+            } else {
+                prt("[r%d+]", oprval(incdec.reg, 4));
+            }
+            break;
+        case ind:
+            prt("[r%d,r%d]", oprval(ind.offset, 4), oprval(ind.base, 4));
+            break;
+        case creg:
+            prt("%s", creg_name[oprval(creg.creg, 4)]);
+            break;
+        case pcdsp:
+            val = oprval(pcdsp.pos, opr(pcdsp, sz));
+            switch (opr(pcdsp, sz)) {
+            case 3:
+                if (val < 3) {
+                    val += 8;
+                }
+                break;
+            case 8:
+                if (val >= 0x80) {
+                    val = -(~val & 0xff) - 1;
+                }
+                break;
+            case 16:
+                val = ((val >> 8) & 0xff) | (val << 8);
+                val &= 0xffff;
+                if (val >= 0x8000) {
+                    val = -(~val & 0xffff) - 1;
+                }
+                break;
+            case 24:
+                val = ((val >> 16) & 0xff) | (val << 16) | (val & 0x00ff00);
+                val &= 0xffffff;
+                if (val >= 0x800000) {
+                    val = -(~val & 0xffffff) - 1;
+                }
+                break;
+            }
+            dis->print_address_func(addr + val, dis);
+            break;
+        case memory: {
+            int id = oprval(memory.id, 2);
+            int mi = NONE;
+            int offset = append;
+
+            /* "mov #imm, dsp[rd]" is destination first */
+            if ((op & 0xfc000000) == 0xf8000000) {
+                offset = 0;
+            }
+            if (opr(memory, mi) >= 0) {
+                mi =  oprval(memory.mi, 2);
+                scale = mi;
+            }
+
+            switch (id) {
+            case 0:
+                prt("[r%d]", oprval(memory.reg, 4));
+                break;
+            case 1 ... 2:
+                memdisp(offset, oprval(memory.reg, 4));
+                break;
+            case 3:
+                prt("r%d", oprval(memory.reg, 4));
+                break;
+            }
+            if (id < 3 && mi >= 0) {
+                prt(".%s", memex[mi]);
+            }
+            break;
+        }
+        case dsp5:
+            val = oprval(dsp5.offset1, opr(dsp5, offset1w));
+            val |= oprval(dsp5.offset2, (5 - opr(dsp5, offset1w)));
+            prt("%d[r%d]", val, oprval(memory.reg, 4));
+            break;
+        case regub: {
+            int id = oprval(regub.id, 2);
+            switch (id) {
+            case 0:
+                prt("[r%d].ub", oprval(regub.reg, 4));
+                break;
+            case 1 ... 2:
+                memdisp(append, oprval(regub.reg, 4));
+                prt(".ub");
+                append += id;
+                break;
+            case 3:
+                prt("r%d", oprval(regub.reg, 4));
+                break;
+            }
+            break;
+        }
+        case psw:
+            prt("%s", psw_bit[oprval(psw.b, 4)]);
+            break;
+        case reg:
+            prt("r%d", oprval(reg.r, 4));
+            break;
+        case reg8:
+            prt("r%d", oprval(reg8.r, 3));
+            break;
+        case range:
+            prt("r%d-r%d", oprval(range.start, 4), oprval(range.end, 4));
+            break;
+        }
+    }
+    return oplen() + append;
+}
diff --git a/include/disas/bfd.h b/include/disas/bfd.h
index 41b61c85f9..8bd21c805e 100644
--- a/include/disas/bfd.h
+++ b/include/disas/bfd.h
@@ -228,6 +228,10 @@ enum bfd_architecture
 #define bfd_mach_nios2r2        2
   bfd_arch_lm32,       /* Lattice Mico32 */
 #define bfd_mach_lm32 1
+  bfd_arch_rx,       /* Renesas RX */
+#define bfd_mach_rx            0x75
+#define bfd_mach_rx_v2         0x76
+#define bfd_mach_rx_v3         0x77
   bfd_arch_last
   };
 #define bfd_mach_s390_31 31
@@ -432,6 +436,7 @@ int print_insn_little_nios2     (bfd_vma, disassemble_info*);
 int print_insn_xtensa           (bfd_vma, disassemble_info*);
 int print_insn_riscv32          (bfd_vma, disassemble_info*);
 int print_insn_riscv64          (bfd_vma, disassemble_info*);
+int print_insn_rx               (bfd_vma, disassemble_info*);
 
 #if 0
 /* Fetch the disassembler for a given BFD, if that support is available.  */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH RFC 06/11] RX62N interrupt contoller.
  2019-01-21 13:15 [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture Yoshinori Sato
                   ` (4 preceding siblings ...)
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 05/11] RX disassembler Yoshinori Sato
@ 2019-01-21 13:15 ` Yoshinori Sato
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 07/11] RX62N internal timer unit Yoshinori Sato
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2019-01-21 13:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yoshinori Sato

This implementation supported only ICUa.
Hardware manual.
https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01uh0033ej0140_rx62n.pdf?key=086621e01bd70347c18ea7f794aa9cc3

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 hw/intc/Makefile.objs    |   1 +
 hw/intc/rx_icu.c         | 313 +++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/intc/rx_icu.h |  49 ++++++++
 3 files changed, 363 insertions(+)
 create mode 100644 hw/intc/rx_icu.c
 create mode 100644 include/hw/intc/rx_icu.h

diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 301a8e972d..ff79edb54b 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -48,3 +48,4 @@ obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpuif.o
 obj-$(CONFIG_MIPS_CPS) += mips_gic.o
 obj-$(CONFIG_NIOS2) += nios2_iic.o
 obj-$(CONFIG_OMPIC) += ompic.o
+obj-$(CONFIG_RX) += rx_icu.o
diff --git a/hw/intc/rx_icu.c b/hw/intc/rx_icu.c
new file mode 100644
index 0000000000..2ee6f93918
--- /dev/null
+++ b/hw/intc/rx_icu.c
@@ -0,0 +1,313 @@
+/*
+ * RX Interrupt control unit
+ *
+ * Copyright (c) 2019 Yoshinori Sato
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/intc/rx_icu.h"
+#include "qemu/error-report.h"
+
+#define request(icu, n) (icu->ipr[icu->map[n]] << 8 | n)
+
+static qemu_irq *rxicu_pin(RXICUState *icu, int n_IRQ)
+{
+    if ((icu->fir & 0x8000) && (icu->fir & 0xff) == n_IRQ) {
+        return &icu->_fir;
+    } else {
+        return &icu->_irq;
+    }
+}
+
+static void rxicu_request(RXICUState *icu, int n_IRQ)
+{
+    int enable;
+
+    enable = icu->ier[n_IRQ / 8] & (1 << (n_IRQ & 7));
+    if (enable != 0 && icu->req_irq < 0) {
+        qemu_set_irq(*rxicu_pin(icu, n_IRQ), 0x1000 | request(icu, n_IRQ));
+        icu->req_irq = n_IRQ;
+    }
+}
+
+static void rxicu_set_irq(void *opaque, int n_IRQ, int level)
+{
+    RXICUState *icu = opaque;
+    struct IRQSource *src;
+    int issue;
+
+    if (n_IRQ >= 256) {
+        error_report("%s: IRQ %d out of range", __func__, n_IRQ);
+        return;
+    }
+
+    src = &icu->src[n_IRQ];
+
+    level = (level != 0);
+    switch (src->sense) {
+    case TRG_LEVEL:
+        /* level-sensitive irq */
+        issue = level;
+        src->level = level;
+        break;
+    case TRG_NEDGE:
+        issue = (level == 0 && src->level == 1);
+        src->level = level;
+        break;
+    case TRG_PEDGE:
+        issue = (level == 1 && src->level == 0);
+        src->level = level;
+        break;
+    case TRG_BEDGE:
+        issue = ((level ^ src->level) & 1);
+        src->level = level;
+        break;
+    }
+    if (issue == 0 && src->sense == TRG_LEVEL) {
+        icu->ir[n_IRQ] = 0;
+        if (icu->req_irq == n_IRQ) {
+            qemu_set_irq(*rxicu_pin(icu, n_IRQ), request(icu, n_IRQ));
+            icu->req_irq = -1;
+        }
+        return;
+    }
+    if (issue) {
+        rxicu_request(icu, n_IRQ);
+    }
+}
+
+static void rxicu_ack_irq(void *opaque, int no, int level)
+{
+    RXICUState *icu = opaque;
+    int i;
+    int n_IRQ;
+    int max_pri;
+
+    if (icu->req_irq < 0) {
+        return;
+    }
+    if (icu->src[icu->req_irq].sense != TRG_LEVEL) {
+        icu->ir[icu->req_irq] = 0;
+    }
+    icu->req_irq = -1;
+
+    max_pri = 0;
+    n_IRQ = -1;
+    for (i = 0; i < 256; i++) {
+        if (icu->ir[i]) {
+            if (max_pri < icu->ipr[icu->map[i]]) {
+                n_IRQ = i;
+                max_pri = icu->ipr[icu->map[i]];
+            }
+        }
+    }
+    if (n_IRQ >= 0) {
+        rxicu_request(icu, n_IRQ);
+    }
+}
+
+static uint64_t icu_read(void *opaque, hwaddr addr, unsigned size)
+{
+    hwaddr offset = addr & 0xfff;
+    RXICUState *icu = opaque;
+    int reg = addr & 0xff;
+    int error;
+
+    error = (!(offset == 0x2f0 && size == 2) &&
+             !(offset != 0x2f0 && size == 1));
+    if (!error) {
+        switch (offset) {
+        case 0x000 ... 0x0ff:
+            return icu->ir[reg] & 1;
+        case 0x100 ... 0x1ff:
+            return icu->dtcer[reg] & 1;
+        case 0x200 ... 0x21f:
+            return icu->ier[reg];
+        case 0x2e0:
+            return 0;
+        case 0x2f0:
+            return icu->fir & 0x80ff;
+        case 0x300 ... 0x38f:
+            return icu->ipr[reg] & 0x0f;
+        case 0x400:
+        case 0x404:
+        case 0x408:
+        case 0x40c:
+            return icu->dmasr[reg >> 2];
+        case 0x500 ... 0x51f:
+            return icu->src[64 + reg].sense << 2;
+        case 0x580:
+        case 0x582:
+            return 0;
+        case 0x581:
+            return icu->nmier;
+        case 0x583:
+            return icu->nmicr;
+        default:
+            error = 1;
+        }
+    }
+    if (error) {
+        error_report("rxicu: unsupported read request at %08lx", addr);
+    }
+    return 0xffffffffffffffffULL;
+}
+
+static void icu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    hwaddr offset = addr & 0xfff;
+    RXICUState *icu = opaque;
+    int reg = addr & 0xff;
+    int error;
+
+    error = (!(offset == 0x2f0 && size == 2) &&
+             !(offset != 0x2f0 && size == 1));
+
+    if (!error) {
+        switch (offset) {
+        case 0x000 ... 0x0ff:
+            if (icu->src[reg].sense != TRG_LEVEL && val == 0) {
+                icu->ir[reg] = 0;
+            }
+            break;
+        case 0x100 ... 0x1ff:
+            icu->dtcer[reg] = val & 1;
+            break;
+        case 0x200 ... 0x21f:
+            icu->ier[reg] = val;
+            break;
+        case 0x2e0:
+            if (val == 1) {
+                qemu_irq_pulse(icu->_swi);
+            }
+            break;
+        case 0x2f0:
+            icu->fir = val;
+            break;
+        case 0x300 ... 0x38f:
+            icu->ipr[reg] = val & 0x0f;
+            break;
+        case 0x400:
+        case 0x404:
+        case 0x408:
+        case 0x40c:
+            icu->dmasr[reg >> 2] = val;
+            break;
+        case 0x500 ... 0x50f:
+            icu->src[64 + reg].sense = val >> 2;
+            break;
+        case 0x582:
+            break;
+        case 0x581:
+            icu->nmier |= val & 7;
+            break;
+        case 0x583:
+            icu->nmicr = val;
+            break;
+        default:
+            error = 1;
+        }
+    }
+    if (error) {
+        error_report("rxicu: unsupported write request at %08lx", addr);
+    }
+}
+
+static const MemoryRegionOps icu_ops = {
+    .write = icu_write,
+    .read  = icu_read,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 2,
+    },
+};
+
+static void rxicu_realize(DeviceState *dev, Error **errp)
+{
+    RXICUState *icu = RXICU(dev);
+    int i, j;
+
+    for (i = j = 0; i < 256; i++) {
+        if (icu->init_sense[j] == i) {
+            icu->src[i].sense = TRG_LEVEL;
+            if (j < icu->nr_sense) {
+                j++;
+            }
+        } else
+            icu->src[i].sense = TRG_PEDGE;
+    }
+    icu->req_irq = -1;
+}
+
+static void rxicu_init(Object *obj)
+{
+    SysBusDevice *d = SYS_BUS_DEVICE(obj);
+    RXICUState *icu = RXICU(obj);
+
+    memory_region_init_io(&icu->memory, OBJECT(icu), &icu_ops,
+                          icu, "rx-icu", 0x600);
+    sysbus_init_mmio(d, &icu->memory);
+
+    qdev_init_gpio_in(DEVICE(d), rxicu_set_irq, 256);
+    qdev_init_gpio_in_named(DEVICE(d), rxicu_ack_irq, "ack", 1);
+    sysbus_init_irq(d, &icu->_irq);
+    sysbus_init_irq(d, &icu->_fir);
+    sysbus_init_irq(d, &icu->_swi);
+}
+
+static void rxicu_fini(Object *obj)
+{
+    RXICUState *icu = RXICU(obj);
+    g_free(icu->map);
+    g_free(icu->init_sense);
+}
+
+static const VMStateDescription vmstate_rxicu = {
+    .name = "rx-icu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property rxicu_properties[] = {
+    DEFINE_PROP_STRING("icutype", RXICUState, icutype),
+    DEFINE_PROP_ARRAY("ipr-map", RXICUState, nr_irqs, map,
+                      qdev_prop_uint32, uint32_t),
+    DEFINE_PROP_ARRAY("trigger-level", RXICUState, nr_sense, init_sense,
+                      qdev_prop_uint32, uint32_t),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rxicu_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = rxicu_realize;
+    dc->props = rxicu_properties;
+    dc->vmsd = &vmstate_rxicu;
+}
+
+static const TypeInfo rxicu_info = {
+    .name       = TYPE_RXICU,
+    .parent     = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RXICUState),
+    .instance_init = rxicu_init,
+    .instance_finalize = rxicu_fini,
+    .class_init = rxicu_class_init,
+};
+
+static void rxicu_register_types(void)
+{
+    type_register_static(&rxicu_info);
+}
+
+type_init(rxicu_register_types)
diff --git a/include/hw/intc/rx_icu.h b/include/hw/intc/rx_icu.h
new file mode 100644
index 0000000000..bc46b3079b
--- /dev/null
+++ b/include/hw/intc/rx_icu.h
@@ -0,0 +1,49 @@
+#ifndef RX_ICU_H
+#define RX_ICU_H
+
+#include "qemu-common.h"
+#include "hw/irq.h"
+
+struct IRQSource {
+    int sense;
+    int level;
+};
+
+struct RXICUState {
+    SysBusDevice parent_obj;
+
+    MemoryRegion memory;
+    struct IRQSource src[256];
+    char *icutype;
+    uint32_t nr_irqs;
+    uint32_t *map;
+    uint32_t nr_sense;
+    uint32_t *init_sense;
+
+    uint8_t ir[256];
+    uint8_t dtcer[256];
+    uint8_t ier[32];
+    uint8_t ipr[142];
+    uint8_t dmasr[4];
+    uint16_t fir;
+    uint8_t nmisr;
+    uint8_t nmier;
+    uint8_t nmiclr;
+    uint8_t nmicr;
+    int req_irq;
+    qemu_irq _irq;
+    qemu_irq _fir;
+    qemu_irq _swi;
+};
+typedef struct RXICUState RXICUState;
+
+#define TYPE_RXICU "rxicu"
+#define RXICU(obj) OBJECT_CHECK(RXICUState, (obj), TYPE_RXICU)
+
+#define SWI 27
+#define TRG_LEVEL 0
+#define TRG_NEDGE 1
+#define TRG_PEDGE 2
+#define TRG_BEDGE 3
+
+#endif /* RX_ICU_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH RFC 07/11] RX62N internal timer unit.
  2019-01-21 13:15 [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture Yoshinori Sato
                   ` (5 preceding siblings ...)
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 06/11] RX62N interrupt contoller Yoshinori Sato
@ 2019-01-21 13:15 ` Yoshinori Sato
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 08/11] RX62N internal serical communication interface Yoshinori Sato
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2019-01-21 13:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yoshinori Sato

renesas_tmr: 8bit timer modules.
renesas_cmt: 16bit compare match timer modules.
This part use many renesas's CPU.
Hardware manual.
https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01uh0033ej0140_rx62n.pdf?key=086621e01bd70347c18ea7f794aa9cc3

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 hw/timer/Makefile.objs         |   2 +
 hw/timer/renesas_cmt.c         | 226 +++++++++++++++++++++++
 hw/timer/renesas_tmr.c         | 401 +++++++++++++++++++++++++++++++++++++++++
 include/hw/timer/renesas_cmt.h |  33 ++++
 include/hw/timer/renesas_tmr.h |  42 +++++
 5 files changed, 704 insertions(+)
 create mode 100644 hw/timer/renesas_cmt.c
 create mode 100644 hw/timer/renesas_tmr.c
 create mode 100644 include/hw/timer/renesas_cmt.h
 create mode 100644 include/hw/timer/renesas_tmr.h

diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 0e9a4530f8..e11aaf5bf5 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -40,6 +40,8 @@ obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
 
 obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
 
+obj-$(CONFIG_RX) += renesas_tmr.o renesas_cmt.o
+
 common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o
 common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o
 
diff --git a/hw/timer/renesas_cmt.c b/hw/timer/renesas_cmt.c
new file mode 100644
index 0000000000..fb48d315c2
--- /dev/null
+++ b/hw/timer/renesas_cmt.c
@@ -0,0 +1,226 @@
+/*
+ * Renesas Compare-match timer
+ *
+ * Copyright (c) 2019 Yoshinori Sato
+ *
+ * This code is licensed under the GPL version 2 or later.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include "cpu.h"
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/timer/renesas_cmt.h"
+#include "qemu/error-report.h"
+
+#define freq_to_ns(freq) (1000000000LL / freq)
+static const int clkdiv[] = {8, 32, 128, 512};
+
+static void update_events(RCMTState *cmt, int ch)
+{
+    uint16_t diff;
+
+    if ((cmt->cmstr & (1 << ch)) != 0) {
+        diff = cmt->cmcor[ch] - cmt->cmcnt[ch];
+        timer_mod(cmt->timer[ch],
+              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+              diff * freq_to_ns(cmt->input_freq) *
+              clkdiv[cmt->cmcr[ch] & 3]);
+    }
+}
+
+static uint64_t read_cmcnt(RCMTState *cmt, int ch)
+{
+    int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+    if (cmt->cmstr & (1 << ch)) {
+        delta = (now - cmt->tick[ch]) / freq_to_ns(cmt->input_freq);
+        delta /= clkdiv[cmt->cmcr[ch] & 0x03];
+        return cmt->cmcnt[ch] + delta;
+    } else {
+        return cmt->cmcnt[ch];
+    }
+}
+
+static uint64_t cmt_read(void *opaque, hwaddr addr, unsigned size)
+{
+    hwaddr offset = addr & 0x0f;
+    RCMTState *cmt = opaque;
+    int ch = offset / 0x08;
+    int error = 1;
+
+    if (offset == 0) {
+        return cmt->cmstr;
+        error = 0;
+    } else {
+        offset &= 0x07;
+        if (ch == 0) {
+            offset -= 0x02;
+        }
+        error = 0;
+        switch (offset) {
+        case 0:
+            return cmt->cmcr[ch];
+        case 2:
+            return read_cmcnt(cmt, ch);
+        case 4:
+            return cmt->cmcor[ch];
+        default:
+            error = 1;
+        }
+    }
+    if (error) {
+        error_report("rcmt: unsupported read request to %08lx", addr);
+    }
+    return 0xffffffffffffffffUL;
+}
+
+static void start_stop(RCMTState *cmt, int ch, int st)
+{
+    if (st) {
+        update_events(cmt, ch);
+    } else {
+        timer_del(cmt->timer[ch]);
+    }
+}
+
+static void cmt_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    hwaddr offset = addr & 0x0f;
+    RCMTState *cmt = opaque;
+    int ch = offset / 0x08;
+    int error = 1;
+
+    if (offset == 0) {
+        cmt->cmstr = val;
+        start_stop(cmt, 0, cmt->cmstr & 1);
+        start_stop(cmt, 1, (cmt->cmstr >> 1) & 1);
+        error = 0;
+    } else {
+        offset &= 0x07;
+        if (ch == 0) {
+            offset -= 0x02;
+        }
+        error = 0;
+        switch (offset) {
+        case 0:
+            cmt->cmcr[ch] = val;
+            break;
+        case 2:
+            cmt->cmcnt[ch] = val;
+            break;
+        case 4:
+            cmt->cmcor[ch] = val;
+            break;
+        default:
+            error = 1;
+        }
+        if (error == 0 && cmt->cmstr & (1 << ch)) {
+            update_events(cmt, ch);
+        }
+    }
+    if (error) {
+        error_report("rcmt: unsupported write request to %08lx", addr);
+    }
+}
+
+static const MemoryRegionOps cmt_ops = {
+    .write = cmt_write,
+    .read  = cmt_read,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 2,
+        .max_access_size = 2,
+    },
+};
+
+static void timer_events(RCMTState *cmt, int ch)
+{
+    cmt->cmcnt[ch] = 0;
+    cmt->tick[ch] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    update_events(cmt, ch);
+    if (cmt->cmcr[ch] & 0x40) {
+        qemu_irq_pulse(cmt->cmi[ch]);
+    }
+}
+
+static void timer_event0(void *opaque)
+{
+    RCMTState *cmt = opaque;
+
+    timer_events(cmt, 0);
+}
+
+static void timer_event1(void *opaque)
+{
+    RCMTState *cmt = opaque;
+
+    timer_events(cmt, 1);
+}
+
+static void rcmt_reset(DeviceState *dev)
+{
+    RCMTState *cmt = RCMT(dev);
+    cmt->cmstr = 0;
+    cmt->cmcr[0] = cmt->cmcr[1] = 0;
+    cmt->cmcnt[0] = cmt->cmcnt[1] = 0;
+    cmt->cmcor[0] = cmt->cmcor[1] = 0xffff;
+}
+
+static void rcmt_init(Object *obj)
+{
+    SysBusDevice *d = SYS_BUS_DEVICE(obj);
+    RCMTState *cmt = RCMT(obj);
+    int i;
+
+    memory_region_init_io(&cmt->memory, OBJECT(cmt), &cmt_ops,
+                          cmt, "renesas-cmt", 0x10);
+    sysbus_init_mmio(d, &cmt->memory);
+
+    for (i = 0; i < 2; i++) {
+        sysbus_init_irq(d, &cmt->cmi[i]);
+    }
+    cmt->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event0, cmt);
+    cmt->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event1, cmt);
+}
+
+static const VMStateDescription vmstate_rcmt = {
+    .name = "rx-cmt",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property rcmt_properties[] = {
+    DEFINE_PROP_UINT64("input-freq", RCMTState, input_freq, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rcmt_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->props = rcmt_properties;
+    dc->vmsd = &vmstate_rcmt;
+    dc->reset = rcmt_reset;
+}
+
+static const TypeInfo rcmt_info = {
+    .name       = TYPE_RENESAS_CMT,
+    .parent     = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RCMTState),
+    .instance_init = rcmt_init,
+    .class_init = rcmt_class_init,
+};
+
+static void rcmt_register_types(void)
+{
+    type_register_static(&rcmt_info);
+}
+
+type_init(rcmt_register_types)
diff --git a/hw/timer/renesas_tmr.c b/hw/timer/renesas_tmr.c
new file mode 100644
index 0000000000..1b59c6c092
--- /dev/null
+++ b/hw/timer/renesas_tmr.c
@@ -0,0 +1,401 @@
+/*
+ * Renesas 8bit timer
+ *
+ * Copyright (c) 2019 Yoshinori Sato
+ *
+ * This code is licensed under the GPL version 2 or later.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include "cpu.h"
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/timer/renesas_tmr.h"
+#include "qemu/error-report.h"
+
+#define freq_to_ns(freq) (1000000000LL / freq)
+static const int clkdiv[] = {0, 1, 2, 8, 32, 64, 1024, 8192};
+
+static void update_events(RTMRState *tmr, int ch)
+{
+    uint16_t diff[3];
+    uint16_t tcnt, tcora, tcorb;
+    int i, min, event;
+
+    if (tmr->tccr[ch] == 0) {
+        return ;
+    }
+    if ((tmr->tccr[ch] & 0x08) == 0) {
+        error_report("rtmr: unsupported count mode %02x", tmr->tccr[ch]);
+        return ;
+    }
+    if ((tmr->tccr[0] & 0x18) == 0x18) {
+        if (ch == 1) {
+            tmr->next[ch] = none;
+            return ;
+        }
+        tcnt = (tmr->tcnt[0] << 8) + tmr->tcnt[1];
+        tcora = (tmr->tcora[0] << 8) | tmr->tcora[1];
+        tcorb = (tmr->tcorb[0] << 8) | tmr->tcorb[1];
+        diff[0] = tcora - tcnt;
+        diff[1] = tcorb - tcnt;
+        diff[2] = 0x10000 - tcnt;
+    } else {
+        diff[0] = tmr->tcora[ch] - tmr->tcnt[ch];
+        diff[1] = tmr->tcorb[ch] - tmr->tcnt[ch];
+        diff[2] = 0x100 - tmr->tcnt[ch];
+    }
+    for (event = 0, min = diff[0], i = 1; i < 3; i++) {
+        if (min > diff[i]) {
+            event = i;
+            min = diff[i];
+        }
+    }
+    tmr->next[ch] = event + 1;
+    timer_mod(tmr->timer[ch],
+              diff[event] * freq_to_ns(tmr->input_freq) *
+              clkdiv[tmr->tccr[ch] & 7]);
+}
+
+#define UPDATE_TIME(tmr, ch, upd, delta)                                \
+    do {                                                                \
+        tmr->div_round[ch] += delta;                                    \
+        if (clkdiv[tmr->tccr[ch] & 0x07] > 0) {                         \
+            upd = tmr->div_round[ch] / clkdiv[tmr->tccr[ch] & 0x07];    \
+            tmr->div_round[ch] %= clkdiv[tmr->tccr[ch] & 0x07];         \
+        } else                                                          \
+            upd = 0;                                                    \
+    } while (0)
+
+static uint64_t read_tcnt(RTMRState *tmr, unsigned size, int ch)
+{
+    int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    int upd, ovf = 0;
+    uint16_t tcnt[2];
+
+    delta = (now - tmr->tick) / freq_to_ns(tmr->input_freq);
+    if (delta > 0) {
+        tmr->tick = now;
+
+        if ((tmr->tccr[1] & 0x18) == 0x08) {
+            UPDATE_TIME(tmr, 1, upd, delta);
+            if (upd >= 0x100) {
+                ovf = upd >> 8;
+                upd -= ovf;
+            }
+            tcnt[1] = tmr->tcnt[1] + upd;
+        }
+        switch (tmr->tccr[0] & 0x18) {
+        case 0x08:
+            UPDATE_TIME(tmr, 0, upd, delta);
+            tcnt[0] = tmr->tcnt[0] + upd;
+            break;
+        case 0x18:
+            if (ovf > 0) {
+                tcnt[0] = tmr->tcnt[0] + ovf;
+            }
+            break;
+        }
+    } else {
+        tcnt[0] = tmr->tcnt[0];
+        tcnt[1] = tmr->tcnt[1];
+    }
+    if (size == 1) {
+        return tcnt[ch];
+    } else {
+        return (tmr->tcnt[0] << 8) | (tmr->tcnt[1] & 0xff);
+    }
+}
+
+static uint64_t tmr_read(void *opaque, hwaddr addr, unsigned size)
+{
+    hwaddr offset = addr & 0x1f;
+    RTMRState *tmr = opaque;
+    int ch = offset & 1;
+    int error = 0;
+
+    if (size == 1) {
+        switch (offset & 0x0e) {
+        case 0x00:
+            return tmr->tcr[ch] & 0xf8;
+        case 0x02:
+            return tmr->tcsr[ch] & 0xf8;
+        case 0x04:
+            return tmr->tcora[ch];
+        case 0x06:
+            return tmr->tcorb[ch];
+        case 0x08:
+            return read_tcnt(tmr, size, ch);
+        case 0x0a:
+            return tmr->tccr[ch];
+        default:
+            error = 1;
+        }
+    } else if (ch == 0) {
+        switch (offset & 0x0e) {
+        case 0x04:
+            return tmr->tcora[0] << 8 | tmr->tcora[1];
+        case 0x06:
+            return tmr->tcorb[0] << 8 | tmr->tcorb[1];;
+        case 0x08:
+            return read_tcnt(tmr, size, 0) & 0xff;
+        case 0x0a:
+            return tmr->tccr[0] << 8 | tmr->tccr[1];
+        default:
+            error = 1;
+        }
+    } else {
+        error = 1;
+    }
+    if (error) {
+        error_report("rtmr: unsupported read request to %08lx", addr);
+    }
+    return 0xffffffffffffffffULL;
+}
+
+static void tmr_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    hwaddr offset = addr & 0x1f;
+    RTMRState *tmr = opaque;
+    int ch = offset & 1;
+    int error = 0;
+
+    if (size == 1) {
+        switch (offset & 0x0e) {
+        case 0x00:
+            tmr->tcr[ch] = val;
+            break;
+        case 0x02:
+            tmr->tcsr[ch] = val;
+            break;
+        case 0x04:
+            tmr->tcora[ch] = val;
+            update_events(tmr, ch);
+            break;
+        case 0x06:
+            tmr->tcora[ch] = val;
+            update_events(tmr, ch);
+            break;
+        case 0x08:
+            tmr->tcnt[ch] = val;
+            update_events(tmr, ch);
+            break;
+        case 0x0a:
+            tmr->tccr[ch] = val;
+            update_events(tmr, ch);
+            break;
+        default:
+            error = 1;
+        }
+    } else if (ch == 0) {
+        switch (offset & 0x0e) {
+        case 0x04:
+            tmr->tcora[0] = (val >> 8) & 0xff;
+            tmr->tcora[1] = val & 0xff;
+            update_events(tmr, 0);
+            update_events(tmr, 1);
+        case 0x06:
+            tmr->tcorb[0] = (val >> 8) & 0xff;
+            tmr->tcorb[1] = val & 0xff;
+            update_events(tmr, 0);
+            update_events(tmr, 1);
+            break;
+        case 0x08:
+            tmr->tcnt[0] = (val >> 8) & 0xff;
+            tmr->tcnt[1] = val & 0xff;
+            update_events(tmr, 0);
+            update_events(tmr, 1);
+            break;
+        case 0x0a:
+            tmr->tccr[0] = (val >> 8) & 0xff;
+            tmr->tccr[1] = val & 0xff;
+            update_events(tmr, 0);
+            update_events(tmr, 1);
+            break;
+        default:
+            error = 1;
+        }
+    } else {
+        error = 1;
+    }
+    if (error) {
+        error_report("rtmr: unsupported write request to %08lx", addr);
+    }
+}
+
+static const MemoryRegionOps tmr_ops = {
+    .write = tmr_write,
+    .read  = tmr_read,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 2,
+    },
+};
+
+static void timer_events(RTMRState *tmr, int ch)
+{
+    tmr->tcnt[ch] = read_tcnt(tmr, 1, ch);
+    if ((tmr->tccr[0] & 0x18) != 0x18) {
+        switch (tmr->next[ch]) {
+        case none:
+            break;
+        case cmia:
+            if (tmr->tcnt[ch] >= tmr->tcora[ch]) {
+                if ((tmr->tcr[ch] & 0x18) == 0x08) {
+                    tmr->tcnt[ch] = 0;
+                }
+                if ((tmr->tcr[ch] & 0x40)) {
+                    qemu_irq_pulse(tmr->cmia[ch]);
+                }
+                if (ch == 0 && (tmr->tccr[1] & 0x18) == 0x18) {
+                    tmr->tcnt[1]++;
+                    timer_events(tmr, 1);
+                }
+            }
+            break;
+        case cmib:
+            if (tmr->tcnt[ch] >= tmr->tcorb[ch]) {
+                if ((tmr->tcr[ch] & 0x18) == 0x10) {
+                    tmr->tcnt[ch] = 0;
+                }
+                if ((tmr->tcr[ch] & 0x80)) {
+                    qemu_irq_pulse(tmr->cmib[ch]);
+                }
+            }
+            break;
+        case ovi:
+            if ((tmr->tcnt[ch] >= 0x100) &&
+                (tmr->tcr[ch] & 0x20)) {
+                qemu_irq_pulse(tmr->ovi[ch]);
+            }
+            break;
+        }
+        tmr->tcnt[ch] &= 0xff;
+    } else {
+        uint32_t tcnt, tcora, tcorb;
+        if (ch == 1) {
+            return ;
+        }
+        tcnt = (tmr->tcnt[0] << 8) + tmr->tcnt[1];
+        tcora = (tmr->tcora[0] << 8) | tmr->tcora[1];
+        tcorb = (tmr->tcorb[0] << 8) | tmr->tcorb[1];
+        switch (tmr->next[ch]) {
+        case none:
+            break;
+        case cmia:
+            if (tcnt >= tcora) {
+                if ((tmr->tcr[ch] & 0x18) == 0x08) {
+                    tcnt = 0;
+                }
+                if ((tmr->tcr[ch] & 0x40)) {
+                    qemu_irq_pulse(tmr->cmia[ch]);
+                }
+            }
+            break;
+        case cmib:
+            if (tcnt >= tcorb) {
+                if ((tmr->tcr[ch] & 0x18) == 0x10) {
+                    tcnt = 0;
+                }
+                if ((tmr->tcr[ch] & 0x80)) {
+                    qemu_irq_pulse(tmr->cmib[ch]);
+                }
+            }
+            break;
+        case ovi:
+            if ((tcnt >= 0x10000) &&
+                (tmr->tcr[ch] & 0x20)) {
+                qemu_irq_pulse(tmr->ovi[ch]);
+            }
+            break;
+        }
+        tmr->tcnt[0] = (tcnt >> 8) & 0xff;
+        tmr->tcnt[1] = tcnt & 0xff;
+    }
+    update_events(tmr, ch);
+}
+
+static void timer_event0(void *opaque)
+{
+    RTMRState *tmr = opaque;
+
+    timer_events(tmr, 0);
+}
+
+static void timer_event1(void *opaque)
+{
+    RTMRState *tmr = opaque;
+
+    timer_events(tmr, 1);
+}
+
+static void rtmr_reset(DeviceState *dev)
+{
+    RTMRState *tmr = RTMR(dev);
+    tmr->tcora[0] = tmr->tcora[1] = 0xff;
+    tmr->tcorb[0] = tmr->tcorb[1] = 0xff;
+    tmr->tcsr[0] = 0x00;
+    tmr->tcsr[1] = 0x10;
+    tmr->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+}
+
+static void rtmr_init(Object *obj)
+{
+    SysBusDevice *d = SYS_BUS_DEVICE(obj);
+    RTMRState *tmr = RTMR(obj);
+    int i;
+
+    memory_region_init_io(&tmr->memory, OBJECT(tmr), &tmr_ops,
+                          tmr, "rx-tmr", 0x10);
+    sysbus_init_mmio(d, &tmr->memory);
+
+    for (i = 0; i < 2; i++) {
+        sysbus_init_irq(d, &tmr->cmia[i]);
+        sysbus_init_irq(d, &tmr->cmib[i]);
+        sysbus_init_irq(d, &tmr->ovi[i]);
+    }
+    tmr->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event0, tmr);
+    tmr->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event1, tmr);
+}
+
+static const VMStateDescription vmstate_rtmr = {
+    .name = "rx-cmt",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property rtmr_properties[] = {
+    DEFINE_PROP_UINT64("input-freq", RTMRState, input_freq, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rtmr_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->props = rtmr_properties;
+    dc->vmsd = &vmstate_rtmr;
+    dc->reset = rtmr_reset;
+}
+
+static const TypeInfo rtmr_info = {
+    .name       = TYPE_RENESAS_TMR,
+    .parent     = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RTMRState),
+    .instance_init = rtmr_init,
+    .class_init = rtmr_class_init,
+};
+
+static void rtmr_register_types(void)
+{
+    type_register_static(&rtmr_info);
+}
+
+type_init(rtmr_register_types)
diff --git a/include/hw/timer/renesas_cmt.h b/include/hw/timer/renesas_cmt.h
new file mode 100644
index 0000000000..764759d4ad
--- /dev/null
+++ b/include/hw/timer/renesas_cmt.h
@@ -0,0 +1,33 @@
+/*
+ * Renesas Compare-match timer Object
+ *
+ * Copyright (c) 2018 Yoshinori Sato
+ *
+ * This code is licensed under the GPL version 2 or later.
+ *
+ */
+
+#ifndef HW_RENESAS_CMT_H
+#define HW_RENESAS_CMT_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_RENESAS_CMT "renesas-cmt"
+#define RCMT(obj) OBJECT_CHECK(RCMTState, (obj), TYPE_RENESAS_CMT)
+
+typedef struct RCMTState {
+    SysBusDevice parent_obj;
+
+    uint64_t input_freq;
+    MemoryRegion memory;
+
+    uint16_t cmstr;
+    uint16_t cmcr[2];
+    uint16_t cmcnt[2];
+    uint16_t cmcor[2];
+    int64_t tick[2];
+    qemu_irq cmi[2];
+    QEMUTimer *timer[2];
+} RCMTState;
+
+#endif
diff --git a/include/hw/timer/renesas_tmr.h b/include/hw/timer/renesas_tmr.h
new file mode 100644
index 0000000000..09333c86fc
--- /dev/null
+++ b/include/hw/timer/renesas_tmr.h
@@ -0,0 +1,42 @@
+/*
+ * Renesas 8bit timer Object
+ *
+ * Copyright (c) 2018 Yoshinori Sato
+ *
+ * This code is licensed under the GPL version 2 or later.
+ *
+ */
+
+#ifndef HW_RENESAS_TMR_H
+#define HW_RENESAS_TMR_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_RENESAS_TMR "renesas-tmr"
+#define RTMR(obj) OBJECT_CHECK(RTMRState, (obj), TYPE_RENESAS_TMR)
+
+enum timer_event {none, cmia, cmib, ovi};
+
+typedef struct RTMRState {
+    SysBusDevice parent_obj;
+
+    uint64_t input_freq;
+    MemoryRegion memory;
+
+    uint16_t tcnt[2];
+    uint8_t tcora[2];
+    uint8_t tcorb[2];
+    uint8_t tcr[2];
+    uint8_t tccr[2];
+    uint8_t tcor[2];
+    uint8_t tcsr[2];
+    int64_t tick;
+    int64_t div_round[2];
+    enum timer_event next[2];
+    qemu_irq cmia[2];
+    qemu_irq cmib[2];
+    qemu_irq ovi[2];
+    QEMUTimer *timer[2];
+} RTMRState;
+
+#endif
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH RFC 08/11] RX62N internal serical communication interface.
  2019-01-21 13:15 [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture Yoshinori Sato
                   ` (6 preceding siblings ...)
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 07/11] RX62N internal timer unit Yoshinori Sato
@ 2019-01-21 13:15 ` Yoshinori Sato
  2019-01-21 13:16 ` [Qemu-devel] [PATCH RFC 09/11] RX Target hardware definition Yoshinori Sato
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2019-01-21 13:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yoshinori Sato

This module supported only non FIFO type.
Hardware manual.
https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01uh0033ej0140_rx62n.pdf?key=086621e01bd70347c18ea7f794aa9cc3

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 hw/char/Makefile.objs         |   2 +-
 hw/char/renesas_sci.c         | 279 ++++++++++++++++++++++++++++++++++++++++++
 include/hw/char/renesas_sci.h |  42 +++++++
 3 files changed, 322 insertions(+), 1 deletion(-)
 create mode 100644 hw/char/renesas_sci.c
 create mode 100644 include/hw/char/renesas_sci.h

diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index c4947d7ae7..68eae7b9a5 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -15,7 +15,7 @@ common-obj-$(CONFIG_CADENCE) += cadence_uart.o
 obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o
 obj-$(CONFIG_COLDFIRE) += mcf_uart.o
 obj-$(CONFIG_OMAP) += omap_uart.o
-obj-$(CONFIG_SH4) += sh_serial.o
+obj-$(CONFIG_RENESAS_SCI) += renesas_sci.o
 obj-$(CONFIG_PSERIES) += spapr_vty.o
 obj-$(CONFIG_DIGIC) += digic-uart.o
 obj-$(CONFIG_STM32F2XX_USART) += stm32f2xx_usart.o
diff --git a/hw/char/renesas_sci.c b/hw/char/renesas_sci.c
new file mode 100644
index 0000000000..88a9077aef
--- /dev/null
+++ b/hw/char/renesas_sci.c
@@ -0,0 +1,279 @@
+/*
+ * Renesas Serial Communication Interface
+ *
+ * Copyright (c) 2019 Yoshinori Sato
+ *
+ * This code is licensed under the GPL version 2.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/char/renesas_sci.h"
+#include "qemu/error-report.h"
+
+#define freq_to_ns(freq) (1000000000LL / freq)
+
+static int can_receive(void *opaque)
+{
+    RSCIState *sci = RSCI(opaque);
+    if (sci->rx_next > qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) {
+        return 0;
+    } else {
+        return sci->scr & 0x10;
+    }
+}
+
+static void receive(void *opaque, const uint8_t *buf, int size)
+{
+    RSCIState *sci = RSCI(opaque);
+    sci->rdr = buf[0];
+    if (sci->ssr & 0x40 || size > 1) {
+        sci->ssr |= 0x20;
+        if (sci->scr & 0x40) {
+            qemu_set_irq(sci->irq[ERI], 1);
+        }
+    } else {
+        sci->ssr |= 0x40;
+        sci->rx_next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + sci->trtime;
+        if (sci->scr & 0x40) {
+            qemu_set_irq(sci->irq[RXI], 1);
+            qemu_set_irq(sci->irq[RXI], 0);
+        }
+    }
+}
+
+static void send_byte(RSCIState *sci)
+{
+    if (qemu_chr_fe_backend_connected(&sci->chr)) {
+        qemu_chr_fe_write_all(&sci->chr, &sci->tdr, 1);
+    }
+    timer_mod(sci->timer,
+              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + sci->trtime);
+    sci->ssr &= ~0x04;
+    sci->ssr |= 0x80;
+    qemu_set_irq(sci->irq[TEI], 0);
+    if (sci->scr & 0x80) {
+        qemu_set_irq(sci->irq[TXI], 1);
+        qemu_set_irq(sci->irq[TXI], 0);
+    }
+}
+
+static void txend(void *opaque)
+{
+    RSCIState *sci = RSCI(opaque);
+    if ((sci->ssr & 0x80) == 0) {
+        send_byte(sci);
+    } else {
+        sci->ssr |= 0x04;
+        if (sci->scr & 0x04) {
+            qemu_set_irq(sci->irq[TEI], 1);
+        }
+    }
+}
+
+static void update_trtime(RSCIState *sci)
+{
+    static const int div[] = {1, 4, 16, 64};
+    int w;
+
+    w = (sci->smr & 0x40) ? 7 : 8;      /* CHR */
+    w += (sci->smr >> 5) & 1;           /* PE */
+    w += (sci->smr & 0x08) ? 2 : 1;     /* STOP */
+    sci->trtime = w * freq_to_ns(sci->input_freq) *
+        32 * div[sci->smr & 0x03] * sci->brr;
+}
+
+static void sci_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    hwaddr offset = addr & 0x07;
+    RSCIState *sci = RSCI(opaque);
+    int error = 0;
+
+    switch (offset) {
+    case 0: /* SMR */
+        if ((sci->scr & 0x30) == 0) {
+            sci->smr = val;
+            update_trtime(sci);
+        }
+        break;
+    case 1: /* BRR */
+        if ((sci->scr & 0x30) == 0) {
+            sci->brr = val;
+            update_trtime(sci);
+        }
+        break;
+    case 2: /* SCR */
+        sci->scr = val;
+        if (sci->scr & 0x20) {
+            sci->ssr |= 0x84;
+            qemu_set_irq(sci->irq[TXI], 1);
+            qemu_set_irq(sci->irq[TXI], 0);
+        }
+        if ((sci->scr & 0x04) == 0) {
+            qemu_set_irq(sci->irq[TEI], 0);
+        }
+        if ((sci->scr & 0x40) == 0) {
+            qemu_set_irq(sci->irq[ERI], 0);
+        }
+        break;
+    case 3: /* TDR */
+        sci->tdr = val;
+        if (sci->ssr & 0x04) {
+            send_byte(sci);
+        } else{
+            sci->ssr &= ~0x80;
+        }
+        break;
+    case 4: /* SSR */
+        sci->ssr &= ~0x38 | (val & 0x38);
+        if (((sci->read_ssr & 0x38) ^ (sci->ssr & 0x38)) &&
+            (sci->ssr & 0x38) == 0) {
+            qemu_set_irq(sci->irq[ERI], 0);
+        }
+        break;
+    case 5: /* RDR */
+        error = 1; break;
+    case 6: /* SCMR */
+        sci->scmr = val; break;
+    case 7: /* SEMR */
+        sci->semr = val; break;
+    }
+
+    if (error) {
+        error_report("rsci: unsupported write request to %08lx", addr);
+    }
+}
+
+static uint64_t sci_read(void *opaque, hwaddr addr, unsigned size)
+{
+    hwaddr offset = addr & 0x07;
+    RSCIState *sci = RSCI(opaque);
+    int error = 0;
+    switch (offset) {
+    case 0: /* SMR */
+        return sci->smr;
+    case 1: /* BRR */
+        return sci->brr;
+    case 2: /* SCR */
+        return sci->scr;
+    case 3: /* TDR */
+        return sci->tdr;
+    case 4: /* SSR */
+        sci->read_ssr = sci->ssr;
+        return sci->ssr;
+    case 5: /* RDR */
+        sci->ssr &= ~0x40;
+        return sci->rdr;
+    case 6: /* SCMR */
+        return sci->scmr;
+    case 7: /* SEMR */
+        return sci->semr;
+    }
+
+    if (error) {
+        error_report("rsci: unsupported write request to %08lx", addr);
+    }
+    return -1;
+}
+
+static const MemoryRegionOps sci_ops = {
+    .write = sci_write,
+    .read  = sci_read,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void rsci_reset(DeviceState *dev)
+{
+    RSCIState *sci = RSCI(dev);
+    sci->smr = sci->scr = 0x00;
+    sci->brr = 0xff;
+    sci->tdr = 0xff;
+    sci->rdr = 0x00;
+    sci->ssr = 0x84;
+    sci->scmr = 0x00;
+    sci->semr = 0x00;
+    sci->rx_next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+}
+
+static void sci_event(void *opaque, int event)
+{
+    RSCIState *sci = RSCI(opaque);
+    if (event == CHR_EVENT_BREAK) {
+        sci->ssr |= 0x10;
+        if (sci->scr & 0x40) {
+            qemu_set_irq(sci->irq[ERI], 1);
+        }
+    }
+}
+
+static void rsci_realize(DeviceState *dev, Error **errp)
+{
+    RSCIState *sci = RSCI(dev);
+
+    qemu_chr_fe_set_handlers(&sci->chr, can_receive, receive,
+                             sci_event, NULL, sci, NULL, true);
+}
+
+static void rsci_init(Object *obj)
+{
+    SysBusDevice *d = SYS_BUS_DEVICE(obj);
+    RSCIState *sci = RSCI(obj);
+    int i;
+
+    memory_region_init_io(&sci->memory, OBJECT(sci), &sci_ops,
+                          sci, "renesas-sci", 0x8);
+    sysbus_init_mmio(d, &sci->memory);
+
+    for (i = 0; i < 4; i++) {
+        sysbus_init_irq(d, &sci->irq[i]);
+    }
+    sci->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, txend, sci);
+}
+
+static const VMStateDescription vmstate_rcmt = {
+    .name = "renesas-sci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property rsci_properties[] = {
+    DEFINE_PROP_UINT64("input-freq", RSCIState, input_freq, 0),
+    DEFINE_PROP_CHR("chardev", RSCIState, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rsci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = rsci_realize;
+    dc->props = rsci_properties;
+    dc->vmsd = &vmstate_rcmt;
+    dc->reset = rsci_reset;
+}
+
+static const TypeInfo rsci_info = {
+    .name       = TYPE_RENESAS_SCI,
+    .parent     = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RSCIState),
+    .instance_init = rsci_init,
+    .class_init = rsci_class_init,
+};
+
+static void rsci_register_types(void)
+{
+    type_register_static(&rsci_info);
+}
+
+type_init(rsci_register_types)
diff --git a/include/hw/char/renesas_sci.h b/include/hw/char/renesas_sci.h
new file mode 100644
index 0000000000..47e3e7a5d7
--- /dev/null
+++ b/include/hw/char/renesas_sci.h
@@ -0,0 +1,42 @@
+/*
+ * Renesas Serial Communication Interface
+ *
+ * Copyright (c) 2018 Yoshinori Sato
+ *
+ * This code is licensed under the GPL version 2 or later.
+ *
+ */
+
+#include "chardev/char-fe.h"
+#include "qemu/timer.h"
+#include "hw/sysbus.h"
+
+#define TYPE_RENESAS_SCI "renesas-sci"
+#define RSCI(obj) OBJECT_CHECK(RSCIState, (obj), TYPE_RENESAS_SCI)
+
+#define ERI 0
+#define RXI 1
+#define TXI 2
+#define TEI 3
+
+typedef struct {
+    SysBusDevice parent_obj;
+    MemoryRegion memory;
+
+    uint8_t smr;
+    uint8_t brr;
+    uint8_t scr;
+    uint8_t tdr;
+    uint8_t ssr;
+    uint8_t rdr;
+    uint8_t scmr;
+    uint8_t semr;
+
+    uint8_t read_ssr;
+    long long trtime;
+    long long rx_next;
+    QEMUTimer *timer;
+    CharBackend chr;
+    uint64_t input_freq;
+    qemu_irq irq[4];
+} RSCIState;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH RFC 09/11] RX Target hardware definition.
  2019-01-21 13:15 [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture Yoshinori Sato
                   ` (7 preceding siblings ...)
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 08/11] RX62N internal serical communication interface Yoshinori Sato
@ 2019-01-21 13:16 ` Yoshinori Sato
  2019-01-21 13:16 ` [Qemu-devel] [PATCH RFC 10/11] Add rx-softmmu Yoshinori Sato
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2019-01-21 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yoshinori Sato

rx62n -  RX62N cpu.
rxqemu - QEMU virtual target.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 hw/rx/Makefile.objs   |   1 +
 hw/rx/rx62n.c         | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/rx/rxqemu.c        | 106 +++++++++++++++++++++++
 include/hw/rx/rx.h    |   7 ++
 include/hw/rx/rx62n.h |  45 ++++++++++
 5 files changed, 392 insertions(+)
 create mode 100644 hw/rx/Makefile.objs
 create mode 100644 hw/rx/rx62n.c
 create mode 100644 hw/rx/rxqemu.c
 create mode 100644 include/hw/rx/rx.h
 create mode 100644 include/hw/rx/rx62n.h

diff --git a/hw/rx/Makefile.objs b/hw/rx/Makefile.objs
new file mode 100644
index 0000000000..e2edbb527e
--- /dev/null
+++ b/hw/rx/Makefile.objs
@@ -0,0 +1 @@
+obj-y += rx62n.o rxqemu.o
diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c
new file mode 100644
index 0000000000..c3ab43ba7f
--- /dev/null
+++ b/hw/rx/rx62n.c
@@ -0,0 +1,233 @@
+/*
+ * RX62N device
+ *
+ * Copyright (c) 2019 Yoshinori Sato
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "hw/rx/rx62n.h"
+#include "hw/loader.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "exec/address-spaces.h"
+
+static const int ipr_table[] = {
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 15 */
+    0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0x02,
+    0xff, 0xff, 0xff, 0x03, 0x04, 0x05, 0x06, 0x07, /* 31 */
+    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x14, 0x14, 0x14, /* 47 */
+    0x15, 0x15, 0x15, 0x15, 0xff, 0xff, 0xff, 0xff,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x1d, 0x1e, 0x1f, /* 63 */
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 79 */
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0x3a, 0x3b, 0x3c, 0xff, 0xff, 0xff, /* 95 */
+    0x40, 0xff, 0x44, 0x45, 0xff, 0xff, 0x48, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 111 */
+    0xff, 0xff, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52,
+    0x52, 0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x56, /* 127 */
+    0x56, 0x57, 0x57, 0x57, 0x57, 0x58, 0x59, 0x59,
+    0x59, 0x59, 0x5a, 0x5b, 0x5b, 0x5b, 0x5c, 0x5c, /* 143 */
+    0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f,
+    0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, 0x62, /* 159 */
+    0x62, 0x63, 0x64, 0x64, 0x64, 0x64, 0x65, 0x66,
+    0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, /* 175 */
+    0x68, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6b,
+    0x6b, 0x6b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 191 */
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x71,
+    0x72, 0x73, 0x74, 0x75, 0xff, 0xff, 0xff, 0xff, /* 207 */
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x80,
+    0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, /* 223 */
+    0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0xff, 0xff,
+    0xff, 0xff, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, /* 239 */
+    0x86, 0x86, 0xff, 0xff, 0xff, 0xff, 0x88, 0x89,
+    0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, /* 255 */
+};
+
+static const uint32_t levelirq[] = {
+     16,  21,  32,  44,  47,  48,  51,  64,  65,  66,
+     67,  68,  69,  70,  71,  72,  73,  74,  75,  76,
+     77,  78,  79,  90,  91, 170, 171, 172, 173, 214,
+    217, 218, 221, 222, 225, 226, 229, 234, 237, 238,
+    241, 246, 249, 250, 253,
+};
+
+static RXICUState *register_icu(RX62NState *s)
+{
+    SysBusDevice *icu;
+    int i;
+
+    icu = SYS_BUS_DEVICE(qdev_create(NULL, TYPE_RXICU));
+    sysbus_mmio_map(icu, 0, 0x00087000);
+    qdev_prop_set_string(DEVICE(icu), "icutype", "icua");
+    qdev_prop_set_uint32(DEVICE(icu), "len-ipr-map", 256);
+    for (i = 0; i < 256; i++) {
+        char propname[32];
+        snprintf(propname, sizeof(propname), "ipr-map[%d]", i);
+        qdev_prop_set_uint32(DEVICE(icu), propname, ipr_table[i]);
+    }
+    qdev_prop_set_uint32(DEVICE(icu), "len-trigger-level", 256);
+    for (i = 0; i < ARRAY_SIZE(levelirq); i++) {
+        char propname[32];
+        snprintf(propname, sizeof(propname), "trigger-level[%d]", i);
+        qdev_prop_set_uint32(DEVICE(icu), propname, levelirq[i]);
+    }
+    for (i = 0; i < 256; i++) {
+        s->irq[i] = qdev_get_gpio_in(DEVICE(icu), i);
+    }
+
+    qdev_init_nofail(DEVICE(icu));
+    sysbus_connect_irq(SYS_BUS_DEVICE(icu), 0,
+                       qdev_get_gpio_in(DEVICE(s->cpu), RX_CPU_IRQ));
+    sysbus_connect_irq(SYS_BUS_DEVICE(icu), 1,
+                       qdev_get_gpio_in(DEVICE(s->cpu), RX_CPU_FIR));
+    sysbus_connect_irq(SYS_BUS_DEVICE(icu), 2, s->irq[SWI]);
+
+    return RXICU(icu);
+}
+
+static RTMRState *register_tmr(RX62NState *s, int unit)
+{
+    SysBusDevice *tmr;
+    int i, irqbase;
+
+    tmr = SYS_BUS_DEVICE(qdev_create(NULL, TYPE_RENESAS_TMR));
+    sysbus_mmio_map(tmr, 0, 0x00088200 + unit * 0x10);
+    qdev_prop_set_uint64(DEVICE(tmr), "input-freq", 48000000);
+
+    qdev_init_nofail(DEVICE(tmr));
+    irqbase = 174 + 6 * unit;
+    for (i = 0; i < 6; i++) {
+        sysbus_connect_irq(tmr, i, s->irq[irqbase + i]);
+    }
+
+    return RTMR(tmr);
+}
+
+static RCMTState *register_cmt(RX62NState *s, int unit)
+{
+    SysBusDevice *cmt;
+    int i, irqbase;
+
+    cmt = SYS_BUS_DEVICE(qdev_create(NULL, TYPE_RENESAS_CMT));
+    sysbus_mmio_map(cmt, 0, 0x00088000 + unit * 0x10);
+    qdev_prop_set_uint64(DEVICE(cmt), "input-freq", 48000000);
+
+    qdev_init_nofail(DEVICE(cmt));
+    irqbase = 28 + 2 * unit;
+    for (i = 0; i < 1; i++) {
+        sysbus_connect_irq(cmt, i, s->irq[irqbase + i]);
+    }
+
+    return RCMT(cmt);
+}
+
+static RSCIState *register_sci(RX62NState *s, int unit)
+{
+    SysBusDevice *sci;
+    int i, irqbase;
+
+    sci = SYS_BUS_DEVICE(qdev_create(NULL, TYPE_RENESAS_SCI));
+    qdev_prop_set_chr(DEVICE(sci), "chardev", serial_hd(unit));
+    qdev_prop_set_uint64(DEVICE(sci), "input-freq", 48000000);
+    qdev_init_nofail(DEVICE(sci));
+    sysbus_mmio_map(sci, 0, 0x00088240 + unit * 0x08);
+    irqbase = 214 + 4 * unit;
+    for (i = 0; i < 4; i++) {
+        sysbus_connect_irq(sci, i, s->irq[irqbase + i]);
+    }
+
+    object_property_set_bool(OBJECT(sci), true, "realized", NULL);
+    return RSCI(sci);
+}
+
+static void rx62n_realize(DeviceState *dev, Error **errp)
+{
+    RX62NState *s = RX62N(dev);
+    Error *err = NULL;
+
+    memory_region_init_ram(&s->iram, NULL, "iram", 0x18000, NULL);
+    memory_region_add_subregion(s->sysmem, 0x00000000, &s->iram);
+    memory_region_init_rom(&s->d_flash, NULL, "dataflash", 0x8000, NULL);
+    memory_region_add_subregion(s->sysmem, 0x00100000, &s->d_flash);
+    memory_region_init_rom(&s->c_flash, NULL, "codeflash", 0x80000, NULL);
+    memory_region_add_subregion(s->sysmem, 0xfff80000, &s->c_flash);
+
+    s->cpu = RXCPU(object_new(TYPE_RXCPU));
+
+    if (!s->kernel) {
+        rom_add_file_fixed(bios_name, 0xfff80000, 0);
+    }
+
+    object_property_set_bool(OBJECT(s->cpu), true, "realized", &err);
+    if (err != NULL) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    s->icu = register_icu(s);
+    s->cpu->env.ack = qdev_get_gpio_in_named(DEVICE(s->icu), "ack", 0);
+    s->tmr[0] = register_tmr(s, 0);
+    s->tmr[1] = register_tmr(s, 1);
+    s->cmt[0] = register_cmt(s, 0);
+    s->cmt[1] = register_cmt(s, 1);
+    s->sci[0] = register_sci(s, 0);
+}
+
+static void rx62n_init(Object *obj)
+{
+}
+
+static Property rx62n_properties[] = {
+    DEFINE_PROP_LINK("memory", RX62NState, sysmem, TYPE_MEMORY_REGION,
+                     MemoryRegion *),
+    DEFINE_PROP_BOOL("load-kernel", RX62NState, kernel, false),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rx62n_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = rx62n_realize;
+    dc->props = rx62n_properties;
+}
+
+static const TypeInfo rx62n_info = {
+    .name = TYPE_RX62N,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RX62NState),
+    .instance_init = rx62n_init,
+    .class_init = rx62n_class_init,
+};
+
+static void rx62n_register_types(void)
+{
+    type_register_static(&rx62n_info);
+}
+
+type_init(rx62n_register_types)
diff --git a/hw/rx/rxqemu.c b/hw/rx/rxqemu.c
new file mode 100644
index 0000000000..e52bf37403
--- /dev/null
+++ b/hw/rx/rxqemu.c
@@ -0,0 +1,106 @@
+/*
+ * RX QEMU virtual target
+ *
+ * Copyright (c) 2019 Yoshinori Sato
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/loader.h"
+#include "hw/rx/rx62n.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/qtest.h"
+#include "sysemu/device_tree.h"
+#include "hw/boards.h"
+#include "exec/address-spaces.h"
+#include "exec/cpu-all.h"
+
+static void rxqemu_init(MachineState *machine)
+{
+    DeviceState *cpu;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *sdram = g_new(MemoryRegion, 1);
+    const char *kernel_filename = machine->kernel_filename;
+    const char *dtb_filename = machine->dtb;
+    void *dtb = NULL;
+    int dtb_size;
+
+    /* Allocate memory space */
+    memory_region_init_ram(sdram, NULL, "rxqemu.sdram", 0x01000000,
+                           &error_fatal);
+    memory_region_add_subregion(sysmem, 0x01000000, sdram);
+
+    cpu = qdev_create(NULL, TYPE_RX62N);
+    object_property_set_link(OBJECT(cpu), OBJECT(get_system_memory()),
+                             "memory", &error_abort);
+    object_property_set_bool(OBJECT(cpu), kernel_filename != NULL,
+                             "load-kernel", &error_abort);
+    /* This will exit with an error if the user passed us a bad cpu_type */
+    qdev_init_nofail(cpu);
+
+    if (kernel_filename) {
+        rx_load_image(RXCPU(first_cpu), kernel_filename,
+                      0x01800000, 0x00800000);
+    }
+    if (dtb_filename) {
+        dtb = load_device_tree(dtb_filename, &dtb_size);
+        if (dtb == NULL) {
+            fprintf(stderr, "Couldn't open dtb file %s\n", dtb_filename);
+            exit(1);
+        }
+        if (machine->kernel_cmdline &&
+            qemu_fdt_setprop_string(dtb, "/chosen", "bootargs",
+                                    machine->kernel_cmdline) < 0) {
+            fprintf(stderr, "couldn't set /chosen/bootargs\n");
+            exit(1);
+        }
+        rom_add_blob_fixed("dtb", dtb, dtb_size, 0x02000000 - dtb_size);
+        /* Set dtb address to R1 */
+        RXCPU(first_cpu)->env.regs[1] = 0x02000000 - dtb_size;
+    }
+}
+
+static void rxqemu_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->desc = "RX QEMU Virtual Target";
+    mc->init = rxqemu_init;
+    mc->is_default = 1;
+    mc->default_cpu_type = TYPE_RXCPU;
+}
+
+static const TypeInfo rxqemu_type = {
+    .name = MACHINE_TYPE_NAME("rx-qemu"),
+    .parent = TYPE_MACHINE,
+    .class_init = rxqemu_class_init,
+};
+
+static void rxqemu_machine_init(void)
+{
+    type_register_static(&rxqemu_type);
+}
+
+type_init(rxqemu_machine_init)
diff --git a/include/hw/rx/rx.h b/include/hw/rx/rx.h
new file mode 100644
index 0000000000..ff5924b81f
--- /dev/null
+++ b/include/hw/rx/rx.h
@@ -0,0 +1,7 @@
+#ifndef QEMU_RX_H
+#define QEMU_RX_H
+/* Definitions for RX board emulation.  */
+
+#include "target/rx/cpu-qom.h"
+
+#endif
diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h
new file mode 100644
index 0000000000..dc3f47e1d1
--- /dev/null
+++ b/include/hw/rx/rx62n.h
@@ -0,0 +1,45 @@
+/*
+ * RX62N Object
+ *
+ * Copyright (c) 2018 Yoshinori Sato
+ *
+ * This code is licensed under the GPL version 2 or later.
+ *
+ */
+
+#ifndef HW_RX_RX62N_H
+#define HW_RX_RX62N_H
+
+#include "hw/sysbus.h"
+#include "hw/rx/rx.h"
+#include "hw/intc/rx_icu.h"
+#include "hw/timer/renesas_tmr.h"
+#include "hw/timer/renesas_cmt.h"
+#include "hw/char/renesas_sci.h"
+
+#define TYPE_RX62N "rx62n"
+#define TYPE_RX62N_CPU RX_CPU_TYPE_NAME(TYPE_RX62N)
+#define RX62N(obj) OBJECT_CHECK(RX62NState, (obj), TYPE_RX62N)
+
+typedef struct RX62NState {
+    SysBusDevice parent_obj;
+
+    RXCPU *cpu;
+    RXICUState *icu;
+    RTMRState *tmr[2];
+    RCMTState *cmt[2];
+    RSCIState *sci[6];
+
+    MemoryRegion *sysmem;
+    bool kernel;
+
+    MemoryRegion iram;
+    MemoryRegion iomem1;
+    MemoryRegion d_flash;
+    MemoryRegion iomem2;
+    MemoryRegion iomem3;
+    MemoryRegion c_flash;
+    qemu_irq irq[256];
+} RX62NState;
+
+#endif
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH RFC 10/11] Add rx-softmmu.
  2019-01-21 13:15 [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture Yoshinori Sato
                   ` (8 preceding siblings ...)
  2019-01-21 13:16 ` [Qemu-devel] [PATCH RFC 09/11] RX Target hardware definition Yoshinori Sato
@ 2019-01-21 13:16 ` Yoshinori Sato
  2019-01-21 13:16 ` [Qemu-devel] [PATCH RFC 11/11] MAINTAINERS: Add RX entry Yoshinori Sato
  2019-01-31 17:48 ` [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture no-reply
  11 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2019-01-21 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yoshinori Sato

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 arch_init.c                    | 2 ++
 configure                      | 8 ++++++++
 default-configs/rx-softmmu.mak | 7 +++++++
 include/sysemu/arch_init.h     | 1 +
 target/rx/Makefile.objs        | 2 ++
 5 files changed, 20 insertions(+)
 create mode 100644 default-configs/rx-softmmu.mak
 create mode 100644 target/rx/Makefile.objs

diff --git a/arch_init.c b/arch_init.c
index f4f3f610c8..cc25ddd7ca 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -74,6 +74,8 @@ int graphic_depth = 32;
 #define QEMU_ARCH QEMU_ARCH_PPC
 #elif defined(TARGET_RISCV)
 #define QEMU_ARCH QEMU_ARCH_RISCV
+#elif defined(TARGET_RX)
+#define QEMU_ARCH QEMU_ARCH_RX
 #elif defined(TARGET_S390X)
 #define QEMU_ARCH QEMU_ARCH_S390X
 #elif defined(TARGET_SH4)
diff --git a/configure b/configure
index 12fd34f30b..72d974283c 100755
--- a/configure
+++ b/configure
@@ -7232,6 +7232,11 @@ case "$target_name" in
     mttcg=yes
     target_compiler=$cross_cc_riscv64
   ;;
+  rx)
+    TARGET_ARCH=rx
+    bflt="yes"
+    target_compiler=$cross_cc_rx
+  ;;
   sh4|sh4eb)
     TARGET_ARCH=sh4
     bflt="yes"
@@ -7452,6 +7457,9 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
   riscv*)
     disas_config "RISCV"
   ;;
+  rx)
+    disas_config "RX"
+  ;;
   s390*)
     disas_config "S390"
   ;;
diff --git a/default-configs/rx-softmmu.mak b/default-configs/rx-softmmu.mak
new file mode 100644
index 0000000000..0aaa8d4332
--- /dev/null
+++ b/default-configs/rx-softmmu.mak
@@ -0,0 +1,7 @@
+# Default configuration for rx-softmmu
+
+CONFIG_SERIAL=y
+CONFIG_PTIMER=y
+CONFIG_RX=y
+CONFIG_RENESAS_SCI=y
+CONFIG_RX_DIS=y
diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
index 32abdfe6a1..b05924ec87 100644
--- a/include/sysemu/arch_init.h
+++ b/include/sysemu/arch_init.h
@@ -25,6 +25,7 @@ enum {
     QEMU_ARCH_NIOS2 = (1 << 17),
     QEMU_ARCH_HPPA = (1 << 18),
     QEMU_ARCH_RISCV = (1 << 19),
+    QEMU_ARCH_RX = (1 << 20),
 };
 
 extern const uint32_t arch_type;
diff --git a/target/rx/Makefile.objs b/target/rx/Makefile.objs
new file mode 100644
index 0000000000..147489460f
--- /dev/null
+++ b/target/rx/Makefile.objs
@@ -0,0 +1,2 @@
+obj-y += translate.o op_helper.o helper.o cpu.o gdbstub.o
+obj-$(CONFIG_SOFTMMU) += monitor.o
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH RFC 11/11] MAINTAINERS: Add RX entry.
  2019-01-21 13:15 [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture Yoshinori Sato
                   ` (9 preceding siblings ...)
  2019-01-21 13:16 ` [Qemu-devel] [PATCH RFC 10/11] Add rx-softmmu Yoshinori Sato
@ 2019-01-21 13:16 ` Yoshinori Sato
  2019-01-31 17:48 ` [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture no-reply
  11 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2019-01-21 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yoshinori Sato

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 MAINTAINERS | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index af339b86db..c2aae46ffa 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -272,6 +272,14 @@ F: include/hw/riscv/
 F: linux-user/host/riscv32/
 F: linux-user/host/riscv64/
 
+RX
+M: Yoshinori Sato <ysato@users.sourceforge.jp>
+S: Maintained
+F: target/rx/
+F: hw/rx/
+F: include/hw/rx/
+F: disas/rx.c
+
 S390
 M: Richard Henderson <rth@twiddle.net>
 M: David Hildenbrand <david@redhat.com>
@@ -1071,6 +1079,18 @@ F: pc-bios/canyonlands.dt[sb]
 F: pc-bios/u-boot-sam460ex-20100605.bin
 F: roms/u-boot-sam460ex
 
+RX Machines
+-----------
+RX-QEMU
+M: Yoshinori Sato <ysato@users.sourceforge.jp>
+S: Maintained
+F: hw/rx/rxqemu.c
+F: hw/intc/rx_icu.c
+F: hw/timer/renesas_*.c
+F: hw/char/renesas_sci.c
+F: include/hw/timer/renesas_*.h
+F: include/hw/char/renesas_sci.h
+
 SH4 Machines
 ------------
 R2D
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 01/11] TCG translation
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 01/11] TCG translation Yoshinori Sato
@ 2019-01-21 13:35   ` Thomas Huth
  2019-01-22 10:02     ` Yoshinori Sato
  2019-01-23  3:17   ` Richard Henderson
  1 sibling, 1 reply; 17+ messages in thread
From: Thomas Huth @ 2019-01-21 13:35 UTC (permalink / raw)
  To: Yoshinori Sato, qemu-devel
  Cc: Richard Henderson, Peter Crosthwaite, Paolo Bonzini

On 2019-01-21 14:15, Yoshinori Sato wrote:
> This part only supported RXv1 instructions.
> Instruction manual.
> https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01us0032ej0120_rxsm.pdf
> 
> Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> ---
[...]
> diff --git a/target/rx/op_helper.c b/target/rx/op_helper.c
> new file mode 100644
> index 0000000000..c9c87dc308
> --- /dev/null
> +++ b/target/rx/op_helper.c
> @@ -0,0 +1,548 @@
> +/*
> + *  RX helper functions
> + *
> + *  Copyright (c) 2018 Yoshinori Sato
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.

 Hi,

just a short meta comment for all the new files in your patch series:
It's either

 GNU *Library* General Public License, version 2

or

 GNU Lesser General Public License, version *2.1*

I'd suggest to go with "Lesser" and "2.1".

Apart from that, it might be a good idea to CC: some people who are
familiar with TCG if you want to make sure to get some review (see the
MAINTAINERS file for example).

 Thanks,
  Thomas


PS: Seems like we've got this "Lesser" vs. "Library" wrong in a couple
of other source files in QEMU ... I'll try to come up with a patch to
fix this in the files that we've already got in the repo.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 01/11] TCG translation
  2019-01-21 13:35   ` Thomas Huth
@ 2019-01-22 10:02     ` Yoshinori Sato
  0 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2019-01-22 10:02 UTC (permalink / raw)
  To: Thomas Huth
  Cc: qemu-devel, Paolo Bonzini, Peter Crosthwaite, Richard Henderson

On Mon, 21 Jan 2019 22:35:43 +0900,
Thomas Huth wrote:
> 
> On 2019-01-21 14:15, Yoshinori Sato wrote:
> > This part only supported RXv1 instructions.
> > Instruction manual.
> > https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01us0032ej0120_rxsm.pdf
> > 
> > Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> > ---
> [...]
> > diff --git a/target/rx/op_helper.c b/target/rx/op_helper.c
> > new file mode 100644
> > index 0000000000..c9c87dc308
> > --- /dev/null
> > +++ b/target/rx/op_helper.c
> > @@ -0,0 +1,548 @@
> > +/*
> > + *  RX helper functions
> > + *
> > + *  Copyright (c) 2018 Yoshinori Sato
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2 of the License, or (at your option) any later version.
> 
>  Hi,
> 
> just a short meta comment for all the new files in your patch series:
> It's either
> 
>  GNU *Library* General Public License, version 2
> 
> or
> 
>  GNU Lesser General Public License, version *2.1*
> 
> I'd suggest to go with "Lesser" and "2.1".
> 
> Apart from that, it might be a good idea to CC: some people who are
> familiar with TCG if you want to make sure to get some review (see the
> MAINTAINERS file for example).

Thanks comment.
OK.
I will update the license text and resend it.

>  Thanks,
>   Thomas
> 
> 
> PS: Seems like we've got this "Lesser" vs. "Library" wrong in a couple
> of other source files in QEMU ... I'll try to come up with a patch to
> fix this in the files that we've already got in the repo.
> 

-- 
Yosinori Sato

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 01/11] TCG translation
  2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 01/11] TCG translation Yoshinori Sato
  2019-01-21 13:35   ` Thomas Huth
@ 2019-01-23  3:17   ` Richard Henderson
  2019-01-23 14:34     ` Yoshinori Sato
  1 sibling, 1 reply; 17+ messages in thread
From: Richard Henderson @ 2019-01-23  3:17 UTC (permalink / raw)
  To: Yoshinori Sato, qemu-devel

On 1/21/19 5:15 AM, Yoshinori Sato wrote:
> +/* PSW condition operation */
> +typedef struct {
> +    TCGv op_mode;
> +    TCGv op_a1[13];
> +    TCGv op_a2[13];
> +    TCGv op_r[13];
> +} CCOP;
> +CCOP ccop;

Why does this have different array sizes than cpu.h?

Indeed, why does this have array sizes at all?  I am confused by your method of
flags generation.  This would be improved with comments, at least.  I suspect
that this is overly complicated and should be simplified to a single set of
variables, like target/i386 or target/s390x.

But I wonder if it might be least complicated, at least to start, if you just
explicitly compute each flag, like target/arm.

Note that computation need not be expensive.  Indeed, the Z and S flags can
generally be "computed" with a single move, if we define the representations as
env->psw_z == 0 and env->psw_s < 0.

> +DEF_HELPER_1(raise_illegal_instruction, noreturn, env)
> +DEF_HELPER_1(raise_access_fault, noreturn, env)
> +DEF_HELPER_1(raise_privilege_violation, noreturn, env)
> +DEF_HELPER_1(wait, noreturn, env)
> +DEF_HELPER_1(debug, noreturn, env)
> +DEF_HELPER_2(rxint, noreturn, env, i32)
> +DEF_HELPER_1(rxbrk, noreturn, env)
> +DEF_HELPER_FLAGS_4(floatop, TCG_CALL_NO_WG, f32, env, i32, f32, f32)
> +DEF_HELPER_2(to_fpsw, void, env, i32)
> +DEF_HELPER_FLAGS_2(ftoi, TCG_CALL_NO_WG, i32, env, f32)
> +DEF_HELPER_FLAGS_2(round, TCG_CALL_NO_WG, i32, env, f32)
> +DEF_HELPER_FLAGS_2(itof, TCG_CALL_NO_WG, f32, env, i32)
> +DEF_HELPER_2(racw, void, env, i32)
> +DEF_HELPER_1(update_psw, void, env)
> +DEF_HELPER_1(psw_c, i32, env)
> +DEF_HELPER_1(psw_s, i32, env)
> +DEF_HELPER_1(psw_o, i32, env)
> +DEF_HELPER_3(mvtc, void, env, i32, i32)
> +DEF_HELPER_2(mvfc, i32, env, i32)
> +DEF_HELPER_2(cond, i32, env, i32)
> +DEF_HELPER_1(unpack_psw, void, env)

Should fill in the flags for all of the non-noreturn helpers.

> +static uint32_t psw_z(CPURXState *env)
> +{
> +    int m = (env->op_mode >> 4) & 0x000f;
> +    if (m == RX_PSW_OP_NONE)
> +        return env->psw_z;

./scripts/checkpatch.pl should have given a diagnostic for the lack of braces here.

> +void helper_update_psw(CPURXState *env)
> +{
> +    struct {
> +        uint32_t *p;
> +        uint32_t (*fn)(CPURXState *);
> +    } const update_proc[] = {
> +        {&env->psw_c, psw_c},
> +        {&env->psw_z, psw_z},
> +        {&env->psw_s, psw_s},
> +        {&env->psw_o, psw_o},
> +    };
> +    int i;
> +
> +    for (i = 0; i < 4; i++) {
> +        *(update_proc[i].p) = update_proc[i].fn(env);
> +    }
> +    g_assert((env->op_mode & 0xffff) == 0);
> +}

All of the helpers already update the variables.  This should simplify to

void helper_update_psw(CPURXState *env)
{
  psw_c(env);
  psw_z(env);
  psw_s(env);
  psw_o(env);
  assert(env->op_mode == 0);
}

> +void rx_cpu_pack_psw(CPURXState *env)
> +{
> +    helper_update_psw(env);
> +    env->psw = (
> +        (env->psw_ipl << 24) | (env->psw_pm << 20) |
> +        (env->psw_u << 17) | (env->psw_i << 16) |
> +        (env->psw_o << 3) | (env->psw_s << 2) |
> +        (env->psw_z << 1) | (env->psw_c << 0));
> +}

I recommend this only return a value, and not modify state.  This is
particularly important for debugging, where you would like to examine state
without modifying anything.

> +typedef float32 (*floatfunc)(float32 f1, float32 f2, float_status *st);
> +float32 helper_floatop(CPURXState *env, uint32_t op,
> +                       float32 t0, float32 t1)
> +{
> +    static const floatfunc fop[] = {
> +        float32_sub,
> +        NULL,
> +        float32_add,
> +        float32_mul,
> +        float32_div,
> +    };
> +    int st, xcpt;
> +    if (op != 1) {
> +        t0 = fop[op](t0, t1, &env->fp_status);
> +        update_fpsw(env, GETPC());
> +    } else {

I recommend that you split this into 5 different functions, one for each
arithmetic operator and one for the comparison.

> +        switch (st) {
> +        case float_relation_unordered:
> +            return (float32)0;
> +        case float_relation_equal:
> +            return (float32)1;
> +        case float_relation_less:
> +            return (float32)2;
> +        }
> +    }
> +    return t0;
> +}

The comparison function should return uint32_t instead of values that are
obviously not normal float32 values.

> +void helper_racw(CPURXState *env, uint32_t shift)
> +{
> +    int64_t acc;
> +    acc = env->acc_m;
> +    acc = (acc << 32) | env->acc_l;

I think that acc should be stored as (u)int64_t within env.

> +    acc <<= shift;
> +    acc += 0x0000000080000000LL;
> +    if (acc > 0x00007FFF00000000LL) {
> +        acc = 0x00007FFF00000000LL;
> +    } else if (acc < 0xFFFF800000000000LL) {

If you want a signed type, use a signed value: -0x800000000000LL.

> +    psw = rx_get_psw_low(env);
> +    psw |= (env->psw_ipl << 24) | (env->psw_pm << 20) |
> +        (env->psw_u << 17) | (env->psw_i << 16);

I think you should use your regular "get everything" helper.

> +static void rx_gen_ldst(int size, int dir, TCGv reg, TCGv mem)
> +{
> +    static void (* const rw[])(TCGv ret, TCGv addr, int idx) = {
> +        tcg_gen_qemu_st8, tcg_gen_qemu_ld8s,
> +        tcg_gen_qemu_st16, tcg_gen_qemu_ld16s,
> +        tcg_gen_qemu_st32, tcg_gen_qemu_ld32s,
> +    };
> +    rw[size * 2 + dir](reg, mem, 0);
> +}

Use tcg_gen_qemu_ld_i32 and tcg_gen_qemu_st_i32 instead:

    if (dir) {
        tcg_gen_qemu_ld_i32(reg, mem, 0, size | MO_SIGN | MO_TE);
    } else {
        tcg_gen_qemu_st_i32(reg, mem, 0, size | MO_TE);
    }

> +DEFINE_INSN(mov1_2)
> +{
> +    TCGv mem;
> +    int r1, r2, dsp, dir, sz;
> +
> +    insn >>= 16;
> +    sz = (insn >> 12) & 3;
> +    dsp = ((insn >> 6) & 0x1e) | ((insn >> 3) & 1);
> +    dsp <<= sz;
> +    r2 = insn & 7;
> +    r1 = (insn >> 4) & 7;
> +    dir = (insn >> 11) & 1;
> +
> +    mem = tcg_temp_local_new();
> +    tcg_gen_addi_i32(mem, cpu_regs[r1], dsp);
> +    rx_gen_ldst(sz, dir, cpu_regs[r2], mem);
> +    tcg_temp_free(mem);
> +    dc->pc += 2;
> +}

Do not use tcg_temp_local_new() unless you need it to hold a value across a
branch or label.  Use tcg_temp_new() instead.

Likewise with tcg_const_local.

> +static void rx_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
> +{
> +    CPURXState *env = cs->env_ptr;
> +    DisasContext *dc = container_of(dcbase, DisasContext, base);
> +    uint32_t insn = 0;
> +    int i;
> +
> +    for (i = 0; i < 4; i++) {
> +        insn <<= 8;
> +        insn |= cpu_ldub_code(env, dc->base.pc_next + i);
> +    }

You're reading 4 bytes when the insn may be only 1-2 bytes long?
This could fail if a branch insn is placed near the end of memory.

I wish Renesas has published a consolidated opcode map, because it is very hard
to compare your decoding to the manual.  I am tempted to try to extend
./scripts/decodetree.py to handle variable width instruction sets to see if we
can make this process easier.


r~

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 01/11] TCG translation
  2019-01-23  3:17   ` Richard Henderson
@ 2019-01-23 14:34     ` Yoshinori Sato
  0 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2019-01-23 14:34 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Wed, 23 Jan 2019 12:17:46 +0900,
Richard Henderson wrote:
> 
> On 1/21/19 5:15 AM, Yoshinori Sato wrote:
> > +/* PSW condition operation */
> > +typedef struct {
> > +    TCGv op_mode;
> > +    TCGv op_a1[13];
> > +    TCGv op_a2[13];
> > +    TCGv op_r[13];
> > +} CCOP;
> > +CCOP ccop;
> 
> Why does this have different array sizes than cpu.h?

It array not use first one.
Bt it confused. I will fix same size.

> Indeed, why does this have array sizes at all?  I am confused by your method of
> flags generation.  This would be improved with comments, at least.  I suspect
> that this is overly complicated and should be simplified to a single set of
> variables, like target/i386 or target/s390x.
> 
> But I wonder if it might be least complicated, at least to start, if you just
> explicitly compute each flag, like target/arm.
> 
> Note that computation need not be expensive.  Indeed, the Z and S flags can
> generally be "computed" with a single move, if we define the representations as
> env->psw_z == 0 and env->psw_s < 0.

Since there are instructions that only change specific flags,
so need to manage the status of each flag individually.
I will consider a simpler method.

> > +DEF_HELPER_1(raise_illegal_instruction, noreturn, env)
> > +DEF_HELPER_1(raise_access_fault, noreturn, env)
> > +DEF_HELPER_1(raise_privilege_violation, noreturn, env)
> > +DEF_HELPER_1(wait, noreturn, env)
> > +DEF_HELPER_1(debug, noreturn, env)
> > +DEF_HELPER_2(rxint, noreturn, env, i32)
> > +DEF_HELPER_1(rxbrk, noreturn, env)
> > +DEF_HELPER_FLAGS_4(floatop, TCG_CALL_NO_WG, f32, env, i32, f32, f32)
> > +DEF_HELPER_2(to_fpsw, void, env, i32)
> > +DEF_HELPER_FLAGS_2(ftoi, TCG_CALL_NO_WG, i32, env, f32)
> > +DEF_HELPER_FLAGS_2(round, TCG_CALL_NO_WG, i32, env, f32)
> > +DEF_HELPER_FLAGS_2(itof, TCG_CALL_NO_WG, f32, env, i32)
> > +DEF_HELPER_2(racw, void, env, i32)
> > +DEF_HELPER_1(update_psw, void, env)
> > +DEF_HELPER_1(psw_c, i32, env)
> > +DEF_HELPER_1(psw_s, i32, env)
> > +DEF_HELPER_1(psw_o, i32, env)
> > +DEF_HELPER_3(mvtc, void, env, i32, i32)
> > +DEF_HELPER_2(mvfc, i32, env, i32)
> > +DEF_HELPER_2(cond, i32, env, i32)
> > +DEF_HELPER_1(unpack_psw, void, env)
> 
> Should fill in the flags for all of the non-noreturn helpers.

OK

> > +static uint32_t psw_z(CPURXState *env)
> > +{
> > +    int m = (env->op_mode >> 4) & 0x000f;
> > +    if (m == RX_PSW_OP_NONE)
> > +        return env->psw_z;
> 
> ./scripts/checkpatch.pl should have given a diagnostic for the lack of braces here.

OK.
It seems I overlooked it.

> > +void helper_update_psw(CPURXState *env)
> > +{
> > +    struct {
> > +        uint32_t *p;
> > +        uint32_t (*fn)(CPURXState *);
> > +    } const update_proc[] = {
> > +        {&env->psw_c, psw_c},
> > +        {&env->psw_z, psw_z},
> > +        {&env->psw_s, psw_s},
> > +        {&env->psw_o, psw_o},
> > +    };
> > +    int i;
> > +
> > +    for (i = 0; i < 4; i++) {
> > +        *(update_proc[i].p) = update_proc[i].fn(env);
> > +    }
> > +    g_assert((env->op_mode & 0xffff) == 0);
> > +}
> 
> All of the helpers already update the variables.  This should simplify to
> 
> void helper_update_psw(CPURXState *env)
> {
>   psw_c(env);
>   psw_z(env);
>   psw_s(env);
>   psw_o(env);
>   assert(env->op_mode == 0);
> }
> 
> > +void rx_cpu_pack_psw(CPURXState *env)
> > +{
> > +    helper_update_psw(env);
> > +    env->psw = (
> > +        (env->psw_ipl << 24) | (env->psw_pm << 20) |
> > +        (env->psw_u << 17) | (env->psw_i << 16) |
> > +        (env->psw_o << 3) | (env->psw_s << 2) |
> > +        (env->psw_z << 1) | (env->psw_c << 0));
> > +}
> 
> I recommend this only return a value, and not modify state.  This is
> particularly important for debugging, where you would like to examine state
> without modifying anything.

OK.

> > +typedef float32 (*floatfunc)(float32 f1, float32 f2, float_status *st);
> > +float32 helper_floatop(CPURXState *env, uint32_t op,
> > +                       float32 t0, float32 t1)
> > +{
> > +    static const floatfunc fop[] = {
> > +        float32_sub,
> > +        NULL,
> > +        float32_add,
> > +        float32_mul,
> > +        float32_div,
> > +    };
> > +    int st, xcpt;
> > +    if (op != 1) {
> > +        t0 = fop[op](t0, t1, &env->fp_status);
> > +        update_fpsw(env, GETPC());
> > +    } else {
> 
> I recommend that you split this into 5 different functions, one for each
> arithmetic operator and one for the comparison.

OK.

> > +        switch (st) {
> > +        case float_relation_unordered:
> > +            return (float32)0;
> > +        case float_relation_equal:
> > +            return (float32)1;
> > +        case float_relation_less:
> > +            return (float32)2;
> > +        }
> > +    }
> > +    return t0;
> > +}
> 
> The comparison function should return uint32_t instead of values that are
> obviously not normal float32 values.

OK.

> > +void helper_racw(CPURXState *env, uint32_t shift)
> > +{
> > +    int64_t acc;
> > +    acc = env->acc_m;
> > +    acc = (acc << 32) | env->acc_l;
> 
> I think that acc should be stored as (u)int64_t within env.

OK.
The new instruction set will be 72 bits here,
so I will consider a bit more.

> > +    acc <<= shift;
> > +    acc += 0x0000000080000000LL;
> > +    if (acc > 0x00007FFF00000000LL) {
> > +        acc = 0x00007FFF00000000LL;
> > +    } else if (acc < 0xFFFF800000000000LL) {
> 
> If you want a signed type, use a signed value: -0x800000000000LL.
> 
> > +    psw = rx_get_psw_low(env);
> > +    psw |= (env->psw_ipl << 24) | (env->psw_pm << 20) |
> > +        (env->psw_u << 17) | (env->psw_i << 16);
> 
> I think you should use your regular "get everything" helper.

OK.

> > +static void rx_gen_ldst(int size, int dir, TCGv reg, TCGv mem)
> > +{
> > +    static void (* const rw[])(TCGv ret, TCGv addr, int idx) = {
> > +        tcg_gen_qemu_st8, tcg_gen_qemu_ld8s,
> > +        tcg_gen_qemu_st16, tcg_gen_qemu_ld16s,
> > +        tcg_gen_qemu_st32, tcg_gen_qemu_ld32s,
> > +    };
> > +    rw[size * 2 + dir](reg, mem, 0);
> > +}
> 
> Use tcg_gen_qemu_ld_i32 and tcg_gen_qemu_st_i32 instead:

OK.

>     if (dir) {
>         tcg_gen_qemu_ld_i32(reg, mem, 0, size | MO_SIGN | MO_TE);
>     } else {
>         tcg_gen_qemu_st_i32(reg, mem, 0, size | MO_TE);
>     }
> 
> > +DEFINE_INSN(mov1_2)
> > +{
> > +    TCGv mem;
> > +    int r1, r2, dsp, dir, sz;
> > +
> > +    insn >>= 16;
> > +    sz = (insn >> 12) & 3;
> > +    dsp = ((insn >> 6) & 0x1e) | ((insn >> 3) & 1);
> > +    dsp <<= sz;
> > +    r2 = insn & 7;
> > +    r1 = (insn >> 4) & 7;
> > +    dir = (insn >> 11) & 1;
> > +
> > +    mem = tcg_temp_local_new();
> > +    tcg_gen_addi_i32(mem, cpu_regs[r1], dsp);
> > +    rx_gen_ldst(sz, dir, cpu_regs[r2], mem);
> > +    tcg_temp_free(mem);
> > +    dc->pc += 2;
> > +}
> 
> Do not use tcg_temp_local_new() unless you need it to hold a value across a
> branch or label.  Use tcg_temp_new() instead.
> 
> Likewise with tcg_const_local.

OK.

> > +static void rx_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
> > +{
> > +    CPURXState *env = cs->env_ptr;
> > +    DisasContext *dc = container_of(dcbase, DisasContext, base);
> > +    uint32_t insn = 0;
> > +    int i;
> > +
> > +    for (i = 0; i < 4; i++) {
> > +        insn <<= 8;
> > +        insn |= cpu_ldub_code(env, dc->base.pc_next + i);
> > +    }
> 
> You're reading 4 bytes when the insn may be only 1-2 bytes long?
> This could fail if a branch insn is placed near the end of memory.

OK.
Since most instructions are less than 4 bytes, they are acquired at once.
I did not assume the case of the memory boundary,
but since there is a problem, I fix it.

> I wish Renesas has published a consolidated opcode map, because it is very hard
> to compare your decoding to the manual.  I am tempted to try to extend
> ./scripts/decodetree.py to handle variable width instruction sets to see if we
> can make this process easier.

Yes. This CPU opode very complex.
I also try decodetree.py.

> 
> r~

Your comment was very helpful.
Thank you.

-- 
Yosinori Sato

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture
  2019-01-21 13:15 [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture Yoshinori Sato
                   ` (10 preceding siblings ...)
  2019-01-21 13:16 ` [Qemu-devel] [PATCH RFC 11/11] MAINTAINERS: Add RX entry Yoshinori Sato
@ 2019-01-31 17:48 ` no-reply
  11 siblings, 0 replies; 17+ messages in thread
From: no-reply @ 2019-01-31 17:48 UTC (permalink / raw)
  To: ysato; +Cc: fam, qemu-devel

Patchew URL: https://patchew.org/QEMU/20190121131602.55003-1-ysato@users.sourceforge.jp/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Subject: [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture
Type: series
Message-id: 20190121131602.55003-1-ysato@users.sourceforge.jp

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
a739c452f4 MAINTAINERS: Add RX entry.
3778b84308 Add rx-softmmu.
9b35f3e02a RX Target hardware definition.
d098f8610b RX62N internal serical communication interface.
d1fda562b0 RX62N internal timer unit.
58ae337613 RX62N interrupt contoller.
9cb21f3ffd RX disassembler
ce17708f0b Target miscellaneous functions.
276096a543 TCG helper functions
02c37e53dc RX CPU definition
228562c3da TCG translation

=== OUTPUT BEGIN ===
1/11 Checking commit 228562c3dabd (TCG translation)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#15: 
new file mode 100644

ERROR: space prohibited between function name and open parenthesis '('
#408: FILE: target/rx/op_helper.c:361:
+typedef float32 (*floatfunc)(float32 f1, float32 f2, float_status *st);

ERROR: spaces required around that '*' (ctx:WxV)
#408: FILE: target/rx/op_helper.c:361:
+typedef float32 (*floatfunc)(float32 f1, float32 f2, float_status *st);
                                                                   ^

total: 2 errors, 1 warnings, 3573 lines checked

Patch 1/11 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

2/11 Checking commit 02c37e53dcae (RX CPU definition)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#11: 
new file mode 100644

total: 0 errors, 1 warnings, 492 lines checked

Patch 2/11 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
3/11 Checking commit 276096a543bc (TCG helper functions)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#11: 
new file mode 100644

total: 0 errors, 1 warnings, 143 lines checked

Patch 3/11 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
4/11 Checking commit ce17708f0bed (Target miscellaneous functions.)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#11: 
new file mode 100644

total: 0 errors, 1 warnings, 152 lines checked

Patch 4/11 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
5/11 Checking commit 9cb21f3ffddb (RX disassembler)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#25: 
new file mode 100644

ERROR: Macros with complex values should be enclosed in parenthesis
#1067: FILE: disas/rx.c:1038:
+#define prt(...) dis->fprintf_func(dis->stream, __VA_ARGS__)

ERROR: space prohibited between function name and open parenthesis '('
#1326: FILE: include/disas/bfd.h:439:
+int print_insn_rx               (bfd_vma, disassemble_info*);

total: 2 errors, 1 warnings, 1301 lines checked

Patch 5/11 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

6/11 Checking commit 58ae3376133f (RX62N interrupt contoller.)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#24: 
new file mode 100644

total: 0 errors, 1 warnings, 366 lines checked

Patch 6/11 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
7/11 Checking commit d1fda562b065 (RX62N internal timer unit.)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#30: 
new file mode 100644

ERROR: return is not a function, parentheses are not required
#375: FILE: hw/timer/renesas_tmr.c:109:
+        return (tmr->tcnt[0] << 8) | (tmr->tcnt[1] & 0xff);

total: 1 errors, 1 warnings, 710 lines checked

Patch 7/11 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

8/11 Checking commit d098f8610bf1 (RX62N internal serical communication interface.)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#28: 
new file mode 100644

total: 0 errors, 1 warnings, 329 lines checked

Patch 8/11 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
9/11 Checking commit 9b35f3e02a44 (RX Target hardware definition.)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#14: 
new file mode 100644

total: 0 errors, 1 warnings, 392 lines checked

Patch 9/11 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
10/11 Checking commit 3778b8430851 (Add rx-softmmu.)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#50: 
new file mode 100644

total: 0 errors, 1 warnings, 44 lines checked

Patch 10/11 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
11/11 Checking commit a739c452f473 (MAINTAINERS: Add RX entry.)
=== OUTPUT END ===

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/20190121131602.55003-1-ysato@users.sourceforge.jp/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2019-01-31 17:49 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-21 13:15 [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture Yoshinori Sato
2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 01/11] TCG translation Yoshinori Sato
2019-01-21 13:35   ` Thomas Huth
2019-01-22 10:02     ` Yoshinori Sato
2019-01-23  3:17   ` Richard Henderson
2019-01-23 14:34     ` Yoshinori Sato
2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 02/11] RX CPU definition Yoshinori Sato
2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 03/11] TCG helper functions Yoshinori Sato
2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 04/11] Target miscellaneous functions Yoshinori Sato
2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 05/11] RX disassembler Yoshinori Sato
2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 06/11] RX62N interrupt contoller Yoshinori Sato
2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 07/11] RX62N internal timer unit Yoshinori Sato
2019-01-21 13:15 ` [Qemu-devel] [PATCH RFC 08/11] RX62N internal serical communication interface Yoshinori Sato
2019-01-21 13:16 ` [Qemu-devel] [PATCH RFC 09/11] RX Target hardware definition Yoshinori Sato
2019-01-21 13:16 ` [Qemu-devel] [PATCH RFC 10/11] Add rx-softmmu Yoshinori Sato
2019-01-21 13:16 ` [Qemu-devel] [PATCH RFC 11/11] MAINTAINERS: Add RX entry Yoshinori Sato
2019-01-31 17:48 ` [Qemu-devel] [PATCH RFC 00/11] Add Renesas RX archtecture no-reply

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.