diff options
author | Thomas Huth <thuth@redhat.com> | 2016-10-11 08:56:52 +0200 |
---|---|---|
committer | Thomas Huth <thuth@redhat.com> | 2016-12-20 21:52:12 +0100 |
commit | fcf5ef2ab52c621a4617ebbef36bf43b4003f4c0 (patch) | |
tree | 2b450d96b01455df8ed908bf8f26ddc388a03380 /target-sh4 | |
parent | 82ecffa8c050bf5bbc13329e9b65eac1caa5b55c (diff) |
Move target-* CPU file into a target/ folder
We've currently got 18 architectures in QEMU, and thus 18 target-xxx
folders in the root folder of the QEMU source tree. More architectures
(e.g. RISC-V, AVR) are likely to be included soon, too, so the main
folder of the QEMU sources slowly gets quite overcrowded with the
target-xxx folders.
To disburden the main folder a little bit, let's move the target-xxx
folders into a dedicated target/ folder, so that target-xxx/ simply
becomes target/xxx/ instead.
Acked-by: Laurent Vivier <laurent@vivier.eu> [m68k part]
Acked-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> [tricore part]
Acked-by: Michael Walle <michael@walle.cc> [lm32 part]
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com> [s390x part]
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com> [s390x part]
Acked-by: Eduardo Habkost <ehabkost@redhat.com> [i386 part]
Acked-by: Artyom Tarasenko <atar4qemu@gmail.com> [sparc part]
Acked-by: Richard Henderson <rth@twiddle.net> [alpha part]
Acked-by: Max Filippov <jcmvbkbc@gmail.com> [xtensa part]
Reviewed-by: David Gibson <david@gibson.dropbear.id.au> [ppc part]
Acked-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> [crisµblaze part]
Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn> [unicore32 part]
Signed-off-by: Thomas Huth <thuth@redhat.com>
Diffstat (limited to 'target-sh4')
-rw-r--r-- | target-sh4/Makefile.objs | 3 | ||||
-rw-r--r-- | target-sh4/README.sh4 | 150 | ||||
-rw-r--r-- | target-sh4/cpu-qom.h | 65 | ||||
-rw-r--r-- | target-sh4/cpu.c | 332 | ||||
-rw-r--r-- | target-sh4/cpu.h | 391 | ||||
-rw-r--r-- | target-sh4/gdbstub.c | 147 | ||||
-rw-r--r-- | target-sh4/helper.c | 872 | ||||
-rw-r--r-- | target-sh4/helper.h | 45 | ||||
-rw-r--r-- | target-sh4/monitor.c | 53 | ||||
-rw-r--r-- | target-sh4/op_helper.c | 498 | ||||
-rw-r--r-- | target-sh4/translate.c | 1944 |
11 files changed, 0 insertions, 4500 deletions
diff --git a/target-sh4/Makefile.objs b/target-sh4/Makefile.objs deleted file mode 100644 index 2c25d96e65..0000000000 --- a/target-sh4/Makefile.objs +++ /dev/null @@ -1,3 +0,0 @@ -obj-y += translate.o op_helper.o helper.o cpu.o -obj-$(CONFIG_SOFTMMU) += monitor.o -obj-y += gdbstub.o diff --git a/target-sh4/README.sh4 b/target-sh4/README.sh4 deleted file mode 100644 index ece046442a..0000000000 --- a/target-sh4/README.sh4 +++ /dev/null @@ -1,150 +0,0 @@ -qemu target: sh4 -author: Samuel Tardieu <sam@rfc1149.net> -last modified: Tue Dec 6 07:22:44 CET 2005 - -The sh4 target is not ready at all yet for integration in qemu. This -file describes the current state of implementation. - -Most places requiring attention and/or modification can be detected by -looking for "XXXXX" or "abort()". - -The sh4 core is located in target-sh4/*, while the 7750 peripheral -features (IO ports for example) are located in hw/sh7750.[ch]. The -main board description is in hw/shix.c, and the NAND flash in -hw/tc58128.[ch]. - -All the shortcomings indicated here will eventually be resolved. This -is a work in progress. Features are added in a semi-random order: if a -point is blocking to progress on booting the Linux kernel for the shix -board, it is addressed first; if feedback is necessary and no progress -can be made on blocking points until it is received, a random feature -is worked on. - -Goals ------ - -The primary model being worked on is the soft MMU target to be able to -emulate the Shix 2.0 board by Alexis Polti, described at -https://web.archive.org/web/20070917001736/http://perso.enst.fr/~polti/realisations/shix20/ - -Ultimately, qemu will be coupled with a system C or a verilog -simulator to simulate the whole board functionalities. - -A sh4 user-mode has also somewhat started but will be worked on -afterwards. The goal is to automate tests for GNAT (GNU Ada) compiler -that I ported recently to the sh4-linux target. - -Registers ---------- - -16 general purpose registers are available at any time. The first 8 -registers are banked and the non-directly visible ones can be accessed -by privileged instructions. In qemu, we define 24 general purpose -registers and the code generation use either [0-7]+[8-15] or -[16-23]+[8-15] depending on the MD and RB flags in the sr -configuration register. - -Instructions ------------- - -Most sh4 instructions have been implemented. The missing ones at this -time are: - - FPU related instructions - - LDTLB to load a new MMU entry - - SLEEP to put the processor in sleep mode - -Most instructions could be optimized a lot. This will be worked on -after the current model is fully functional unless debugging -convenience requires that it is done early. - -Many instructions did not have a chance to be tested yet. The plan is -to implement unit and regression testing of those in the future. - -MMU ---- - -The MMU is implemented in the sh4 core. MMU management has not been -tested at all yet. In the sh7750, it can be manipulated through memory -mapped registers and this part has not yet been implemented. - -Exceptions ----------- - -Exceptions are implemented as described in the sh4 reference manual -but have not been tested yet. They do not use qemu EXCP_ features -yet. - -IRQ ---- - -IRQ are not implemented yet. - -Peripheral features -------------------- - - + Serial ports - -Configuration and use of the first serial port (SCI) without -interrupts is supported. Input has not yet been tested. - -Configuration of the second serial port (SCIF) is supported. FIFO -handling infrastructure has been started but is not completed yet. - - + GPIO ports - -GPIO ports have been implemented. A registration function allows -external modules to register interest in some port changes (see -hw/tc58128.[ch] for an example) and will be called back. Interrupt -generation is not yet supported but some infrastructure is in place -for this purpose. Note that in the current model a peripheral module -cannot directly simulate a H->L->H input port transition and have an -interrupt generated on the low level. - - + TC58128 NAND flash - -TC58128 NAND flash is partially implemented through GPIO ports. It -supports reading from flash. - -GDB ---- - -GDB remote target support has been implemented and lightly tested. - -Files ------ - -File names are hardcoded at this time. The bootloader must be stored in -shix_bios.bin in the current directory. The initial Linux image must -be stored in shix_linux_nand.bin in the current directory in NAND -format. Test files can be obtained from -http://perso.enst.fr/~polti/robot/ as well as the various datasheets I -use. - -qemu disk parameter on the command line is unused. You can supply any -existing image and it will be ignored. As the goal is to simulate an -embedded target, it is not clear how this parameter will be handled in -the future. - -To build an ELF kernel image from the NAND image, 16 bytes have to be -stripped off the end of every 528 bytes, keeping only 512 of them. The -following Python code snippet does it: - -#! /usr/bin/python - -def denand (infd, outfd): - while True: - d = infd.read (528) - if not d: return - outfd.write (d[:512]) - -if __name__ == '__main__': - import sys - denand (open (sys.argv[1], 'rb'), - open (sys.argv[2], 'wb')) - -Style isssues -------------- - -There is currently a mix between my style (space before opening -parenthesis) and qemu style. This will be resolved before final -integration is proposed. diff --git a/target-sh4/cpu-qom.h b/target-sh4/cpu-qom.h deleted file mode 100644 index 01abb206e4..0000000000 --- a/target-sh4/cpu-qom.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * QEMU SuperH CPU - * - * Copyright (c) 2012 SUSE LINUX Products GmbH - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * <http://www.gnu.org/licenses/lgpl-2.1.html> - */ -#ifndef QEMU_SUPERH_CPU_QOM_H -#define QEMU_SUPERH_CPU_QOM_H - -#include "qom/cpu.h" - -#define TYPE_SUPERH_CPU "superh-cpu" - -#define TYPE_SH7750R_CPU "sh7750r-" TYPE_SUPERH_CPU -#define TYPE_SH7751R_CPU "sh7751r-" TYPE_SUPERH_CPU -#define TYPE_SH7785_CPU "sh7785-" TYPE_SUPERH_CPU - -#define SUPERH_CPU_CLASS(klass) \ - OBJECT_CLASS_CHECK(SuperHCPUClass, (klass), TYPE_SUPERH_CPU) -#define SUPERH_CPU(obj) \ - OBJECT_CHECK(SuperHCPU, (obj), TYPE_SUPERH_CPU) -#define SUPERH_CPU_GET_CLASS(obj) \ - OBJECT_GET_CLASS(SuperHCPUClass, (obj), TYPE_SUPERH_CPU) - -/** - * SuperHCPUClass: - * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. - * @name: The name. - * @pvr: Processor Version Register - * @prr: Processor Revision Register - * @cvr: Cache Version Register - * - * A SuperH CPU model. - */ -typedef struct SuperHCPUClass { - /*< private >*/ - CPUClass parent_class; - /*< public >*/ - - DeviceRealize parent_realize; - void (*parent_reset)(CPUState *cpu); - - const char *name; - uint32_t pvr; - uint32_t prr; - uint32_t cvr; -} SuperHCPUClass; - -typedef struct SuperHCPU SuperHCPU; - -#endif diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c deleted file mode 100644 index a38f6a6ded..0000000000 --- a/target-sh4/cpu.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - * QEMU SuperH CPU - * - * Copyright (c) 2005 Samuel Tardieu - * Copyright (c) 2012 SUSE LINUX Products GmbH - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * <http://www.gnu.org/licenses/lgpl-2.1.html> - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "cpu.h" -#include "qemu-common.h" -#include "migration/vmstate.h" -#include "exec/exec-all.h" - - -static void superh_cpu_set_pc(CPUState *cs, vaddr value) -{ - SuperHCPU *cpu = SUPERH_CPU(cs); - - cpu->env.pc = value; -} - -static void superh_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb) -{ - SuperHCPU *cpu = SUPERH_CPU(cs); - - cpu->env.pc = tb->pc; - cpu->env.flags = tb->flags; -} - -static bool superh_cpu_has_work(CPUState *cs) -{ - return cs->interrupt_request & CPU_INTERRUPT_HARD; -} - -/* CPUClass::reset() */ -static void superh_cpu_reset(CPUState *s) -{ - SuperHCPU *cpu = SUPERH_CPU(s); - SuperHCPUClass *scc = SUPERH_CPU_GET_CLASS(cpu); - CPUSH4State *env = &cpu->env; - - scc->parent_reset(s); - - memset(env, 0, offsetof(CPUSH4State, id)); - tlb_flush(s, 1); - - env->pc = 0xA0000000; -#if defined(CONFIG_USER_ONLY) - env->fpscr = FPSCR_PR; /* value for userspace according to the kernel */ - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); /* ?! */ -#else - env->sr = (1u << SR_MD) | (1u << SR_RB) | (1u << SR_BL) | - (1u << SR_I3) | (1u << SR_I2) | (1u << SR_I1) | (1u << SR_I0); - env->fpscr = FPSCR_DN | FPSCR_RM_ZERO; /* CPU reset value according to SH4 manual */ - set_float_rounding_mode(float_round_to_zero, &env->fp_status); - set_flush_to_zero(1, &env->fp_status); -#endif - set_default_nan_mode(1, &env->fp_status); - set_snan_bit_is_one(1, &env->fp_status); -} - -static void superh_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) -{ - info->mach = bfd_mach_sh4; - info->print_insn = print_insn_sh; -} - -typedef struct SuperHCPUListState { - fprintf_function cpu_fprintf; - FILE *file; -} SuperHCPUListState; - -/* Sort alphabetically by type name. */ -static gint superh_cpu_list_compare(gconstpointer a, gconstpointer b) -{ - ObjectClass *class_a = (ObjectClass *)a; - ObjectClass *class_b = (ObjectClass *)b; - const char *name_a, *name_b; - - name_a = object_class_get_name(class_a); - name_b = object_class_get_name(class_b); - return strcmp(name_a, name_b); -} - -static void superh_cpu_list_entry(gpointer data, gpointer user_data) -{ - ObjectClass *oc = data; - SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); - SuperHCPUListState *s = user_data; - - (*s->cpu_fprintf)(s->file, "%s\n", - scc->name); -} - -void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf) -{ - SuperHCPUListState s = { - .cpu_fprintf = cpu_fprintf, - .file = f, - }; - GSList *list; - - list = object_class_get_list(TYPE_SUPERH_CPU, false); - list = g_slist_sort(list, superh_cpu_list_compare); - g_slist_foreach(list, superh_cpu_list_entry, &s); - g_slist_free(list); -} - -static gint superh_cpu_name_compare(gconstpointer a, gconstpointer b) -{ - const SuperHCPUClass *scc = SUPERH_CPU_CLASS(a); - const char *name = b; - - return strcasecmp(scc->name, name); -} - -static ObjectClass *superh_cpu_class_by_name(const char *cpu_model) -{ - ObjectClass *oc; - GSList *list, *item; - - if (cpu_model == NULL) { - return NULL; - } - if (strcasecmp(cpu_model, "any") == 0) { - return object_class_by_name(TYPE_SH7750R_CPU); - } - - oc = object_class_by_name(cpu_model); - if (oc != NULL && object_class_dynamic_cast(oc, TYPE_SUPERH_CPU) != NULL - && !object_class_is_abstract(oc)) { - return oc; - } - - oc = NULL; - list = object_class_get_list(TYPE_SUPERH_CPU, false); - item = g_slist_find_custom(list, cpu_model, superh_cpu_name_compare); - if (item != NULL) { - oc = item->data; - } - g_slist_free(list); - return oc; -} - -SuperHCPU *cpu_sh4_init(const char *cpu_model) -{ - return SUPERH_CPU(cpu_generic_init(TYPE_SUPERH_CPU, cpu_model)); -} - -static void sh7750r_cpu_initfn(Object *obj) -{ - SuperHCPU *cpu = SUPERH_CPU(obj); - CPUSH4State *env = &cpu->env; - - env->id = SH_CPU_SH7750R; - env->features = SH_FEATURE_BCR3_AND_BCR4; -} - -static void sh7750r_class_init(ObjectClass *oc, void *data) -{ - SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); - - scc->name = "SH7750R"; - scc->pvr = 0x00050000; - scc->prr = 0x00000100; - scc->cvr = 0x00110000; -} - -static const TypeInfo sh7750r_type_info = { - .name = TYPE_SH7750R_CPU, - .parent = TYPE_SUPERH_CPU, - .class_init = sh7750r_class_init, - .instance_init = sh7750r_cpu_initfn, -}; - -static void sh7751r_cpu_initfn(Object *obj) -{ - SuperHCPU *cpu = SUPERH_CPU(obj); - CPUSH4State *env = &cpu->env; - - env->id = SH_CPU_SH7751R; - env->features = SH_FEATURE_BCR3_AND_BCR4; -} - -static void sh7751r_class_init(ObjectClass *oc, void *data) -{ - SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); - - scc->name = "SH7751R"; - scc->pvr = 0x04050005; - scc->prr = 0x00000113; - scc->cvr = 0x00110000; /* Neutered caches, should be 0x20480000 */ -} - -static const TypeInfo sh7751r_type_info = { - .name = TYPE_SH7751R_CPU, - .parent = TYPE_SUPERH_CPU, - .class_init = sh7751r_class_init, - .instance_init = sh7751r_cpu_initfn, -}; - -static void sh7785_cpu_initfn(Object *obj) -{ - SuperHCPU *cpu = SUPERH_CPU(obj); - CPUSH4State *env = &cpu->env; - - env->id = SH_CPU_SH7785; - env->features = SH_FEATURE_SH4A; -} - -static void sh7785_class_init(ObjectClass *oc, void *data) -{ - SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); - - scc->name = "SH7785"; - scc->pvr = 0x10300700; - scc->prr = 0x00000200; - scc->cvr = 0x71440211; -} - -static const TypeInfo sh7785_type_info = { - .name = TYPE_SH7785_CPU, - .parent = TYPE_SUPERH_CPU, - .class_init = sh7785_class_init, - .instance_init = sh7785_cpu_initfn, -}; - -static void superh_cpu_realizefn(DeviceState *dev, Error **errp) -{ - CPUState *cs = CPU(dev); - SuperHCPUClass *scc = SUPERH_CPU_GET_CLASS(dev); - Error *local_err = NULL; - - cpu_exec_realizefn(cs, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - - cpu_reset(cs); - qemu_init_vcpu(cs); - - scc->parent_realize(dev, errp); -} - -static void superh_cpu_initfn(Object *obj) -{ - CPUState *cs = CPU(obj); - SuperHCPU *cpu = SUPERH_CPU(obj); - CPUSH4State *env = &cpu->env; - - cs->env_ptr = env; - - env->movcal_backup_tail = &(env->movcal_backup); - - if (tcg_enabled()) { - sh4_translate_init(); - } -} - -static const VMStateDescription vmstate_sh_cpu = { - .name = "cpu", - .unmigratable = 1, -}; - -static void superh_cpu_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); - SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); - - scc->parent_realize = dc->realize; - dc->realize = superh_cpu_realizefn; - - scc->parent_reset = cc->reset; - cc->reset = superh_cpu_reset; - - cc->class_by_name = superh_cpu_class_by_name; - cc->has_work = superh_cpu_has_work; - cc->do_interrupt = superh_cpu_do_interrupt; - cc->cpu_exec_interrupt = superh_cpu_exec_interrupt; - cc->dump_state = superh_cpu_dump_state; - cc->set_pc = superh_cpu_set_pc; - cc->synchronize_from_tb = superh_cpu_synchronize_from_tb; - cc->gdb_read_register = superh_cpu_gdb_read_register; - cc->gdb_write_register = superh_cpu_gdb_write_register; -#ifdef CONFIG_USER_ONLY - cc->handle_mmu_fault = superh_cpu_handle_mmu_fault; -#else - cc->get_phys_page_debug = superh_cpu_get_phys_page_debug; -#endif - cc->disas_set_info = superh_cpu_disas_set_info; - - cc->gdb_num_core_regs = 59; - - dc->vmsd = &vmstate_sh_cpu; -} - -static const TypeInfo superh_cpu_type_info = { - .name = TYPE_SUPERH_CPU, - .parent = TYPE_CPU, - .instance_size = sizeof(SuperHCPU), - .instance_init = superh_cpu_initfn, - .abstract = true, - .class_size = sizeof(SuperHCPUClass), - .class_init = superh_cpu_class_init, -}; - -static void superh_cpu_register_types(void) -{ - type_register_static(&superh_cpu_type_info); - type_register_static(&sh7750r_type_info); - type_register_static(&sh7751r_type_info); - type_register_static(&sh7785_type_info); -} - -type_init(superh_cpu_register_types) diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h deleted file mode 100644 index 478ab55868..0000000000 --- a/target-sh4/cpu.h +++ /dev/null @@ -1,391 +0,0 @@ -/* - * SH4 emulation - * - * Copyright (c) 2005 Samuel Tardieu - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef SH4_CPU_H -#define SH4_CPU_H - -#include "qemu-common.h" -#include "cpu-qom.h" - -#define TARGET_LONG_BITS 32 - -/* CPU Subtypes */ -#define SH_CPU_SH7750 (1 << 0) -#define SH_CPU_SH7750S (1 << 1) -#define SH_CPU_SH7750R (1 << 2) -#define SH_CPU_SH7751 (1 << 3) -#define SH_CPU_SH7751R (1 << 4) -#define SH_CPU_SH7785 (1 << 5) -#define SH_CPU_SH7750_ALL (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7750R) -#define SH_CPU_SH7751_ALL (SH_CPU_SH7751 | SH_CPU_SH7751R) - -#define CPUArchState struct CPUSH4State - -#include "exec/cpu-defs.h" - -#include "fpu/softfloat.h" - -#define TARGET_PAGE_BITS 12 /* 4k XXXXX */ - -#define TARGET_PHYS_ADDR_SPACE_BITS 32 -#define TARGET_VIRT_ADDR_SPACE_BITS 32 - -#define SR_MD 30 -#define SR_RB 29 -#define SR_BL 28 -#define SR_FD 15 -#define SR_M 9 -#define SR_Q 8 -#define SR_I3 7 -#define SR_I2 6 -#define SR_I1 5 -#define SR_I0 4 -#define SR_S 1 -#define SR_T 0 - -#define FPSCR_MASK (0x003fffff) -#define FPSCR_FR (1 << 21) -#define FPSCR_SZ (1 << 20) -#define FPSCR_PR (1 << 19) -#define FPSCR_DN (1 << 18) -#define FPSCR_CAUSE_MASK (0x3f << 12) -#define FPSCR_CAUSE_SHIFT (12) -#define FPSCR_CAUSE_E (1 << 17) -#define FPSCR_CAUSE_V (1 << 16) -#define FPSCR_CAUSE_Z (1 << 15) -#define FPSCR_CAUSE_O (1 << 14) -#define FPSCR_CAUSE_U (1 << 13) -#define FPSCR_CAUSE_I (1 << 12) -#define FPSCR_ENABLE_MASK (0x1f << 7) -#define FPSCR_ENABLE_SHIFT (7) -#define FPSCR_ENABLE_V (1 << 11) -#define FPSCR_ENABLE_Z (1 << 10) -#define FPSCR_ENABLE_O (1 << 9) -#define FPSCR_ENABLE_U (1 << 8) -#define FPSCR_ENABLE_I (1 << 7) -#define FPSCR_FLAG_MASK (0x1f << 2) -#define FPSCR_FLAG_SHIFT (2) -#define FPSCR_FLAG_V (1 << 6) -#define FPSCR_FLAG_Z (1 << 5) -#define FPSCR_FLAG_O (1 << 4) -#define FPSCR_FLAG_U (1 << 3) -#define FPSCR_FLAG_I (1 << 2) -#define FPSCR_RM_MASK (0x03 << 0) -#define FPSCR_RM_NEAREST (0 << 0) -#define FPSCR_RM_ZERO (1 << 0) - -#define DELAY_SLOT (1 << 0) -#define DELAY_SLOT_CONDITIONAL (1 << 1) -#define DELAY_SLOT_TRUE (1 << 2) -#define DELAY_SLOT_CLEARME (1 << 3) -/* The dynamic value of the DELAY_SLOT_TRUE flag determines whether the jump - * after the delay slot should be taken or not. It is calculated from SR_T. - * - * It is unclear if it is permitted to modify the SR_T flag in a delay slot. - * The use of DELAY_SLOT_TRUE flag makes us accept such SR_T modification. - */ - -typedef struct tlb_t { - uint32_t vpn; /* virtual page number */ - uint32_t ppn; /* physical page number */ - uint32_t size; /* mapped page size in bytes */ - uint8_t asid; /* address space identifier */ - uint8_t v:1; /* validity */ - uint8_t sz:2; /* page size */ - uint8_t sh:1; /* share status */ - uint8_t c:1; /* cacheability */ - uint8_t pr:2; /* protection key */ - uint8_t d:1; /* dirty */ - uint8_t wt:1; /* write through */ - uint8_t sa:3; /* space attribute (PCMCIA) */ - uint8_t tc:1; /* timing control */ -} tlb_t; - -#define UTLB_SIZE 64 -#define ITLB_SIZE 4 - -#define NB_MMU_MODES 2 -#define TARGET_INSN_START_EXTRA_WORDS 1 - -enum sh_features { - SH_FEATURE_SH4A = 1, - SH_FEATURE_BCR3_AND_BCR4 = 2, -}; - -typedef struct memory_content { - uint32_t address; - uint32_t value; - struct memory_content *next; -} memory_content; - -typedef struct CPUSH4State { - uint32_t flags; /* general execution flags */ - uint32_t gregs[24]; /* general registers */ - float32 fregs[32]; /* floating point registers */ - uint32_t sr; /* status register (with T split out) */ - uint32_t sr_m; /* M bit of status register */ - uint32_t sr_q; /* Q bit of status register */ - uint32_t sr_t; /* T bit of status register */ - uint32_t ssr; /* saved status register */ - uint32_t spc; /* saved program counter */ - uint32_t gbr; /* global base register */ - uint32_t vbr; /* vector base register */ - uint32_t sgr; /* saved global register 15 */ - uint32_t dbr; /* debug base register */ - uint32_t pc; /* program counter */ - uint32_t delayed_pc; /* target of delayed jump */ - uint32_t mach; /* multiply and accumulate high */ - uint32_t macl; /* multiply and accumulate low */ - uint32_t pr; /* procedure register */ - uint32_t fpscr; /* floating point status/control register */ - uint32_t fpul; /* floating point communication register */ - - /* float point status register */ - float_status fp_status; - - /* Those belong to the specific unit (SH7750) but are handled here */ - uint32_t mmucr; /* MMU control register */ - uint32_t pteh; /* page table entry high register */ - uint32_t ptel; /* page table entry low register */ - uint32_t ptea; /* page table entry assistance register */ - uint32_t ttb; /* tranlation table base register */ - uint32_t tea; /* TLB exception address register */ - uint32_t tra; /* TRAPA exception register */ - uint32_t expevt; /* exception event register */ - uint32_t intevt; /* interrupt event register */ - - tlb_t itlb[ITLB_SIZE]; /* instruction translation table */ - tlb_t utlb[UTLB_SIZE]; /* unified translation table */ - - uint32_t ldst; - - CPU_COMMON - - /* Fields from here on are preserved over CPU reset. */ - int id; /* CPU model */ - - /* The features that we should emulate. See sh_features above. */ - uint32_t features; - - void *intc_handle; - int in_sleep; /* SR_BL ignored during sleep */ - memory_content *movcal_backup; - memory_content **movcal_backup_tail; -} CPUSH4State; - -/** - * SuperHCPU: - * @env: #CPUSH4State - * - * A SuperH CPU. - */ -struct SuperHCPU { - /*< private >*/ - CPUState parent_obj; - /*< public >*/ - - CPUSH4State env; -}; - -static inline SuperHCPU *sh_env_get_cpu(CPUSH4State *env) -{ - return container_of(env, SuperHCPU, env); -} - -#define ENV_GET_CPU(e) CPU(sh_env_get_cpu(e)) - -#define ENV_OFFSET offsetof(SuperHCPU, env) - -void superh_cpu_do_interrupt(CPUState *cpu); -bool superh_cpu_exec_interrupt(CPUState *cpu, int int_req); -void superh_cpu_dump_state(CPUState *cpu, FILE *f, - fprintf_function cpu_fprintf, int flags); -hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -int superh_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); -int superh_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); - -void sh4_translate_init(void); -SuperHCPU *cpu_sh4_init(const char *cpu_model); -int cpu_sh4_signal_handler(int host_signum, void *pinfo, - void *puc); -int superh_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw, - int mmu_idx); - -void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf); -#if !defined(CONFIG_USER_ONLY) -void cpu_sh4_invalidate_tlb(CPUSH4State *s); -uint32_t cpu_sh4_read_mmaped_itlb_addr(CPUSH4State *s, - hwaddr addr); -void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, hwaddr addr, - uint32_t mem_value); -uint32_t cpu_sh4_read_mmaped_itlb_data(CPUSH4State *s, - hwaddr addr); -void cpu_sh4_write_mmaped_itlb_data(CPUSH4State *s, hwaddr addr, - uint32_t mem_value); -uint32_t cpu_sh4_read_mmaped_utlb_addr(CPUSH4State *s, - hwaddr addr); -void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, hwaddr addr, - uint32_t mem_value); -uint32_t cpu_sh4_read_mmaped_utlb_data(CPUSH4State *s, - hwaddr addr); -void cpu_sh4_write_mmaped_utlb_data(CPUSH4State *s, hwaddr addr, - uint32_t mem_value); -#endif - -int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr); - -void cpu_load_tlb(CPUSH4State * env); - -#define cpu_init(cpu_model) CPU(cpu_sh4_init(cpu_model)) - -#define cpu_signal_handler cpu_sh4_signal_handler -#define cpu_list sh4_cpu_list - -/* MMU modes definitions */ -#define MMU_MODE0_SUFFIX _kernel -#define MMU_MODE1_SUFFIX _user -#define MMU_USER_IDX 1 -static inline int cpu_mmu_index (CPUSH4State *env, bool ifetch) -{ - return (env->sr & (1u << SR_MD)) == 0 ? 1 : 0; -} - -#include "exec/cpu-all.h" - -/* Memory access type */ -enum { - /* Privilege */ - ACCESS_PRIV = 0x01, - /* Direction */ - ACCESS_WRITE = 0x02, - /* Type of instruction */ - ACCESS_CODE = 0x10, - ACCESS_INT = 0x20 -}; - -/* MMU control register */ -#define MMUCR 0x1F000010 -#define MMUCR_AT (1<<0) -#define MMUCR_TI (1<<2) -#define MMUCR_SV (1<<8) -#define MMUCR_URC_BITS (6) -#define MMUCR_URC_OFFSET (10) -#define MMUCR_URC_SIZE (1 << MMUCR_URC_BITS) -#define MMUCR_URC_MASK (((MMUCR_URC_SIZE) - 1) << MMUCR_URC_OFFSET) -static inline int cpu_mmucr_urc (uint32_t mmucr) -{ - return ((mmucr & MMUCR_URC_MASK) >> MMUCR_URC_OFFSET); -} - -/* PTEH : Page Translation Entry High register */ -#define PTEH_ASID_BITS (8) -#define PTEH_ASID_SIZE (1 << PTEH_ASID_BITS) -#define PTEH_ASID_MASK (PTEH_ASID_SIZE - 1) -#define cpu_pteh_asid(pteh) ((pteh) & PTEH_ASID_MASK) -#define PTEH_VPN_BITS (22) -#define PTEH_VPN_OFFSET (10) -#define PTEH_VPN_SIZE (1 << PTEH_VPN_BITS) -#define PTEH_VPN_MASK (((PTEH_VPN_SIZE) - 1) << PTEH_VPN_OFFSET) -static inline int cpu_pteh_vpn (uint32_t pteh) -{ - return ((pteh & PTEH_VPN_MASK) >> PTEH_VPN_OFFSET); -} - -/* PTEL : Page Translation Entry Low register */ -#define PTEL_V (1 << 8) -#define cpu_ptel_v(ptel) (((ptel) & PTEL_V) >> 8) -#define PTEL_C (1 << 3) -#define cpu_ptel_c(ptel) (((ptel) & PTEL_C) >> 3) -#define PTEL_D (1 << 2) -#define cpu_ptel_d(ptel) (((ptel) & PTEL_D) >> 2) -#define PTEL_SH (1 << 1) -#define cpu_ptel_sh(ptel)(((ptel) & PTEL_SH) >> 1) -#define PTEL_WT (1 << 0) -#define cpu_ptel_wt(ptel) ((ptel) & PTEL_WT) - -#define PTEL_SZ_HIGH_OFFSET (7) -#define PTEL_SZ_HIGH (1 << PTEL_SZ_HIGH_OFFSET) -#define PTEL_SZ_LOW_OFFSET (4) -#define PTEL_SZ_LOW (1 << PTEL_SZ_LOW_OFFSET) -static inline int cpu_ptel_sz (uint32_t ptel) -{ - int sz; - sz = (ptel & PTEL_SZ_HIGH) >> PTEL_SZ_HIGH_OFFSET; - sz <<= 1; - sz |= (ptel & PTEL_SZ_LOW) >> PTEL_SZ_LOW_OFFSET; - return sz; -} - -#define PTEL_PPN_BITS (19) -#define PTEL_PPN_OFFSET (10) -#define PTEL_PPN_SIZE (1 << PTEL_PPN_BITS) -#define PTEL_PPN_MASK (((PTEL_PPN_SIZE) - 1) << PTEL_PPN_OFFSET) -static inline int cpu_ptel_ppn (uint32_t ptel) -{ - return ((ptel & PTEL_PPN_MASK) >> PTEL_PPN_OFFSET); -} - -#define PTEL_PR_BITS (2) -#define PTEL_PR_OFFSET (5) -#define PTEL_PR_SIZE (1 << PTEL_PR_BITS) -#define PTEL_PR_MASK (((PTEL_PR_SIZE) - 1) << PTEL_PR_OFFSET) -static inline int cpu_ptel_pr (uint32_t ptel) -{ - return ((ptel & PTEL_PR_MASK) >> PTEL_PR_OFFSET); -} - -/* PTEA : Page Translation Entry Assistance register */ -#define PTEA_SA_BITS (3) -#define PTEA_SA_SIZE (1 << PTEA_SA_BITS) -#define PTEA_SA_MASK (PTEA_SA_SIZE - 1) -#define cpu_ptea_sa(ptea) ((ptea) & PTEA_SA_MASK) -#define PTEA_TC (1 << 3) -#define cpu_ptea_tc(ptea) (((ptea) & PTEA_TC) >> 3) - -#define TB_FLAG_PENDING_MOVCA (1 << 4) - -static inline target_ulong cpu_read_sr(CPUSH4State *env) -{ - return env->sr | (env->sr_m << SR_M) | - (env->sr_q << SR_Q) | - (env->sr_t << SR_T); -} - -static inline void cpu_write_sr(CPUSH4State *env, target_ulong sr) -{ - env->sr_m = (sr >> SR_M) & 1; - env->sr_q = (sr >> SR_Q) & 1; - env->sr_t = (sr >> SR_T) & 1; - env->sr = sr & ~((1u << SR_M) | (1u << SR_Q) | (1u << SR_T)); -} - -static inline void cpu_get_tb_cpu_state(CPUSH4State *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) -{ - *pc = env->pc; - *cs_base = 0; - *flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL - | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME)) /* Bits 0- 3 */ - | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR)) /* Bits 19-21 */ - | (env->sr & ((1u << SR_MD) | (1u << SR_RB))) /* Bits 29-30 */ - | (env->sr & (1u << SR_FD)) /* Bit 15 */ - | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 4 */ -} - -#endif /* SH4_CPU_H */ diff --git a/target-sh4/gdbstub.c b/target-sh4/gdbstub.c deleted file mode 100644 index 13bea00d7d..0000000000 --- a/target-sh4/gdbstub.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * SuperH gdb server stub - * - * Copyright (c) 2003-2005 Fabrice Bellard - * Copyright (c) 2013 SUSE LINUX Products GmbH - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "cpu.h" -#include "exec/gdbstub.h" - -/* Hint: Use "set architecture sh4" in GDB to see fpu registers */ -/* FIXME: We should use XML for this. */ - -int superh_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) -{ - SuperHCPU *cpu = SUPERH_CPU(cs); - CPUSH4State *env = &cpu->env; - - switch (n) { - case 0 ... 7: - if ((env->sr & (1u << SR_MD)) && (env->sr & (1u << SR_RB))) { - return gdb_get_regl(mem_buf, env->gregs[n + 16]); - } else { - return gdb_get_regl(mem_buf, env->gregs[n]); - } - case 8 ... 15: - return gdb_get_regl(mem_buf, env->gregs[n]); - case 16: - return gdb_get_regl(mem_buf, env->pc); - case 17: - return gdb_get_regl(mem_buf, env->pr); - case 18: - return gdb_get_regl(mem_buf, env->gbr); - case 19: - return gdb_get_regl(mem_buf, env->vbr); - case 20: - return gdb_get_regl(mem_buf, env->mach); - case 21: - return gdb_get_regl(mem_buf, env->macl); - case 22: - return gdb_get_regl(mem_buf, cpu_read_sr(env)); - case 23: - return gdb_get_regl(mem_buf, env->fpul); - case 24: - return gdb_get_regl(mem_buf, env->fpscr); - case 25 ... 40: - if (env->fpscr & FPSCR_FR) { - stfl_p(mem_buf, env->fregs[n - 9]); - } else { - stfl_p(mem_buf, env->fregs[n - 25]); - } - return 4; - case 41: - return gdb_get_regl(mem_buf, env->ssr); - case 42: - return gdb_get_regl(mem_buf, env->spc); - case 43 ... 50: - return gdb_get_regl(mem_buf, env->gregs[n - 43]); - case 51 ... 58: - return gdb_get_regl(mem_buf, env->gregs[n - (51 - 16)]); - } - - return 0; -} - -int superh_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) -{ - SuperHCPU *cpu = SUPERH_CPU(cs); - CPUSH4State *env = &cpu->env; - - switch (n) { - case 0 ... 7: - if ((env->sr & (1u << SR_MD)) && (env->sr & (1u << SR_RB))) { - env->gregs[n + 16] = ldl_p(mem_buf); - } else { - env->gregs[n] = ldl_p(mem_buf); - } - break; - case 8 ... 15: - env->gregs[n] = ldl_p(mem_buf); - break; - case 16: - env->pc = ldl_p(mem_buf); - break; - case 17: - env->pr = ldl_p(mem_buf); - break; - case 18: - env->gbr = ldl_p(mem_buf); - break; - case 19: - env->vbr = ldl_p(mem_buf); - break; - case 20: - env->mach = ldl_p(mem_buf); - break; - case 21: - env->macl = ldl_p(mem_buf); - break; - case 22: - cpu_write_sr(env, ldl_p(mem_buf)); - break; - case 23: - env->fpul = ldl_p(mem_buf); - break; - case 24: - env->fpscr = ldl_p(mem_buf); - break; - case 25 ... 40: - if (env->fpscr & FPSCR_FR) { - env->fregs[n - 9] = ldfl_p(mem_buf); - } else { - env->fregs[n - 25] = ldfl_p(mem_buf); - } - break; - case 41: - env->ssr = ldl_p(mem_buf); - break; - case 42: - env->spc = ldl_p(mem_buf); - break; - case 43 ... 50: - env->gregs[n - 43] = ldl_p(mem_buf); - break; - case 51 ... 58: - env->gregs[n - (51 - 16)] = ldl_p(mem_buf); - break; - default: - return 0; - } - - return 4; -} diff --git a/target-sh4/helper.c b/target-sh4/helper.c deleted file mode 100644 index a33ac697c5..0000000000 --- a/target-sh4/helper.c +++ /dev/null @@ -1,872 +0,0 @@ -/* - * SH4 emulation - * - * Copyright (c) 2005 Samuel Tardieu - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ -#include "qemu/osdep.h" - -#include "cpu.h" -#include "exec/exec-all.h" -#include "exec/log.h" - -#if !defined(CONFIG_USER_ONLY) -#include "hw/sh4/sh_intc.h" -#endif - -#if defined(CONFIG_USER_ONLY) - -void superh_cpu_do_interrupt(CPUState *cs) -{ - cs->exception_index = -1; -} - -int superh_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, - int mmu_idx) -{ - SuperHCPU *cpu = SUPERH_CPU(cs); - CPUSH4State *env = &cpu->env; - - env->tea = address; - cs->exception_index = -1; - switch (rw) { - case 0: - cs->exception_index = 0x0a0; - break; - case 1: - cs->exception_index = 0x0c0; - break; - case 2: - cs->exception_index = 0x0a0; - break; - } - return 1; -} - -int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr) -{ - /* For user mode, only U0 area is cacheable. */ - return !(addr & 0x80000000); -} - -#else /* !CONFIG_USER_ONLY */ - -#define MMU_OK 0 -#define MMU_ITLB_MISS (-1) -#define MMU_ITLB_MULTIPLE (-2) -#define MMU_ITLB_VIOLATION (-3) -#define MMU_DTLB_MISS_READ (-4) -#define MMU_DTLB_MISS_WRITE (-5) -#define MMU_DTLB_INITIAL_WRITE (-6) -#define MMU_DTLB_VIOLATION_READ (-7) -#define MMU_DTLB_VIOLATION_WRITE (-8) -#define MMU_DTLB_MULTIPLE (-9) -#define MMU_DTLB_MISS (-10) -#define MMU_IADDR_ERROR (-11) -#define MMU_DADDR_ERROR_READ (-12) -#define MMU_DADDR_ERROR_WRITE (-13) - -void superh_cpu_do_interrupt(CPUState *cs) -{ - SuperHCPU *cpu = SUPERH_CPU(cs); - CPUSH4State *env = &cpu->env; - int do_irq = cs->interrupt_request & CPU_INTERRUPT_HARD; - int do_exp, irq_vector = cs->exception_index; - - /* prioritize exceptions over interrupts */ - - do_exp = cs->exception_index != -1; - do_irq = do_irq && (cs->exception_index == -1); - - if (env->sr & (1u << SR_BL)) { - if (do_exp && cs->exception_index != 0x1e0) { - cs->exception_index = 0x000; /* masked exception -> reset */ - } - if (do_irq && !env->in_sleep) { - return; /* masked */ - } - } - env->in_sleep = 0; - - if (do_irq) { - irq_vector = sh_intc_get_pending_vector(env->intc_handle, - (env->sr >> 4) & 0xf); - if (irq_vector == -1) { - return; /* masked */ - } - } - - if (qemu_loglevel_mask(CPU_LOG_INT)) { - const char *expname; - switch (cs->exception_index) { - case 0x0e0: - expname = "addr_error"; - break; - case 0x040: - expname = "tlb_miss"; - break; - case 0x0a0: - expname = "tlb_violation"; - break; - case 0x180: - expname = "illegal_instruction"; - break; - case 0x1a0: - expname = "slot_illegal_instruction"; - break; - case 0x800: - expname = "fpu_disable"; - break; - case 0x820: - expname = "slot_fpu"; - break; - case 0x100: - expname = "data_write"; - break; - case 0x060: - expname = "dtlb_miss_write"; - break; - case 0x0c0: - expname = "dtlb_violation_write"; - break; - case 0x120: - expname = "fpu_exception"; - break; - case 0x080: - expname = "initial_page_write"; - break; - case 0x160: - expname = "trapa"; - break; - default: - expname = do_irq ? "interrupt" : "???"; - break; - } - qemu_log("exception 0x%03x [%s] raised\n", - irq_vector, expname); - log_cpu_state(cs, 0); - } - - env->ssr = cpu_read_sr(env); - env->spc = env->pc; - env->sgr = env->gregs[15]; - env->sr |= (1u << SR_BL) | (1u << SR_MD) | (1u << SR_RB); - - if (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { - /* Branch instruction should be executed again before delay slot. */ - env->spc -= 2; - /* Clear flags for exception/interrupt routine. */ - env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL | DELAY_SLOT_TRUE); - } - if (env->flags & DELAY_SLOT_CLEARME) - env->flags = 0; - - if (do_exp) { - env->expevt = cs->exception_index; - switch (cs->exception_index) { - case 0x000: - case 0x020: - case 0x140: - env->sr &= ~(1u << SR_FD); - env->sr |= 0xf << 4; /* IMASK */ - env->pc = 0xa0000000; - break; - case 0x040: - case 0x060: - env->pc = env->vbr + 0x400; - break; - case 0x160: - env->spc += 2; /* special case for TRAPA */ - /* fall through */ - default: - env->pc = env->vbr + 0x100; - break; - } - return; - } - - if (do_irq) { - env->intevt = irq_vector; - env->pc = env->vbr + 0x600; - return; - } -} - -static void update_itlb_use(CPUSH4State * env, int itlbnb) -{ - uint8_t or_mask = 0, and_mask = (uint8_t) - 1; - - switch (itlbnb) { - case 0: - and_mask = 0x1f; - break; - case 1: - and_mask = 0xe7; - or_mask = 0x80; - break; - case 2: - and_mask = 0xfb; - or_mask = 0x50; - break; - case 3: - or_mask = 0x2c; - break; - } - - env->mmucr &= (and_mask << 24) | 0x00ffffff; - env->mmucr |= (or_mask << 24); -} - -static int itlb_replacement(CPUSH4State * env) -{ - SuperHCPU *cpu = sh_env_get_cpu(env); - - if ((env->mmucr & 0xe0000000) == 0xe0000000) { - return 0; - } - if ((env->mmucr & 0x98000000) == 0x18000000) { - return 1; - } - if ((env->mmucr & 0x54000000) == 0x04000000) { - return 2; - } - if ((env->mmucr & 0x2c000000) == 0x00000000) { - return 3; - } - cpu_abort(CPU(cpu), "Unhandled itlb_replacement"); -} - -/* Find the corresponding entry in the right TLB - Return entry, MMU_DTLB_MISS or MMU_DTLB_MULTIPLE -*/ -static int find_tlb_entry(CPUSH4State * env, target_ulong address, - tlb_t * entries, uint8_t nbtlb, int use_asid) -{ - int match = MMU_DTLB_MISS; - uint32_t start, end; - uint8_t asid; - int i; - - asid = env->pteh & 0xff; - - for (i = 0; i < nbtlb; i++) { - if (!entries[i].v) - continue; /* Invalid entry */ - if (!entries[i].sh && use_asid && entries[i].asid != asid) - continue; /* Bad ASID */ - start = (entries[i].vpn << 10) & ~(entries[i].size - 1); - end = start + entries[i].size - 1; - if (address >= start && address <= end) { /* Match */ - if (match != MMU_DTLB_MISS) - return MMU_DTLB_MULTIPLE; /* Multiple match */ - match = i; - } - } - return match; -} - -static void increment_urc(CPUSH4State * env) -{ - uint8_t urb, urc; - - /* Increment URC */ - urb = ((env->mmucr) >> 18) & 0x3f; - urc = ((env->mmucr) >> 10) & 0x3f; - urc++; - if ((urb > 0 && urc > urb) || urc > (UTLB_SIZE - 1)) - urc = 0; - env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10); -} - -/* Copy and utlb entry into itlb - Return entry -*/ -static int copy_utlb_entry_itlb(CPUSH4State *env, int utlb) -{ - int itlb; - - tlb_t * ientry; - itlb = itlb_replacement(env); - ientry = &env->itlb[itlb]; - if (ientry->v) { - tlb_flush_page(CPU(sh_env_get_cpu(env)), ientry->vpn << 10); - } - *ientry = env->utlb[utlb]; - update_itlb_use(env, itlb); - return itlb; -} - -/* Find itlb entry - Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE -*/ -static int find_itlb_entry(CPUSH4State * env, target_ulong address, - int use_asid) -{ - int e; - - e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid); - if (e == MMU_DTLB_MULTIPLE) { - e = MMU_ITLB_MULTIPLE; - } else if (e == MMU_DTLB_MISS) { - e = MMU_ITLB_MISS; - } else if (e >= 0) { - update_itlb_use(env, e); - } - return e; -} - -/* Find utlb entry - Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */ -static int find_utlb_entry(CPUSH4State * env, target_ulong address, int use_asid) -{ - /* per utlb access */ - increment_urc(env); - - /* Return entry */ - return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid); -} - -/* Match address against MMU - Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE, - MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ, - MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS, - MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION, - MMU_IADDR_ERROR, MMU_DADDR_ERROR_READ, MMU_DADDR_ERROR_WRITE. -*/ -static int get_mmu_address(CPUSH4State * env, target_ulong * physical, - int *prot, target_ulong address, - int rw, int access_type) -{ - int use_asid, n; - tlb_t *matching = NULL; - - use_asid = !(env->mmucr & MMUCR_SV) || !(env->sr & (1u << SR_MD)); - - if (rw == 2) { - n = find_itlb_entry(env, address, use_asid); - if (n >= 0) { - matching = &env->itlb[n]; - if (!(env->sr & (1u << SR_MD)) && !(matching->pr & 2)) { - n = MMU_ITLB_VIOLATION; - } else { - *prot = PAGE_EXEC; - } - } else { - n = find_utlb_entry(env, address, use_asid); - if (n >= 0) { - n = copy_utlb_entry_itlb(env, n); - matching = &env->itlb[n]; - if (!(env->sr & (1u << SR_MD)) && !(matching->pr & 2)) { - n = MMU_ITLB_VIOLATION; - } else { - *prot = PAGE_READ | PAGE_EXEC; - if ((matching->pr & 1) && matching->d) { - *prot |= PAGE_WRITE; - } - } - } else if (n == MMU_DTLB_MULTIPLE) { - n = MMU_ITLB_MULTIPLE; - } else if (n == MMU_DTLB_MISS) { - n = MMU_ITLB_MISS; - } - } - } else { - n = find_utlb_entry(env, address, use_asid); - if (n >= 0) { - matching = &env->utlb[n]; - if (!(env->sr & (1u << SR_MD)) && !(matching->pr & 2)) { - n = (rw == 1) ? MMU_DTLB_VIOLATION_WRITE : - MMU_DTLB_VIOLATION_READ; - } else if ((rw == 1) && !(matching->pr & 1)) { - n = MMU_DTLB_VIOLATION_WRITE; - } else if ((rw == 1) && !matching->d) { - n = MMU_DTLB_INITIAL_WRITE; - } else { - *prot = PAGE_READ; - if ((matching->pr & 1) && matching->d) { - *prot |= PAGE_WRITE; - } - } - } else if (n == MMU_DTLB_MISS) { - n = (rw == 1) ? MMU_DTLB_MISS_WRITE : - MMU_DTLB_MISS_READ; - } - } - if (n >= 0) { - n = MMU_OK; - *physical = ((matching->ppn << 10) & ~(matching->size - 1)) | - (address & (matching->size - 1)); - } - return n; -} - -static int get_physical_address(CPUSH4State * env, target_ulong * physical, - int *prot, target_ulong address, - int rw, int access_type) -{ - /* P1, P2 and P4 areas do not use translation */ - if ((address >= 0x80000000 && address < 0xc0000000) || - address >= 0xe0000000) { - if (!(env->sr & (1u << SR_MD)) - && (address < 0xe0000000 || address >= 0xe4000000)) { - /* Unauthorized access in user mode (only store queues are available) */ - fprintf(stderr, "Unauthorized access\n"); - if (rw == 0) - return MMU_DADDR_ERROR_READ; - else if (rw == 1) - return MMU_DADDR_ERROR_WRITE; - else - return MMU_IADDR_ERROR; - } - if (address >= 0x80000000 && address < 0xc0000000) { - /* Mask upper 3 bits for P1 and P2 areas */ - *physical = address & 0x1fffffff; - } else { - *physical = address; - } - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - return MMU_OK; - } - - /* If MMU is disabled, return the corresponding physical page */ - if (!(env->mmucr & MMUCR_AT)) { - *physical = address & 0x1FFFFFFF; - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - return MMU_OK; - } - - /* We need to resort to the MMU */ - return get_mmu_address(env, physical, prot, address, rw, access_type); -} - -int superh_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, - int mmu_idx) -{ - SuperHCPU *cpu = SUPERH_CPU(cs); - CPUSH4State *env = &cpu->env; - target_ulong physical; - int prot, ret, access_type; - - access_type = ACCESS_INT; - ret = - get_physical_address(env, &physical, &prot, address, rw, - access_type); - - if (ret != MMU_OK) { - env->tea = address; - if (ret != MMU_DTLB_MULTIPLE && ret != MMU_ITLB_MULTIPLE) { - env->pteh = (env->pteh & PTEH_ASID_MASK) | - (address & PTEH_VPN_MASK); - } - switch (ret) { - case MMU_ITLB_MISS: - case MMU_DTLB_MISS_READ: - cs->exception_index = 0x040; - break; - case MMU_DTLB_MULTIPLE: - case MMU_ITLB_MULTIPLE: - cs->exception_index = 0x140; - break; - case MMU_ITLB_VIOLATION: - cs->exception_index = 0x0a0; - break; - case MMU_DTLB_MISS_WRITE: - cs->exception_index = 0x060; - break; - case MMU_DTLB_INITIAL_WRITE: - cs->exception_index = 0x080; - break; - case MMU_DTLB_VIOLATION_READ: - cs->exception_index = 0x0a0; - break; - case MMU_DTLB_VIOLATION_WRITE: - cs->exception_index = 0x0c0; - break; - case MMU_IADDR_ERROR: - case MMU_DADDR_ERROR_READ: - cs->exception_index = 0x0e0; - break; - case MMU_DADDR_ERROR_WRITE: - cs->exception_index = 0x100; - break; - default: - cpu_abort(cs, "Unhandled MMU fault"); - } - return 1; - } - - address &= TARGET_PAGE_MASK; - physical &= TARGET_PAGE_MASK; - - tlb_set_page(cs, address, physical, prot, mmu_idx, TARGET_PAGE_SIZE); - return 0; -} - -hwaddr superh_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) -{ - SuperHCPU *cpu = SUPERH_CPU(cs); - target_ulong physical; - int prot; - - get_physical_address(&cpu->env, &physical, &prot, addr, 0, 0); - return physical; -} - -void cpu_load_tlb(CPUSH4State * env) -{ - SuperHCPU *cpu = sh_env_get_cpu(env); - int n = cpu_mmucr_urc(env->mmucr); - tlb_t * entry = &env->utlb[n]; - - if (entry->v) { - /* Overwriting valid entry in utlb. */ - target_ulong address = entry->vpn << 10; - tlb_flush_page(CPU(cpu), address); - } - - /* Take values into cpu status from registers. */ - entry->asid = (uint8_t)cpu_pteh_asid(env->pteh); - entry->vpn = cpu_pteh_vpn(env->pteh); - entry->v = (uint8_t)cpu_ptel_v(env->ptel); - entry->ppn = cpu_ptel_ppn(env->ptel); - entry->sz = (uint8_t)cpu_ptel_sz(env->ptel); - switch (entry->sz) { - case 0: /* 00 */ - entry->size = 1024; /* 1K */ - break; - case 1: /* 01 */ - entry->size = 1024 * 4; /* 4K */ - break; - case 2: /* 10 */ - entry->size = 1024 * 64; /* 64K */ - break; - case 3: /* 11 */ - entry->size = 1024 * 1024; /* 1M */ - break; - default: - cpu_abort(CPU(cpu), "Unhandled load_tlb"); - break; - } - entry->sh = (uint8_t)cpu_ptel_sh(env->ptel); - entry->c = (uint8_t)cpu_ptel_c(env->ptel); - entry->pr = (uint8_t)cpu_ptel_pr(env->ptel); - entry->d = (uint8_t)cpu_ptel_d(env->ptel); - entry->wt = (uint8_t)cpu_ptel_wt(env->ptel); - entry->sa = (uint8_t)cpu_ptea_sa(env->ptea); - entry->tc = (uint8_t)cpu_ptea_tc(env->ptea); -} - - void cpu_sh4_invalidate_tlb(CPUSH4State *s) -{ - int i; - - /* UTLB */ - for (i = 0; i < UTLB_SIZE; i++) { - tlb_t * entry = &s->utlb[i]; - entry->v = 0; - } - /* ITLB */ - for (i = 0; i < ITLB_SIZE; i++) { - tlb_t * entry = &s->itlb[i]; - entry->v = 0; - } - - tlb_flush(CPU(sh_env_get_cpu(s)), 1); -} - -uint32_t cpu_sh4_read_mmaped_itlb_addr(CPUSH4State *s, - hwaddr addr) -{ - int index = (addr & 0x00000300) >> 8; - tlb_t * entry = &s->itlb[index]; - - return (entry->vpn << 10) | - (entry->v << 8) | - (entry->asid); -} - -void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, hwaddr addr, - uint32_t mem_value) -{ - uint32_t vpn = (mem_value & 0xfffffc00) >> 10; - uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8); - uint8_t asid = (uint8_t)(mem_value & 0x000000ff); - - int index = (addr & 0x00000300) >> 8; - tlb_t * entry = &s->itlb[index]; - if (entry->v) { - /* Overwriting valid entry in itlb. */ - target_ulong address = entry->vpn << 10; - tlb_flush_page(CPU(sh_env_get_cpu(s)), address); - } - entry->asid = asid; - entry->vpn = vpn; - entry->v = v; -} - -uint32_t cpu_sh4_read_mmaped_itlb_data(CPUSH4State *s, - hwaddr addr) -{ - int array = (addr & 0x00800000) >> 23; - int index = (addr & 0x00000300) >> 8; - tlb_t * entry = &s->itlb[index]; - - if (array == 0) { - /* ITLB Data Array 1 */ - return (entry->ppn << 10) | - (entry->v << 8) | - (entry->pr << 5) | - ((entry->sz & 1) << 6) | - ((entry->sz & 2) << 4) | - (entry->c << 3) | - (entry->sh << 1); - } else { - /* ITLB Data Array 2 */ - return (entry->tc << 1) | - (entry->sa); - } -} - -void cpu_sh4_write_mmaped_itlb_data(CPUSH4State *s, hwaddr addr, - uint32_t mem_value) -{ - int array = (addr & 0x00800000) >> 23; - int index = (addr & 0x00000300) >> 8; - tlb_t * entry = &s->itlb[index]; - - if (array == 0) { - /* ITLB Data Array 1 */ - if (entry->v) { - /* Overwriting valid entry in utlb. */ - target_ulong address = entry->vpn << 10; - tlb_flush_page(CPU(sh_env_get_cpu(s)), address); - } - entry->ppn = (mem_value & 0x1ffffc00) >> 10; - entry->v = (mem_value & 0x00000100) >> 8; - entry->sz = (mem_value & 0x00000080) >> 6 | - (mem_value & 0x00000010) >> 4; - entry->pr = (mem_value & 0x00000040) >> 5; - entry->c = (mem_value & 0x00000008) >> 3; - entry->sh = (mem_value & 0x00000002) >> 1; - } else { - /* ITLB Data Array 2 */ - entry->tc = (mem_value & 0x00000008) >> 3; - entry->sa = (mem_value & 0x00000007); - } -} - -uint32_t cpu_sh4_read_mmaped_utlb_addr(CPUSH4State *s, - hwaddr addr) -{ - int index = (addr & 0x00003f00) >> 8; - tlb_t * entry = &s->utlb[index]; - - increment_urc(s); /* per utlb access */ - - return (entry->vpn << 10) | - (entry->v << 8) | - (entry->asid); -} - -void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, hwaddr addr, - uint32_t mem_value) -{ - int associate = addr & 0x0000080; - uint32_t vpn = (mem_value & 0xfffffc00) >> 10; - uint8_t d = (uint8_t)((mem_value & 0x00000200) >> 9); - uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8); - uint8_t asid = (uint8_t)(mem_value & 0x000000ff); - int use_asid = !(s->mmucr & MMUCR_SV) || !(s->sr & (1u << SR_MD)); - - if (associate) { - int i; - tlb_t * utlb_match_entry = NULL; - int needs_tlb_flush = 0; - - /* search UTLB */ - for (i = 0; i < UTLB_SIZE; i++) { - tlb_t * entry = &s->utlb[i]; - if (!entry->v) - continue; - - if (entry->vpn == vpn - && (!use_asid || entry->asid == asid || entry->sh)) { - if (utlb_match_entry) { - CPUState *cs = CPU(sh_env_get_cpu(s)); - - /* Multiple TLB Exception */ - cs->exception_index = 0x140; - s->tea = addr; - break; - } - if (entry->v && !v) - needs_tlb_flush = 1; - entry->v = v; - entry->d = d; - utlb_match_entry = entry; - } - increment_urc(s); /* per utlb access */ - } - - /* search ITLB */ - for (i = 0; i < ITLB_SIZE; i++) { - tlb_t * entry = &s->itlb[i]; - if (entry->vpn == vpn - && (!use_asid || entry->asid == asid || entry->sh)) { - if (entry->v && !v) - needs_tlb_flush = 1; - if (utlb_match_entry) - *entry = *utlb_match_entry; - else - entry->v = v; - break; - } - } - - if (needs_tlb_flush) { - tlb_flush_page(CPU(sh_env_get_cpu(s)), vpn << 10); - } - - } else { - int index = (addr & 0x00003f00) >> 8; - tlb_t * entry = &s->utlb[index]; - if (entry->v) { - CPUState *cs = CPU(sh_env_get_cpu(s)); - - /* Overwriting valid entry in utlb. */ - target_ulong address = entry->vpn << 10; - tlb_flush_page(cs, address); - } - entry->asid = asid; - entry->vpn = vpn; - entry->d = d; - entry->v = v; - increment_urc(s); - } -} - -uint32_t cpu_sh4_read_mmaped_utlb_data(CPUSH4State *s, - hwaddr addr) -{ - int array = (addr & 0x00800000) >> 23; - int index = (addr & 0x00003f00) >> 8; - tlb_t * entry = &s->utlb[index]; - - increment_urc(s); /* per utlb access */ - - if (array == 0) { - /* ITLB Data Array 1 */ - return (entry->ppn << 10) | - (entry->v << 8) | - (entry->pr << 5) | - ((entry->sz & 1) << 6) | - ((entry->sz & 2) << 4) | - (entry->c << 3) | - (entry->d << 2) | - (entry->sh << 1) | - (entry->wt); - } else { - /* ITLB Data Array 2 */ - return (entry->tc << 1) | - (entry->sa); - } -} - -void cpu_sh4_write_mmaped_utlb_data(CPUSH4State *s, hwaddr addr, - uint32_t mem_value) -{ - int array = (addr & 0x00800000) >> 23; - int index = (addr & 0x00003f00) >> 8; - tlb_t * entry = &s->utlb[index]; - - increment_urc(s); /* per utlb access */ - - if (array == 0) { - /* UTLB Data Array 1 */ - if (entry->v) { - /* Overwriting valid entry in utlb. */ - target_ulong address = entry->vpn << 10; - tlb_flush_page(CPU(sh_env_get_cpu(s)), address); - } - entry->ppn = (mem_value & 0x1ffffc00) >> 10; - entry->v = (mem_value & 0x00000100) >> 8; - entry->sz = (mem_value & 0x00000080) >> 6 | - (mem_value & 0x00000010) >> 4; - entry->pr = (mem_value & 0x00000060) >> 5; - entry->c = (mem_value & 0x00000008) >> 3; - entry->d = (mem_value & 0x00000004) >> 2; - entry->sh = (mem_value & 0x00000002) >> 1; - entry->wt = (mem_value & 0x00000001); - } else { - /* UTLB Data Array 2 */ - entry->tc = (mem_value & 0x00000008) >> 3; - entry->sa = (mem_value & 0x00000007); - } -} - -int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr) -{ - int n; - int use_asid = !(env->mmucr & MMUCR_SV) || !(env->sr & (1u << SR_MD)); - - /* check area */ - if (env->sr & (1u << SR_MD)) { - /* For privileged mode, P2 and P4 area is not cacheable. */ - if ((0xA0000000 <= addr && addr < 0xC0000000) || 0xE0000000 <= addr) - return 0; - } else { - /* For user mode, only U0 area is cacheable. */ - if (0x80000000 <= addr) - return 0; - } - - /* - * TODO : Evaluate CCR and check if the cache is on or off. - * Now CCR is not in CPUSH4State, but in SH7750State. - * When you move the ccr into CPUSH4State, the code will be - * as follows. - */ -#if 0 - /* check if operand cache is enabled or not. */ - if (!(env->ccr & 1)) - return 0; -#endif - - /* if MMU is off, no check for TLB. */ - if (env->mmucr & MMUCR_AT) - return 1; - - /* check TLB */ - n = find_tlb_entry(env, addr, env->itlb, ITLB_SIZE, use_asid); - if (n >= 0) - return env->itlb[n].c; - - n = find_tlb_entry(env, addr, env->utlb, UTLB_SIZE, use_asid); - if (n >= 0) - return env->utlb[n].c; - - return 0; -} - -#endif - -bool superh_cpu_exec_interrupt(CPUState *cs, int interrupt_request) -{ - if (interrupt_request & CPU_INTERRUPT_HARD) { - superh_cpu_do_interrupt(cs); - return true; - } - return false; -} diff --git a/target-sh4/helper.h b/target-sh4/helper.h deleted file mode 100644 index dce859caea..0000000000 --- a/target-sh4/helper.h +++ /dev/null @@ -1,45 +0,0 @@ -DEF_HELPER_1(ldtlb, void, env) -DEF_HELPER_1(raise_illegal_instruction, noreturn, env) -DEF_HELPER_1(raise_slot_illegal_instruction, noreturn, env) -DEF_HELPER_1(raise_fpu_disable, noreturn, env) -DEF_HELPER_1(raise_slot_fpu_disable, noreturn, env) -DEF_HELPER_1(debug, noreturn, env) -DEF_HELPER_1(sleep, noreturn, env) -DEF_HELPER_2(trapa, noreturn, env, i32) - -DEF_HELPER_3(movcal, void, env, i32, i32) -DEF_HELPER_1(discard_movcal_backup, void, env) -DEF_HELPER_2(ocbi, void, env, i32) - -DEF_HELPER_3(macl, void, env, i32, i32) -DEF_HELPER_3(macw, void, env, i32, i32) - -DEF_HELPER_2(ld_fpscr, void, env, i32) - -DEF_HELPER_FLAGS_1(fabs_FT, TCG_CALL_NO_RWG_SE, f32, f32) -DEF_HELPER_FLAGS_1(fabs_DT, TCG_CALL_NO_RWG_SE, f64, f64) -DEF_HELPER_FLAGS_3(fadd_FT, TCG_CALL_NO_WG, f32, env, f32, f32) -DEF_HELPER_FLAGS_3(fadd_DT, TCG_CALL_NO_WG, f64, env, f64, f64) -DEF_HELPER_FLAGS_2(fcnvsd_FT_DT, TCG_CALL_NO_WG, f64, env, f32) -DEF_HELPER_FLAGS_2(fcnvds_DT_FT, TCG_CALL_NO_WG, f32, env, f64) - -DEF_HELPER_3(fcmp_eq_FT, void, env, f32, f32) -DEF_HELPER_3(fcmp_eq_DT, void, env, f64, f64) -DEF_HELPER_3(fcmp_gt_FT, void, env, f32, f32) -DEF_HELPER_3(fcmp_gt_DT, void, env, f64, f64) -DEF_HELPER_FLAGS_3(fdiv_FT, TCG_CALL_NO_WG, f32, env, f32, f32) -DEF_HELPER_FLAGS_3(fdiv_DT, TCG_CALL_NO_WG, f64, env, f64, f64) -DEF_HELPER_FLAGS_2(float_FT, TCG_CALL_NO_WG, f32, env, i32) -DEF_HELPER_FLAGS_2(float_DT, TCG_CALL_NO_WG, f64, env, i32) -DEF_HELPER_FLAGS_4(fmac_FT, TCG_CALL_NO_WG, f32, env, f32, f32, f32) -DEF_HELPER_FLAGS_3(fmul_FT, TCG_CALL_NO_WG, f32, env, f32, f32) -DEF_HELPER_FLAGS_3(fmul_DT, TCG_CALL_NO_WG, f64, env, f64, f64) -DEF_HELPER_FLAGS_1(fneg_T, TCG_CALL_NO_RWG_SE, f32, f32) -DEF_HELPER_FLAGS_3(fsub_FT, TCG_CALL_NO_WG, f32, env, f32, f32) -DEF_HELPER_FLAGS_3(fsub_DT, TCG_CALL_NO_WG, f64, env, f64, f64) -DEF_HELPER_FLAGS_2(fsqrt_FT, TCG_CALL_NO_WG, f32, env, f32) -DEF_HELPER_FLAGS_2(fsqrt_DT, TCG_CALL_NO_WG, f64, env, f64) -DEF_HELPER_FLAGS_2(ftrc_FT, TCG_CALL_NO_WG, i32, env, f32) -DEF_HELPER_FLAGS_2(ftrc_DT, TCG_CALL_NO_WG, i32, env, f64) -DEF_HELPER_3(fipr, void, env, i32, i32) -DEF_HELPER_2(ftrv, void, env, i32) diff --git a/target-sh4/monitor.c b/target-sh4/monitor.c deleted file mode 100644 index 426e5d4914..0000000000 --- a/target-sh4/monitor.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * QEMU monitor - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "cpu.h" -#include "monitor/monitor.h" -#include "monitor/hmp-target.h" -#include "hmp.h" - -static void print_tlb(Monitor *mon, int idx, tlb_t *tlb) -{ - monitor_printf(mon, " tlb%i:\t" - "asid=%hhu vpn=%x\tppn=%x\tsz=%hhu size=%u\t" - "v=%hhu shared=%hhu cached=%hhu prot=%hhu " - "dirty=%hhu writethrough=%hhu\n", - idx, - tlb->asid, tlb->vpn, tlb->ppn, tlb->sz, tlb->size, - tlb->v, tlb->sh, tlb->c, tlb->pr, - tlb->d, tlb->wt); -} - -void hmp_info_tlb(Monitor *mon, const QDict *qdict) -{ - CPUArchState *env = mon_get_cpu_env(); - int i; - - monitor_printf (mon, "ITLB:\n"); - for (i = 0 ; i < ITLB_SIZE ; i++) - print_tlb (mon, i, &env->itlb[i]); - monitor_printf (mon, "UTLB:\n"); - for (i = 0 ; i < UTLB_SIZE ; i++) - print_tlb (mon, i, &env->utlb[i]); -} diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c deleted file mode 100644 index 684d3f3758..0000000000 --- a/target-sh4/op_helper.c +++ /dev/null @@ -1,498 +0,0 @@ -/* - * SH4 emulation - * - * Copyright (c) 2005 Samuel Tardieu - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" -#include "exec/exec-all.h" -#include "exec/cpu_ldst.h" - -#ifndef CONFIG_USER_ONLY - -void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr) -{ - int ret; - - ret = superh_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); - if (ret) { - /* now we have a real cpu fault */ - if (retaddr) { - cpu_restore_state(cs, retaddr); - } - cpu_loop_exit(cs); - } -} - -#endif - -void helper_ldtlb(CPUSH4State *env) -{ -#ifdef CONFIG_USER_ONLY - SuperHCPU *cpu = sh_env_get_cpu(env); - - /* XXXXX */ - cpu_abort(CPU(cpu), "Unhandled ldtlb"); -#else - cpu_load_tlb(env); -#endif -} - -static inline void QEMU_NORETURN raise_exception(CPUSH4State *env, int index, - uintptr_t retaddr) -{ - CPUState *cs = CPU(sh_env_get_cpu(env)); - - cs->exception_index = index; - if (retaddr) { - cpu_restore_state(cs, retaddr); - } - cpu_loop_exit(cs); -} - -void helper_raise_illegal_instruction(CPUSH4State *env) -{ - raise_exception(env, 0x180, 0); -} - -void helper_raise_slot_illegal_instruction(CPUSH4State *env) -{ - raise_exception(env, 0x1a0, 0); -} - -void helper_raise_fpu_disable(CPUSH4State *env) -{ - raise_exception(env, 0x800, 0); -} - -void helper_raise_slot_fpu_disable(CPUSH4State *env) -{ - raise_exception(env, 0x820, 0); -} - -void helper_debug(CPUSH4State *env) -{ - raise_exception(env, EXCP_DEBUG, 0); -} - -void helper_sleep(CPUSH4State *env) -{ - CPUState *cs = CPU(sh_env_get_cpu(env)); - - cs->halted = 1; - env->in_sleep = 1; - raise_exception(env, EXCP_HLT, 0); -} - -void helper_trapa(CPUSH4State *env, uint32_t tra) -{ - env->tra = tra << 2; - raise_exception(env, 0x160, 0); -} - -void helper_movcal(CPUSH4State *env, uint32_t address, uint32_t value) -{ - if (cpu_sh4_is_cached (env, address)) - { - memory_content *r = g_new(memory_content, 1); - - r->address = address; - r->value = value; - r->next = NULL; - - *(env->movcal_backup_tail) = r; - env->movcal_backup_tail = &(r->next); - } -} - -void helper_discard_movcal_backup(CPUSH4State *env) -{ - memory_content *current = env->movcal_backup; - - while(current) - { - memory_content *next = current->next; - g_free(current); - env->movcal_backup = current = next; - if (current == NULL) - env->movcal_backup_tail = &(env->movcal_backup); - } -} - -void helper_ocbi(CPUSH4State *env, uint32_t address) -{ - memory_content **current = &(env->movcal_backup); - while (*current) - { - uint32_t a = (*current)->address; - if ((a & ~0x1F) == (address & ~0x1F)) - { - memory_content *next = (*current)->next; - cpu_stl_data(env, a, (*current)->value); - - if (next == NULL) - { - env->movcal_backup_tail = current; - } - - g_free(*current); - *current = next; - break; - } - } -} - -void helper_macl(CPUSH4State *env, uint32_t arg0, uint32_t arg1) -{ - int64_t res; - - res = ((uint64_t) env->mach << 32) | env->macl; - res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1; - env->mach = (res >> 32) & 0xffffffff; - env->macl = res & 0xffffffff; - if (env->sr & (1u << SR_S)) { - if (res < 0) - env->mach |= 0xffff0000; - else - env->mach &= 0x00007fff; - } -} - -void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1) -{ - int64_t res; - - res = ((uint64_t) env->mach << 32) | env->macl; - res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1; - env->mach = (res >> 32) & 0xffffffff; - env->macl = res & 0xffffffff; - if (env->sr & (1u << SR_S)) { - if (res < -0x80000000) { - env->mach = 1; - env->macl = 0x80000000; - } else if (res > 0x000000007fffffff) { - env->mach = 1; - env->macl = 0x7fffffff; - } - } -} - -void helper_ld_fpscr(CPUSH4State *env, uint32_t val) -{ - env->fpscr = val & FPSCR_MASK; - if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) { - set_float_rounding_mode(float_round_to_zero, &env->fp_status); - } else { - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - } - set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status); -} - -static void update_fpscr(CPUSH4State *env, uintptr_t retaddr) -{ - int xcpt, cause, enable; - - xcpt = get_float_exception_flags(&env->fp_status); - - /* Clear the flag entries */ - env->fpscr &= ~FPSCR_FLAG_MASK; - - if (unlikely(xcpt)) { - if (xcpt & float_flag_invalid) { - env->fpscr |= FPSCR_FLAG_V; - } - if (xcpt & float_flag_divbyzero) { - env->fpscr |= FPSCR_FLAG_Z; - } - if (xcpt & float_flag_overflow) { - env->fpscr |= FPSCR_FLAG_O; - } - if (xcpt & float_flag_underflow) { - env->fpscr |= FPSCR_FLAG_U; - } - if (xcpt & float_flag_inexact) { - env->fpscr |= FPSCR_FLAG_I; - } - - /* Accumulate in cause entries */ - env->fpscr |= (env->fpscr & FPSCR_FLAG_MASK) - << (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT); - - /* Generate an exception if enabled */ - cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT; - enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT; - if (cause & enable) { - raise_exception(env, 0x120, retaddr); - } - } -} - -float32 helper_fabs_FT(float32 t0) -{ - return float32_abs(t0); -} - -float64 helper_fabs_DT(float64 t0) -{ - return float64_abs(t0); -} - -float32 helper_fadd_FT(CPUSH4State *env, float32 t0, float32 t1) -{ - set_float_exception_flags(0, &env->fp_status); - t0 = float32_add(t0, t1, &env->fp_status); - update_fpscr(env, GETPC()); - return t0; -} - -float64 helper_fadd_DT(CPUSH4State *env, float64 t0, float64 t1) -{ - set_float_exception_flags(0, &env->fp_status); - t0 = float64_add(t0, t1, &env->fp_status); - update_fpscr(env, GETPC()); - return t0; -} - -void helper_fcmp_eq_FT(CPUSH4State *env, float32 t0, float32 t1) -{ - int relation; - - set_float_exception_flags(0, &env->fp_status); - relation = float32_compare(t0, t1, &env->fp_status); - if (unlikely(relation == float_relation_unordered)) { - update_fpscr(env, GETPC()); - } else { - env->sr_t = (relation == float_relation_equal); - } -} - -void helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1) -{ - int relation; - - set_float_exception_flags(0, &env->fp_status); - relation = float64_compare(t0, t1, &env->fp_status); - if (unlikely(relation == float_relation_unordered)) { - update_fpscr(env, GETPC()); - } else { - env->sr_t = (relation == float_relation_equal); - } -} - -void helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1) -{ - int relation; - - set_float_exception_flags(0, &env->fp_status); - relation = float32_compare(t0, t1, &env->fp_status); - if (unlikely(relation == float_relation_unordered)) { - update_fpscr(env, GETPC()); - } else { - env->sr_t = (relation == float_relation_greater); - } -} - -void helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1) -{ - int relation; - - set_float_exception_flags(0, &env->fp_status); - relation = float64_compare(t0, t1, &env->fp_status); - if (unlikely(relation == float_relation_unordered)) { - update_fpscr(env, GETPC()); - } else { - env->sr_t = (relation == float_relation_greater); - } -} - -float64 helper_fcnvsd_FT_DT(CPUSH4State *env, float32 t0) -{ - float64 ret; - set_float_exception_flags(0, &env->fp_status); - ret = float32_to_float64(t0, &env->fp_status); - update_fpscr(env, GETPC()); - return ret; -} - -float32 helper_fcnvds_DT_FT(CPUSH4State *env, float64 t0) -{ - float32 ret; - set_float_exception_flags(0, &env->fp_status); - ret = float64_to_float32(t0, &env->fp_status); - update_fpscr(env, GETPC()); - return ret; -} - -float32 helper_fdiv_FT(CPUSH4State *env, float32 t0, float32 t1) -{ - set_float_exception_flags(0, &env->fp_status); - t0 = float32_div(t0, t1, &env->fp_status); - update_fpscr(env, GETPC()); - return t0; -} - -float64 helper_fdiv_DT(CPUSH4State *env, float64 t0, float64 t1) -{ - set_float_exception_flags(0, &env->fp_status); - t0 = float64_div(t0, t1, &env->fp_status); - update_fpscr(env, GETPC()); - return t0; -} - -float32 helper_float_FT(CPUSH4State *env, uint32_t t0) -{ - float32 ret; - set_float_exception_flags(0, &env->fp_status); - ret = int32_to_float32(t0, &env->fp_status); - update_fpscr(env, GETPC()); - return ret; -} - -float64 helper_float_DT(CPUSH4State *env, uint32_t t0) -{ - float64 ret; - set_float_exception_flags(0, &env->fp_status); - ret = int32_to_float64(t0, &env->fp_status); - update_fpscr(env, GETPC()); - return ret; -} - -float32 helper_fmac_FT(CPUSH4State *env, float32 t0, float32 t1, float32 t2) -{ - set_float_exception_flags(0, &env->fp_status); - t0 = float32_muladd(t0, t1, t2, 0, &env->fp_status); - update_fpscr(env, GETPC()); - return t0; -} - -float32 helper_fmul_FT(CPUSH4State *env, float32 t0, float32 t1) -{ - set_float_exception_flags(0, &env->fp_status); - t0 = float32_mul(t0, t1, &env->fp_status); - update_fpscr(env, GETPC()); - return t0; -} - -float64 helper_fmul_DT(CPUSH4State *env, float64 t0, float64 t1) -{ - set_float_exception_flags(0, &env->fp_status); - t0 = float64_mul(t0, t1, &env->fp_status); - update_fpscr(env, GETPC()); - return t0; -} - -float32 helper_fneg_T(float32 t0) -{ - return float32_chs(t0); -} - -float32 helper_fsqrt_FT(CPUSH4State *env, float32 t0) -{ - set_float_exception_flags(0, &env->fp_status); - t0 = float32_sqrt(t0, &env->fp_status); - update_fpscr(env, GETPC()); - return t0; -} - -float64 helper_fsqrt_DT(CPUSH4State *env, float64 t0) -{ - set_float_exception_flags(0, &env->fp_status); - t0 = float64_sqrt(t0, &env->fp_status); - update_fpscr(env, GETPC()); - return t0; -} - -float32 helper_fsub_FT(CPUSH4State *env, float32 t0, float32 t1) -{ - set_float_exception_flags(0, &env->fp_status); - t0 = float32_sub(t0, t1, &env->fp_status); - update_fpscr(env, GETPC()); - return t0; -} - -float64 helper_fsub_DT(CPUSH4State *env, float64 t0, float64 t1) -{ - set_float_exception_flags(0, &env->fp_status); - t0 = float64_sub(t0, t1, &env->fp_status); - update_fpscr(env, GETPC()); - return t0; -} - -uint32_t helper_ftrc_FT(CPUSH4State *env, float32 t0) -{ - uint32_t ret; - set_float_exception_flags(0, &env->fp_status); - ret = float32_to_int32_round_to_zero(t0, &env->fp_status); - update_fpscr(env, GETPC()); - return ret; -} - -uint32_t helper_ftrc_DT(CPUSH4State *env, float64 t0) -{ - uint32_t ret; - set_float_exception_flags(0, &env->fp_status); - ret = float64_to_int32_round_to_zero(t0, &env->fp_status); - update_fpscr(env, GETPC()); - return ret; -} - -void helper_fipr(CPUSH4State *env, uint32_t m, uint32_t n) -{ - int bank, i; - float32 r, p; - - bank = (env->sr & FPSCR_FR) ? 16 : 0; - r = float32_zero; - set_float_exception_flags(0, &env->fp_status); - - for (i = 0 ; i < 4 ; i++) { - p = float32_mul(env->fregs[bank + m + i], - env->fregs[bank + n + i], - &env->fp_status); - r = float32_add(r, p, &env->fp_status); - } - update_fpscr(env, GETPC()); - - env->fregs[bank + n + 3] = r; -} - -void helper_ftrv(CPUSH4State *env, uint32_t n) -{ - int bank_matrix, bank_vector; - int i, j; - float32 r[4]; - float32 p; - - bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16; - bank_vector = (env->sr & FPSCR_FR) ? 16 : 0; - set_float_exception_flags(0, &env->fp_status); - for (i = 0 ; i < 4 ; i++) { - r[i] = float32_zero; - for (j = 0 ; j < 4 ; j++) { - p = float32_mul(env->fregs[bank_matrix + 4 * j + i], - env->fregs[bank_vector + j], - &env->fp_status); - r[i] = float32_add(r[i], p, &env->fp_status); - } - } - update_fpscr(env, GETPC()); - - for (i = 0 ; i < 4 ; i++) { - env->fregs[bank_vector + i] = r[i]; - } -} diff --git a/target-sh4/translate.c b/target-sh4/translate.c deleted file mode 100644 index c89a14733f..0000000000 --- a/target-sh4/translate.c +++ /dev/null @@ -1,1944 +0,0 @@ -/* - * SH4 translation - * - * Copyright (c) 2005 Samuel Tardieu - * - * 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/>. - */ - -#define DEBUG_DISAS - -#include "qemu/osdep.h" -#include "cpu.h" -#include "disas/disas.h" -#include "exec/exec-all.h" -#include "tcg-op.h" -#include "exec/cpu_ldst.h" - -#include "exec/helper-proto.h" -#include "exec/helper-gen.h" - -#include "trace-tcg.h" -#include "exec/log.h" - - -typedef struct DisasContext { - struct TranslationBlock *tb; - target_ulong pc; - uint16_t opcode; - uint32_t flags; - int bstate; - int memidx; - uint32_t delayed_pc; - int singlestep_enabled; - uint32_t features; - int has_movcal; -} DisasContext; - -#if defined(CONFIG_USER_ONLY) -#define IS_USER(ctx) 1 -#else -#define IS_USER(ctx) (!(ctx->flags & (1u << SR_MD))) -#endif - -enum { - BS_NONE = 0, /* We go out of the TB without reaching a branch or an - * exception condition - */ - BS_STOP = 1, /* We want to stop translation for any reason */ - BS_BRANCH = 2, /* We reached a branch condition */ - BS_EXCP = 3, /* We reached an exception condition */ -}; - -/* global register indexes */ -static TCGv_env cpu_env; -static TCGv cpu_gregs[24]; -static TCGv cpu_sr, cpu_sr_m, cpu_sr_q, cpu_sr_t; -static TCGv cpu_pc, cpu_ssr, cpu_spc, cpu_gbr; -static TCGv cpu_vbr, cpu_sgr, cpu_dbr, cpu_mach, cpu_macl; -static TCGv cpu_pr, cpu_fpscr, cpu_fpul, cpu_ldst; -static TCGv cpu_fregs[32]; - -/* internal register indexes */ -static TCGv cpu_flags, cpu_delayed_pc; - -#include "exec/gen-icount.h" - -void sh4_translate_init(void) -{ - int i; - static int done_init = 0; - static const char * const gregnames[24] = { - "R0_BANK0", "R1_BANK0", "R2_BANK0", "R3_BANK0", - "R4_BANK0", "R5_BANK0", "R6_BANK0", "R7_BANK0", - "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", - "R0_BANK1", "R1_BANK1", "R2_BANK1", "R3_BANK1", - "R4_BANK1", "R5_BANK1", "R6_BANK1", "R7_BANK1" - }; - static const char * const fregnames[32] = { - "FPR0_BANK0", "FPR1_BANK0", "FPR2_BANK0", "FPR3_BANK0", - "FPR4_BANK0", "FPR5_BANK0", "FPR6_BANK0", "FPR7_BANK0", - "FPR8_BANK0", "FPR9_BANK0", "FPR10_BANK0", "FPR11_BANK0", - "FPR12_BANK0", "FPR13_BANK0", "FPR14_BANK0", "FPR15_BANK0", - "FPR0_BANK1", "FPR1_BANK1", "FPR2_BANK1", "FPR3_BANK1", - "FPR4_BANK1", "FPR5_BANK1", "FPR6_BANK1", "FPR7_BANK1", - "FPR8_BANK1", "FPR9_BANK1", "FPR10_BANK1", "FPR11_BANK1", - "FPR12_BANK1", "FPR13_BANK1", "FPR14_BANK1", "FPR15_BANK1", - }; - - if (done_init) - return; - - cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); - tcg_ctx.tcg_env = cpu_env; - - for (i = 0; i < 24; i++) - cpu_gregs[i] = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, gregs[i]), - gregnames[i]); - - cpu_pc = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, pc), "PC"); - cpu_sr = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, sr), "SR"); - cpu_sr_m = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, sr_m), "SR_M"); - cpu_sr_q = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, sr_q), "SR_Q"); - cpu_sr_t = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, sr_t), "SR_T"); - cpu_ssr = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, ssr), "SSR"); - cpu_spc = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, spc), "SPC"); - cpu_gbr = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, gbr), "GBR"); - cpu_vbr = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, vbr), "VBR"); - cpu_sgr = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, sgr), "SGR"); - cpu_dbr = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, dbr), "DBR"); - cpu_mach = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, mach), "MACH"); - cpu_macl = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, macl), "MACL"); - cpu_pr = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, pr), "PR"); - cpu_fpscr = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, fpscr), "FPSCR"); - cpu_fpul = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, fpul), "FPUL"); - - cpu_flags = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, flags), "_flags_"); - cpu_delayed_pc = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, delayed_pc), - "_delayed_pc_"); - cpu_ldst = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, ldst), "_ldst_"); - - for (i = 0; i < 32; i++) - cpu_fregs[i] = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, fregs[i]), - fregnames[i]); - - done_init = 1; -} - -void superh_cpu_dump_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, int flags) -{ - SuperHCPU *cpu = SUPERH_CPU(cs); - CPUSH4State *env = &cpu->env; - int i; - cpu_fprintf(f, "pc=0x%08x sr=0x%08x pr=0x%08x fpscr=0x%08x\n", - env->pc, cpu_read_sr(env), env->pr, env->fpscr); - cpu_fprintf(f, "spc=0x%08x ssr=0x%08x gbr=0x%08x vbr=0x%08x\n", - env->spc, env->ssr, env->gbr, env->vbr); - cpu_fprintf(f, "sgr=0x%08x dbr=0x%08x delayed_pc=0x%08x fpul=0x%08x\n", - env->sgr, env->dbr, env->delayed_pc, env->fpul); - for (i = 0; i < 24; i += 4) { - cpu_fprintf(f, "r%d=0x%08x r%d=0x%08x r%d=0x%08x r%d=0x%08x\n", - i, env->gregs[i], i + 1, env->gregs[i + 1], - i + 2, env->gregs[i + 2], i + 3, env->gregs[i + 3]); - } - if (env->flags & DELAY_SLOT) { - cpu_fprintf(f, "in delay slot (delayed_pc=0x%08x)\n", - env->delayed_pc); - } else if (env->flags & DELAY_SLOT_CONDITIONAL) { - cpu_fprintf(f, "in conditional delay slot (delayed_pc=0x%08x)\n", - env->delayed_pc); - } -} - -static void gen_read_sr(TCGv dst) -{ - TCGv t0 = tcg_temp_new(); - tcg_gen_shli_i32(t0, cpu_sr_q, SR_Q); - tcg_gen_or_i32(dst, dst, t0); - tcg_gen_shli_i32(t0, cpu_sr_m, SR_M); - tcg_gen_or_i32(dst, dst, t0); - tcg_gen_shli_i32(t0, cpu_sr_t, SR_T); - tcg_gen_or_i32(dst, cpu_sr, t0); - tcg_temp_free_i32(t0); -} - -static void gen_write_sr(TCGv src) -{ - tcg_gen_andi_i32(cpu_sr, src, - ~((1u << SR_Q) | (1u << SR_M) | (1u << SR_T))); - tcg_gen_shri_i32(cpu_sr_q, src, SR_Q); - tcg_gen_andi_i32(cpu_sr_q, cpu_sr_q, 1); - tcg_gen_shri_i32(cpu_sr_m, src, SR_M); - tcg_gen_andi_i32(cpu_sr_m, cpu_sr_m, 1); - tcg_gen_shri_i32(cpu_sr_t, src, SR_T); - tcg_gen_andi_i32(cpu_sr_t, cpu_sr_t, 1); -} - -static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) -{ - if (unlikely(ctx->singlestep_enabled)) { - return false; - } - -#ifndef CONFIG_USER_ONLY - return (ctx->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); -#else - return true; -#endif -} - -static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) -{ - if (use_goto_tb(ctx, dest)) { - /* Use a direct jump if in same page and singlestep not enabled */ - tcg_gen_goto_tb(n); - tcg_gen_movi_i32(cpu_pc, dest); - tcg_gen_exit_tb((uintptr_t)ctx->tb + n); - } else { - tcg_gen_movi_i32(cpu_pc, dest); - if (ctx->singlestep_enabled) - gen_helper_debug(cpu_env); - tcg_gen_exit_tb(0); - } -} - -static void gen_jump(DisasContext * ctx) -{ - if (ctx->delayed_pc == (uint32_t) - 1) { - /* Target is not statically known, it comes necessarily from a - delayed jump as immediate jump are conditinal jumps */ - tcg_gen_mov_i32(cpu_pc, cpu_delayed_pc); - if (ctx->singlestep_enabled) - gen_helper_debug(cpu_env); - tcg_gen_exit_tb(0); - } else { - gen_goto_tb(ctx, 0, ctx->delayed_pc); - } -} - -static inline void gen_branch_slot(uint32_t delayed_pc, int t) -{ - TCGLabel *label = gen_new_label(); - tcg_gen_movi_i32(cpu_delayed_pc, delayed_pc); - tcg_gen_brcondi_i32(t ? TCG_COND_EQ : TCG_COND_NE, cpu_sr_t, 0, label); - tcg_gen_ori_i32(cpu_flags, cpu_flags, DELAY_SLOT_TRUE); - gen_set_label(label); -} - -/* Immediate conditional jump (bt or bf) */ -static void gen_conditional_jump(DisasContext * ctx, - target_ulong ift, target_ulong ifnott) -{ - TCGLabel *l1 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_sr_t, 0, l1); - gen_goto_tb(ctx, 0, ifnott); - gen_set_label(l1); - gen_goto_tb(ctx, 1, ift); -} - -/* Delayed conditional jump (bt or bf) */ -static void gen_delayed_conditional_jump(DisasContext * ctx) -{ - TCGLabel *l1; - TCGv ds; - - l1 = gen_new_label(); - ds = tcg_temp_new(); - tcg_gen_andi_i32(ds, cpu_flags, DELAY_SLOT_TRUE); - tcg_gen_brcondi_i32(TCG_COND_NE, ds, 0, l1); - gen_goto_tb(ctx, 1, ctx->pc + 2); - gen_set_label(l1); - tcg_gen_andi_i32(cpu_flags, cpu_flags, ~DELAY_SLOT_TRUE); - gen_jump(ctx); -} - -static inline void gen_store_flags(uint32_t flags) -{ - tcg_gen_andi_i32(cpu_flags, cpu_flags, DELAY_SLOT_TRUE); - tcg_gen_ori_i32(cpu_flags, cpu_flags, flags); -} - -static inline void gen_load_fpr64(TCGv_i64 t, int reg) -{ - tcg_gen_concat_i32_i64(t, cpu_fregs[reg + 1], cpu_fregs[reg]); -} - -static inline void gen_store_fpr64 (TCGv_i64 t, int reg) -{ - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_extrl_i64_i32(tmp, t); - tcg_gen_mov_i32(cpu_fregs[reg + 1], tmp); - tcg_gen_shri_i64(t, t, 32); - tcg_gen_extrl_i64_i32(tmp, t); - tcg_gen_mov_i32(cpu_fregs[reg], tmp); - tcg_temp_free_i32(tmp); -} - -#define B3_0 (ctx->opcode & 0xf) -#define B6_4 ((ctx->opcode >> 4) & 0x7) -#define B7_4 ((ctx->opcode >> 4) & 0xf) -#define B7_0 (ctx->opcode & 0xff) -#define B7_0s ((int32_t) (int8_t) (ctx->opcode & 0xff)) -#define B11_0s (ctx->opcode & 0x800 ? 0xfffff000 | (ctx->opcode & 0xfff) : \ - (ctx->opcode & 0xfff)) -#define B11_8 ((ctx->opcode >> 8) & 0xf) -#define B15_12 ((ctx->opcode >> 12) & 0xf) - -#define REG(x) ((x) < 8 && (ctx->flags & (1u << SR_MD))\ - && (ctx->flags & (1u << SR_RB))\ - ? (cpu_gregs[x + 16]) : (cpu_gregs[x])) - -#define ALTREG(x) ((x) < 8 && (!(ctx->flags & (1u << SR_MD))\ - || !(ctx->flags & (1u << SR_RB)))\ - ? (cpu_gregs[x + 16]) : (cpu_gregs[x])) - -#define FREG(x) (ctx->flags & FPSCR_FR ? (x) ^ 0x10 : (x)) -#define XHACK(x) ((((x) & 1 ) << 4) | ((x) & 0xe)) -#define XREG(x) (ctx->flags & FPSCR_FR ? XHACK(x) ^ 0x10 : XHACK(x)) -#define DREG(x) FREG(x) /* Assumes lsb of (x) is always 0 */ - -#define CHECK_NOT_DELAY_SLOT \ - if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \ - { \ - tcg_gen_movi_i32(cpu_pc, ctx->pc); \ - gen_helper_raise_slot_illegal_instruction(cpu_env); \ - ctx->bstate = BS_BRANCH; \ - return; \ - } - -#define CHECK_PRIVILEGED \ - if (IS_USER(ctx)) { \ - tcg_gen_movi_i32(cpu_pc, ctx->pc); \ - if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { \ - gen_helper_raise_slot_illegal_instruction(cpu_env); \ - } else { \ - gen_helper_raise_illegal_instruction(cpu_env); \ - } \ - ctx->bstate = BS_BRANCH; \ - return; \ - } - -#define CHECK_FPU_ENABLED \ - if (ctx->flags & (1u << SR_FD)) { \ - tcg_gen_movi_i32(cpu_pc, ctx->pc); \ - if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { \ - gen_helper_raise_slot_fpu_disable(cpu_env); \ - } else { \ - gen_helper_raise_fpu_disable(cpu_env); \ - } \ - ctx->bstate = BS_BRANCH; \ - return; \ - } - -static void _decode_opc(DisasContext * ctx) -{ - /* This code tries to make movcal emulation sufficiently - accurate for Linux purposes. This instruction writes - memory, and prior to that, always allocates a cache line. - It is used in two contexts: - - in memcpy, where data is copied in blocks, the first write - of to a block uses movca.l for performance. - - in arch/sh/mm/cache-sh4.c, movcal.l + ocbi combination is used - to flush the cache. Here, the data written by movcal.l is never - written to memory, and the data written is just bogus. - - To simulate this, we simulate movcal.l, we store the value to memory, - but we also remember the previous content. If we see ocbi, we check - if movcal.l for that address was done previously. If so, the write should - not have hit the memory, so we restore the previous content. - When we see an instruction that is neither movca.l - nor ocbi, the previous content is discarded. - - To optimize, we only try to flush stores when we're at the start of - TB, or if we already saw movca.l in this TB and did not flush stores - yet. */ - if (ctx->has_movcal) - { - int opcode = ctx->opcode & 0xf0ff; - if (opcode != 0x0093 /* ocbi */ - && opcode != 0x00c3 /* movca.l */) - { - gen_helper_discard_movcal_backup(cpu_env); - ctx->has_movcal = 0; - } - } - -#if 0 - fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode); -#endif - - switch (ctx->opcode) { - case 0x0019: /* div0u */ - tcg_gen_movi_i32(cpu_sr_m, 0); - tcg_gen_movi_i32(cpu_sr_q, 0); - tcg_gen_movi_i32(cpu_sr_t, 0); - return; - case 0x000b: /* rts */ - CHECK_NOT_DELAY_SLOT - tcg_gen_mov_i32(cpu_delayed_pc, cpu_pr); - ctx->flags |= DELAY_SLOT; - ctx->delayed_pc = (uint32_t) - 1; - return; - case 0x0028: /* clrmac */ - tcg_gen_movi_i32(cpu_mach, 0); - tcg_gen_movi_i32(cpu_macl, 0); - return; - case 0x0048: /* clrs */ - tcg_gen_andi_i32(cpu_sr, cpu_sr, ~(1u << SR_S)); - return; - case 0x0008: /* clrt */ - tcg_gen_movi_i32(cpu_sr_t, 0); - return; - case 0x0038: /* ldtlb */ - CHECK_PRIVILEGED - gen_helper_ldtlb(cpu_env); - return; - case 0x002b: /* rte */ - CHECK_PRIVILEGED - CHECK_NOT_DELAY_SLOT - gen_write_sr(cpu_ssr); - tcg_gen_mov_i32(cpu_delayed_pc, cpu_spc); - ctx->flags |= DELAY_SLOT; - ctx->delayed_pc = (uint32_t) - 1; - return; - case 0x0058: /* sets */ - tcg_gen_ori_i32(cpu_sr, cpu_sr, (1u << SR_S)); - return; - case 0x0018: /* sett */ - tcg_gen_movi_i32(cpu_sr_t, 1); - return; - case 0xfbfd: /* frchg */ - tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_FR); - ctx->bstate = BS_STOP; - return; - case 0xf3fd: /* fschg */ - tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_SZ); - ctx->bstate = BS_STOP; - return; - case 0x0009: /* nop */ - return; - case 0x001b: /* sleep */ - CHECK_PRIVILEGED - tcg_gen_movi_i32(cpu_pc, ctx->pc + 2); - gen_helper_sleep(cpu_env); - return; - } - - switch (ctx->opcode & 0xf000) { - case 0x1000: /* mov.l Rm,@(disp,Rn) */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_addi_i32(addr, REG(B11_8), B3_0 * 4); - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL); - tcg_temp_free(addr); - } - return; - case 0x5000: /* mov.l @(disp,Rm),Rn */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 4); - tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL); - tcg_temp_free(addr); - } - return; - case 0xe000: /* mov #imm,Rn */ - tcg_gen_movi_i32(REG(B11_8), B7_0s); - return; - case 0x9000: /* mov.w @(disp,PC),Rn */ - { - TCGv addr = tcg_const_i32(ctx->pc + 4 + B7_0 * 2); - tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESW); - tcg_temp_free(addr); - } - return; - case 0xd000: /* mov.l @(disp,PC),Rn */ - { - TCGv addr = tcg_const_i32((ctx->pc + 4 + B7_0 * 4) & ~3); - tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL); - tcg_temp_free(addr); - } - return; - case 0x7000: /* add #imm,Rn */ - tcg_gen_addi_i32(REG(B11_8), REG(B11_8), B7_0s); - return; - case 0xa000: /* bra disp */ - CHECK_NOT_DELAY_SLOT - ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2; - tcg_gen_movi_i32(cpu_delayed_pc, ctx->delayed_pc); - ctx->flags |= DELAY_SLOT; - return; - case 0xb000: /* bsr disp */ - CHECK_NOT_DELAY_SLOT - tcg_gen_movi_i32(cpu_pr, ctx->pc + 4); - ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2; - tcg_gen_movi_i32(cpu_delayed_pc, ctx->delayed_pc); - ctx->flags |= DELAY_SLOT; - return; - } - - switch (ctx->opcode & 0xf00f) { - case 0x6003: /* mov Rm,Rn */ - tcg_gen_mov_i32(REG(B11_8), REG(B7_4)); - return; - case 0x2000: /* mov.b Rm,@Rn */ - tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, MO_UB); - return; - case 0x2001: /* mov.w Rm,@Rn */ - tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, MO_TEUW); - return; - case 0x2002: /* mov.l Rm,@Rn */ - tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, MO_TEUL); - return; - case 0x6000: /* mov.b @Rm,Rn */ - tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_SB); - return; - case 0x6001: /* mov.w @Rm,Rn */ - tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESW); - return; - case 0x6002: /* mov.l @Rm,Rn */ - tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESL); - return; - case 0x2004: /* mov.b Rm,@-Rn */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_subi_i32(addr, REG(B11_8), 1); - /* might cause re-execution */ - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_UB); - tcg_gen_mov_i32(REG(B11_8), addr); /* modify register status */ - tcg_temp_free(addr); - } - return; - case 0x2005: /* mov.w Rm,@-Rn */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_subi_i32(addr, REG(B11_8), 2); - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUW); - tcg_gen_mov_i32(REG(B11_8), addr); - tcg_temp_free(addr); - } - return; - case 0x2006: /* mov.l Rm,@-Rn */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_subi_i32(addr, REG(B11_8), 4); - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL); - tcg_gen_mov_i32(REG(B11_8), addr); - } - return; - case 0x6004: /* mov.b @Rm+,Rn */ - tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_SB); - if ( B11_8 != B7_4 ) - tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 1); - return; - case 0x6005: /* mov.w @Rm+,Rn */ - tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESW); - if ( B11_8 != B7_4 ) - tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2); - return; - case 0x6006: /* mov.l @Rm+,Rn */ - tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESL); - if ( B11_8 != B7_4 ) - tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4); - return; - case 0x0004: /* mov.b Rm,@(R0,Rn) */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_add_i32(addr, REG(B11_8), REG(0)); - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_UB); - tcg_temp_free(addr); - } - return; - case 0x0005: /* mov.w Rm,@(R0,Rn) */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_add_i32(addr, REG(B11_8), REG(0)); - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUW); - tcg_temp_free(addr); - } - return; - case 0x0006: /* mov.l Rm,@(R0,Rn) */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_add_i32(addr, REG(B11_8), REG(0)); - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL); - tcg_temp_free(addr); - } - return; - case 0x000c: /* mov.b @(R0,Rm),Rn */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_add_i32(addr, REG(B7_4), REG(0)); - tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_SB); - tcg_temp_free(addr); - } - return; - case 0x000d: /* mov.w @(R0,Rm),Rn */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_add_i32(addr, REG(B7_4), REG(0)); - tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESW); - tcg_temp_free(addr); - } - return; - case 0x000e: /* mov.l @(R0,Rm),Rn */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_add_i32(addr, REG(B7_4), REG(0)); - tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL); - tcg_temp_free(addr); - } - return; - case 0x6008: /* swap.b Rm,Rn */ - { - TCGv low = tcg_temp_new();; - tcg_gen_ext16u_i32(low, REG(B7_4)); - tcg_gen_bswap16_i32(low, low); - tcg_gen_deposit_i32(REG(B11_8), REG(B7_4), low, 0, 16); - tcg_temp_free(low); - } - return; - case 0x6009: /* swap.w Rm,Rn */ - tcg_gen_rotli_i32(REG(B11_8), REG(B7_4), 16); - return; - case 0x200d: /* xtrct Rm,Rn */ - { - TCGv high, low; - high = tcg_temp_new(); - tcg_gen_shli_i32(high, REG(B7_4), 16); - low = tcg_temp_new(); - tcg_gen_shri_i32(low, REG(B11_8), 16); - tcg_gen_or_i32(REG(B11_8), high, low); - tcg_temp_free(low); - tcg_temp_free(high); - } - return; - case 0x300c: /* add Rm,Rn */ - tcg_gen_add_i32(REG(B11_8), REG(B11_8), REG(B7_4)); - return; - case 0x300e: /* addc Rm,Rn */ - { - TCGv t0, t1; - t0 = tcg_const_tl(0); - t1 = tcg_temp_new(); - tcg_gen_add2_i32(t1, cpu_sr_t, cpu_sr_t, t0, REG(B7_4), t0); - tcg_gen_add2_i32(REG(B11_8), cpu_sr_t, - REG(B11_8), t0, t1, cpu_sr_t); - tcg_temp_free(t0); - tcg_temp_free(t1); - } - return; - case 0x300f: /* addv Rm,Rn */ - { - TCGv t0, t1, t2; - t0 = tcg_temp_new(); - tcg_gen_add_i32(t0, REG(B7_4), REG(B11_8)); - t1 = tcg_temp_new(); - tcg_gen_xor_i32(t1, t0, REG(B11_8)); - t2 = tcg_temp_new(); - tcg_gen_xor_i32(t2, REG(B7_4), REG(B11_8)); - tcg_gen_andc_i32(cpu_sr_t, t1, t2); - tcg_temp_free(t2); - tcg_gen_shri_i32(cpu_sr_t, cpu_sr_t, 31); - tcg_temp_free(t1); - tcg_gen_mov_i32(REG(B7_4), t0); - tcg_temp_free(t0); - } - return; - case 0x2009: /* and Rm,Rn */ - tcg_gen_and_i32(REG(B11_8), REG(B11_8), REG(B7_4)); - return; - case 0x3000: /* cmp/eq Rm,Rn */ - tcg_gen_setcond_i32(TCG_COND_EQ, cpu_sr_t, REG(B11_8), REG(B7_4)); - return; - case 0x3003: /* cmp/ge Rm,Rn */ - tcg_gen_setcond_i32(TCG_COND_GE, cpu_sr_t, REG(B11_8), REG(B7_4)); - return; - case 0x3007: /* cmp/gt Rm,Rn */ - tcg_gen_setcond_i32(TCG_COND_GT, cpu_sr_t, REG(B11_8), REG(B7_4)); - return; - case 0x3006: /* cmp/hi Rm,Rn */ - tcg_gen_setcond_i32(TCG_COND_GTU, cpu_sr_t, REG(B11_8), REG(B7_4)); - return; - case 0x3002: /* cmp/hs Rm,Rn */ - tcg_gen_setcond_i32(TCG_COND_GEU, cpu_sr_t, REG(B11_8), REG(B7_4)); - return; - case 0x200c: /* cmp/str Rm,Rn */ - { - TCGv cmp1 = tcg_temp_new(); - TCGv cmp2 = tcg_temp_new(); - tcg_gen_xor_i32(cmp2, REG(B7_4), REG(B11_8)); - tcg_gen_subi_i32(cmp1, cmp2, 0x01010101); - tcg_gen_andc_i32(cmp1, cmp1, cmp2); - tcg_gen_andi_i32(cmp1, cmp1, 0x80808080); - tcg_gen_setcondi_i32(TCG_COND_NE, cpu_sr_t, cmp1, 0); - tcg_temp_free(cmp2); - tcg_temp_free(cmp1); - } - return; - case 0x2007: /* div0s Rm,Rn */ - tcg_gen_shri_i32(cpu_sr_q, REG(B11_8), 31); /* SR_Q */ - tcg_gen_shri_i32(cpu_sr_m, REG(B7_4), 31); /* SR_M */ - tcg_gen_xor_i32(cpu_sr_t, cpu_sr_q, cpu_sr_m); /* SR_T */ - return; - case 0x3004: /* div1 Rm,Rn */ - { - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - TCGv t2 = tcg_temp_new(); - TCGv zero = tcg_const_i32(0); - - /* shift left arg1, saving the bit being pushed out and inserting - T on the right */ - tcg_gen_shri_i32(t0, REG(B11_8), 31); - tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1); - tcg_gen_or_i32(REG(B11_8), REG(B11_8), cpu_sr_t); - - /* Add or subtract arg0 from arg1 depending if Q == M. To avoid - using 64-bit temps, we compute arg0's high part from q ^ m, so - that it is 0x00000000 when adding the value or 0xffffffff when - subtracting it. */ - tcg_gen_xor_i32(t1, cpu_sr_q, cpu_sr_m); - tcg_gen_subi_i32(t1, t1, 1); - tcg_gen_neg_i32(t2, REG(B7_4)); - tcg_gen_movcond_i32(TCG_COND_EQ, t2, t1, zero, REG(B7_4), t2); - tcg_gen_add2_i32(REG(B11_8), t1, REG(B11_8), zero, t2, t1); - - /* compute T and Q depending on carry */ - tcg_gen_andi_i32(t1, t1, 1); - tcg_gen_xor_i32(t1, t1, t0); - tcg_gen_xori_i32(cpu_sr_t, t1, 1); - tcg_gen_xor_i32(cpu_sr_q, cpu_sr_m, t1); - - tcg_temp_free(zero); - tcg_temp_free(t2); - tcg_temp_free(t1); - tcg_temp_free(t0); - } - return; - case 0x300d: /* dmuls.l Rm,Rn */ - tcg_gen_muls2_i32(cpu_macl, cpu_mach, REG(B7_4), REG(B11_8)); - return; - case 0x3005: /* dmulu.l Rm,Rn */ - tcg_gen_mulu2_i32(cpu_macl, cpu_mach, REG(B7_4), REG(B11_8)); - return; - case 0x600e: /* exts.b Rm,Rn */ - tcg_gen_ext8s_i32(REG(B11_8), REG(B7_4)); - return; - case 0x600f: /* exts.w Rm,Rn */ - tcg_gen_ext16s_i32(REG(B11_8), REG(B7_4)); - return; - case 0x600c: /* extu.b Rm,Rn */ - tcg_gen_ext8u_i32(REG(B11_8), REG(B7_4)); - return; - case 0x600d: /* extu.w Rm,Rn */ - tcg_gen_ext16u_i32(REG(B11_8), REG(B7_4)); - return; - case 0x000f: /* mac.l @Rm+,@Rn+ */ - { - TCGv arg0, arg1; - arg0 = tcg_temp_new(); - tcg_gen_qemu_ld_i32(arg0, REG(B7_4), ctx->memidx, MO_TESL); - arg1 = tcg_temp_new(); - tcg_gen_qemu_ld_i32(arg1, REG(B11_8), ctx->memidx, MO_TESL); - gen_helper_macl(cpu_env, arg0, arg1); - tcg_temp_free(arg1); - tcg_temp_free(arg0); - tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4); - tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); - } - return; - case 0x400f: /* mac.w @Rm+,@Rn+ */ - { - TCGv arg0, arg1; - arg0 = tcg_temp_new(); - tcg_gen_qemu_ld_i32(arg0, REG(B7_4), ctx->memidx, MO_TESL); - arg1 = tcg_temp_new(); - tcg_gen_qemu_ld_i32(arg1, REG(B11_8), ctx->memidx, MO_TESL); - gen_helper_macw(cpu_env, arg0, arg1); - tcg_temp_free(arg1); - tcg_temp_free(arg0); - tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 2); - tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2); - } - return; - case 0x0007: /* mul.l Rm,Rn */ - tcg_gen_mul_i32(cpu_macl, REG(B7_4), REG(B11_8)); - return; - case 0x200f: /* muls.w Rm,Rn */ - { - TCGv arg0, arg1; - arg0 = tcg_temp_new(); - tcg_gen_ext16s_i32(arg0, REG(B7_4)); - arg1 = tcg_temp_new(); - tcg_gen_ext16s_i32(arg1, REG(B11_8)); - tcg_gen_mul_i32(cpu_macl, arg0, arg1); - tcg_temp_free(arg1); - tcg_temp_free(arg0); - } - return; - case 0x200e: /* mulu.w Rm,Rn */ - { - TCGv arg0, arg1; - arg0 = tcg_temp_new(); - tcg_gen_ext16u_i32(arg0, REG(B7_4)); - arg1 = tcg_temp_new(); - tcg_gen_ext16u_i32(arg1, REG(B11_8)); - tcg_gen_mul_i32(cpu_macl, arg0, arg1); - tcg_temp_free(arg1); - tcg_temp_free(arg0); - } - return; - case 0x600b: /* neg Rm,Rn */ - tcg_gen_neg_i32(REG(B11_8), REG(B7_4)); - return; - case 0x600a: /* negc Rm,Rn */ - { - TCGv t0 = tcg_const_i32(0); - tcg_gen_add2_i32(REG(B11_8), cpu_sr_t, - REG(B7_4), t0, cpu_sr_t, t0); - tcg_gen_sub2_i32(REG(B11_8), cpu_sr_t, - t0, t0, REG(B11_8), cpu_sr_t); - tcg_gen_andi_i32(cpu_sr_t, cpu_sr_t, 1); - tcg_temp_free(t0); - } - return; - case 0x6007: /* not Rm,Rn */ - tcg_gen_not_i32(REG(B11_8), REG(B7_4)); - return; - case 0x200b: /* or Rm,Rn */ - tcg_gen_or_i32(REG(B11_8), REG(B11_8), REG(B7_4)); - return; - case 0x400c: /* shad Rm,Rn */ - { - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - TCGv t2 = tcg_temp_new(); - - tcg_gen_andi_i32(t0, REG(B7_4), 0x1f); - - /* positive case: shift to the left */ - tcg_gen_shl_i32(t1, REG(B11_8), t0); - - /* negative case: shift to the right in two steps to - correctly handle the -32 case */ - tcg_gen_xori_i32(t0, t0, 0x1f); - tcg_gen_sar_i32(t2, REG(B11_8), t0); - tcg_gen_sari_i32(t2, t2, 1); - - /* select between the two cases */ - tcg_gen_movi_i32(t0, 0); - tcg_gen_movcond_i32(TCG_COND_GE, REG(B11_8), REG(B7_4), t0, t1, t2); - - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free(t2); - } - return; - case 0x400d: /* shld Rm,Rn */ - { - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - TCGv t2 = tcg_temp_new(); - - tcg_gen_andi_i32(t0, REG(B7_4), 0x1f); - - /* positive case: shift to the left */ - tcg_gen_shl_i32(t1, REG(B11_8), t0); - - /* negative case: shift to the right in two steps to - correctly handle the -32 case */ - tcg_gen_xori_i32(t0, t0, 0x1f); - tcg_gen_shr_i32(t2, REG(B11_8), t0); - tcg_gen_shri_i32(t2, t2, 1); - - /* select between the two cases */ - tcg_gen_movi_i32(t0, 0); - tcg_gen_movcond_i32(TCG_COND_GE, REG(B11_8), REG(B7_4), t0, t1, t2); - - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free(t2); - } - return; - case 0x3008: /* sub Rm,Rn */ - tcg_gen_sub_i32(REG(B11_8), REG(B11_8), REG(B7_4)); - return; - case 0x300a: /* subc Rm,Rn */ - { - TCGv t0, t1; - t0 = tcg_const_tl(0); - t1 = tcg_temp_new(); - tcg_gen_add2_i32(t1, cpu_sr_t, cpu_sr_t, t0, REG(B7_4), t0); - tcg_gen_sub2_i32(REG(B11_8), cpu_sr_t, - REG(B11_8), t0, t1, cpu_sr_t); - tcg_gen_andi_i32(cpu_sr_t, cpu_sr_t, 1); - tcg_temp_free(t0); - tcg_temp_free(t1); - } - return; - case 0x300b: /* subv Rm,Rn */ - { - TCGv t0, t1, t2; - t0 = tcg_temp_new(); - tcg_gen_sub_i32(t0, REG(B11_8), REG(B7_4)); - t1 = tcg_temp_new(); - tcg_gen_xor_i32(t1, t0, REG(B7_4)); - t2 = tcg_temp_new(); - tcg_gen_xor_i32(t2, REG(B11_8), REG(B7_4)); - tcg_gen_and_i32(t1, t1, t2); - tcg_temp_free(t2); - tcg_gen_shri_i32(cpu_sr_t, t1, 31); - tcg_temp_free(t1); - tcg_gen_mov_i32(REG(B11_8), t0); - tcg_temp_free(t0); - } - return; - case 0x2008: /* tst Rm,Rn */ - { - TCGv val = tcg_temp_new(); - tcg_gen_and_i32(val, REG(B7_4), REG(B11_8)); - tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, val, 0); - tcg_temp_free(val); - } - return; - case 0x200a: /* xor Rm,Rn */ - tcg_gen_xor_i32(REG(B11_8), REG(B11_8), REG(B7_4)); - return; - case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn - FPSCR: Nothing */ - CHECK_FPU_ENABLED - if (ctx->flags & FPSCR_SZ) { - TCGv_i64 fp = tcg_temp_new_i64(); - gen_load_fpr64(fp, XREG(B7_4)); - gen_store_fpr64(fp, XREG(B11_8)); - tcg_temp_free_i64(fp); - } else { - tcg_gen_mov_i32(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]); - } - return; - case 0xf00a: /* fmov {F,D,X}Rm,@Rn - FPSCR: Nothing */ - CHECK_FPU_ENABLED - if (ctx->flags & FPSCR_SZ) { - TCGv addr_hi = tcg_temp_new(); - int fr = XREG(B7_4); - tcg_gen_addi_i32(addr_hi, REG(B11_8), 4); - tcg_gen_qemu_st_i32(cpu_fregs[fr], REG(B11_8), - ctx->memidx, MO_TEUL); - tcg_gen_qemu_st_i32(cpu_fregs[fr+1], addr_hi, - ctx->memidx, MO_TEUL); - tcg_temp_free(addr_hi); - } else { - tcg_gen_qemu_st_i32(cpu_fregs[FREG(B7_4)], REG(B11_8), - ctx->memidx, MO_TEUL); - } - return; - case 0xf008: /* fmov @Rm,{F,D,X}Rn - FPSCR: Nothing */ - CHECK_FPU_ENABLED - if (ctx->flags & FPSCR_SZ) { - TCGv addr_hi = tcg_temp_new(); - int fr = XREG(B11_8); - tcg_gen_addi_i32(addr_hi, REG(B7_4), 4); - tcg_gen_qemu_ld_i32(cpu_fregs[fr], REG(B7_4), ctx->memidx, MO_TEUL); - tcg_gen_qemu_ld_i32(cpu_fregs[fr+1], addr_hi, ctx->memidx, MO_TEUL); - tcg_temp_free(addr_hi); - } else { - tcg_gen_qemu_ld_i32(cpu_fregs[FREG(B11_8)], REG(B7_4), - ctx->memidx, MO_TEUL); - } - return; - case 0xf009: /* fmov @Rm+,{F,D,X}Rn - FPSCR: Nothing */ - CHECK_FPU_ENABLED - if (ctx->flags & FPSCR_SZ) { - TCGv addr_hi = tcg_temp_new(); - int fr = XREG(B11_8); - tcg_gen_addi_i32(addr_hi, REG(B7_4), 4); - tcg_gen_qemu_ld_i32(cpu_fregs[fr], REG(B7_4), ctx->memidx, MO_TEUL); - tcg_gen_qemu_ld_i32(cpu_fregs[fr+1], addr_hi, ctx->memidx, MO_TEUL); - tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 8); - tcg_temp_free(addr_hi); - } else { - tcg_gen_qemu_ld_i32(cpu_fregs[FREG(B11_8)], REG(B7_4), - ctx->memidx, MO_TEUL); - tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4); - } - return; - case 0xf00b: /* fmov {F,D,X}Rm,@-Rn - FPSCR: Nothing */ - CHECK_FPU_ENABLED - TCGv addr = tcg_temp_new_i32(); - tcg_gen_subi_i32(addr, REG(B11_8), 4); - if (ctx->flags & FPSCR_SZ) { - int fr = XREG(B7_4); - tcg_gen_qemu_st_i32(cpu_fregs[fr+1], addr, ctx->memidx, MO_TEUL); - tcg_gen_subi_i32(addr, addr, 4); - tcg_gen_qemu_st_i32(cpu_fregs[fr], addr, ctx->memidx, MO_TEUL); - } else { - tcg_gen_qemu_st_i32(cpu_fregs[FREG(B7_4)], addr, - ctx->memidx, MO_TEUL); - } - tcg_gen_mov_i32(REG(B11_8), addr); - tcg_temp_free(addr); - return; - case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */ - CHECK_FPU_ENABLED - { - TCGv addr = tcg_temp_new_i32(); - tcg_gen_add_i32(addr, REG(B7_4), REG(0)); - if (ctx->flags & FPSCR_SZ) { - int fr = XREG(B11_8); - tcg_gen_qemu_ld_i32(cpu_fregs[fr], addr, - ctx->memidx, MO_TEUL); - tcg_gen_addi_i32(addr, addr, 4); - tcg_gen_qemu_ld_i32(cpu_fregs[fr+1], addr, - ctx->memidx, MO_TEUL); - } else { - tcg_gen_qemu_ld_i32(cpu_fregs[FREG(B11_8)], addr, - ctx->memidx, MO_TEUL); - } - tcg_temp_free(addr); - } - return; - case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) - FPSCR: Nothing */ - CHECK_FPU_ENABLED - { - TCGv addr = tcg_temp_new(); - tcg_gen_add_i32(addr, REG(B11_8), REG(0)); - if (ctx->flags & FPSCR_SZ) { - int fr = XREG(B7_4); - tcg_gen_qemu_ld_i32(cpu_fregs[fr], addr, - ctx->memidx, MO_TEUL); - tcg_gen_addi_i32(addr, addr, 4); - tcg_gen_qemu_ld_i32(cpu_fregs[fr+1], addr, - ctx->memidx, MO_TEUL); - } else { - tcg_gen_qemu_st_i32(cpu_fregs[FREG(B7_4)], addr, - ctx->memidx, MO_TEUL); - } - tcg_temp_free(addr); - } - return; - case 0xf000: /* fadd Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */ - case 0xf001: /* fsub Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */ - case 0xf002: /* fmul Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */ - case 0xf003: /* fdiv Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */ - case 0xf004: /* fcmp/eq Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ - case 0xf005: /* fcmp/gt Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ - { - CHECK_FPU_ENABLED - if (ctx->flags & FPSCR_PR) { - TCGv_i64 fp0, fp1; - - if (ctx->opcode & 0x0110) - break; /* illegal instruction */ - fp0 = tcg_temp_new_i64(); - fp1 = tcg_temp_new_i64(); - gen_load_fpr64(fp0, DREG(B11_8)); - gen_load_fpr64(fp1, DREG(B7_4)); - switch (ctx->opcode & 0xf00f) { - case 0xf000: /* fadd Rm,Rn */ - gen_helper_fadd_DT(fp0, cpu_env, fp0, fp1); - break; - case 0xf001: /* fsub Rm,Rn */ - gen_helper_fsub_DT(fp0, cpu_env, fp0, fp1); - break; - case 0xf002: /* fmul Rm,Rn */ - gen_helper_fmul_DT(fp0, cpu_env, fp0, fp1); - break; - case 0xf003: /* fdiv Rm,Rn */ - gen_helper_fdiv_DT(fp0, cpu_env, fp0, fp1); - break; - case 0xf004: /* fcmp/eq Rm,Rn */ - gen_helper_fcmp_eq_DT(cpu_env, fp0, fp1); - return; - case 0xf005: /* fcmp/gt Rm,Rn */ - gen_helper_fcmp_gt_DT(cpu_env, fp0, fp1); - return; - } - gen_store_fpr64(fp0, DREG(B11_8)); - tcg_temp_free_i64(fp0); - tcg_temp_free_i64(fp1); - } else { - switch (ctx->opcode & 0xf00f) { - case 0xf000: /* fadd Rm,Rn */ - gen_helper_fadd_FT(cpu_fregs[FREG(B11_8)], cpu_env, - cpu_fregs[FREG(B11_8)], - cpu_fregs[FREG(B7_4)]); - break; - case 0xf001: /* fsub Rm,Rn */ - gen_helper_fsub_FT(cpu_fregs[FREG(B11_8)], cpu_env, - cpu_fregs[FREG(B11_8)], - cpu_fregs[FREG(B7_4)]); - break; - case 0xf002: /* fmul Rm,Rn */ - gen_helper_fmul_FT(cpu_fregs[FREG(B11_8)], cpu_env, - cpu_fregs[FREG(B11_8)], - cpu_fregs[FREG(B7_4)]); - break; - case 0xf003: /* fdiv Rm,Rn */ - gen_helper_fdiv_FT(cpu_fregs[FREG(B11_8)], cpu_env, - cpu_fregs[FREG(B11_8)], - cpu_fregs[FREG(B7_4)]); - break; - case 0xf004: /* fcmp/eq Rm,Rn */ - gen_helper_fcmp_eq_FT(cpu_env, cpu_fregs[FREG(B11_8)], - cpu_fregs[FREG(B7_4)]); - return; - case 0xf005: /* fcmp/gt Rm,Rn */ - gen_helper_fcmp_gt_FT(cpu_env, cpu_fregs[FREG(B11_8)], - cpu_fregs[FREG(B7_4)]); - return; - } - } - } - return; - case 0xf00e: /* fmac FR0,RM,Rn */ - { - CHECK_FPU_ENABLED - if (ctx->flags & FPSCR_PR) { - break; /* illegal instruction */ - } else { - gen_helper_fmac_FT(cpu_fregs[FREG(B11_8)], cpu_env, - cpu_fregs[FREG(0)], cpu_fregs[FREG(B7_4)], - cpu_fregs[FREG(B11_8)]); - return; - } - } - } - - switch (ctx->opcode & 0xff00) { - case 0xc900: /* and #imm,R0 */ - tcg_gen_andi_i32(REG(0), REG(0), B7_0); - return; - case 0xcd00: /* and.b #imm,@(R0,GBR) */ - { - TCGv addr, val; - addr = tcg_temp_new(); - tcg_gen_add_i32(addr, REG(0), cpu_gbr); - val = tcg_temp_new(); - tcg_gen_qemu_ld_i32(val, addr, ctx->memidx, MO_UB); - tcg_gen_andi_i32(val, val, B7_0); - tcg_gen_qemu_st_i32(val, addr, ctx->memidx, MO_UB); - tcg_temp_free(val); - tcg_temp_free(addr); - } - return; - case 0x8b00: /* bf label */ - CHECK_NOT_DELAY_SLOT - gen_conditional_jump(ctx, ctx->pc + 2, - ctx->pc + 4 + B7_0s * 2); - ctx->bstate = BS_BRANCH; - return; - case 0x8f00: /* bf/s label */ - CHECK_NOT_DELAY_SLOT - gen_branch_slot(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2, 0); - ctx->flags |= DELAY_SLOT_CONDITIONAL; - return; - case 0x8900: /* bt label */ - CHECK_NOT_DELAY_SLOT - gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2, - ctx->pc + 2); - ctx->bstate = BS_BRANCH; - return; - case 0x8d00: /* bt/s label */ - CHECK_NOT_DELAY_SLOT - gen_branch_slot(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2, 1); - ctx->flags |= DELAY_SLOT_CONDITIONAL; - return; - case 0x8800: /* cmp/eq #imm,R0 */ - tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, REG(0), B7_0s); - return; - case 0xc400: /* mov.b @(disp,GBR),R0 */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_addi_i32(addr, cpu_gbr, B7_0); - tcg_gen_qemu_ld_i32(REG(0), addr, ctx->memidx, MO_SB); - tcg_temp_free(addr); - } - return; - case 0xc500: /* mov.w @(disp,GBR),R0 */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 2); - tcg_gen_qemu_ld_i32(REG(0), addr, ctx->memidx, MO_TESW); - tcg_temp_free(addr); - } - return; - case 0xc600: /* mov.l @(disp,GBR),R0 */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 4); - tcg_gen_qemu_ld_i32(REG(0), addr, ctx->memidx, MO_TESL); - tcg_temp_free(addr); - } - return; - case 0xc000: /* mov.b R0,@(disp,GBR) */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_addi_i32(addr, cpu_gbr, B7_0); - tcg_gen_qemu_st_i32(REG(0), addr, ctx->memidx, MO_UB); - tcg_temp_free(addr); - } - return; - case 0xc100: /* mov.w R0,@(disp,GBR) */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 2); - tcg_gen_qemu_st_i32(REG(0), addr, ctx->memidx, MO_TEUW); - tcg_temp_free(addr); - } - return; - case 0xc200: /* mov.l R0,@(disp,GBR) */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 4); - tcg_gen_qemu_st_i32(REG(0), addr, ctx->memidx, MO_TEUL); - tcg_temp_free(addr); - } - return; - case 0x8000: /* mov.b R0,@(disp,Rn) */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_addi_i32(addr, REG(B7_4), B3_0); - tcg_gen_qemu_st_i32(REG(0), addr, ctx->memidx, MO_UB); - tcg_temp_free(addr); - } - return; - case 0x8100: /* mov.w R0,@(disp,Rn) */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 2); - tcg_gen_qemu_st_i32(REG(0), addr, ctx->memidx, MO_TEUW); - tcg_temp_free(addr); - } - return; - case 0x8400: /* mov.b @(disp,Rn),R0 */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_addi_i32(addr, REG(B7_4), B3_0); - tcg_gen_qemu_ld_i32(REG(0), addr, ctx->memidx, MO_SB); - tcg_temp_free(addr); - } - return; - case 0x8500: /* mov.w @(disp,Rn),R0 */ - { - TCGv addr = tcg_temp_new(); - tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 2); - tcg_gen_qemu_ld_i32(REG(0), addr, ctx->memidx, MO_TESW); - tcg_temp_free(addr); - } - return; - case 0xc700: /* mova @(disp,PC),R0 */ - tcg_gen_movi_i32(REG(0), ((ctx->pc & 0xfffffffc) + 4 + B7_0 * 4) & ~3); - return; - case 0xcb00: /* or #imm,R0 */ - tcg_gen_ori_i32(REG(0), REG(0), B7_0); - return; - case 0xcf00: /* or.b #imm,@(R0,GBR) */ - { - TCGv addr, val; - addr = tcg_temp_new(); - tcg_gen_add_i32(addr, REG(0), cpu_gbr); - val = tcg_temp_new(); - tcg_gen_qemu_ld_i32(val, addr, ctx->memidx, MO_UB); - tcg_gen_ori_i32(val, val, B7_0); - tcg_gen_qemu_st_i32(val, addr, ctx->memidx, MO_UB); - tcg_temp_free(val); - tcg_temp_free(addr); - } - return; - case 0xc300: /* trapa #imm */ - { - TCGv imm; - CHECK_NOT_DELAY_SLOT - tcg_gen_movi_i32(cpu_pc, ctx->pc); - imm = tcg_const_i32(B7_0); - gen_helper_trapa(cpu_env, imm); - tcg_temp_free(imm); - ctx->bstate = BS_BRANCH; - } - return; - case 0xc800: /* tst #imm,R0 */ - { - TCGv val = tcg_temp_new(); - tcg_gen_andi_i32(val, REG(0), B7_0); - tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, val, 0); - tcg_temp_free(val); - } - return; - case 0xcc00: /* tst.b #imm,@(R0,GBR) */ - { - TCGv val = tcg_temp_new(); - tcg_gen_add_i32(val, REG(0), cpu_gbr); - tcg_gen_qemu_ld_i32(val, val, ctx->memidx, MO_UB); - tcg_gen_andi_i32(val, val, B7_0); - tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, val, 0); - tcg_temp_free(val); - } - return; - case 0xca00: /* xor #imm,R0 */ - tcg_gen_xori_i32(REG(0), REG(0), B7_0); - return; - case 0xce00: /* xor.b #imm,@(R0,GBR) */ - { - TCGv addr, val; - addr = tcg_temp_new(); - tcg_gen_add_i32(addr, REG(0), cpu_gbr); - val = tcg_temp_new(); - tcg_gen_qemu_ld_i32(val, addr, ctx->memidx, MO_UB); - tcg_gen_xori_i32(val, val, B7_0); - tcg_gen_qemu_st_i32(val, addr, ctx->memidx, MO_UB); - tcg_temp_free(val); - tcg_temp_free(addr); - } - return; - } - - switch (ctx->opcode & 0xf08f) { - case 0x408e: /* ldc Rm,Rn_BANK */ - CHECK_PRIVILEGED - tcg_gen_mov_i32(ALTREG(B6_4), REG(B11_8)); - return; - case 0x4087: /* ldc.l @Rm+,Rn_BANK */ - CHECK_PRIVILEGED - tcg_gen_qemu_ld_i32(ALTREG(B6_4), REG(B11_8), ctx->memidx, MO_TESL); - tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); - return; - case 0x0082: /* stc Rm_BANK,Rn */ - CHECK_PRIVILEGED - tcg_gen_mov_i32(REG(B11_8), ALTREG(B6_4)); - return; - case 0x4083: /* stc.l Rm_BANK,@-Rn */ - CHECK_PRIVILEGED - { - TCGv addr = tcg_temp_new(); - tcg_gen_subi_i32(addr, REG(B11_8), 4); - tcg_gen_qemu_st_i32(ALTREG(B6_4), addr, ctx->memidx, MO_TEUL); - tcg_gen_mov_i32(REG(B11_8), addr); - tcg_temp_free(addr); - } - return; - } - - switch (ctx->opcode & 0xf0ff) { - case 0x0023: /* braf Rn */ - CHECK_NOT_DELAY_SLOT - tcg_gen_addi_i32(cpu_delayed_pc, REG(B11_8), ctx->pc + 4); - ctx->flags |= DELAY_SLOT; - ctx->delayed_pc = (uint32_t) - 1; - return; - case 0x0003: /* bsrf Rn */ - CHECK_NOT_DELAY_SLOT - tcg_gen_movi_i32(cpu_pr, ctx->pc + 4); - tcg_gen_add_i32(cpu_delayed_pc, REG(B11_8), cpu_pr); - ctx->flags |= DELAY_SLOT; - ctx->delayed_pc = (uint32_t) - 1; - return; - case 0x4015: /* cmp/pl Rn */ - tcg_gen_setcondi_i32(TCG_COND_GT, cpu_sr_t, REG(B11_8), 0); - return; - case 0x4011: /* cmp/pz Rn */ - tcg_gen_setcondi_i32(TCG_COND_GE, cpu_sr_t, REG(B11_8), 0); - return; - case 0x4010: /* dt Rn */ - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 1); - tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, REG(B11_8), 0); - return; - case 0x402b: /* jmp @Rn */ - CHECK_NOT_DELAY_SLOT - tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8)); - ctx->flags |= DELAY_SLOT; - ctx->delayed_pc = (uint32_t) - 1; - return; - case 0x400b: /* jsr @Rn */ - CHECK_NOT_DELAY_SLOT - tcg_gen_movi_i32(cpu_pr, ctx->pc + 4); - tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8)); - ctx->flags |= DELAY_SLOT; - ctx->delayed_pc = (uint32_t) - 1; - return; - case 0x400e: /* ldc Rm,SR */ - CHECK_PRIVILEGED - { - TCGv val = tcg_temp_new(); - tcg_gen_andi_i32(val, REG(B11_8), 0x700083f3); - gen_write_sr(val); - tcg_temp_free(val); - ctx->bstate = BS_STOP; - } - return; - case 0x4007: /* ldc.l @Rm+,SR */ - CHECK_PRIVILEGED - { - TCGv val = tcg_temp_new(); - tcg_gen_qemu_ld_i32(val, REG(B11_8), ctx->memidx, MO_TESL); - tcg_gen_andi_i32(val, val, 0x700083f3); - gen_write_sr(val); - tcg_temp_free(val); - tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); - ctx->bstate = BS_STOP; - } - return; - case 0x0002: /* stc SR,Rn */ - CHECK_PRIVILEGED - gen_read_sr(REG(B11_8)); - return; - case 0x4003: /* stc SR,@-Rn */ - CHECK_PRIVILEGED - { - TCGv addr = tcg_temp_new(); - TCGv val = tcg_temp_new(); - tcg_gen_subi_i32(addr, REG(B11_8), 4); - gen_read_sr(val); - tcg_gen_qemu_st_i32(val, addr, ctx->memidx, MO_TEUL); - tcg_gen_mov_i32(REG(B11_8), addr); - tcg_temp_free(val); - tcg_temp_free(addr); - } - return; -#define LD(reg,ldnum,ldpnum,prechk) \ - case ldnum: \ - prechk \ - tcg_gen_mov_i32 (cpu_##reg, REG(B11_8)); \ - return; \ - case ldpnum: \ - prechk \ - tcg_gen_qemu_ld_i32(cpu_##reg, REG(B11_8), ctx->memidx, MO_TESL); \ - tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); \ - return; -#define ST(reg,stnum,stpnum,prechk) \ - case stnum: \ - prechk \ - tcg_gen_mov_i32 (REG(B11_8), cpu_##reg); \ - return; \ - case stpnum: \ - prechk \ - { \ - TCGv addr = tcg_temp_new(); \ - tcg_gen_subi_i32(addr, REG(B11_8), 4); \ - tcg_gen_qemu_st_i32(cpu_##reg, addr, ctx->memidx, MO_TEUL); \ - tcg_gen_mov_i32(REG(B11_8), addr); \ - tcg_temp_free(addr); \ - } \ - return; -#define LDST(reg,ldnum,ldpnum,stnum,stpnum,prechk) \ - LD(reg,ldnum,ldpnum,prechk) \ - ST(reg,stnum,stpnum,prechk) - LDST(gbr, 0x401e, 0x4017, 0x0012, 0x4013, {}) - LDST(vbr, 0x402e, 0x4027, 0x0022, 0x4023, CHECK_PRIVILEGED) - LDST(ssr, 0x403e, 0x4037, 0x0032, 0x4033, CHECK_PRIVILEGED) - LDST(spc, 0x404e, 0x4047, 0x0042, 0x4043, CHECK_PRIVILEGED) - ST(sgr, 0x003a, 0x4032, CHECK_PRIVILEGED) - LD(sgr, 0x403a, 0x4036, CHECK_PRIVILEGED if (!(ctx->features & SH_FEATURE_SH4A)) break;) - LDST(dbr, 0x40fa, 0x40f6, 0x00fa, 0x40f2, CHECK_PRIVILEGED) - LDST(mach, 0x400a, 0x4006, 0x000a, 0x4002, {}) - LDST(macl, 0x401a, 0x4016, 0x001a, 0x4012, {}) - LDST(pr, 0x402a, 0x4026, 0x002a, 0x4022, {}) - LDST(fpul, 0x405a, 0x4056, 0x005a, 0x4052, {CHECK_FPU_ENABLED}) - case 0x406a: /* lds Rm,FPSCR */ - CHECK_FPU_ENABLED - gen_helper_ld_fpscr(cpu_env, REG(B11_8)); - ctx->bstate = BS_STOP; - return; - case 0x4066: /* lds.l @Rm+,FPSCR */ - CHECK_FPU_ENABLED - { - TCGv addr = tcg_temp_new(); - tcg_gen_qemu_ld_i32(addr, REG(B11_8), ctx->memidx, MO_TESL); - tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); - gen_helper_ld_fpscr(cpu_env, addr); - tcg_temp_free(addr); - ctx->bstate = BS_STOP; - } - return; - case 0x006a: /* sts FPSCR,Rn */ - CHECK_FPU_ENABLED - tcg_gen_andi_i32(REG(B11_8), cpu_fpscr, 0x003fffff); - return; - case 0x4062: /* sts FPSCR,@-Rn */ - CHECK_FPU_ENABLED - { - TCGv addr, val; - val = tcg_temp_new(); - tcg_gen_andi_i32(val, cpu_fpscr, 0x003fffff); - addr = tcg_temp_new(); - tcg_gen_subi_i32(addr, REG(B11_8), 4); - tcg_gen_qemu_st_i32(val, addr, ctx->memidx, MO_TEUL); - tcg_gen_mov_i32(REG(B11_8), addr); - tcg_temp_free(addr); - tcg_temp_free(val); - } - return; - case 0x00c3: /* movca.l R0,@Rm */ - { - TCGv val = tcg_temp_new(); - tcg_gen_qemu_ld_i32(val, REG(B11_8), ctx->memidx, MO_TEUL); - gen_helper_movcal(cpu_env, REG(B11_8), val); - tcg_gen_qemu_st_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL); - } - ctx->has_movcal = 1; - return; - case 0x40a9: - /* MOVUA.L @Rm,R0 (Rm) -> R0 - Load non-boundary-aligned data */ - tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL); - return; - case 0x40e9: - /* MOVUA.L @Rm+,R0 (Rm) -> R0, Rm + 4 -> Rm - Load non-boundary-aligned data */ - tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL); - tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); - return; - case 0x0029: /* movt Rn */ - tcg_gen_mov_i32(REG(B11_8), cpu_sr_t); - return; - case 0x0073: - /* MOVCO.L - LDST -> T - If (T == 1) R0 -> (Rn) - 0 -> LDST - */ - if (ctx->features & SH_FEATURE_SH4A) { - TCGLabel *label = gen_new_label(); - tcg_gen_mov_i32(cpu_sr_t, cpu_ldst); - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ldst, 0, label); - tcg_gen_qemu_st_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL); - gen_set_label(label); - tcg_gen_movi_i32(cpu_ldst, 0); - return; - } else - break; - case 0x0063: - /* MOVLI.L @Rm,R0 - 1 -> LDST - (Rm) -> R0 - When interrupt/exception - occurred 0 -> LDST - */ - if (ctx->features & SH_FEATURE_SH4A) { - tcg_gen_movi_i32(cpu_ldst, 0); - tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx, MO_TESL); - tcg_gen_movi_i32(cpu_ldst, 1); - return; - } else - break; - case 0x0093: /* ocbi @Rn */ - { - gen_helper_ocbi(cpu_env, REG(B11_8)); - } - return; - case 0x00a3: /* ocbp @Rn */ - case 0x00b3: /* ocbwb @Rn */ - /* These instructions are supposed to do nothing in case of - a cache miss. Given that we only partially emulate caches - it is safe to simply ignore them. */ - return; - case 0x0083: /* pref @Rn */ - return; - case 0x00d3: /* prefi @Rn */ - if (ctx->features & SH_FEATURE_SH4A) - return; - else - break; - case 0x00e3: /* icbi @Rn */ - if (ctx->features & SH_FEATURE_SH4A) - return; - else - break; - case 0x00ab: /* synco */ - if (ctx->features & SH_FEATURE_SH4A) - return; - else - break; - case 0x4024: /* rotcl Rn */ - { - TCGv tmp = tcg_temp_new(); - tcg_gen_mov_i32(tmp, cpu_sr_t); - tcg_gen_shri_i32(cpu_sr_t, REG(B11_8), 31); - tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1); - tcg_gen_or_i32(REG(B11_8), REG(B11_8), tmp); - tcg_temp_free(tmp); - } - return; - case 0x4025: /* rotcr Rn */ - { - TCGv tmp = tcg_temp_new(); - tcg_gen_shli_i32(tmp, cpu_sr_t, 31); - tcg_gen_andi_i32(cpu_sr_t, REG(B11_8), 1); - tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 1); - tcg_gen_or_i32(REG(B11_8), REG(B11_8), tmp); - tcg_temp_free(tmp); - } - return; - case 0x4004: /* rotl Rn */ - tcg_gen_rotli_i32(REG(B11_8), REG(B11_8), 1); - tcg_gen_andi_i32(cpu_sr_t, REG(B11_8), 0); - return; - case 0x4005: /* rotr Rn */ - tcg_gen_andi_i32(cpu_sr_t, REG(B11_8), 0); - tcg_gen_rotri_i32(REG(B11_8), REG(B11_8), 1); - return; - case 0x4000: /* shll Rn */ - case 0x4020: /* shal Rn */ - tcg_gen_shri_i32(cpu_sr_t, REG(B11_8), 31); - tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1); - return; - case 0x4021: /* shar Rn */ - tcg_gen_andi_i32(cpu_sr_t, REG(B11_8), 1); - tcg_gen_sari_i32(REG(B11_8), REG(B11_8), 1); - return; - case 0x4001: /* shlr Rn */ - tcg_gen_andi_i32(cpu_sr_t, REG(B11_8), 1); - tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 1); - return; - case 0x4008: /* shll2 Rn */ - tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 2); - return; - case 0x4018: /* shll8 Rn */ - tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 8); - return; - case 0x4028: /* shll16 Rn */ - tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 16); - return; - case 0x4009: /* shlr2 Rn */ - tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 2); - return; - case 0x4019: /* shlr8 Rn */ - tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 8); - return; - case 0x4029: /* shlr16 Rn */ - tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 16); - return; - case 0x401b: /* tas.b @Rn */ - { - TCGv addr, val; - addr = tcg_temp_local_new(); - tcg_gen_mov_i32(addr, REG(B11_8)); - val = tcg_temp_local_new(); - tcg_gen_qemu_ld_i32(val, addr, ctx->memidx, MO_UB); - tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, val, 0); - tcg_gen_ori_i32(val, val, 0x80); - tcg_gen_qemu_st_i32(val, addr, ctx->memidx, MO_UB); - tcg_temp_free(val); - tcg_temp_free(addr); - } - return; - case 0xf00d: /* fsts FPUL,FRn - FPSCR: Nothing */ - CHECK_FPU_ENABLED - tcg_gen_mov_i32(cpu_fregs[FREG(B11_8)], cpu_fpul); - return; - case 0xf01d: /* flds FRm,FPUL - FPSCR: Nothing */ - CHECK_FPU_ENABLED - tcg_gen_mov_i32(cpu_fpul, cpu_fregs[FREG(B11_8)]); - return; - case 0xf02d: /* float FPUL,FRn/DRn - FPSCR: R[PR,Enable.I]/W[Cause,Flag] */ - CHECK_FPU_ENABLED - if (ctx->flags & FPSCR_PR) { - TCGv_i64 fp; - if (ctx->opcode & 0x0100) - break; /* illegal instruction */ - fp = tcg_temp_new_i64(); - gen_helper_float_DT(fp, cpu_env, cpu_fpul); - gen_store_fpr64(fp, DREG(B11_8)); - tcg_temp_free_i64(fp); - } - else { - gen_helper_float_FT(cpu_fregs[FREG(B11_8)], cpu_env, cpu_fpul); - } - return; - case 0xf03d: /* ftrc FRm/DRm,FPUL - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ - CHECK_FPU_ENABLED - if (ctx->flags & FPSCR_PR) { - TCGv_i64 fp; - if (ctx->opcode & 0x0100) - break; /* illegal instruction */ - fp = tcg_temp_new_i64(); - gen_load_fpr64(fp, DREG(B11_8)); - gen_helper_ftrc_DT(cpu_fpul, cpu_env, fp); - tcg_temp_free_i64(fp); - } - else { - gen_helper_ftrc_FT(cpu_fpul, cpu_env, cpu_fregs[FREG(B11_8)]); - } - return; - case 0xf04d: /* fneg FRn/DRn - FPSCR: Nothing */ - CHECK_FPU_ENABLED - { - gen_helper_fneg_T(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)]); - } - return; - case 0xf05d: /* fabs FRn/DRn */ - CHECK_FPU_ENABLED - if (ctx->flags & FPSCR_PR) { - if (ctx->opcode & 0x0100) - break; /* illegal instruction */ - TCGv_i64 fp = tcg_temp_new_i64(); - gen_load_fpr64(fp, DREG(B11_8)); - gen_helper_fabs_DT(fp, fp); - gen_store_fpr64(fp, DREG(B11_8)); - tcg_temp_free_i64(fp); - } else { - gen_helper_fabs_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)]); - } - return; - case 0xf06d: /* fsqrt FRn */ - CHECK_FPU_ENABLED - if (ctx->flags & FPSCR_PR) { - if (ctx->opcode & 0x0100) - break; /* illegal instruction */ - TCGv_i64 fp = tcg_temp_new_i64(); - gen_load_fpr64(fp, DREG(B11_8)); - gen_helper_fsqrt_DT(fp, cpu_env, fp); - gen_store_fpr64(fp, DREG(B11_8)); - tcg_temp_free_i64(fp); - } else { - gen_helper_fsqrt_FT(cpu_fregs[FREG(B11_8)], cpu_env, - cpu_fregs[FREG(B11_8)]); - } - return; - case 0xf07d: /* fsrra FRn */ - CHECK_FPU_ENABLED - break; - case 0xf08d: /* fldi0 FRn - FPSCR: R[PR] */ - CHECK_FPU_ENABLED - if (!(ctx->flags & FPSCR_PR)) { - tcg_gen_movi_i32(cpu_fregs[FREG(B11_8)], 0); - } - return; - case 0xf09d: /* fldi1 FRn - FPSCR: R[PR] */ - CHECK_FPU_ENABLED - if (!(ctx->flags & FPSCR_PR)) { - tcg_gen_movi_i32(cpu_fregs[FREG(B11_8)], 0x3f800000); - } - return; - case 0xf0ad: /* fcnvsd FPUL,DRn */ - CHECK_FPU_ENABLED - { - TCGv_i64 fp = tcg_temp_new_i64(); - gen_helper_fcnvsd_FT_DT(fp, cpu_env, cpu_fpul); - gen_store_fpr64(fp, DREG(B11_8)); - tcg_temp_free_i64(fp); - } - return; - case 0xf0bd: /* fcnvds DRn,FPUL */ - CHECK_FPU_ENABLED - { - TCGv_i64 fp = tcg_temp_new_i64(); - gen_load_fpr64(fp, DREG(B11_8)); - gen_helper_fcnvds_DT_FT(cpu_fpul, cpu_env, fp); - tcg_temp_free_i64(fp); - } - return; - case 0xf0ed: /* fipr FVm,FVn */ - CHECK_FPU_ENABLED - if ((ctx->flags & FPSCR_PR) == 0) { - TCGv m, n; - m = tcg_const_i32((ctx->opcode >> 8) & 3); - n = tcg_const_i32((ctx->opcode >> 10) & 3); - gen_helper_fipr(cpu_env, m, n); - tcg_temp_free(m); - tcg_temp_free(n); - return; - } - break; - case 0xf0fd: /* ftrv XMTRX,FVn */ - CHECK_FPU_ENABLED - if ((ctx->opcode & 0x0300) == 0x0100 && - (ctx->flags & FPSCR_PR) == 0) { - TCGv n; - n = tcg_const_i32((ctx->opcode >> 10) & 3); - gen_helper_ftrv(cpu_env, n); - tcg_temp_free(n); - return; - } - break; - } -#if 0 - fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n", - ctx->opcode, ctx->pc); - fflush(stderr); -#endif - tcg_gen_movi_i32(cpu_pc, ctx->pc); - if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { - gen_helper_raise_slot_illegal_instruction(cpu_env); - } else { - gen_helper_raise_illegal_instruction(cpu_env); - } - ctx->bstate = BS_BRANCH; -} - -static void decode_opc(DisasContext * ctx) -{ - uint32_t old_flags = ctx->flags; - - _decode_opc(ctx); - - if (old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { - if (ctx->flags & DELAY_SLOT_CLEARME) { - gen_store_flags(0); - } else { - /* go out of the delay slot */ - uint32_t new_flags = ctx->flags; - new_flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL); - gen_store_flags(new_flags); - } - ctx->flags = 0; - ctx->bstate = BS_BRANCH; - if (old_flags & DELAY_SLOT_CONDITIONAL) { - gen_delayed_conditional_jump(ctx); - } else if (old_flags & DELAY_SLOT) { - gen_jump(ctx); - } - - } - - /* go into a delay slot */ - if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) - gen_store_flags(ctx->flags); -} - -void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb) -{ - SuperHCPU *cpu = sh_env_get_cpu(env); - CPUState *cs = CPU(cpu); - DisasContext ctx; - target_ulong pc_start; - int num_insns; - int max_insns; - - pc_start = tb->pc; - ctx.pc = pc_start; - ctx.flags = (uint32_t)tb->flags; - ctx.bstate = BS_NONE; - ctx.memidx = (ctx.flags & (1u << SR_MD)) == 0 ? 1 : 0; - /* We don't know if the delayed pc came from a dynamic or static branch, - so assume it is a dynamic branch. */ - ctx.delayed_pc = -1; /* use delayed pc from env pointer */ - ctx.tb = tb; - ctx.singlestep_enabled = cs->singlestep_enabled; - ctx.features = env->features; - ctx.has_movcal = (ctx.flags & TB_FLAG_PENDING_MOVCA); - - num_insns = 0; - max_insns = tb->cflags & CF_COUNT_MASK; - if (max_insns == 0) { - max_insns = CF_COUNT_MASK; - } - if (max_insns > TCG_MAX_INSNS) { - max_insns = TCG_MAX_INSNS; - } - - gen_tb_start(tb); - while (ctx.bstate == BS_NONE && !tcg_op_buf_full()) { - tcg_gen_insn_start(ctx.pc, ctx.flags); - num_insns++; - - if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) { - /* We have hit a breakpoint - make sure PC is up-to-date */ - tcg_gen_movi_i32(cpu_pc, ctx.pc); - gen_helper_debug(cpu_env); - ctx.bstate = BS_BRANCH; - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the logic setting tb->size below does the right thing. */ - ctx.pc += 2; - break; - } - - if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { - gen_io_start(); - } - - ctx.opcode = cpu_lduw_code(env, ctx.pc); - decode_opc(&ctx); - ctx.pc += 2; - if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) - break; - if (cs->singlestep_enabled) { - break; - } - if (num_insns >= max_insns) - break; - if (singlestep) - break; - } - if (tb->cflags & CF_LAST_IO) - gen_io_end(); - if (cs->singlestep_enabled) { - tcg_gen_movi_i32(cpu_pc, ctx.pc); - gen_helper_debug(cpu_env); - } else { - switch (ctx.bstate) { - case BS_STOP: - /* gen_op_interrupt_restart(); */ - /* fall through */ - case BS_NONE: - if (ctx.flags) { - gen_store_flags(ctx.flags | DELAY_SLOT_CLEARME); - } - gen_goto_tb(&ctx, 0, ctx.pc); - break; - case BS_EXCP: - /* gen_op_interrupt_restart(); */ - tcg_gen_exit_tb(0); - break; - case BS_BRANCH: - default: - break; - } - } - - gen_tb_end(tb, num_insns); - - tb->size = ctx.pc - pc_start; - tb->icount = num_insns; - -#ifdef DEBUG_DISAS - if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) - && qemu_log_in_addr_range(pc_start)) { - qemu_log_lock(); - qemu_log("IN:\n"); /* , lookup_symbol(pc_start)); */ - log_target_disas(cs, pc_start, ctx.pc - pc_start, 0); - qemu_log("\n"); - qemu_log_unlock(); - } -#endif -} - -void restore_state_to_opc(CPUSH4State *env, TranslationBlock *tb, - target_ulong *data) -{ - env->pc = data[0]; - env->flags = data[1]; -} |