mirror of https://github.com/xemu-project/xemu.git
Introduce the architectural part of the Renesas RX
architecture emulation, developed by Yoshinori Sato. CI jobs results: https://gitlab.com/philmd/qemu/pipelines/127886344 https://travis-ci.org/github/philmd/qemu/builds/664579420 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAl50mpQACgkQ4+MsLN6t wN62zw//Y3ZRo9wYFIeILtDJzIzLRuZwmF1lN7j6o15gdwyjWjn08N4wsM/kyPPH hdF6faWYIoiAaxe5IHzI4dxhH+Mv6zyae1gpOVOAO4TzF1HNpdILrCBvQbJQu2lF jpqXBDeaa/4ugniANzSTVhCcelIdIoI56rV+E3hzgdoDxOrveA1m0NUGMGzSayEh xT+y/oaTfmgJHI9GBwSJFVTrI1+jMp6VnrOv5I0pZrE55g1IiZ0TTK12JheQMFvS 98MHFZ1PiKIJEVzEQTBra0T8hbTsZLETn35mOgt9Kf3YRN4Cgqel6gFGlgtXUs5z 8u+pVDb8cK4+hcyFs0FLtUqWO+SXMF215zT23ra/ebhcC2pQRVHlqOjlI85aaJnf 7VfLJFMd3U4tl/yqbkcmkkjc1zl0IQjaa2mLaS+xstWAXGEqeP8EGdhIIzxtHBgQ 1RgHzjbTYMenCisUwzvH9+I7Wc9LB8Vik1UrebbCju99zwt/cIG3FSlleSiuKbtX U5prRyBw4xyIe1IwcBUcuEBtibD473eBP/m2nF6TorHE0rH1X0n644aHSlTZhGoM G/GvMZ45zHGlOouqYHX81vzR/WfRBYNiFcXHkJ0Im4zkvpXEnsvoTei9wt2QQ1Wi YyHKxQUQo8OvBHR4QMUXbS2XVR0tv43NtDiR4mz+vhjC7eDCVc8= =mNmV -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/philmd-gitlab/tags/target_renesas_rx-20200320' into staging Introduce the architectural part of the Renesas RX architecture emulation, developed by Yoshinori Sato. CI jobs results: https://gitlab.com/philmd/qemu/pipelines/127886344 https://travis-ci.org/github/philmd/qemu/builds/664579420 # gpg: Signature made Fri 20 Mar 2020 10:27:32 GMT # gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE # gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full] # Primary key fingerprint: FAAB E75E 1291 7221 DCFD 6BB2 E3E3 2C2C DEAD C0DE * remotes/philmd-gitlab/tags/target_renesas_rx-20200320: Add rx-softmmu target/rx: Dump bytes for each insn during disassembly target/rx: Collect all bytes during disassembly target/rx: Emit all disassembly in one prt() target/rx: Use prt_ldmi for XCHG_mr disassembly target/rx: Replace operand with prt_ldmi in disassembler target/rx: Disassemble rx_index_addr into a string target/rx: RX disassembler target/rx: CPU definitions target/rx: TCG helpers target/rx: TCG translation MAINTAINERS: Add entry for the Renesas RX architecture hw/registerfields.h: Add 8bit and 16bit register macros Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
226cd20706
|
@ -277,6 +277,11 @@ F: include/hw/riscv/
|
|||
F: linux-user/host/riscv32/
|
||||
F: linux-user/host/riscv64/
|
||||
|
||||
RENESAS RX CPUs
|
||||
M: Yoshinori Sato <ysato@users.sourceforge.jp>
|
||||
S: Maintained
|
||||
F: target/rx/
|
||||
|
||||
S390 TCG CPUs
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
M: David Hildenbrand <david@redhat.com>
|
||||
|
|
|
@ -77,6 +77,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)
|
||||
|
|
|
@ -4227,7 +4227,7 @@ fi
|
|||
fdt_required=no
|
||||
for target in $target_list; do
|
||||
case $target in
|
||||
aarch64*-softmmu|arm*-softmmu|ppc*-softmmu|microblaze*-softmmu|mips64el-softmmu|riscv*-softmmu)
|
||||
aarch64*-softmmu|arm*-softmmu|ppc*-softmmu|microblaze*-softmmu|mips64el-softmmu|riscv*-softmmu|rx-softmmu)
|
||||
fdt_required=yes
|
||||
;;
|
||||
esac
|
||||
|
@ -7912,6 +7912,12 @@ case "$target_name" in
|
|||
mttcg=yes
|
||||
gdb_xml_files="riscv-64bit-cpu.xml riscv-32bit-fpu.xml riscv-64bit-fpu.xml riscv-64bit-csr.xml riscv-64bit-virtual.xml"
|
||||
;;
|
||||
rx)
|
||||
TARGET_ARCH=rx
|
||||
bflt="yes"
|
||||
target_compiler=$cross_cc_rx
|
||||
gdb_xml_files="rx-core.xml"
|
||||
;;
|
||||
sh4|sh4eb)
|
||||
TARGET_ARCH=sh4
|
||||
bflt="yes"
|
||||
|
@ -8093,6 +8099,9 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
|
|||
riscv*)
|
||||
disas_config "RISCV"
|
||||
;;
|
||||
rx)
|
||||
disas_config "RX"
|
||||
;;
|
||||
s390*)
|
||||
disas_config "S390"
|
||||
;;
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# Default configuration for rx-softmmu
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
||||
<feature name="org.gnu.gdb.rx.core">
|
||||
<reg name="r0" bitsize="32" type="data_ptr"/>
|
||||
<reg name="r1" bitsize="32" type="uint32"/>
|
||||
<reg name="r2" bitsize="32" type="uint32"/>
|
||||
<reg name="r3" bitsize="32" type="uint32"/>
|
||||
<reg name="r4" bitsize="32" type="uint32"/>
|
||||
<reg name="r5" bitsize="32" type="uint32"/>
|
||||
<reg name="r6" bitsize="32" type="uint32"/>
|
||||
<reg name="r7" bitsize="32" type="uint32"/>
|
||||
<reg name="r8" bitsize="32" type="uint32"/>
|
||||
<reg name="r9" bitsize="32" type="uint32"/>
|
||||
<reg name="r10" bitsize="32" type="uint32"/>
|
||||
<reg name="r11" bitsize="32" type="uint32"/>
|
||||
<reg name="r12" bitsize="32" type="uint32"/>
|
||||
<reg name="r13" bitsize="32" type="uint32"/>
|
||||
<reg name="r14" bitsize="32" type="uint32"/>
|
||||
<reg name="r15" bitsize="32" type="uint32"/>
|
||||
|
||||
<flags id="psw_flags" size="4">
|
||||
<field name="C" start="0" end="0"/>
|
||||
<field name="Z" start="1" end="1"/>
|
||||
<field name="S" start="2" end="2"/>
|
||||
<field name="O" start="3" end="3"/>
|
||||
<field name="I" start="16" end="16"/>
|
||||
<field name="U" start="17" end="17"/>
|
||||
<field name="PM" start="20" end="20"/>
|
||||
<field name="IPL" start="24" end="27"/>
|
||||
</flags>
|
||||
|
||||
<flags id="fpsw_flags" size="4">
|
||||
<field name="RM" start="0" end="1"/>
|
||||
<field name="CV" start="2" end="2"/>
|
||||
<field name="CO" start="3" end="3"/>
|
||||
<field name="CZ" start="4" end="4"/>
|
||||
<field name="CU" start="5" end="5"/>
|
||||
<field name="CX" start="6" end="6"/>
|
||||
<field name="CE" start="7" end="7"/>
|
||||
<field name="DN" start="8" end="8"/>
|
||||
<field name="EV" start="10" end="10"/>
|
||||
<field name="EO" start="11" end="11"/>
|
||||
<field name="EZ" start="12" end="12"/>
|
||||
<field name="EU" start="13" end="13"/>
|
||||
<field name="EX" start="14" end="14"/>
|
||||
<field name="FV" start="26" end="26"/>
|
||||
<field name="FO" start="27" end="27"/>
|
||||
<field name="FZ" start="28" end="28"/>
|
||||
<field name="FU" start="29" end="29"/>
|
||||
<field name="FX" start="30" end="30"/>
|
||||
<field name="FS" start="31" end="31"/>
|
||||
</flags>
|
||||
|
||||
<reg name="usp" bitsize="32" type="data_ptr"/>
|
||||
<reg name="isp" bitsize="32" type="data_ptr"/>
|
||||
<reg name="psw" bitsize="32" type="psw_flags"/>
|
||||
<reg name="pc" bitsize="32" type="code_ptr"/>
|
||||
<reg name="intb" bitsize="32" type="data_ptr"/>
|
||||
<reg name="bpsw" bitsize="32" type="psw_flags"/>
|
||||
<reg name="bpc" bitsize="32" type="code_ptr"/>
|
||||
<reg name="fintv" bitsize="32" type="code_ptr"/>
|
||||
<reg name="fpsw" bitsize="32" type="fpsw_flags"/>
|
||||
<reg name="acc" bitsize="64" type="uint64"/>
|
||||
</feature>
|
|
@ -226,6 +226,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
|
||||
|
@ -436,6 +440,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. */
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#pragma GCC poison TARGET_PPC
|
||||
#pragma GCC poison TARGET_PPC64
|
||||
#pragma GCC poison TARGET_ABI32
|
||||
#pragma GCC poison TARGET_RX
|
||||
#pragma GCC poison TARGET_S390X
|
||||
#pragma GCC poison TARGET_SH4
|
||||
#pragma GCC poison TARGET_SPARC
|
||||
|
|
|
@ -22,6 +22,14 @@
|
|||
enum { A_ ## reg = (addr) }; \
|
||||
enum { R_ ## reg = (addr) / 4 };
|
||||
|
||||
#define REG8(reg, addr) \
|
||||
enum { A_ ## reg = (addr) }; \
|
||||
enum { R_ ## reg = (addr) };
|
||||
|
||||
#define REG16(reg, addr) \
|
||||
enum { A_ ## reg = (addr) }; \
|
||||
enum { R_ ## reg = (addr) / 2 };
|
||||
|
||||
/* Define SHIFT, LENGTH and MASK constants for a field within a register */
|
||||
|
||||
/* This macro will define R_FOO_BAR_MASK, R_FOO_BAR_SHIFT and R_FOO_BAR_LENGTH
|
||||
|
@ -34,6 +42,12 @@
|
|||
MAKE_64BIT_MASK(shift, length)};
|
||||
|
||||
/* Extract a field from a register */
|
||||
#define FIELD_EX8(storage, reg, field) \
|
||||
extract8((storage), R_ ## reg ## _ ## field ## _SHIFT, \
|
||||
R_ ## reg ## _ ## field ## _LENGTH)
|
||||
#define FIELD_EX16(storage, reg, field) \
|
||||
extract16((storage), R_ ## reg ## _ ## field ## _SHIFT, \
|
||||
R_ ## reg ## _ ## field ## _LENGTH)
|
||||
#define FIELD_EX32(storage, reg, field) \
|
||||
extract32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
|
||||
R_ ## reg ## _ ## field ## _LENGTH)
|
||||
|
@ -49,6 +63,22 @@
|
|||
* Assigning values larger then the target field will result in
|
||||
* compilation warnings.
|
||||
*/
|
||||
#define FIELD_DP8(storage, reg, field, val) ({ \
|
||||
struct { \
|
||||
unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \
|
||||
} v = { .v = val }; \
|
||||
uint8_t d; \
|
||||
d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
|
||||
R_ ## reg ## _ ## field ## _LENGTH, v.v); \
|
||||
d; })
|
||||
#define FIELD_DP16(storage, reg, field, val) ({ \
|
||||
struct { \
|
||||
unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \
|
||||
} v = { .v = val }; \
|
||||
uint16_t d; \
|
||||
d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
|
||||
R_ ## reg ## _ ## field ## _LENGTH, v.v); \
|
||||
d; })
|
||||
#define FIELD_DP32(storage, reg, field, val) ({ \
|
||||
struct { \
|
||||
unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \
|
||||
|
|
|
@ -24,6 +24,7 @@ enum {
|
|||
QEMU_ARCH_NIOS2 = (1 << 17),
|
||||
QEMU_ARCH_HPPA = (1 << 18),
|
||||
QEMU_ARCH_RISCV = (1 << 19),
|
||||
QEMU_ARCH_RX = (1 << 20),
|
||||
|
||||
QEMU_ARCH_NONE = (1 << 31),
|
||||
};
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
# individual target constants are not documented here, for the time
|
||||
# being.
|
||||
#
|
||||
# @rx: since 5.0
|
||||
#
|
||||
# Notes: The resulting QMP strings can be appended to the "qemu-system-"
|
||||
# prefix to produce the corresponding QEMU executable name. This
|
||||
# is true even for "qemu-system-x86_64".
|
||||
|
@ -26,7 +28,7 @@
|
|||
'data' : [ 'aarch64', 'alpha', 'arm', 'cris', 'hppa', 'i386', 'lm32',
|
||||
'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
|
||||
'mips64el', 'mipsel', 'moxie', 'nios2', 'or1k', 'ppc',
|
||||
'ppc64', 'riscv32', 'riscv64', 's390x', 'sh4',
|
||||
'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4',
|
||||
'sh4eb', 'sparc', 'sparc64', 'tricore', 'unicore32',
|
||||
'x86_64', 'xtensa', 'xtensaeb' ] }
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
obj-y += translate.o op_helper.o helper.o cpu.o gdbstub.o disas.o
|
||||
|
||||
DECODETREE = $(SRC_PATH)/scripts/decodetree.py
|
||||
|
||||
target/rx/decode.inc.c: \
|
||||
$(SRC_PATH)/target/rx/insns.decode $(DECODETREE)
|
||||
$(call quiet-command,\
|
||||
$(PYTHON) $(DECODETREE) --varinsnwidth 32 -o $@ $<, "GEN", $(TARGET_DIR)$@)
|
||||
|
||||
target/rx/translate.o: target/rx/decode.inc.c
|
||||
target/rx/disas.o: target/rx/decode.inc.c
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* RX cpu parameters
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RX_CPU_PARAM_H
|
||||
#define RX_CPU_PARAM_H
|
||||
|
||||
#define TARGET_LONG_BITS 32
|
||||
#define TARGET_PAGE_BITS 12
|
||||
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 32
|
||||
#define TARGET_VIRT_ADDR_SPACE_BITS 32
|
||||
|
||||
#define NB_MMU_MODES 1
|
||||
|
||||
#endif
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* RX CPU
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RX_CPU_QOM_H
|
||||
#define RX_CPU_QOM_H
|
||||
|
||||
#include "hw/core/cpu.h"
|
||||
|
||||
#define TYPE_RX_CPU "rx-cpu"
|
||||
|
||||
#define TYPE_RX62N_CPU RX_CPU_TYPE_NAME("rx62n")
|
||||
|
||||
#define RXCPU_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(RXCPUClass, (klass), TYPE_RX_CPU)
|
||||
#define RXCPU(obj) \
|
||||
OBJECT_CHECK(RXCPU, (obj), TYPE_RX_CPU)
|
||||
#define RXCPU_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(RXCPUClass, (obj), TYPE_RX_CPU)
|
||||
|
||||
/*
|
||||
* 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;
|
||||
DeviceReset parent_reset;
|
||||
} RXCPUClass;
|
||||
|
||||
#define CPUArchState struct CPURXState
|
||||
|
||||
#endif
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* QEMU RX CPU
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/qemu-print.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"
|
||||
#include "fpu/softfloat.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 | CPU_INTERRUPT_FIR);
|
||||
}
|
||||
|
||||
static void rx_cpu_reset(DeviceState *dev)
|
||||
{
|
||||
RXCPU *cpu = RXCPU(dev);
|
||||
RXCPUClass *rcc = RXCPU_GET_CLASS(cpu);
|
||||
CPURXState *env = &cpu->env;
|
||||
uint32_t *resetvec;
|
||||
|
||||
rcc->parent_reset(dev);
|
||||
|
||||
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);
|
||||
}
|
||||
rx_cpu_unpack_psw(env, 0, 1);
|
||||
env->regs[0] = env->isp = env->usp = 0;
|
||||
env->fpsw = 0;
|
||||
set_flush_to_zero(1, &env->fp_status);
|
||||
set_flush_inputs_to_zero(1, &env->fp_status);
|
||||
}
|
||||
|
||||
static void rx_cpu_list_entry(gpointer data, gpointer user_data)
|
||||
{
|
||||
ObjectClass *oc = data;
|
||||
|
||||
qemu_printf(" %s\n", object_class_get_name(oc));
|
||||
}
|
||||
|
||||
void rx_cpu_list(void)
|
||||
{
|
||||
GSList *list;
|
||||
list = object_class_get_list_sorted(TYPE_RX_CPU, false);
|
||||
qemu_printf("Available CPUs:\n");
|
||||
g_slist_foreach(list, rx_cpu_list_entry, NULL);
|
||||
g_slist_free(list);
|
||||
}
|
||||
|
||||
static ObjectClass *rx_cpu_class_by_name(const char *cpu_model)
|
||||
{
|
||||
ObjectClass *oc;
|
||||
char *typename;
|
||||
|
||||
oc = object_class_by_name(cpu_model);
|
||||
if (oc != NULL && object_class_dynamic_cast(oc, TYPE_RX_CPU) != NULL &&
|
||||
!object_class_is_abstract(oc)) {
|
||||
return oc;
|
||||
}
|
||||
typename = g_strdup_printf(RX_CPU_TYPE_NAME("%s"), cpu_model);
|
||||
oc = object_class_by_name(typename);
|
||||
g_free(typename);
|
||||
if (oc != NULL && object_class_is_abstract(oc)) {
|
||||
oc = NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
qemu_init_vcpu(cs);
|
||||
cpu_reset(cs);
|
||||
|
||||
rcc->parent_realize(dev, errp);
|
||||
}
|
||||
|
||||
static void rx_cpu_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 (irq) {
|
||||
cpu->env.req_irq = irq;
|
||||
cpu->env.req_ipl = (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 bool rx_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, 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);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void rx_cpu_init(Object *obj)
|
||||
{
|
||||
CPUState *cs = CPU(obj);
|
||||
RXCPU *cpu = RXCPU(obj);
|
||||
CPURXState *env = &cpu->env;
|
||||
|
||||
cpu_set_cpustate_pointers(cpu);
|
||||
cs->env_ptr = env;
|
||||
qdev_init_gpio_in(DEVICE(cpu), rx_cpu_set_irq, 2);
|
||||
}
|
||||
|
||||
static void rx_cpu_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);
|
||||
device_class_set_parent_reset(dc, rx_cpu_reset,
|
||||
&rcc->parent_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->tlb_fill = rx_cpu_tlb_fill;
|
||||
|
||||
cc->gdb_num_core_regs = 26;
|
||||
cc->gdb_core_xml_file = "rx-core.xml";
|
||||
}
|
||||
|
||||
static const TypeInfo rx_cpu_info = {
|
||||
.name = TYPE_RX_CPU,
|
||||
.parent = TYPE_CPU,
|
||||
.instance_size = sizeof(RXCPU),
|
||||
.instance_init = rx_cpu_init,
|
||||
.abstract = true,
|
||||
.class_size = sizeof(RXCPUClass),
|
||||
.class_init = rx_cpu_class_init,
|
||||
};
|
||||
|
||||
static const TypeInfo rx62n_rx_cpu_info = {
|
||||
.name = TYPE_RX62N_CPU,
|
||||
.parent = TYPE_RX_CPU,
|
||||
};
|
||||
|
||||
static void rx_cpu_register_types(void)
|
||||
{
|
||||
type_register_static(&rx_cpu_info);
|
||||
type_register_static(&rx62n_rx_cpu_info);
|
||||
}
|
||||
|
||||
type_init(rx_cpu_register_types)
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* RX emulation definition
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RX_CPU_H
|
||||
#define RX_CPU_H
|
||||
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu-common.h"
|
||||
#include "hw/registerfields.h"
|
||||
#include "cpu-qom.h"
|
||||
|
||||
#include "exec/cpu-defs.h"
|
||||
|
||||
/* PSW define */
|
||||
REG32(PSW, 0)
|
||||
FIELD(PSW, C, 0, 1)
|
||||
FIELD(PSW, Z, 1, 1)
|
||||
FIELD(PSW, S, 2, 1)
|
||||
FIELD(PSW, O, 3, 1)
|
||||
FIELD(PSW, I, 16, 1)
|
||||
FIELD(PSW, U, 17, 1)
|
||||
FIELD(PSW, PM, 20, 1)
|
||||
FIELD(PSW, IPL, 24, 4)
|
||||
|
||||
/* FPSW define */
|
||||
REG32(FPSW, 0)
|
||||
FIELD(FPSW, RM, 0, 2)
|
||||
FIELD(FPSW, CV, 2, 1)
|
||||
FIELD(FPSW, CO, 3, 1)
|
||||
FIELD(FPSW, CZ, 4, 1)
|
||||
FIELD(FPSW, CU, 5, 1)
|
||||
FIELD(FPSW, CX, 6, 1)
|
||||
FIELD(FPSW, CE, 7, 1)
|
||||
FIELD(FPSW, CAUSE, 2, 6)
|
||||
FIELD(FPSW, DN, 8, 1)
|
||||
FIELD(FPSW, EV, 10, 1)
|
||||
FIELD(FPSW, EO, 11, 1)
|
||||
FIELD(FPSW, EZ, 12, 1)
|
||||
FIELD(FPSW, EU, 13, 1)
|
||||
FIELD(FPSW, EX, 14, 1)
|
||||
FIELD(FPSW, ENABLE, 10, 5)
|
||||
FIELD(FPSW, FV, 26, 1)
|
||||
FIELD(FPSW, FO, 27, 1)
|
||||
FIELD(FPSW, FZ, 28, 1)
|
||||
FIELD(FPSW, FU, 29, 1)
|
||||
FIELD(FPSW, FX, 30, 1)
|
||||
FIELD(FPSW, FLAGS, 26, 4)
|
||||
FIELD(FPSW, FS, 31, 1)
|
||||
|
||||
enum {
|
||||
NUM_REGS = 16,
|
||||
};
|
||||
|
||||
typedef struct CPURXState {
|
||||
/* CPU registers */
|
||||
uint32_t regs[NUM_REGS]; /* general registers */
|
||||
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;
|
||||
uint64_t acc;
|
||||
|
||||
/* Fields up to this point are cleared by a CPU reset */
|
||||
struct {} end_reset_fields;
|
||||
|
||||
/* Internal use */
|
||||
uint32_t in_sleep;
|
||||
uint32_t req_irq; /* Requested interrupt no (hard) */
|
||||
uint32_t req_ipl; /* Requested interrupt level */
|
||||
uint32_t ack_irq; /* execute irq */
|
||||
uint32_t ack_ipl; /* execute ipl */
|
||||
float_status fp_status;
|
||||
qemu_irq ack; /* Interrupt acknowledge */
|
||||
} CPURXState;
|
||||
|
||||
/*
|
||||
* RXCPU:
|
||||
* @env: #CPURXState
|
||||
*
|
||||
* A RX CPU
|
||||
*/
|
||||
struct RXCPU {
|
||||
/*< private >*/
|
||||
CPUState parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
CPUNegativeOffsetState neg;
|
||||
CPURXState env;
|
||||
};
|
||||
|
||||
typedef struct RXCPU RXCPU;
|
||||
typedef RXCPU ArchCPU;
|
||||
|
||||
#define ENV_OFFSET offsetof(RXCPU, env)
|
||||
|
||||
#define RX_CPU_TYPE_SUFFIX "-" TYPE_RX_CPU
|
||||
#define RX_CPU_TYPE_NAME(model) model RX_CPU_TYPE_SUFFIX
|
||||
#define CPU_RESOLVING_TYPE TYPE_RX_CPU
|
||||
|
||||
const char *rx_crname(uint8_t cr);
|
||||
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, int flags);
|
||||
int rx_cpu_gdb_read_register(CPUState *cpu, GByteArray *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(void);
|
||||
void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte);
|
||||
|
||||
#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 = FIELD_DP32(0, PSW, PM, env->psw_pm);
|
||||
}
|
||||
|
||||
static inline int cpu_mmu_index(CPURXState *env, bool ifetch)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint32_t rx_cpu_pack_psw(CPURXState *env)
|
||||
{
|
||||
uint32_t psw = 0;
|
||||
psw = FIELD_DP32(psw, PSW, IPL, env->psw_ipl);
|
||||
psw = FIELD_DP32(psw, PSW, PM, env->psw_pm);
|
||||
psw = FIELD_DP32(psw, PSW, U, env->psw_u);
|
||||
psw = FIELD_DP32(psw, PSW, I, env->psw_i);
|
||||
psw = FIELD_DP32(psw, PSW, O, env->psw_o >> 31);
|
||||
psw = FIELD_DP32(psw, PSW, S, env->psw_s >> 31);
|
||||
psw = FIELD_DP32(psw, PSW, Z, env->psw_z == 0);
|
||||
psw = FIELD_DP32(psw, PSW, C, env->psw_c);
|
||||
return psw;
|
||||
}
|
||||
|
||||
#endif /* RX_CPU_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* RX gdb server stub
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/gdbstub.h"
|
||||
|
||||
int rx_cpu_gdb_read_register(CPUState *cs, GByteArray *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:
|
||||
return gdb_get_regl(mem_buf, rx_cpu_pack_psw(env));
|
||||
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;
|
||||
uint32_t psw;
|
||||
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:
|
||||
psw = ldl_p(mem_buf);
|
||||
rx_cpu_unpack_psw(env, psw, 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;
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* RX emulation
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/log.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/irq.h"
|
||||
|
||||
void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte)
|
||||
{
|
||||
if (env->psw_pm == 0) {
|
||||
env->psw_ipl = FIELD_EX32(psw, PSW, IPL);
|
||||
if (rte) {
|
||||
/* PSW.PM can write RTE and RTFI */
|
||||
env->psw_pm = FIELD_EX32(psw, PSW, PM);
|
||||
}
|
||||
env->psw_u = FIELD_EX32(psw, PSW, U);
|
||||
env->psw_i = FIELD_EX32(psw, PSW, I);
|
||||
}
|
||||
env->psw_o = FIELD_EX32(psw, PSW, O) << 31;
|
||||
env->psw_s = FIELD_EX32(psw, PSW, S) << 31;
|
||||
env->psw_z = 1 - FIELD_EX32(psw, PSW, Z);
|
||||
env->psw_c = FIELD_EX32(psw, PSW, C);
|
||||
}
|
||||
|
||||
#define INT_FLAGS (CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIR)
|
||||
void rx_cpu_do_interrupt(CPUState *cs)
|
||||
{
|
||||
RXCPU *cpu = RXCPU(cs);
|
||||
CPURXState *env = &cpu->env;
|
||||
int do_irq = cs->interrupt_request & INT_FLAGS;
|
||||
uint32_t save_psw;
|
||||
|
||||
env->in_sleep = 0;
|
||||
|
||||
if (env->psw_u) {
|
||||
env->usp = env->regs[0];
|
||||
} else {
|
||||
env->isp = env->regs[0];
|
||||
}
|
||||
save_psw = rx_cpu_pack_psw(env);
|
||||
env->psw_pm = env->psw_i = env->psw_u = 0;
|
||||
|
||||
if (do_irq) {
|
||||
if (do_irq & CPU_INTERRUPT_FIR) {
|
||||
env->bpc = env->pc;
|
||||
env->bpsw = save_psw;
|
||||
env->pc = env->fintv;
|
||||
env->psw_ipl = 15;
|
||||
cs->interrupt_request &= ~CPU_INTERRUPT_FIR;
|
||||
qemu_set_irq(env->ack, env->ack_irq);
|
||||
qemu_log_mask(CPU_LOG_INT, "fast interrupt raised\n");
|
||||
} else if (do_irq & CPU_INTERRUPT_HARD) {
|
||||
env->isp -= 4;
|
||||
cpu_stl_data(env, env->isp, save_psw);
|
||||
env->isp -= 4;
|
||||
cpu_stl_data(env, env->isp, env->pc);
|
||||
env->pc = cpu_ldl_data(env, env->intb + env->ack_irq * 4);
|
||||
env->psw_ipl = env->ack_ipl;
|
||||
cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
||||
qemu_set_irq(env->ack, env->ack_irq);
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"interrupt 0x%02x raised\n", env->ack_irq);
|
||||
}
|
||||
} else {
|
||||
uint32_t vec = cs->exception_index;
|
||||
const char *expname = "unknown exception";
|
||||
|
||||
env->isp -= 4;
|
||||
cpu_stl_data(env, env->isp, save_psw);
|
||||
env->isp -= 4;
|
||||
cpu_stl_data(env, env->isp, env->pc);
|
||||
|
||||
if (vec < 0x100) {
|
||||
env->pc = cpu_ldl_data(env, 0xffffffc0 + vec * 4);
|
||||
} else {
|
||||
env->pc = cpu_ldl_data(env, env->intb + (vec & 0xff) * 4);
|
||||
}
|
||||
switch (vec) {
|
||||
case 20:
|
||||
expname = "privilege violation";
|
||||
break;
|
||||
case 21:
|
||||
expname = "access exception";
|
||||
break;
|
||||
case 23:
|
||||
expname = "illegal instruction";
|
||||
break;
|
||||
case 25:
|
||||
expname = "fpu exception";
|
||||
break;
|
||||
case 30:
|
||||
expname = "non-maskable interrupt";
|
||||
break;
|
||||
case 0x100 ... 0x1ff:
|
||||
expname = "unconditional trap";
|
||||
}
|
||||
qemu_log_mask(CPU_LOG_INT, "exception 0x%02x [%s] raised\n",
|
||||
(vec & 0xff), expname);
|
||||
}
|
||||
env->regs[0] = env->isp;
|
||||
}
|
||||
|
||||
bool rx_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
{
|
||||
RXCPU *cpu = RXCPU(cs);
|
||||
CPURXState *env = &cpu->env;
|
||||
int accept = 0;
|
||||
/* hardware interrupt (Normal) */
|
||||
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
env->psw_i && (env->psw_ipl < env->req_ipl)) {
|
||||
env->ack_irq = env->req_irq;
|
||||
env->ack_ipl = env->req_ipl;
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
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_3(fadd, TCG_CALL_NO_WG, f32, env, f32, f32)
|
||||
DEF_HELPER_FLAGS_3(fsub, TCG_CALL_NO_WG, f32, env, f32, f32)
|
||||
DEF_HELPER_FLAGS_3(fmul, TCG_CALL_NO_WG, f32, env, f32, f32)
|
||||
DEF_HELPER_FLAGS_3(fdiv, TCG_CALL_NO_WG, f32, env, f32, f32)
|
||||
DEF_HELPER_FLAGS_3(fcmp, TCG_CALL_NO_WG, void, env, f32, f32)
|
||||
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(set_fpsw, void, env, i32)
|
||||
DEF_HELPER_FLAGS_2(racw, TCG_CALL_NO_WG, void, env, i32)
|
||||
DEF_HELPER_FLAGS_2(set_psw_rte, TCG_CALL_NO_WG, void, env, i32)
|
||||
DEF_HELPER_FLAGS_2(set_psw, TCG_CALL_NO_WG, void, env, i32)
|
||||
DEF_HELPER_1(pack_psw, i32, env)
|
||||
DEF_HELPER_FLAGS_3(div, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(divu, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(scmpu, TCG_CALL_NO_WG, void, env)
|
||||
DEF_HELPER_1(smovu, void, env)
|
||||
DEF_HELPER_1(smovf, void, env)
|
||||
DEF_HELPER_1(smovb, void, env)
|
||||
DEF_HELPER_2(sstr, void, env, i32)
|
||||
DEF_HELPER_FLAGS_2(swhile, TCG_CALL_NO_WG, void, env, i32)
|
||||
DEF_HELPER_FLAGS_2(suntil, TCG_CALL_NO_WG, void, env, i32)
|
||||
DEF_HELPER_FLAGS_2(rmpa, TCG_CALL_NO_WG, void, env, i32)
|
||||
DEF_HELPER_1(satr, void, env)
|
|
@ -0,0 +1,621 @@
|
|||
#
|
||||
# Renesas RX instruction decode definitions.
|
||||
#
|
||||
# Copyright (c) 2019 Richard Henderson <richard.henderson@linaro.org>
|
||||
# Copyright (c) 2019 Yoshinori Sato <ysato@users.sourceforge.jp>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
&bcnd cd dsp sz
|
||||
&jdsp dsp sz
|
||||
&jreg rs
|
||||
&rr rd rs
|
||||
&ri rd imm
|
||||
&rrr rd rs rs2
|
||||
&rri rd imm rs2
|
||||
&rm rd rs ld mi
|
||||
&mi rs ld mi imm
|
||||
&mr rs ld mi rs2
|
||||
&mcnd ld sz rd cd
|
||||
########
|
||||
%b1_bdsp 24:3 !function=bdsp_s
|
||||
|
||||
@b1_bcnd_s .... cd:1 ... &bcnd dsp=%b1_bdsp sz=1
|
||||
@b1_bra_s .... .... &jdsp dsp=%b1_bdsp sz=1
|
||||
|
||||
%b2_r_0 16:4
|
||||
%b2_li_2 18:2 !function=li
|
||||
%b2_li_8 24:2 !function=li
|
||||
%b2_dsp5_3 23:4 19:1
|
||||
|
||||
@b2_rds .... .... .... rd:4 &rr rs=%b2_r_0
|
||||
@b2_rds_li .... .... .... rd:4 &rri rs2=%b2_r_0 imm=%b2_li_8
|
||||
@b2_rds_uimm4 .... .... imm:4 rd:4 &rri rs2=%b2_r_0
|
||||
@b2_rs2_uimm4 .... .... imm:4 rs2:4 &rri rd=0
|
||||
@b2_rds_imm5 .... ... imm:5 rd:4 &rri rs2=%b2_r_0
|
||||
@b2_rd_rs_li .... .... rs2:4 rd:4 &rri imm=%b2_li_8
|
||||
@b2_rd_ld_ub .... .. ld:2 rs:4 rd:4 &rm mi=4
|
||||
@b2_ld_imm3 .... .. ld:2 rs:4 . imm:3 &mi mi=4
|
||||
@b2_bcnd_b .... cd:4 dsp:s8 &bcnd sz=2
|
||||
@b2_bra_b .... .... dsp:s8 &jdsp sz=2
|
||||
|
||||
########
|
||||
|
||||
%b3_r_0 8:4
|
||||
%b3_li_10 18:2 !function=li
|
||||
%b3_dsp5_8 23:1 16:4
|
||||
%b3_bdsp 8:s8 16:8
|
||||
|
||||
@b3_rd_rs .... .... .... .... rs:4 rd:4 &rr
|
||||
@b3_rs_rd .... .... .... .... rd:4 rs:4 &rr
|
||||
@b3_rd_li .... .... .... .... .... rd:4 \
|
||||
&rri rs2=%b3_r_0 imm=%b3_li_10
|
||||
@b3_rd_ld .... .... mi:2 .... ld:2 rs:4 rd:4 &rm
|
||||
@b3_rd_ld_ub .... .... .... .. ld:2 rs:4 rd:4 &rm mi=4
|
||||
@b3_rd_ld_ul .... .... .... .. ld:2 rs:4 rd:4 &rm mi=2
|
||||
@b3_rd_rs_rs2 .... .... .... rd:4 rs:4 rs2:4 &rrr
|
||||
@b3_rds_imm5 .... .... ....... imm:5 rd:4 &rri rs2=%b3_r_0
|
||||
@b3_rd_rs_imm5 .... .... ... imm:5 rs2:4 rd:4 &rri
|
||||
@b3_bcnd_w .... ... cd:1 .... .... .... .... &bcnd dsp=%b3_bdsp sz=3
|
||||
@b3_bra_w .... .... .... .... .... .... &jdsp dsp=%b3_bdsp sz=3
|
||||
@b3_ld_rd_rs .... .... .... .. ld:2 rs:4 rd:4 &rm mi=0
|
||||
@b3_sz_ld_rd_cd .... .... .... sz:2 ld:2 rd:4 cd:4 &mcnd
|
||||
|
||||
########
|
||||
|
||||
%b4_li_18 18:2 !function=li
|
||||
%b4_dsp_16 0:s8 8:8
|
||||
%b4_bdsp 0:s8 8:8 16:8
|
||||
|
||||
@b4_rd_ldmi .... .... mi:2 .... ld:2 .... .... rs:4 rd:4 &rm
|
||||
@b4_bra_a .... .... .... .... .... .... .... .... \
|
||||
&jdsp dsp=%b4_bdsp sz=4
|
||||
########
|
||||
# ABS rd
|
||||
ABS_rr 0111 1110 0010 .... @b2_rds
|
||||
# ABS rs, rd
|
||||
ABS_rr 1111 1100 0000 1111 .... .... @b3_rd_rs
|
||||
|
||||
# ADC #imm, rd
|
||||
ADC_ir 1111 1101 0111 ..00 0010 .... @b3_rd_li
|
||||
# ADC rs, rd
|
||||
ADC_rr 1111 1100 0000 1011 .... .... @b3_rd_rs
|
||||
# ADC dsp[rs].l, rd
|
||||
# Note only mi==2 allowed.
|
||||
ADC_mr 0000 0110 ..10 00.. 0000 0010 .... .... @b4_rd_ldmi
|
||||
|
||||
# ADD #uimm4, rd
|
||||
ADD_irr 0110 0010 .... .... @b2_rds_uimm4
|
||||
# ADD #imm, rs, rd
|
||||
ADD_irr 0111 00.. .... .... @b2_rd_rs_li
|
||||
# ADD dsp[rs].ub, rd
|
||||
# ADD rs, rd
|
||||
ADD_mr 0100 10.. .... .... @b2_rd_ld_ub
|
||||
# ADD dsp[rs], rd
|
||||
ADD_mr 0000 0110 ..00 10.. .... .... @b3_rd_ld
|
||||
# ADD rs, rs2, rd
|
||||
ADD_rrr 1111 1111 0010 .... .... .... @b3_rd_rs_rs2
|
||||
|
||||
# AND #uimm4, rd
|
||||
AND_ir 0110 0100 .... .... @b2_rds_uimm4
|
||||
# AND #imm, rd
|
||||
AND_ir 0111 01.. 0010 .... @b2_rds_li
|
||||
# AND dsp[rs].ub, rd
|
||||
# AND rs, rd
|
||||
AND_mr 0101 00.. .... .... @b2_rd_ld_ub
|
||||
# AND dsp[rs], rd
|
||||
AND_mr 0000 0110 ..01 00.. .... .... @b3_rd_ld
|
||||
# AND rs, rs2, rd
|
||||
AND_rrr 1111 1111 0100 .... .... .... @b3_rd_rs_rs2
|
||||
|
||||
# BCLR #imm, dsp[rd]
|
||||
BCLR_im 1111 00.. .... 1... @b2_ld_imm3
|
||||
# BCLR #imm, rs
|
||||
BCLR_ir 0111 101. .... .... @b2_rds_imm5
|
||||
# BCLR rs, rd
|
||||
# BCLR rs, dsp[rd]
|
||||
{
|
||||
BCLR_rr 1111 1100 0110 0111 .... .... @b3_rs_rd
|
||||
BCLR_rm 1111 1100 0110 01.. .... .... @b3_rd_ld_ub
|
||||
}
|
||||
|
||||
# BCnd.s dsp
|
||||
BCnd 0001 .... @b1_bcnd_s
|
||||
# BRA.b dsp
|
||||
# BCnd.b dsp
|
||||
{
|
||||
BRA 0010 1110 .... .... @b2_bra_b
|
||||
BCnd 0010 .... .... .... @b2_bcnd_b
|
||||
}
|
||||
|
||||
# BCnd.w dsp
|
||||
BCnd 0011 101 . .... .... .... .... @b3_bcnd_w
|
||||
|
||||
# BNOT #imm, dsp[rd]
|
||||
# BMCnd #imm, dsp[rd]
|
||||
{
|
||||
BNOT_im 1111 1100 111 imm:3 ld:2 rs:4 1111
|
||||
BMCnd_im 1111 1100 111 imm:3 ld:2 rd:4 cd:4
|
||||
}
|
||||
|
||||
# BNOT #imm, rd
|
||||
# BMCnd #imm, rd
|
||||
{
|
||||
BNOT_ir 1111 1101 111 imm:5 1111 rd:4
|
||||
BMCnd_ir 1111 1101 111 imm:5 cd:4 rd:4
|
||||
}
|
||||
|
||||
# BNOT rs, rd
|
||||
# BNOT rs, dsp[rd]
|
||||
{
|
||||
BNOT_rr 1111 1100 0110 1111 .... .... @b3_rs_rd
|
||||
BNOT_rm 1111 1100 0110 11.. .... .... @b3_rd_ld_ub
|
||||
}
|
||||
|
||||
# BRA.s dsp
|
||||
BRA 0000 1 ... @b1_bra_s
|
||||
# BRA.w dsp
|
||||
BRA 0011 1000 .... .... .... .... @b3_bra_w
|
||||
# BRA.a dsp
|
||||
BRA 0000 0100 .... .... .... .... .... .... @b4_bra_a
|
||||
# BRA.l rs
|
||||
BRA_l 0111 1111 0100 rd:4
|
||||
|
||||
BRK 0000 0000
|
||||
|
||||
# BSET #imm, dsp[rd]
|
||||
BSET_im 1111 00.. .... 0... @b2_ld_imm3
|
||||
# BSET #imm, rd
|
||||
BSET_ir 0111 100. .... .... @b2_rds_imm5
|
||||
# BSET rs, rd
|
||||
# BSET rs, dsp[rd]
|
||||
{
|
||||
BSET_rr 1111 1100 0110 0011 .... .... @b3_rs_rd
|
||||
BSET_rm 1111 1100 0110 00.. .... .... @b3_rd_ld_ub
|
||||
}
|
||||
|
||||
# BSR.w dsp
|
||||
BSR 0011 1001 .... .... .... .... @b3_bra_w
|
||||
# BSR.a dsp
|
||||
BSR 0000 0101 .... .... .... .... .... .... @b4_bra_a
|
||||
# BSR.l rs
|
||||
BSR_l 0111 1111 0101 rd:4
|
||||
|
||||
# BSET #imm, dsp[rd]
|
||||
BTST_im 1111 01.. .... 0... @b2_ld_imm3
|
||||
# BSET #imm, rd
|
||||
BTST_ir 0111 110. .... .... @b2_rds_imm5
|
||||
# BSET rs, rd
|
||||
# BSET rs, dsp[rd]
|
||||
{
|
||||
BTST_rr 1111 1100 0110 1011 .... .... @b3_rs_rd
|
||||
BTST_rm 1111 1100 0110 10.. .... .... @b3_rd_ld_ub
|
||||
}
|
||||
|
||||
# CLRSPW psw
|
||||
CLRPSW 0111 1111 1011 cb:4
|
||||
|
||||
# CMP #uimm4, rs2
|
||||
CMP_ir 0110 0001 .... .... @b2_rs2_uimm4
|
||||
# CMP #uimm8, rs2
|
||||
CMP_ir 0111 0101 0101 rs2:4 imm:8 &rri rd=0
|
||||
# CMP #imm, rs2
|
||||
CMP_ir 0111 01.. 0000 rs2:4 &rri imm=%b2_li_8 rd=0
|
||||
# CMP dsp[rs].ub, rs2
|
||||
# CMP rs, rs2
|
||||
CMP_mr 0100 01.. .... .... @b2_rd_ld_ub
|
||||
# CMP dsp[rs], rs2
|
||||
CMP_mr 0000 0110 ..00 01.. .... .... @b3_rd_ld
|
||||
|
||||
# DIV #imm, rd
|
||||
DIV_ir 1111 1101 0111 ..00 1000 .... @b3_rd_li
|
||||
# DIV dsp[rs].ub, rd
|
||||
# DIV rs, rd
|
||||
DIV_mr 1111 1100 0010 00.. .... .... @b3_rd_ld_ub
|
||||
# DIV dsp[rs], rd
|
||||
DIV_mr 0000 0110 ..10 00.. 0000 1000 .... .... @b4_rd_ldmi
|
||||
|
||||
# DIVU #imm, rd
|
||||
DIVU_ir 1111 1101 0111 ..00 1001 .... @b3_rd_li
|
||||
# DIVU dsp[rs].ub, rd
|
||||
# DIVU rs, rd
|
||||
DIVU_mr 1111 1100 0010 01.. .... .... @b3_rd_ld_ub
|
||||
# DIVU dsp[rs], rd
|
||||
DIVU_mr 0000 0110 ..10 00.. 0000 1001 .... .... @b4_rd_ldmi
|
||||
|
||||
# EMUL #imm, rd
|
||||
EMUL_ir 1111 1101 0111 ..00 0110 .... @b3_rd_li
|
||||
# EMUL dsp[rs].ub, rd
|
||||
# EMUL rs, rd
|
||||
EMUL_mr 1111 1100 0001 10.. .... .... @b3_rd_ld_ub
|
||||
# EMUL dsp[rs], rd
|
||||
EMUL_mr 0000 0110 ..10 00.. 0000 0110 .... .... @b4_rd_ldmi
|
||||
|
||||
# EMULU #imm, rd
|
||||
EMULU_ir 1111 1101 0111 ..00 0111 .... @b3_rd_li
|
||||
# EMULU dsp[rs].ub, rd
|
||||
# EMULU rs, rd
|
||||
EMULU_mr 1111 1100 0001 11.. .... .... @b3_rd_ld_ub
|
||||
# EMULU dsp[rs], rd
|
||||
EMULU_mr 0000 0110 ..10 00.. 0000 0111 .... .... @b4_rd_ldmi
|
||||
|
||||
# FADD #imm, rd
|
||||
FADD_ir 1111 1101 0111 0010 0010 rd:4
|
||||
# FADD rs, rd
|
||||
# FADD dsp[rs], rd
|
||||
FADD_mr 1111 1100 1000 10.. .... .... @b3_rd_ld_ul
|
||||
|
||||
# FCMP #imm, rd
|
||||
FCMP_ir 1111 1101 0111 0010 0001 rd:4
|
||||
# FCMP rs, rd
|
||||
# FCMP dsp[rs], rd
|
||||
FCMP_mr 1111 1100 1000 01.. .... .... @b3_rd_ld_ul
|
||||
|
||||
# FDIV #imm, rd
|
||||
FDIV_ir 1111 1101 0111 0010 0100 rd:4
|
||||
# FDIV rs, rd
|
||||
# FDIV dsp[rs], rd
|
||||
FDIV_mr 1111 1100 1001 00.. .... .... @b3_rd_ld_ul
|
||||
|
||||
# FMUL #imm, rd
|
||||
FMUL_ir 1111 1101 0111 0010 0011 rd:4
|
||||
# FMUL rs, rd
|
||||
# FMUL dsp[rs], rd
|
||||
FMUL_mr 1111 1100 1000 11.. .... .... @b3_rd_ld_ul
|
||||
|
||||
# FSUB #imm, rd
|
||||
FSUB_ir 1111 1101 0111 0010 0000 rd:4
|
||||
# FSUB rs, rd
|
||||
# FSUB dsp[rs], rd
|
||||
FSUB_mr 1111 1100 1000 00.. .... .... @b3_rd_ld_ul
|
||||
|
||||
# FTOI rs, rd
|
||||
# FTOI dsp[rs], rd
|
||||
FTOI 1111 1100 1001 01.. .... .... @b3_rd_ld_ul
|
||||
|
||||
# INT #uimm8
|
||||
INT 0111 0101 0110 0000 imm:8
|
||||
|
||||
# ITOF dsp[rs].ub, rd
|
||||
# ITOF rs, rd
|
||||
ITOF 1111 1100 0100 01.. .... .... @b3_rd_ld_ub
|
||||
# ITOF dsp[rs], rd
|
||||
ITOF 0000 0110 ..10 00.. 0001 0001 .... .... @b4_rd_ldmi
|
||||
|
||||
# JMP rs
|
||||
JMP 0111 1111 0000 rs:4 &jreg
|
||||
# JSR rs
|
||||
JSR 0111 1111 0001 rs:4 &jreg
|
||||
|
||||
# MACHI rs, rs2
|
||||
MACHI 1111 1101 0000 0100 rs:4 rs2:4
|
||||
# MACLO rs, rs2
|
||||
MACLO 1111 1101 0000 0101 rs:4 rs2:4
|
||||
|
||||
# MAX #imm, rd
|
||||
MAX_ir 1111 1101 0111 ..00 0100 .... @b3_rd_li
|
||||
# MAX dsp[rs].ub, rd
|
||||
# MAX rs, rd
|
||||
MAX_mr 1111 1100 0001 00.. .... .... @b3_rd_ld_ub
|
||||
# MAX dsp[rs], rd
|
||||
MAX_mr 0000 0110 ..10 00.. 0000 0100 .... .... @b4_rd_ldmi
|
||||
|
||||
# MIN #imm, rd
|
||||
MIN_ir 1111 1101 0111 ..00 0101 .... @b3_rd_li
|
||||
# MIN dsp[rs].ub, rd
|
||||
# MIN rs, rd
|
||||
MIN_mr 1111 1100 0001 01.. .... .... @b3_rd_ld_ub
|
||||
# MIN dsp[rs], rd
|
||||
MIN_mr 0000 0110 ..10 00.. 0000 0101 .... .... @b4_rd_ldmi
|
||||
|
||||
# MOV.b rs, dsp5[rd]
|
||||
MOV_rm 1000 0 .... rd:3 . rs:3 dsp=%b2_dsp5_3 sz=0
|
||||
# MOV.w rs, dsp5[rd]
|
||||
MOV_rm 1001 0 .... rd:3 . rs:3 dsp=%b2_dsp5_3 sz=1
|
||||
# MOV.l rs, dsp5[rd]
|
||||
MOV_rm 1010 0 .... rd:3 . rs:3 dsp=%b2_dsp5_3 sz=2
|
||||
# MOV.b dsp5[rs], rd
|
||||
MOV_mr 1000 1 .... rs:3 . rd:3 dsp=%b2_dsp5_3 sz=0
|
||||
# MOV.w dsp5[rs], rd
|
||||
MOV_mr 1001 1 .... rs:3 . rd:3 dsp=%b2_dsp5_3 sz=1
|
||||
# MOV.l dsp5[rs], rd
|
||||
MOV_mr 1010 1 .... rs:3 . rd:3 dsp=%b2_dsp5_3 sz=2
|
||||
# MOV.l #uimm4, rd
|
||||
MOV_ir 0110 0110 imm:4 rd:4
|
||||
# MOV.b #imm8, dsp5[rd]
|
||||
MOV_im 0011 1100 . rd:3 .... imm:8 sz=0 dsp=%b3_dsp5_8
|
||||
# MOV.w #imm8, dsp5[rd]
|
||||
MOV_im 0011 1101 . rd:3 .... imm:8 sz=1 dsp=%b3_dsp5_8
|
||||
# MOV.l #imm8, dsp5[rd]
|
||||
MOV_im 0011 1110 . rd:3 .... imm:8 sz=2 dsp=%b3_dsp5_8
|
||||
# MOV.l #imm8, rd
|
||||
MOV_ir 0111 0101 0100 rd:4 imm:8
|
||||
# MOV.l #mm8, rd
|
||||
MOV_ir 1111 1011 rd:4 .. 10 imm=%b2_li_2
|
||||
# MOV.<bwl> #imm, [rd]
|
||||
MOV_im 1111 1000 rd:4 .. sz:2 dsp=0 imm=%b2_li_2
|
||||
# MOV.<bwl> #imm, dsp8[rd]
|
||||
MOV_im 1111 1001 rd:4 .. sz:2 dsp:8 imm=%b3_li_10
|
||||
# MOV.<bwl> #imm, dsp16[rd]
|
||||
MOV_im 1111 1010 rd:4 .. sz:2 .... .... .... .... \
|
||||
imm=%b4_li_18 dsp=%b4_dsp_16
|
||||
# MOV.<bwl> [ri,rb], rd
|
||||
MOV_ar 1111 1110 01 sz:2 ri:4 rb:4 rd:4
|
||||
# MOV.<bwl> rs, [ri,rb]
|
||||
MOV_ra 1111 1110 00 sz:2 ri:4 rb:4 rs:4
|
||||
# Note ldd=3 and lds=3 indicate register src or dst
|
||||
# MOV.b rs, rd
|
||||
# MOV.b rs, dsp[rd]
|
||||
# MOV.b dsp[rs], rd
|
||||
# MOV.b dsp[rs], dsp[rd]
|
||||
MOV_mm 1100 ldd:2 lds:2 rs:4 rd:4 sz=0
|
||||
# MOV.w rs, rd
|
||||
# MOV.w rs, dsp[rd]
|
||||
# MOV.w dsp[rs], rd
|
||||
# MOV.w dsp[rs], dsp[rd]
|
||||
MOV_mm 1101 ldd:2 lds:2 rs:4 rd:4 sz=1
|
||||
# MOV.l rs, rd
|
||||
# MOV.l rs, dsp[rd]
|
||||
# MOV.l dsp[rs], rd
|
||||
# MOV.l dsp[rs], dsp[rd]
|
||||
MOV_mm 1110 ldd:2 lds:2 rs:4 rd:4 sz=2
|
||||
# MOV.l rs, [rd+]
|
||||
# MOV.l rs, [-rd]
|
||||
MOV_rp 1111 1101 0010 0 ad:1 sz:2 rd:4 rs:4
|
||||
# MOV.l [rs+], rd
|
||||
# MOV.l [-rs], rd
|
||||
MOV_pr 1111 1101 0010 1 ad:1 sz:2 rd:4 rs:4
|
||||
|
||||
# MOVU.<bw> dsp5[rs], rd
|
||||
MOVU_mr 1011 sz:1 ... . rs:3 . rd:3 dsp=%b2_dsp5_3
|
||||
# MOVU.<bw> [rs], rd
|
||||
MOVU_mr 0101 1 sz:1 00 rs:4 rd:4 dsp=0
|
||||
# MOVU.<bw> dsp8[rs], rd
|
||||
MOVU_mr 0101 1 sz:1 01 rs:4 rd:4 dsp:8
|
||||
# MOVU.<bw> dsp16[rs], rd
|
||||
MOVU_mr 0101 1 sz:1 10 rs:4 rd:4 .... .... .... .... dsp=%b4_dsp_16
|
||||
# MOVU.<bw> rs, rd
|
||||
MOVU_rr 0101 1 sz:1 11 rs:4 rd:4
|
||||
# MOVU.<bw> [ri, rb], rd
|
||||
MOVU_ar 1111 1110 110 sz:1 ri:4 rb:4 rd:4
|
||||
# MOVU.<bw> [rs+], rd
|
||||
MOVU_pr 1111 1101 0011 1 ad:1 0 sz:1 rd:4 rs:4
|
||||
|
||||
# MUL #uimm4, rd
|
||||
MUL_ir 0110 0011 .... .... @b2_rds_uimm4
|
||||
# MUL #imm4, rd
|
||||
MUL_ir 0111 01.. 0001 .... @b2_rds_li
|
||||
# MUL dsp[rs].ub, rd
|
||||
# MUL rs, rd
|
||||
MUL_mr 0100 11.. .... .... @b2_rd_ld_ub
|
||||
# MUL dsp[rs], rd
|
||||
MUL_mr 0000 0110 ..00 11.. .... .... @b3_rd_ld
|
||||
# MOV rs, rs2, rd
|
||||
MUL_rrr 1111 1111 0011 .... .... .... @b3_rd_rs_rs2
|
||||
|
||||
# MULHI rs, rs2
|
||||
MULHI 1111 1101 0000 0000 rs:4 rs2:4
|
||||
# MULLO rs, rs2
|
||||
MULLO 1111 1101 0000 0001 rs:4 rs2:4
|
||||
|
||||
# MVFACHI rd
|
||||
MVFACHI 1111 1101 0001 1111 0000 rd:4
|
||||
# MVFACMI rd
|
||||
MVFACMI 1111 1101 0001 1111 0010 rd:4
|
||||
|
||||
# MVFC cr, rd
|
||||
MVFC 1111 1101 0110 1010 cr:4 rd:4
|
||||
|
||||
# MVTACHI rs
|
||||
MVTACHI 1111 1101 0001 0111 0000 rs:4
|
||||
# MVTACLO rs
|
||||
MVTACLO 1111 1101 0001 0111 0001 rs:4
|
||||
|
||||
# MVTC #imm, cr
|
||||
MVTC_i 1111 1101 0111 ..11 0000 cr:4 imm=%b3_li_10
|
||||
# MVTC rs, cr
|
||||
MVTC_r 1111 1101 0110 1000 rs:4 cr:4
|
||||
|
||||
# MVTIPL #imm
|
||||
MVTIPL 0111 0101 0111 0000 0000 imm:4
|
||||
|
||||
# NEG rd
|
||||
NEG_rr 0111 1110 0001 .... @b2_rds
|
||||
# NEG rs, rd
|
||||
NEG_rr 1111 1100 0000 0111 .... .... @b3_rd_rs
|
||||
|
||||
NOP 0000 0011
|
||||
|
||||
# NOT rd
|
||||
NOT_rr 0111 1110 0000 .... @b2_rds
|
||||
# NOT rs, rd
|
||||
NOT_rr 1111 1100 0011 1011 .... .... @b3_rd_rs
|
||||
|
||||
# OR #uimm4, rd
|
||||
OR_ir 0110 0101 .... .... @b2_rds_uimm4
|
||||
# OR #imm, rd
|
||||
OR_ir 0111 01.. 0011 .... @b2_rds_li
|
||||
# OR dsp[rs].ub, rd
|
||||
# OR rs, rd
|
||||
OR_mr 0101 01.. .... .... @b2_rd_ld_ub
|
||||
# OR dsp[rs], rd
|
||||
OR_mr 0000 0110 .. 0101 .. .... .... @b3_rd_ld
|
||||
# OR rs, rs2, rd
|
||||
OR_rrr 1111 1111 0101 .... .... .... @b3_rd_rs_rs2
|
||||
|
||||
# POP cr
|
||||
POPC 0111 1110 1110 cr:4
|
||||
# POP rd-rd2
|
||||
POPM 0110 1111 rd:4 rd2:4
|
||||
|
||||
# POP rd
|
||||
# PUSH.<bwl> rs
|
||||
{
|
||||
POP 0111 1110 1011 rd:4
|
||||
PUSH_r 0111 1110 10 sz:2 rs:4
|
||||
}
|
||||
# PUSH.<bwl> dsp[rs]
|
||||
PUSH_m 1111 01 ld:2 rs:4 10 sz:2
|
||||
# PUSH cr
|
||||
PUSHC 0111 1110 1100 cr:4
|
||||
# PUSHM rs-rs2
|
||||
PUSHM 0110 1110 rs:4 rs2:4
|
||||
|
||||
# RACW #imm
|
||||
RACW 1111 1101 0001 1000 000 imm:1 0000
|
||||
|
||||
# REVL rs,rd
|
||||
REVL 1111 1101 0110 0111 .... .... @b3_rd_rs
|
||||
# REVW rs,rd
|
||||
REVW 1111 1101 0110 0101 .... .... @b3_rd_rs
|
||||
|
||||
# SMOVF
|
||||
# RPMA.<bwl>
|
||||
{
|
||||
SMOVF 0111 1111 1000 1111
|
||||
RMPA 0111 1111 1000 11 sz:2
|
||||
}
|
||||
|
||||
# ROLC rd
|
||||
ROLC 0111 1110 0101 .... @b2_rds
|
||||
# RORC rd
|
||||
RORC 0111 1110 0100 .... @b2_rds
|
||||
|
||||
# ROTL #imm, rd
|
||||
ROTL_ir 1111 1101 0110 111. .... .... @b3_rds_imm5
|
||||
# ROTL rs, rd
|
||||
ROTL_rr 1111 1101 0110 0110 .... .... @b3_rd_rs
|
||||
|
||||
# ROTR #imm, rd
|
||||
ROTR_ir 1111 1101 0110 110. .... .... @b3_rds_imm5
|
||||
# ROTR #imm, rd
|
||||
ROTR_rr 1111 1101 0110 0100 .... .... @b3_rd_rs
|
||||
|
||||
# ROUND rs,rd
|
||||
# ROUND dsp[rs],rd
|
||||
ROUND 1111 1100 1001 10 .. .... .... @b3_ld_rd_rs
|
||||
|
||||
RTE 0111 1111 1001 0101
|
||||
|
||||
RTFI 0111 1111 1001 0100
|
||||
|
||||
RTS 0000 0010
|
||||
|
||||
# RTSD #imm
|
||||
RTSD_i 0110 0111 imm:8
|
||||
# RTSD #imm, rd-rd2
|
||||
RTSD_irr 0011 1111 rd:4 rd2:4 imm:8
|
||||
|
||||
# SAT rd
|
||||
SAT 0111 1110 0011 .... @b2_rds
|
||||
# SATR
|
||||
SATR 0111 1111 1001 0011
|
||||
|
||||
# SBB rs, rd
|
||||
SBB_rr 1111 1100 0000 0011 .... .... @b3_rd_rs
|
||||
# SBB dsp[rs].l, rd
|
||||
# Note only mi==2 allowed.
|
||||
SBB_mr 0000 0110 ..10 00.. 0000 0000 .... .... @b4_rd_ldmi
|
||||
|
||||
# SCCnd dsp[rd]
|
||||
# SCCnd rd
|
||||
SCCnd 1111 1100 1101 .... .... .... @b3_sz_ld_rd_cd
|
||||
|
||||
# SETPSW psw
|
||||
SETPSW 0111 1111 1010 cb:4
|
||||
|
||||
# SHAR #imm, rd
|
||||
SHAR_irr 0110 101. .... .... @b2_rds_imm5
|
||||
# SHAR #imm, rs, rd
|
||||
SHAR_irr 1111 1101 101. .... .... .... @b3_rd_rs_imm5
|
||||
# SHAR rs, rd
|
||||
SHAR_rr 1111 1101 0110 0001 .... .... @b3_rd_rs
|
||||
|
||||
# SHLL #imm, rd
|
||||
SHLL_irr 0110 110. .... .... @b2_rds_imm5
|
||||
# SHLL #imm, rs, rd
|
||||
SHLL_irr 1111 1101 110. .... .... .... @b3_rd_rs_imm5
|
||||
# SHLL rs, rd
|
||||
SHLL_rr 1111 1101 0110 0010 .... .... @b3_rd_rs
|
||||
|
||||
# SHLR #imm, rd
|
||||
SHLR_irr 0110 100. .... .... @b2_rds_imm5
|
||||
# SHLR #imm, rs, rd
|
||||
SHLR_irr 1111 1101 100. .... .... .... @b3_rd_rs_imm5
|
||||
# SHLR rs, rd
|
||||
SHLR_rr 1111 1101 0110 0000 .... .... @b3_rd_rs
|
||||
|
||||
# SMOVB
|
||||
# SSTR.<bwl>
|
||||
{
|
||||
SMOVB 0111 1111 1000 1011
|
||||
SSTR 0111 1111 1000 10 sz:2
|
||||
}
|
||||
|
||||
# STNZ #imm, rd
|
||||
STNZ 1111 1101 0111 ..00 1111 .... @b3_rd_li
|
||||
# STZ #imm, rd
|
||||
STZ 1111 1101 0111 ..00 1110 .... @b3_rd_li
|
||||
|
||||
# SUB #uimm4, rd
|
||||
SUB_ir 0110 0000 .... .... @b2_rds_uimm4
|
||||
# SUB dsp[rs].ub, rd
|
||||
# SUB rs, rd
|
||||
SUB_mr 0100 00.. .... .... @b2_rd_ld_ub
|
||||
# SUB dsp[rs], rd
|
||||
SUB_mr 0000 0110 ..00 00.. .... .... @b3_rd_ld
|
||||
# SUB rs, rs2, rd
|
||||
SUB_rrr 1111 1111 0000 .... .... .... @b3_rd_rs_rs2
|
||||
|
||||
# SCMPU
|
||||
# SUNTIL.<bwl>
|
||||
{
|
||||
SCMPU 0111 1111 1000 0011
|
||||
SUNTIL 0111 1111 1000 00 sz:2
|
||||
}
|
||||
|
||||
# SMOVU
|
||||
# SWHILE.<bwl>
|
||||
{
|
||||
SMOVU 0111 1111 1000 0111
|
||||
SWHILE 0111 1111 1000 01 sz:2
|
||||
}
|
||||
|
||||
# TST #imm, rd
|
||||
TST_ir 1111 1101 0111 ..00 1100 .... @b3_rd_li
|
||||
# TST dsp[rs].ub, rd
|
||||
# TST rs, rd
|
||||
TST_mr 1111 1100 0011 00.. .... .... @b3_rd_ld_ub
|
||||
# TST dsp[rs], rd
|
||||
TST_mr 0000 0110 ..10 00.. 0000 1100 .... .... @b4_rd_ldmi
|
||||
|
||||
WAIT 0111 1111 1001 0110
|
||||
|
||||
# XCHG rs, rd
|
||||
# XCHG dsp[rs].ub, rd
|
||||
{
|
||||
XCHG_rr 1111 1100 0100 0011 .... .... @b3_rd_rs
|
||||
XCHG_mr 1111 1100 0100 00.. .... .... @b3_rd_ld_ub
|
||||
}
|
||||
# XCHG dsp[rs], rd
|
||||
XCHG_mr 0000 0110 ..10 00.. 0001 0000 .... .... @b4_rd_ldmi
|
||||
|
||||
# XOR #imm, rd
|
||||
XOR_ir 1111 1101 0111 ..00 1101 .... @b3_rd_li
|
||||
# XOR dsp[rs].ub, rd
|
||||
# XOR rs, rd
|
||||
XOR_mr 1111 1100 0011 01.. .... .... @b3_rd_ld_ub
|
||||
# XOR dsp[rs], rd
|
||||
XOR_mr 0000 0110 ..10 00.. 0000 1101 .... .... @b4_rd_ldmi
|
|
@ -0,0 +1,470 @@
|
|||
/*
|
||||
* RX helper functions
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "fpu/softfloat.h"
|
||||
|
||||
static inline void QEMU_NORETURN raise_exception(CPURXState *env, int index,
|
||||
uintptr_t retaddr);
|
||||
|
||||
static void _set_psw(CPURXState *env, uint32_t psw, uint32_t rte)
|
||||
{
|
||||
uint32_t prev_u;
|
||||
prev_u = env->psw_u;
|
||||
rx_cpu_unpack_psw(env, psw, rte);
|
||||
if (prev_u != env->psw_u) {
|
||||
/* switch r0 */
|
||||
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_set_psw(CPURXState *env, uint32_t psw)
|
||||
{
|
||||
_set_psw(env, psw, 0);
|
||||
}
|
||||
|
||||
void helper_set_psw_rte(CPURXState *env, uint32_t psw)
|
||||
{
|
||||
_set_psw(env, psw, 1);
|
||||
}
|
||||
|
||||
uint32_t helper_pack_psw(CPURXState *env)
|
||||
{
|
||||
return rx_cpu_pack_psw(env);
|
||||
}
|
||||
|
||||
#define SET_FPSW(b) \
|
||||
do { \
|
||||
env->fpsw = FIELD_DP32(env->fpsw, FPSW, C ## b, 1); \
|
||||
if (!FIELD_EX32(env->fpsw, FPSW, E ## b)) { \
|
||||
env->fpsw = FIELD_DP32(env->fpsw, FPSW, F ## b, 1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* fp operations */
|
||||
static void update_fpsw(CPURXState *env, float32 ret, uintptr_t retaddr)
|
||||
{
|
||||
int xcpt, cause, enable;
|
||||
|
||||
env->psw_z = ret & ~(1 << 31); /* mask sign bit */
|
||||
env->psw_s = ret;
|
||||
|
||||
xcpt = get_float_exception_flags(&env->fp_status);
|
||||
|
||||
/* Clear the cause entries */
|
||||
env->fpsw = FIELD_DP32(env->fpsw, FPSW, CAUSE, 0);
|
||||
|
||||
/* set FPSW */
|
||||
if (unlikely(xcpt)) {
|
||||
if (xcpt & float_flag_invalid) {
|
||||
SET_FPSW(V);
|
||||
}
|
||||
if (xcpt & float_flag_divbyzero) {
|
||||
SET_FPSW(Z);
|
||||
}
|
||||
if (xcpt & float_flag_overflow) {
|
||||
SET_FPSW(O);
|
||||
}
|
||||
if (xcpt & float_flag_underflow) {
|
||||
SET_FPSW(U);
|
||||
}
|
||||
if (xcpt & float_flag_inexact) {
|
||||
SET_FPSW(X);
|
||||
}
|
||||
if ((xcpt & (float_flag_input_denormal
|
||||
| float_flag_output_denormal))
|
||||
&& !FIELD_EX32(env->fpsw, FPSW, DN)) {
|
||||
env->fpsw = FIELD_DP32(env->fpsw, FPSW, CE, 1);
|
||||
}
|
||||
|
||||
/* update FPSW_FLAG_S */
|
||||
if (FIELD_EX32(env->fpsw, FPSW, FLAGS) != 0) {
|
||||
env->fpsw = FIELD_DP32(env->fpsw, FPSW, FS, 1);
|
||||
}
|
||||
|
||||
/* Generate an exception if enabled */
|
||||
cause = FIELD_EX32(env->fpsw, FPSW, CAUSE);
|
||||
enable = FIELD_EX32(env->fpsw, FPSW, ENABLE);
|
||||
enable |= 1 << 5; /* CE always enabled */
|
||||
if (cause & enable) {
|
||||
raise_exception(env, 21, retaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void helper_set_fpsw(CPURXState *env, uint32_t val)
|
||||
{
|
||||
static const int roundmode[] = {
|
||||
float_round_nearest_even,
|
||||
float_round_to_zero,
|
||||
float_round_up,
|
||||
float_round_down,
|
||||
};
|
||||
uint32_t fpsw = env->fpsw;
|
||||
fpsw |= 0x7fffff03;
|
||||
val &= ~0x80000000;
|
||||
fpsw &= val;
|
||||
FIELD_DP32(fpsw, FPSW, FS, FIELD_EX32(fpsw, FPSW, FLAGS) != 0);
|
||||
env->fpsw = fpsw;
|
||||
set_float_rounding_mode(roundmode[FIELD_EX32(env->fpsw, FPSW, RM)],
|
||||
&env->fp_status);
|
||||
}
|
||||
|
||||
#define FLOATOP(op, func) \
|
||||
float32 helper_##op(CPURXState *env, float32 t0, float32 t1) \
|
||||
{ \
|
||||
float32 ret; \
|
||||
ret = func(t0, t1, &env->fp_status); \
|
||||
update_fpsw(env, *(uint32_t *)&ret, GETPC()); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
FLOATOP(fadd, float32_add)
|
||||
FLOATOP(fsub, float32_sub)
|
||||
FLOATOP(fmul, float32_mul)
|
||||
FLOATOP(fdiv, float32_div)
|
||||
|
||||
void helper_fcmp(CPURXState *env, float32 t0, float32 t1)
|
||||
{
|
||||
int st;
|
||||
st = float32_compare(t0, t1, &env->fp_status);
|
||||
update_fpsw(env, 0, GETPC());
|
||||
env->psw_z = 1;
|
||||
env->psw_s = env->psw_o = 0;
|
||||
switch (st) {
|
||||
case float_relation_equal:
|
||||
env->psw_z = 0;
|
||||
break;
|
||||
case float_relation_less:
|
||||
env->psw_s = -1;
|
||||
break;
|
||||
case float_relation_unordered:
|
||||
env->psw_o = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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, ret, 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, ret, GETPC());
|
||||
return ret;
|
||||
}
|
||||
|
||||
float32 helper_itof(CPURXState *env, uint32_t t0)
|
||||
{
|
||||
float32 ret;
|
||||
ret = int32_to_float32(t0, &env->fp_status);
|
||||
update_fpsw(env, ret, GETPC());
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* string operations */
|
||||
void helper_scmpu(CPURXState *env)
|
||||
{
|
||||
uint8_t tmp0, tmp1;
|
||||
if (env->regs[3] == 0) {
|
||||
return;
|
||||
}
|
||||
while (env->regs[3] != 0) {
|
||||
tmp0 = cpu_ldub_data_ra(env, env->regs[1]++, GETPC());
|
||||
tmp1 = cpu_ldub_data_ra(env, env->regs[2]++, GETPC());
|
||||
env->regs[3]--;
|
||||
if (tmp0 != tmp1 || tmp0 == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
env->psw_z = tmp0 - tmp1;
|
||||
env->psw_c = (tmp0 >= tmp1);
|
||||
}
|
||||
|
||||
static uint32_t (* const cpu_ldufn[])(CPUArchState *env,
|
||||
target_ulong ptr,
|
||||
uintptr_t retaddr) = {
|
||||
cpu_ldub_data_ra, cpu_lduw_data_ra, cpu_ldl_data_ra,
|
||||
};
|
||||
|
||||
static uint32_t (* const cpu_ldfn[])(CPUArchState *env,
|
||||
target_ulong ptr,
|
||||
uintptr_t retaddr) = {
|
||||
cpu_ldub_data_ra, cpu_lduw_data_ra, cpu_ldl_data_ra,
|
||||
};
|
||||
|
||||
static void (* const cpu_stfn[])(CPUArchState *env,
|
||||
target_ulong ptr,
|
||||
uint32_t val,
|
||||
uintptr_t retaddr) = {
|
||||
cpu_stb_data_ra, cpu_stw_data_ra, cpu_stl_data_ra,
|
||||
};
|
||||
|
||||
void helper_sstr(CPURXState *env, uint32_t sz)
|
||||
{
|
||||
tcg_debug_assert(sz < 3);
|
||||
while (env->regs[3] != 0) {
|
||||
cpu_stfn[sz](env, env->regs[1], env->regs[2], GETPC());
|
||||
env->regs[1] += 1 << sz;
|
||||
env->regs[3]--;
|
||||
}
|
||||
}
|
||||
|
||||
#define OP_SMOVU 1
|
||||
#define OP_SMOVF 0
|
||||
#define OP_SMOVB 2
|
||||
|
||||
static void smov(uint32_t mode, CPURXState *env)
|
||||
{
|
||||
uint8_t tmp;
|
||||
int dir;
|
||||
|
||||
dir = (mode & OP_SMOVB) ? -1 : 1;
|
||||
while (env->regs[3] != 0) {
|
||||
tmp = cpu_ldub_data_ra(env, env->regs[2], GETPC());
|
||||
cpu_stb_data_ra(env, env->regs[1], tmp, GETPC());
|
||||
env->regs[1] += dir;
|
||||
env->regs[2] += dir;
|
||||
env->regs[3]--;
|
||||
if ((mode & OP_SMOVU) && tmp == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void helper_smovu(CPURXState *env)
|
||||
{
|
||||
smov(OP_SMOVU, env);
|
||||
}
|
||||
|
||||
void helper_smovf(CPURXState *env)
|
||||
{
|
||||
smov(OP_SMOVF, env);
|
||||
}
|
||||
|
||||
void helper_smovb(CPURXState *env)
|
||||
{
|
||||
smov(OP_SMOVB, env);
|
||||
}
|
||||
|
||||
|
||||
void helper_suntil(CPURXState *env, uint32_t sz)
|
||||
{
|
||||
uint32_t tmp;
|
||||
tcg_debug_assert(sz < 3);
|
||||
if (env->regs[3] == 0) {
|
||||
return ;
|
||||
}
|
||||
while (env->regs[3] != 0) {
|
||||
tmp = cpu_ldufn[sz](env, env->regs[1], GETPC());
|
||||
env->regs[1] += 1 << sz;
|
||||
env->regs[3]--;
|
||||
if (tmp == env->regs[2]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
env->psw_z = tmp - env->regs[2];
|
||||
env->psw_c = (tmp <= env->regs[2]);
|
||||
}
|
||||
|
||||
void helper_swhile(CPURXState *env, uint32_t sz)
|
||||
{
|
||||
uint32_t tmp;
|
||||
tcg_debug_assert(sz < 3);
|
||||
if (env->regs[3] == 0) {
|
||||
return ;
|
||||
}
|
||||
while (env->regs[3] != 0) {
|
||||
tmp = cpu_ldufn[sz](env, env->regs[1], GETPC());
|
||||
env->regs[1] += 1 << sz;
|
||||
env->regs[3]--;
|
||||
if (tmp != env->regs[2]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
env->psw_z = env->regs[3];
|
||||
env->psw_c = (tmp <= env->regs[2]);
|
||||
}
|
||||
|
||||
/* accumlator operations */
|
||||
void helper_rmpa(CPURXState *env, uint32_t sz)
|
||||
{
|
||||
uint64_t result_l, prev;
|
||||
int32_t result_h;
|
||||
int64_t tmp0, tmp1;
|
||||
|
||||
if (env->regs[3] == 0) {
|
||||
return;
|
||||
}
|
||||
result_l = env->regs[5];
|
||||
result_l <<= 32;
|
||||
result_l |= env->regs[4];
|
||||
result_h = env->regs[6];
|
||||
env->psw_o = 0;
|
||||
|
||||
while (env->regs[3] != 0) {
|
||||
tmp0 = cpu_ldfn[sz](env, env->regs[1], GETPC());
|
||||
tmp1 = cpu_ldfn[sz](env, env->regs[2], GETPC());
|
||||
tmp0 *= tmp1;
|
||||
prev = result_l;
|
||||
result_l += tmp0;
|
||||
/* carry / bollow */
|
||||
if (tmp0 < 0) {
|
||||
if (prev > result_l) {
|
||||
result_h--;
|
||||
}
|
||||
} else {
|
||||
if (prev < result_l) {
|
||||
result_h++;
|
||||
}
|
||||
}
|
||||
|
||||
env->regs[1] += 1 << sz;
|
||||
env->regs[2] += 1 << sz;
|
||||
}
|
||||
env->psw_s = result_h;
|
||||
env->psw_o = (result_h != 0 && result_h != -1) << 31;
|
||||
env->regs[6] = result_h;
|
||||
env->regs[5] = result_l >> 32;
|
||||
env->regs[4] = result_l & 0xffffffff;
|
||||
}
|
||||
|
||||
void helper_racw(CPURXState *env, uint32_t imm)
|
||||
{
|
||||
int64_t acc;
|
||||
acc = env->acc;
|
||||
acc <<= (imm + 1);
|
||||
acc += 0x0000000080000000LL;
|
||||
if (acc > 0x00007fff00000000LL) {
|
||||
acc = 0x00007fff00000000LL;
|
||||
} else if (acc < -0x800000000000LL) {
|
||||
acc = -0x800000000000LL;
|
||||
} else {
|
||||
acc &= 0xffffffff00000000LL;
|
||||
}
|
||||
env->acc = acc;
|
||||
}
|
||||
|
||||
void helper_satr(CPURXState *env)
|
||||
{
|
||||
if (env->psw_o >> 31) {
|
||||
if ((int)env->psw_s < 0) {
|
||||
env->regs[6] = 0x00000000;
|
||||
env->regs[5] = 0x7fffffff;
|
||||
env->regs[4] = 0xffffffff;
|
||||
} else {
|
||||
env->regs[6] = 0xffffffff;
|
||||
env->regs[5] = 0x80000000;
|
||||
env->regs[4] = 0x00000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* div */
|
||||
uint32_t helper_div(CPURXState *env, uint32_t num, uint32_t den)
|
||||
{
|
||||
uint32_t ret = num;
|
||||
if (!((num == INT_MIN && den == -1) || den == 0)) {
|
||||
ret = (int32_t)num / (int32_t)den;
|
||||
env->psw_o = 0;
|
||||
} else {
|
||||
env->psw_o = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t helper_divu(CPURXState *env, uint32_t num, uint32_t den)
|
||||
{
|
||||
uint32_t ret = num;
|
||||
if (den != 0) {
|
||||
ret = num / den;
|
||||
env->psw_o = 0;
|
||||
} else {
|
||||
env->psw_o = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* exception */
|
||||
static inline void QEMU_NORETURN raise_exception(CPURXState *env, int index,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
CPUState *cs = env_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 = env_cpu(env);
|
||||
|
||||
cs->halted = 1;
|
||||
env->in_sleep = 1;
|
||||
raise_exception(env, EXCP_HLT, 0);
|
||||
}
|
||||
|
||||
void QEMU_NORETURN helper_debug(CPURXState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
cs->exception_index = EXCP_DEBUG;
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
void QEMU_NORETURN helper_rxint(CPURXState *env, uint32_t vec)
|
||||
{
|
||||
raise_exception(env, 0x100 + vec, 0);
|
||||
}
|
||||
|
||||
void QEMU_NORETURN helper_rxbrk(CPURXState *env)
|
||||
{
|
||||
raise_exception(env, 0x100, 0);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -56,6 +56,7 @@ static struct arch2cpu cpus_map[] = {
|
|||
{ "hppa", "hppa" },
|
||||
{ "riscv64", "rv64gcsu-v1.10.0" },
|
||||
{ "riscv32", "rv32gcsu-v1.9.1" },
|
||||
{ "rx", "rx62n" },
|
||||
};
|
||||
|
||||
static const char *get_cpu_model_by_arch(const char *arch)
|
||||
|
|
Loading…
Reference in New Issue