From patchwork Mon Jan 21 13:15:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 10773871 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2479A1515 for ; Mon, 21 Jan 2019 13:25:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 071CE2844B for ; Mon, 21 Jan 2019 13:25:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EEF8829C68; Mon, 21 Jan 2019 13:25:40 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 55A8E2844B for ; Mon, 21 Jan 2019 13:25:36 +0000 (UTC) Received: from localhost ([127.0.0.1]:53730 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZa3-0005av-Fk for patchwork-qemu-devel@patchwork.kernel.org; Mon, 21 Jan 2019 08:25:35 -0500 Received: from eggs.gnu.org ([209.51.188.92]:45261) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRf-0006jt-02 for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:17:02 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1glZRT-0004JG-2s for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:54 -0500 Received: from mail03.asahi-net.or.jp ([202.224.55.15]:42032) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRQ-000437-UG for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:42 -0500 Received: from h61-195-96-97.vps.ablenet.jp (h61-195-96-97.vps.ablenet.jp [61.195.96.97]) (Authenticated sender: PQ4Y-STU) by mail03.asahi-net.or.jp (Postfix) with ESMTPA id AA0EC238B5; Mon, 21 Jan 2019 22:16:15 +0900 (JST) Received: from ysato.dip.jp (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by h61-195-96-97.vps.ablenet.jp (Postfix) with ESMTPSA id D60DF24008A; Mon, 21 Jan 2019 22:16:14 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Date: Mon, 21 Jan 2019 22:15:52 +0900 Message-Id: <20190121131602.55003-2-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190121131602.55003-1-ysato@users.sourceforge.jp> References: <20190121131602.55003-1-ysato@users.sourceforge.jp> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.224.55.15 Subject: [Qemu-devel] [PATCH RFC 01/11] TCG translation X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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 . + */ + +#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 . + */ + +#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; + } + } + } +} From patchwork Mon Jan 21 13:15:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 10773867 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 545241390 for ; Mon, 21 Jan 2019 13:24:48 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 400052844B for ; Mon, 21 Jan 2019 13:24:48 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3385A29B6F; Mon, 21 Jan 2019 13:24:48 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 2B8BB2844B for ; Mon, 21 Jan 2019 13:24:47 +0000 (UTC) Received: from localhost ([127.0.0.1]:53694 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZZG-0004vA-CD for patchwork-qemu-devel@patchwork.kernel.org; Mon, 21 Jan 2019 08:24:46 -0500 Received: from eggs.gnu.org ([209.51.188.92]:45194) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRY-0006ff-3w for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:52 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1glZRT-0004J4-0z for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:48 -0500 Received: from mail02.asahi-net.or.jp ([202.224.55.14]:54416) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRQ-000439-P3 for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:42 -0500 Received: from h61-195-96-97.vps.ablenet.jp (h61-195-96-97.vps.ablenet.jp [61.195.96.97]) (Authenticated sender: PQ4Y-STU) by mail02.asahi-net.or.jp (Postfix) with ESMTPA id AEA4A20836; Mon, 21 Jan 2019 22:16:15 +0900 (JST) Received: from ysato.dip.jp (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by h61-195-96-97.vps.ablenet.jp (Postfix) with ESMTPSA id 4292D24008B; Mon, 21 Jan 2019 22:16:15 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Date: Mon, 21 Jan 2019 22:15:53 +0900 Message-Id: <20190121131602.55003-3-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190121131602.55003-1-ysato@users.sourceforge.jp> References: <20190121131602.55003-1-ysato@users.sourceforge.jp> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.224.55.14 Subject: [Qemu-devel] [PATCH RFC 02/11] RX CPU definition X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Yoshinori Sato --- 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 + * + */ + +#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 + * + */ + +#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 . + */ + +#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 */ From patchwork Mon Jan 21 13:15:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 10773847 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E22FD91E for ; Mon, 21 Jan 2019 13:18:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C6C2A285DA for ; Mon, 21 Jan 2019 13:18:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B91B229865; Mon, 21 Jan 2019 13:18:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 34468285DA for ; Mon, 21 Jan 2019 13:18:39 +0000 (UTC) Received: from localhost ([127.0.0.1]:53610 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZTK-0007s5-Dd for patchwork-qemu-devel@patchwork.kernel.org; Mon, 21 Jan 2019 08:18:38 -0500 Received: from eggs.gnu.org ([209.51.188.92]:45055) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRS-0006dl-Te for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:46 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1glZRQ-0004Gs-O3 for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:42 -0500 Received: from mail03.asahi-net.or.jp ([202.224.55.15]:42034) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRK-00043D-NG for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:36 -0500 Received: from h61-195-96-97.vps.ablenet.jp (h61-195-96-97.vps.ablenet.jp [61.195.96.97]) (Authenticated sender: PQ4Y-STU) by mail03.asahi-net.or.jp (Postfix) with ESMTPA id 2334B2395B; Mon, 21 Jan 2019 22:16:16 +0900 (JST) Received: from ysato.dip.jp (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by h61-195-96-97.vps.ablenet.jp (Postfix) with ESMTPSA id 80E6524008C; Mon, 21 Jan 2019 22:16:15 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Date: Mon, 21 Jan 2019 22:15:54 +0900 Message-Id: <20190121131602.55003-4-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190121131602.55003-1-ysato@users.sourceforge.jp> References: <20190121131602.55003-1-ysato@users.sourceforge.jp> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.224.55.15 Subject: [Qemu-devel] [PATCH RFC 03/11] TCG helper functions X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Yoshinori Sato --- 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 . + */ + +#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; +} From patchwork Mon Jan 21 13:15:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 10773861 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8C3AF1515 for ; Mon, 21 Jan 2019 13:23:01 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7D5EF2A082 for ; Mon, 21 Jan 2019 13:23:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7B7602A086; Mon, 21 Jan 2019 13:23:01 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 570D02A088 for ; Mon, 21 Jan 2019 13:22:59 +0000 (UTC) Received: from localhost ([127.0.0.1]:53674 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZXW-00035E-Iq for patchwork-qemu-devel@patchwork.kernel.org; Mon, 21 Jan 2019 08:22:58 -0500 Received: from eggs.gnu.org ([209.51.188.92]:45142) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRV-0006eL-7B for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1glZRT-0004JC-07 for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:45 -0500 Received: from mail02.asahi-net.or.jp ([202.224.55.14]:54418) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRQ-00043E-Sa for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:42 -0500 Received: from h61-195-96-97.vps.ablenet.jp (h61-195-96-97.vps.ablenet.jp [61.195.96.97]) (Authenticated sender: PQ4Y-STU) by mail02.asahi-net.or.jp (Postfix) with ESMTPA id 249F72086F; Mon, 21 Jan 2019 22:16:16 +0900 (JST) Received: from ysato.dip.jp (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by h61-195-96-97.vps.ablenet.jp (Postfix) with ESMTPSA id BABF2240084; Mon, 21 Jan 2019 22:16:15 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Date: Mon, 21 Jan 2019 22:15:55 +0900 Message-Id: <20190121131602.55003-5-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190121131602.55003-1-ysato@users.sourceforge.jp> References: <20190121131602.55003-1-ysato@users.sourceforge.jp> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.224.55.14 Subject: [Qemu-devel] [PATCH RFC 04/11] Target miscellaneous functions. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Yoshinori Sato --- 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 . + */ +#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; + } +} From patchwork Mon Jan 21 13:15:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 10773851 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 27E9A91E for ; Mon, 21 Jan 2019 13:18:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 12990284DC for ; Mon, 21 Jan 2019 13:18:47 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 06AC12985B; Mon, 21 Jan 2019 13:18:47 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 0C0BD284DC for ; Mon, 21 Jan 2019 13:18:45 +0000 (UTC) Received: from localhost ([127.0.0.1]:53614 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZTQ-0007vL-6r for patchwork-qemu-devel@patchwork.kernel.org; Mon, 21 Jan 2019 08:18:44 -0500 Received: from eggs.gnu.org ([209.51.188.92]:45022) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRQ-0006d9-OC for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:46 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1glZRK-0004EB-Qd for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:39 -0500 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:35847) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRK-00043F-Bm for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:34 -0500 Received: from h61-195-96-97.vps.ablenet.jp (h61-195-96-97.vps.ablenet.jp [61.195.96.97]) (Authenticated sender: PQ4Y-STU) by mail01.asahi-net.or.jp (Postfix) with ESMTPA id 5841810179D; Mon, 21 Jan 2019 22:16:16 +0900 (JST) Received: from ysato.dip.jp (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by h61-195-96-97.vps.ablenet.jp (Postfix) with ESMTPSA id 036E624008A; Mon, 21 Jan 2019 22:16:15 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Date: Mon, 21 Jan 2019 22:15:56 +0900 Message-Id: <20190121131602.55003-6-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190121131602.55003-1-ysato@users.sourceforge.jp> References: <20190121131602.55003-1-ysato@users.sourceforge.jp> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.224.55.13 Subject: [Qemu-devel] [PATCH RFC 05/11] RX disassembler X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP It only supported RXv1 instructions. Signed-off-by: Yoshinori Sato --- 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 + * + * 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 . + */ + +#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", "", "", +}; + +static const char size[] = { 'b', 'w', 'l', '?' }; + +static const char *creg_name[] = { + "psw", "pc", "usp", "fpsw", "", "", "", "", + "bpsw", "bpc", "isp", "fintv", "intb", "", "", "", +}; + +static const char *psw_bit[] = { + "c", "s", "z", "o", "", "", "", "", + "i", "u", "", "", "", "", "", "", +}; + +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. */ From patchwork Mon Jan 21 13:15:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 10773869 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 189DF1515 for ; Mon, 21 Jan 2019 13:24:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 05B052844B for ; Mon, 21 Jan 2019 13:24:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EB1A429B6F; Mon, 21 Jan 2019 13:24:55 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 294052844B for ; Mon, 21 Jan 2019 13:24:55 +0000 (UTC) Received: from localhost ([127.0.0.1]:53697 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZZO-000506-Cl for patchwork-qemu-devel@patchwork.kernel.org; Mon, 21 Jan 2019 08:24:54 -0500 Received: from eggs.gnu.org ([209.51.188.92]:45155) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRW-0006eN-05 for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:52 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1glZRS-0004Ix-W7 for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:45 -0500 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:35849) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRR-00043Q-0i for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:42 -0500 Received: from h61-195-96-97.vps.ablenet.jp (h61-195-96-97.vps.ablenet.jp [61.195.96.97]) (Authenticated sender: PQ4Y-STU) by mail01.asahi-net.or.jp (Postfix) with ESMTPA id 962BE101A74; Mon, 21 Jan 2019 22:16:16 +0900 (JST) Received: from ysato.dip.jp (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by h61-195-96-97.vps.ablenet.jp (Postfix) with ESMTPSA id 55507240084; Mon, 21 Jan 2019 22:16:16 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Date: Mon, 21 Jan 2019 22:15:57 +0900 Message-Id: <20190121131602.55003-7-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190121131602.55003-1-ysato@users.sourceforge.jp> References: <20190121131602.55003-1-ysato@users.sourceforge.jp> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.224.55.13 Subject: [Qemu-devel] [PATCH RFC 06/11] RX62N interrupt contoller. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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 */ From patchwork Mon Jan 21 13:15:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 10773873 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 61B991390 for ; Mon, 21 Jan 2019 13:26:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4E23229B6F for ; Mon, 21 Jan 2019 13:26:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 428EE29C68; Mon, 21 Jan 2019 13:26:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 0815D2A058 for ; Mon, 21 Jan 2019 13:25:58 +0000 (UTC) Received: from localhost ([127.0.0.1]:53692 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZaQ-0004bW-6J for patchwork-qemu-devel@patchwork.kernel.org; Mon, 21 Jan 2019 08:25:58 -0500 Received: from eggs.gnu.org ([209.51.188.92]:45075) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRT-0006e0-8U for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1glZRQ-0004HK-Pu for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:43 -0500 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:35851) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRK-00043c-Nk for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:38 -0500 Received: from h61-195-96-97.vps.ablenet.jp (h61-195-96-97.vps.ablenet.jp [61.195.96.97]) (Authenticated sender: PQ4Y-STU) by mail01.asahi-net.or.jp (Postfix) with ESMTPA id 05F8610320E; Mon, 21 Jan 2019 22:16:17 +0900 (JST) Received: from ysato.dip.jp (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by h61-195-96-97.vps.ablenet.jp (Postfix) with ESMTPSA id 8F6DA24008A; Mon, 21 Jan 2019 22:16:16 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Date: Mon, 21 Jan 2019 22:15:58 +0900 Message-Id: <20190121131602.55003-8-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190121131602.55003-1-ysato@users.sourceforge.jp> References: <20190121131602.55003-1-ysato@users.sourceforge.jp> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.224.55.13 Subject: [Qemu-devel] [PATCH RFC 07/11] RX62N internal timer unit. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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 From patchwork Mon Jan 21 13:15:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 10773853 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EDDF91390 for ; Mon, 21 Jan 2019 13:19:16 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DAA3929E0D for ; Mon, 21 Jan 2019 13:19:16 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CF2A529E12; Mon, 21 Jan 2019 13:19:16 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 1880129E0D for ; Mon, 21 Jan 2019 13:19:16 +0000 (UTC) Received: from localhost ([127.0.0.1]:53616 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZTv-0008Qw-81 for patchwork-qemu-devel@patchwork.kernel.org; Mon, 21 Jan 2019 08:19:15 -0500 Received: from eggs.gnu.org ([209.51.188.92]:45188) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRX-0006fa-UX for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:51 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1glZRT-0004Jx-FP for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:47 -0500 Received: from mail02.asahi-net.or.jp ([202.224.55.14]:54419) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRT-00043r-4K for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:43 -0500 Received: from h61-195-96-97.vps.ablenet.jp (h61-195-96-97.vps.ablenet.jp [61.195.96.97]) (Authenticated sender: PQ4Y-STU) by mail02.asahi-net.or.jp (Postfix) with ESMTPA id 7FB8220887; Mon, 21 Jan 2019 22:16:17 +0900 (JST) Received: from ysato.dip.jp (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by h61-195-96-97.vps.ablenet.jp (Postfix) with ESMTPSA id 2E9E1240084; Mon, 21 Jan 2019 22:16:17 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Date: Mon, 21 Jan 2019 22:15:59 +0900 Message-Id: <20190121131602.55003-9-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190121131602.55003-1-ysato@users.sourceforge.jp> References: <20190121131602.55003-1-ysato@users.sourceforge.jp> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.224.55.14 Subject: [Qemu-devel] [PATCH RFC 08/11] RX62N internal serical communication interface. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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; From patchwork Mon Jan 21 13:16:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 10773859 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 03E4C1390 for ; Mon, 21 Jan 2019 13:22:21 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E58832A06A for ; Mon, 21 Jan 2019 13:22:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E0AA02A063; Mon, 21 Jan 2019 13:22:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id CA2F32A05C for ; Mon, 21 Jan 2019 13:22:19 +0000 (UTC) Received: from localhost ([127.0.0.1]:53672 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZWs-0002ca-VW for patchwork-qemu-devel@patchwork.kernel.org; Mon, 21 Jan 2019 08:22:19 -0500 Received: from eggs.gnu.org ([209.51.188.92]:45221) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRZ-0006gV-J3 for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:51 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1glZRT-0004KH-KJ for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:49 -0500 Received: from mail02.asahi-net.or.jp ([202.224.55.14]:54421) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRT-000440-3o for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:43 -0500 Received: from h61-195-96-97.vps.ablenet.jp (h61-195-96-97.vps.ablenet.jp [61.195.96.97]) (Authenticated sender: PQ4Y-STU) by mail02.asahi-net.or.jp (Postfix) with ESMTPA id B964A2089A; Mon, 21 Jan 2019 22:16:17 +0900 (JST) Received: from ysato.dip.jp (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by h61-195-96-97.vps.ablenet.jp (Postfix) with ESMTPSA id 7DFD924008A; Mon, 21 Jan 2019 22:16:17 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Date: Mon, 21 Jan 2019 22:16:00 +0900 Message-Id: <20190121131602.55003-10-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190121131602.55003-1-ysato@users.sourceforge.jp> References: <20190121131602.55003-1-ysato@users.sourceforge.jp> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.224.55.14 Subject: [Qemu-devel] [PATCH RFC 09/11] RX Target hardware definition. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP rx62n - RX62N cpu. rxqemu - QEMU virtual target. Signed-off-by: Yoshinori Sato --- 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 From patchwork Mon Jan 21 13:16:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 10773857 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8D38A1515 for ; Mon, 21 Jan 2019 13:21:55 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7DD2329F50 for ; Mon, 21 Jan 2019 13:21:55 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 725DD2A04F; Mon, 21 Jan 2019 13:21:55 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 1AF3E2A058 for ; Mon, 21 Jan 2019 13:21:55 +0000 (UTC) Received: from localhost ([127.0.0.1]:53670 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZWU-0002HS-BL for patchwork-qemu-devel@patchwork.kernel.org; Mon, 21 Jan 2019 08:21:54 -0500 Received: from eggs.gnu.org ([209.51.188.92]:45056) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRS-0006dn-UR for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:45 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1glZRQ-0004HE-PJ for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:42 -0500 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:35855) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRK-00045F-Qd for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:38 -0500 Received: from h61-195-96-97.vps.ablenet.jp (h61-195-96-97.vps.ablenet.jp [61.195.96.97]) (Authenticated sender: PQ4Y-STU) by mail01.asahi-net.or.jp (Postfix) with ESMTPA id 2E45210322A; Mon, 21 Jan 2019 22:16:18 +0900 (JST) Received: from ysato.dip.jp (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by h61-195-96-97.vps.ablenet.jp (Postfix) with ESMTPSA id B78C4240084; Mon, 21 Jan 2019 22:16:17 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Date: Mon, 21 Jan 2019 22:16:01 +0900 Message-Id: <20190121131602.55003-11-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190121131602.55003-1-ysato@users.sourceforge.jp> References: <20190121131602.55003-1-ysato@users.sourceforge.jp> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.224.55.13 Subject: [Qemu-devel] [PATCH RFC 10/11] Add rx-softmmu. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Yoshinori Sato --- 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 From patchwork Mon Jan 21 13:16:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 10773855 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 738541515 for ; Mon, 21 Jan 2019 13:21:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 63E6A2A054 for ; Mon, 21 Jan 2019 13:21:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 589E22A036; Mon, 21 Jan 2019 13:21:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id CC4CE2A04B for ; Mon, 21 Jan 2019 13:21:44 +0000 (UTC) Received: from localhost ([127.0.0.1]:53668 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZWI-0002B0-JW for patchwork-qemu-devel@patchwork.kernel.org; Mon, 21 Jan 2019 08:21:42 -0500 Received: from eggs.gnu.org ([209.51.188.92]:45157) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRW-0006eV-6L for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1glZRT-0004Kv-US for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:46 -0500 Received: from mail02.asahi-net.or.jp ([202.224.55.14]:54518) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1glZRT-0004Je-KY for qemu-devel@nongnu.org; Mon, 21 Jan 2019 08:16:43 -0500 Received: from h61-195-96-97.vps.ablenet.jp (h61-195-96-97.vps.ablenet.jp [61.195.96.97]) (Authenticated sender: PQ4Y-STU) by mail02.asahi-net.or.jp (Postfix) with ESMTPA id 5411B208D7; Mon, 21 Jan 2019 22:16:18 +0900 (JST) Received: from ysato.dip.jp (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by h61-195-96-97.vps.ablenet.jp (Postfix) with ESMTPSA id 2BA5B24008A; Mon, 21 Jan 2019 22:16:18 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Date: Mon, 21 Jan 2019 22:16:02 +0900 Message-Id: <20190121131602.55003-12-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190121131602.55003-1-ysato@users.sourceforge.jp> References: <20190121131602.55003-1-ysato@users.sourceforge.jp> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.224.55.14 Subject: [Qemu-devel] [PATCH RFC 11/11] MAINTAINERS: Add RX entry. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Yoshinori Sato --- 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 +S: Maintained +F: target/rx/ +F: hw/rx/ +F: include/hw/rx/ +F: disas/rx.c + S390 M: Richard Henderson M: David Hildenbrand @@ -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 +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