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:
Peter Maydell 2020-03-20 12:15:19 +00:00
commit 226cd20706
23 changed files with 5897 additions and 2 deletions

View File

@ -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>

View File

@ -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)

11
configure vendored
View File

@ -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"
;;

View File

@ -0,0 +1,2 @@
# Default configuration for rx-softmmu

70
gdb-xml/rx-core.xml Normal file
View File

@ -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>

View File

@ -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. */

View File

@ -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

View File

@ -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; \

View File

@ -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),
};

View File

@ -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' ] }

11
target/rx/Makefile.objs Normal file
View File

@ -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

30
target/rx/cpu-param.h Normal file
View File

@ -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

53
target/rx/cpu-qom.h Normal file
View File

@ -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

225
target/rx/cpu.c Normal file
View File

@ -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)

180
target/rx/cpu.h Normal file
View File

@ -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 */

1446
target/rx/disas.c Normal file

File diff suppressed because it is too large Load Diff

112
target/rx/gdbstub.c Normal file
View File

@ -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;
}

149
target/rx/helper.c Normal file
View File

@ -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;
}

31
target/rx/helper.h Normal file
View File

@ -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)

621
target/rx/insns.decode Normal file
View File

@ -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

470
target/rx/op_helper.c Normal file
View File

@ -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);
}

2439
target/rx/translate.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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)