diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2021-05-13 20:13:24 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-05-13 20:13:24 +0100 |
commit | 2d3fc4e2b069494b1e9e2e4a1e3de24cbc036426 (patch) | |
tree | d7b6b804dc1306dda29fc775b7e91791d8ad5277 /target | |
parent | dab59ce031228066eb95a9c518846fcacfb0dbbf (diff) | |
parent | 4369223902a79b7fc56ca076d99b88ff14964ddd (diff) |
Merge remote-tracking branch 'remotes/armbru/tags/pull-misc-2021-05-12' into staging
Miscellaneous patches for 2021-05-12
# gpg: Signature made Wed 12 May 2021 17:22:15 BST
# gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653
# gpg: issuer "armbru@redhat.com"
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full]
# gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full]
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653
* remotes/armbru/tags/pull-misc-2021-05-12:
Drop the deprecated unicore32 target
Drop the deprecated lm32 target
block: Drop the sheepdog block driver
Remove the deprecated moxie target
monitor/qmp: fix race on CHR_EVENT_CLOSED without OOB
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target')
37 files changed, 0 insertions, 7613 deletions
diff --git a/target/lm32/README b/target/lm32/README deleted file mode 100644 index ba3508a711..0000000000 --- a/target/lm32/README +++ /dev/null @@ -1,45 +0,0 @@ -LatticeMico32 target --------------------- - -General -------- -All opcodes including the JUART CSRs are supported. - - -JTAG UART ---------- -JTAG UART is routed to a serial console device. For the current boards it -is the second one. Ie to enable it in the qemu virtual console window use -the following command line parameters: - -serial vc -serial vc -This will make serial0 (the lm32_uart) and serial1 (the JTAG UART) -available as virtual consoles. - - -Semihosting ------------ -Semihosting on this target is supported. Some system calls like read, write -and exit are executed on the host if semihosting is enabled. See -target/lm32-semi.c for all supported system calls. Emulation aware programs -can use this mechanism to shut down the virtual machine and print to the -host console. See the tcg tests for an example. - - -Special instructions --------------------- -The translation recognizes one special instruction to halt the cpu: - and r0, r0, r0 -On real hardware this instruction is a nop. It is not used by GCC and -should (hopefully) not be used within hand-crafted assembly. -Insert this instruction in your idle loop to reduce the cpu load on the -host. - - -Ignoring the MSB of the address bus ------------------------------------ -Some SoC ignores the MSB on the address bus. Thus creating a shadow memory -area. As a general rule, 0x00000000-0x7fffffff is cached, whereas -0x80000000-0xffffffff is not cached and used to access IO devices. This -behaviour can be enabled with: - cpu_lm32_set_phys_msb_ignore(env, 1); - diff --git a/target/lm32/TODO b/target/lm32/TODO deleted file mode 100644 index e163c42ebe..0000000000 --- a/target/lm32/TODO +++ /dev/null @@ -1 +0,0 @@ -* linux-user emulation diff --git a/target/lm32/cpu-param.h b/target/lm32/cpu-param.h deleted file mode 100644 index d89574ad19..0000000000 --- a/target/lm32/cpu-param.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * LatticeMico32 cpu parameters for qemu. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * SPDX-License-Identifier: LGPL-2.0+ - */ - -#ifndef LM32_CPU_PARAM_H -#define LM32_CPU_PARAM_H 1 - -#define TARGET_LONG_BITS 32 -#define TARGET_PAGE_BITS 12 -#define TARGET_PHYS_ADDR_SPACE_BITS 32 -#define TARGET_VIRT_ADDR_SPACE_BITS 32 -#define NB_MMU_MODES 1 - -#endif diff --git a/target/lm32/cpu-qom.h b/target/lm32/cpu-qom.h deleted file mode 100644 index 245b35cd1d..0000000000 --- a/target/lm32/cpu-qom.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * QEMU LatticeMico32 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_LM32_CPU_QOM_H -#define QEMU_LM32_CPU_QOM_H - -#include "hw/core/cpu.h" -#include "qom/object.h" - -#define TYPE_LM32_CPU "lm32-cpu" - -OBJECT_DECLARE_TYPE(LM32CPU, LM32CPUClass, - LM32_CPU) - -/** - * LM32CPUClass: - * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. - * - * A LatticeMico32 CPU model. - */ -struct LM32CPUClass { - /*< private >*/ - CPUClass parent_class; - /*< public >*/ - - DeviceRealize parent_realize; - DeviceReset parent_reset; -}; - - -#endif diff --git a/target/lm32/cpu.c b/target/lm32/cpu.c deleted file mode 100644 index c23d72874c..0000000000 --- a/target/lm32/cpu.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * QEMU LatticeMico32 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> - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu/qemu-print.h" -#include "cpu.h" - - -static void lm32_cpu_set_pc(CPUState *cs, vaddr value) -{ - LM32CPU *cpu = LM32_CPU(cs); - - cpu->env.pc = value; -} - -static void lm32_cpu_list_entry(gpointer data, gpointer user_data) -{ - ObjectClass *oc = data; - const char *typename = object_class_get_name(oc); - char *name; - - name = g_strndup(typename, strlen(typename) - strlen(LM32_CPU_TYPE_SUFFIX)); - qemu_printf(" %s\n", name); - g_free(name); -} - - -void lm32_cpu_list(void) -{ - GSList *list; - - list = object_class_get_list_sorted(TYPE_LM32_CPU, false); - qemu_printf("Available CPUs:\n"); - g_slist_foreach(list, lm32_cpu_list_entry, NULL); - g_slist_free(list); -} - -static void lm32_cpu_init_cfg_reg(LM32CPU *cpu) -{ - CPULM32State *env = &cpu->env; - uint32_t cfg = 0; - - if (cpu->features & LM32_FEATURE_MULTIPLY) { - cfg |= CFG_M; - } - - if (cpu->features & LM32_FEATURE_DIVIDE) { - cfg |= CFG_D; - } - - if (cpu->features & LM32_FEATURE_SHIFT) { - cfg |= CFG_S; - } - - if (cpu->features & LM32_FEATURE_SIGN_EXTEND) { - cfg |= CFG_X; - } - - if (cpu->features & LM32_FEATURE_I_CACHE) { - cfg |= CFG_IC; - } - - if (cpu->features & LM32_FEATURE_D_CACHE) { - cfg |= CFG_DC; - } - - if (cpu->features & LM32_FEATURE_CYCLE_COUNT) { - cfg |= CFG_CC; - } - - cfg |= (cpu->num_interrupts << CFG_INT_SHIFT); - cfg |= (cpu->num_breakpoints << CFG_BP_SHIFT); - cfg |= (cpu->num_watchpoints << CFG_WP_SHIFT); - cfg |= (cpu->revision << CFG_REV_SHIFT); - - env->cfg = cfg; -} - -static bool lm32_cpu_has_work(CPUState *cs) -{ - return cs->interrupt_request & CPU_INTERRUPT_HARD; -} - -static void lm32_cpu_reset(DeviceState *dev) -{ - CPUState *s = CPU(dev); - LM32CPU *cpu = LM32_CPU(s); - LM32CPUClass *lcc = LM32_CPU_GET_CLASS(cpu); - CPULM32State *env = &cpu->env; - - lcc->parent_reset(dev); - - /* reset cpu state */ - memset(env, 0, offsetof(CPULM32State, end_reset_fields)); - - lm32_cpu_init_cfg_reg(cpu); -} - -static void lm32_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) -{ - info->mach = bfd_mach_lm32; - info->print_insn = print_insn_lm32; -} - -static void lm32_cpu_realizefn(DeviceState *dev, Error **errp) -{ - CPUState *cs = CPU(dev); - LM32CPUClass *lcc = LM32_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); - - lcc->parent_realize(dev, errp); -} - -static void lm32_cpu_initfn(Object *obj) -{ - LM32CPU *cpu = LM32_CPU(obj); - CPULM32State *env = &cpu->env; - - cpu_set_cpustate_pointers(cpu); - - env->flags = 0; -} - -static void lm32_basic_cpu_initfn(Object *obj) -{ - LM32CPU *cpu = LM32_CPU(obj); - - cpu->revision = 3; - cpu->num_interrupts = 32; - cpu->num_breakpoints = 4; - cpu->num_watchpoints = 4; - cpu->features = LM32_FEATURE_SHIFT - | LM32_FEATURE_SIGN_EXTEND - | LM32_FEATURE_CYCLE_COUNT; -} - -static void lm32_standard_cpu_initfn(Object *obj) -{ - LM32CPU *cpu = LM32_CPU(obj); - - cpu->revision = 3; - cpu->num_interrupts = 32; - cpu->num_breakpoints = 4; - cpu->num_watchpoints = 4; - cpu->features = LM32_FEATURE_MULTIPLY - | LM32_FEATURE_DIVIDE - | LM32_FEATURE_SHIFT - | LM32_FEATURE_SIGN_EXTEND - | LM32_FEATURE_I_CACHE - | LM32_FEATURE_CYCLE_COUNT; -} - -static void lm32_full_cpu_initfn(Object *obj) -{ - LM32CPU *cpu = LM32_CPU(obj); - - cpu->revision = 3; - cpu->num_interrupts = 32; - cpu->num_breakpoints = 4; - cpu->num_watchpoints = 4; - cpu->features = LM32_FEATURE_MULTIPLY - | LM32_FEATURE_DIVIDE - | LM32_FEATURE_SHIFT - | LM32_FEATURE_SIGN_EXTEND - | LM32_FEATURE_I_CACHE - | LM32_FEATURE_D_CACHE - | LM32_FEATURE_CYCLE_COUNT; -} - -static ObjectClass *lm32_cpu_class_by_name(const char *cpu_model) -{ - ObjectClass *oc; - char *typename; - - typename = g_strdup_printf(LM32_CPU_TYPE_NAME("%s"), cpu_model); - oc = object_class_by_name(typename); - g_free(typename); - if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_LM32_CPU) || - object_class_is_abstract(oc))) { - oc = NULL; - } - return oc; -} - -#include "hw/core/tcg-cpu-ops.h" - -static struct TCGCPUOps lm32_tcg_ops = { - .initialize = lm32_translate_init, - .cpu_exec_interrupt = lm32_cpu_exec_interrupt, - .tlb_fill = lm32_cpu_tlb_fill, - .debug_excp_handler = lm32_debug_excp_handler, - -#ifndef CONFIG_USER_ONLY - .do_interrupt = lm32_cpu_do_interrupt, -#endif /* !CONFIG_USER_ONLY */ -}; - -static void lm32_cpu_class_init(ObjectClass *oc, void *data) -{ - LM32CPUClass *lcc = LM32_CPU_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); - DeviceClass *dc = DEVICE_CLASS(oc); - - device_class_set_parent_realize(dc, lm32_cpu_realizefn, - &lcc->parent_realize); - device_class_set_parent_reset(dc, lm32_cpu_reset, &lcc->parent_reset); - - cc->class_by_name = lm32_cpu_class_by_name; - cc->has_work = lm32_cpu_has_work; - cc->dump_state = lm32_cpu_dump_state; - cc->set_pc = lm32_cpu_set_pc; - cc->gdb_read_register = lm32_cpu_gdb_read_register; - cc->gdb_write_register = lm32_cpu_gdb_write_register; -#ifndef CONFIG_USER_ONLY - cc->get_phys_page_debug = lm32_cpu_get_phys_page_debug; - cc->vmsd = &vmstate_lm32_cpu; -#endif - cc->gdb_num_core_regs = 32 + 7; - cc->gdb_stop_before_watchpoint = true; - cc->disas_set_info = lm32_cpu_disas_set_info; - cc->tcg_ops = &lm32_tcg_ops; -} - -#define DEFINE_LM32_CPU_TYPE(cpu_model, initfn) \ - { \ - .parent = TYPE_LM32_CPU, \ - .name = LM32_CPU_TYPE_NAME(cpu_model), \ - .instance_init = initfn, \ - } - -static const TypeInfo lm32_cpus_type_infos[] = { - { /* base class should be registered first */ - .name = TYPE_LM32_CPU, - .parent = TYPE_CPU, - .instance_size = sizeof(LM32CPU), - .instance_init = lm32_cpu_initfn, - .abstract = true, - .class_size = sizeof(LM32CPUClass), - .class_init = lm32_cpu_class_init, - }, - DEFINE_LM32_CPU_TYPE("lm32-basic", lm32_basic_cpu_initfn), - DEFINE_LM32_CPU_TYPE("lm32-standard", lm32_standard_cpu_initfn), - DEFINE_LM32_CPU_TYPE("lm32-full", lm32_full_cpu_initfn), -}; - -DEFINE_TYPES(lm32_cpus_type_infos) diff --git a/target/lm32/cpu.h b/target/lm32/cpu.h deleted file mode 100644 index ea7c01ca8b..0000000000 --- a/target/lm32/cpu.h +++ /dev/null @@ -1,262 +0,0 @@ -/* - * LatticeMico32 virtual CPU header. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * 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/>. - */ - -#ifndef LM32_CPU_H -#define LM32_CPU_H - -#include "cpu-qom.h" -#include "exec/cpu-defs.h" - -typedef struct CPULM32State CPULM32State; - -static inline int cpu_mmu_index(CPULM32State *env, bool ifetch) -{ - return 0; -} - -/* Exceptions indices */ -enum { - EXCP_RESET = 0, - EXCP_BREAKPOINT, - EXCP_INSN_BUS_ERROR, - EXCP_WATCHPOINT, - EXCP_DATA_BUS_ERROR, - EXCP_DIVIDE_BY_ZERO, - EXCP_IRQ, - EXCP_SYSTEMCALL -}; - -/* Registers */ -enum { - R_R0 = 0, R_R1, R_R2, R_R3, R_R4, R_R5, R_R6, R_R7, R_R8, R_R9, R_R10, - R_R11, R_R12, R_R13, R_R14, R_R15, R_R16, R_R17, R_R18, R_R19, R_R20, - R_R21, R_R22, R_R23, R_R24, R_R25, R_R26, R_R27, R_R28, R_R29, R_R30, - R_R31 -}; - -/* Register aliases */ -enum { - R_GP = R_R26, - R_FP = R_R27, - R_SP = R_R28, - R_RA = R_R29, - R_EA = R_R30, - R_BA = R_R31 -}; - -/* IE flags */ -enum { - IE_IE = (1<<0), - IE_EIE = (1<<1), - IE_BIE = (1<<2), -}; - -/* DC flags */ -enum { - DC_SS = (1<<0), - DC_RE = (1<<1), - DC_C0 = (1<<2), - DC_C1 = (1<<3), - DC_C2 = (1<<4), - DC_C3 = (1<<5), -}; - -/* CFG mask */ -enum { - CFG_M = (1<<0), - CFG_D = (1<<1), - CFG_S = (1<<2), - CFG_U = (1<<3), - CFG_X = (1<<4), - CFG_CC = (1<<5), - CFG_IC = (1<<6), - CFG_DC = (1<<7), - CFG_G = (1<<8), - CFG_H = (1<<9), - CFG_R = (1<<10), - CFG_J = (1<<11), - CFG_INT_SHIFT = 12, - CFG_BP_SHIFT = 18, - CFG_WP_SHIFT = 22, - CFG_REV_SHIFT = 26, -}; - -/* CSRs */ -enum { - CSR_IE = 0x00, - CSR_IM = 0x01, - CSR_IP = 0x02, - CSR_ICC = 0x03, - CSR_DCC = 0x04, - CSR_CC = 0x05, - CSR_CFG = 0x06, - CSR_EBA = 0x07, - CSR_DC = 0x08, - CSR_DEBA = 0x09, - CSR_JTX = 0x0e, - CSR_JRX = 0x0f, - CSR_BP0 = 0x10, - CSR_BP1 = 0x11, - CSR_BP2 = 0x12, - CSR_BP3 = 0x13, - CSR_WP0 = 0x18, - CSR_WP1 = 0x19, - CSR_WP2 = 0x1a, - CSR_WP3 = 0x1b, -}; - -enum { - LM32_FEATURE_MULTIPLY = 1, - LM32_FEATURE_DIVIDE = 2, - LM32_FEATURE_SHIFT = 4, - LM32_FEATURE_SIGN_EXTEND = 8, - LM32_FEATURE_I_CACHE = 16, - LM32_FEATURE_D_CACHE = 32, - LM32_FEATURE_CYCLE_COUNT = 64, -}; - -enum { - LM32_FLAG_IGNORE_MSB = 1, -}; - -struct CPULM32State { - /* general registers */ - uint32_t regs[32]; - - /* special registers */ - uint32_t pc; /* program counter */ - uint32_t ie; /* interrupt enable */ - uint32_t icc; /* instruction cache control */ - uint32_t dcc; /* data cache control */ - uint32_t cc; /* cycle counter */ - uint32_t cfg; /* configuration */ - - /* debug registers */ - uint32_t dc; /* debug control */ - uint32_t bp[4]; /* breakpoints */ - uint32_t wp[4]; /* watchpoints */ - - struct CPUBreakpoint *cpu_breakpoint[4]; - struct CPUWatchpoint *cpu_watchpoint[4]; - - /* Fields up to this point are cleared by a CPU reset */ - struct {} end_reset_fields; - - /* Fields from here on are preserved across CPU reset. */ - uint32_t eba; /* exception base address */ - uint32_t deba; /* debug exception base address */ - - /* interrupt controller handle for callbacks */ - DeviceState *pic_state; - /* JTAG UART handle for callbacks */ - DeviceState *juart_state; - - /* processor core features */ - uint32_t flags; - -}; - -/** - * LM32CPU: - * @env: #CPULM32State - * - * A LatticeMico32 CPU. - */ -struct LM32CPU { - /*< private >*/ - CPUState parent_obj; - /*< public >*/ - - CPUNegativeOffsetState neg; - CPULM32State env; - - uint32_t revision; - uint8_t num_interrupts; - uint8_t num_breakpoints; - uint8_t num_watchpoints; - uint32_t features; -}; - - -#ifndef CONFIG_USER_ONLY -extern const VMStateDescription vmstate_lm32_cpu; -#endif - -void lm32_cpu_do_interrupt(CPUState *cpu); -bool lm32_cpu_exec_interrupt(CPUState *cs, int int_req); -void lm32_cpu_dump_state(CPUState *cpu, FILE *f, int flags); -hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -int lm32_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); -int lm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); - -typedef enum { - LM32_WP_DISABLED = 0, - LM32_WP_READ, - LM32_WP_WRITE, - LM32_WP_READ_WRITE, -} lm32_wp_t; - -static inline lm32_wp_t lm32_wp_type(uint32_t dc, int idx) -{ - assert(idx < 4); - return (dc >> (idx+1)*2) & 0x3; -} - -/* you can call this signal handler from your SIGBUS and SIGSEGV - signal handlers to inform the virtual CPU of exceptions. non zero - is returned if the signal was handled by the virtual CPU. */ -int cpu_lm32_signal_handler(int host_signum, void *pinfo, - void *puc); -void lm32_cpu_list(void); -void lm32_translate_init(void); -void cpu_lm32_set_phys_msb_ignore(CPULM32State *env, int value); -void QEMU_NORETURN raise_exception(CPULM32State *env, int index); -void lm32_debug_excp_handler(CPUState *cs); -void lm32_breakpoint_insert(CPULM32State *env, int index, target_ulong address); -void lm32_breakpoint_remove(CPULM32State *env, int index); -void lm32_watchpoint_insert(CPULM32State *env, int index, target_ulong address, - lm32_wp_t wp_type); -void lm32_watchpoint_remove(CPULM32State *env, int index); -bool lm32_cpu_do_semihosting(CPUState *cs); - -#define LM32_CPU_TYPE_SUFFIX "-" TYPE_LM32_CPU -#define LM32_CPU_TYPE_NAME(model) model LM32_CPU_TYPE_SUFFIX -#define CPU_RESOLVING_TYPE TYPE_LM32_CPU - -#define cpu_list lm32_cpu_list -#define cpu_signal_handler cpu_lm32_signal_handler - -bool lm32_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr); - -typedef CPULM32State CPUArchState; -typedef LM32CPU ArchCPU; - -#include "exec/cpu-all.h" - -static inline void cpu_get_tb_cpu_state(CPULM32State *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) -{ - *pc = env->pc; - *cs_base = 0; - *flags = 0; -} - -#endif diff --git a/target/lm32/gdbstub.c b/target/lm32/gdbstub.c deleted file mode 100644 index 56f508a5b6..0000000000 --- a/target/lm32/gdbstub.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * LM32 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.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/>. - */ -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/gdbstub.h" -#include "hw/lm32/lm32_pic.h" - -int lm32_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - - if (n < 32) { - return gdb_get_reg32(mem_buf, env->regs[n]); - } else { - switch (n) { - case 32: - return gdb_get_reg32(mem_buf, env->pc); - /* FIXME: put in right exception ID */ - case 33: - return gdb_get_reg32(mem_buf, 0); - case 34: - return gdb_get_reg32(mem_buf, env->eba); - case 35: - return gdb_get_reg32(mem_buf, env->deba); - case 36: - return gdb_get_reg32(mem_buf, env->ie); - case 37: - return gdb_get_reg32(mem_buf, lm32_pic_get_im(env->pic_state)); - case 38: - return gdb_get_reg32(mem_buf, lm32_pic_get_ip(env->pic_state)); - } - } - return 0; -} - -int lm32_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPUClass *cc = CPU_GET_CLASS(cs); - CPULM32State *env = &cpu->env; - uint32_t tmp; - - if (n > cc->gdb_num_core_regs) { - return 0; - } - - tmp = ldl_p(mem_buf); - - if (n < 32) { - env->regs[n] = tmp; - } else { - switch (n) { - case 32: - env->pc = tmp; - break; - case 34: - env->eba = tmp; - break; - case 35: - env->deba = tmp; - break; - case 36: - env->ie = tmp; - break; - case 37: - lm32_pic_set_im(env->pic_state, tmp); - break; - case 38: - lm32_pic_set_ip(env->pic_state, tmp); - break; - } - } - return 4; -} diff --git a/target/lm32/helper.c b/target/lm32/helper.c deleted file mode 100644 index 01cc3c53a5..0000000000 --- a/target/lm32/helper.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * LatticeMico32 helper routines. - * - * Copyright (c) 2010-2014 Michael Walle <michael@walle.cc> - * - * 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/>. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/exec-all.h" -#include "qemu/host-utils.h" -#include "semihosting/semihost.h" -#include "exec/log.h" - -bool lm32_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - int prot; - - address &= TARGET_PAGE_MASK; - prot = PAGE_BITS; - if (env->flags & LM32_FLAG_IGNORE_MSB) { - tlb_set_page(cs, address, address & 0x7fffffff, prot, mmu_idx, - TARGET_PAGE_SIZE); - } else { - tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE); - } - return true; -} - -hwaddr lm32_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) -{ - LM32CPU *cpu = LM32_CPU(cs); - - addr &= TARGET_PAGE_MASK; - if (cpu->env.flags & LM32_FLAG_IGNORE_MSB) { - return addr & 0x7fffffff; - } else { - return addr; - } -} - -void lm32_breakpoint_insert(CPULM32State *env, int idx, target_ulong address) -{ - cpu_breakpoint_insert(env_cpu(env), address, BP_CPU, - &env->cpu_breakpoint[idx]); -} - -void lm32_breakpoint_remove(CPULM32State *env, int idx) -{ - if (!env->cpu_breakpoint[idx]) { - return; - } - - cpu_breakpoint_remove_by_ref(env_cpu(env), env->cpu_breakpoint[idx]); - env->cpu_breakpoint[idx] = NULL; -} - -void lm32_watchpoint_insert(CPULM32State *env, int idx, target_ulong address, - lm32_wp_t wp_type) -{ - int flags = 0; - - switch (wp_type) { - case LM32_WP_DISABLED: - /* nothing to do */ - break; - case LM32_WP_READ: - flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_READ; - break; - case LM32_WP_WRITE: - flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_WRITE; - break; - case LM32_WP_READ_WRITE: - flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_ACCESS; - break; - } - - if (flags != 0) { - cpu_watchpoint_insert(env_cpu(env), address, 1, flags, - &env->cpu_watchpoint[idx]); - } -} - -void lm32_watchpoint_remove(CPULM32State *env, int idx) -{ - if (!env->cpu_watchpoint[idx]) { - return; - } - - cpu_watchpoint_remove_by_ref(env_cpu(env), env->cpu_watchpoint[idx]); - env->cpu_watchpoint[idx] = NULL; -} - -static bool check_watchpoints(CPULM32State *env) -{ - LM32CPU *cpu = env_archcpu(env); - int i; - - for (i = 0; i < cpu->num_watchpoints; i++) { - if (env->cpu_watchpoint[i] && - env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) { - return true; - } - } - return false; -} - -void lm32_debug_excp_handler(CPUState *cs) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - CPUBreakpoint *bp; - - if (cs->watchpoint_hit) { - if (cs->watchpoint_hit->flags & BP_CPU) { - cs->watchpoint_hit = NULL; - if (check_watchpoints(env)) { - raise_exception(env, EXCP_WATCHPOINT); - } else { - cpu_loop_exit_noexc(cs); - } - } - } else { - QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { - if (bp->pc == env->pc) { - if (bp->flags & BP_CPU) { - raise_exception(env, EXCP_BREAKPOINT); - } - break; - } - } - } -} - -void lm32_cpu_do_interrupt(CPUState *cs) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - - qemu_log_mask(CPU_LOG_INT, - "exception at pc=%x type=%x\n", env->pc, cs->exception_index); - - switch (cs->exception_index) { - case EXCP_SYSTEMCALL: - if (unlikely(semihosting_enabled())) { - /* do_semicall() returns true if call was handled. Otherwise - * do the normal exception handling. */ - if (lm32_cpu_do_semihosting(cs)) { - env->pc += 4; - break; - } - } - /* fall through */ - case EXCP_INSN_BUS_ERROR: - case EXCP_DATA_BUS_ERROR: - case EXCP_DIVIDE_BY_ZERO: - case EXCP_IRQ: - /* non-debug exceptions */ - env->regs[R_EA] = env->pc; - env->ie |= (env->ie & IE_IE) ? IE_EIE : 0; - env->ie &= ~IE_IE; - if (env->dc & DC_RE) { - env->pc = env->deba + (cs->exception_index * 32); - } else { - env->pc = env->eba + (cs->exception_index * 32); - } - log_cpu_state_mask(CPU_LOG_INT, cs, 0); - break; - case EXCP_BREAKPOINT: - case EXCP_WATCHPOINT: - /* debug exceptions */ - env->regs[R_BA] = env->pc; - env->ie |= (env->ie & IE_IE) ? IE_BIE : 0; - env->ie &= ~IE_IE; - env->pc = env->deba + (cs->exception_index * 32); - log_cpu_state_mask(CPU_LOG_INT, cs, 0); - break; - default: - cpu_abort(cs, "unhandled exception type=%d\n", - cs->exception_index); - break; - } -} - -bool lm32_cpu_exec_interrupt(CPUState *cs, int interrupt_request) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - - if ((interrupt_request & CPU_INTERRUPT_HARD) && (env->ie & IE_IE)) { - cs->exception_index = EXCP_IRQ; - lm32_cpu_do_interrupt(cs); - return true; - } - return false; -} - -/* Some soc ignores the MSB on the address bus. Thus creating a shadow memory - * area. As a general rule, 0x00000000-0x7fffffff is cached, whereas - * 0x80000000-0xffffffff is not cached and used to access IO devices. */ -void cpu_lm32_set_phys_msb_ignore(CPULM32State *env, int value) -{ - if (value) { - env->flags |= LM32_FLAG_IGNORE_MSB; - } else { - env->flags &= ~LM32_FLAG_IGNORE_MSB; - } -} diff --git a/target/lm32/helper.h b/target/lm32/helper.h deleted file mode 100644 index 445578c439..0000000000 --- a/target/lm32/helper.h +++ /dev/null @@ -1,14 +0,0 @@ -DEF_HELPER_2(raise_exception, void, env, i32) -DEF_HELPER_1(hlt, void, env) -DEF_HELPER_3(wcsr_bp, void, env, i32, i32) -DEF_HELPER_3(wcsr_wp, void, env, i32, i32) -DEF_HELPER_2(wcsr_dc, void, env, i32) -DEF_HELPER_2(wcsr_im, void, env, i32) -DEF_HELPER_2(wcsr_ip, void, env, i32) -DEF_HELPER_2(wcsr_jtx, void, env, i32) -DEF_HELPER_2(wcsr_jrx, void, env, i32) -DEF_HELPER_1(rcsr_im, i32, env) -DEF_HELPER_1(rcsr_ip, i32, env) -DEF_HELPER_1(rcsr_jtx, i32, env) -DEF_HELPER_1(rcsr_jrx, i32, env) -DEF_HELPER_1(ill, void, env) diff --git a/target/lm32/lm32-semi.c b/target/lm32/lm32-semi.c deleted file mode 100644 index 661a770249..0000000000 --- a/target/lm32/lm32-semi.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Lattice Mico32 semihosting syscall interface - * - * Copyright (c) 2014 Michael Walle <michael@walle.cc> - * - * Based on target/m68k/m68k-semi.c, which is - * Copyright (c) 2005-2007 CodeSourcery. - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" -#include "exec/softmmu-semi.h" - -enum { - TARGET_SYS_exit = 1, - TARGET_SYS_open = 2, - TARGET_SYS_close = 3, - TARGET_SYS_read = 4, - TARGET_SYS_write = 5, - TARGET_SYS_lseek = 6, - TARGET_SYS_fstat = 10, - TARGET_SYS_stat = 15, -}; - -enum { - NEWLIB_O_RDONLY = 0x0, - NEWLIB_O_WRONLY = 0x1, - NEWLIB_O_RDWR = 0x2, - NEWLIB_O_APPEND = 0x8, - NEWLIB_O_CREAT = 0x200, - NEWLIB_O_TRUNC = 0x400, - NEWLIB_O_EXCL = 0x800, -}; - -static int translate_openflags(int flags) -{ - int hf; - - if (flags & NEWLIB_O_WRONLY) { - hf = O_WRONLY; - } else if (flags & NEWLIB_O_RDWR) { - hf = O_RDWR; - } else { - hf = O_RDONLY; - } - - if (flags & NEWLIB_O_APPEND) { - hf |= O_APPEND; - } - - if (flags & NEWLIB_O_CREAT) { - hf |= O_CREAT; - } - - if (flags & NEWLIB_O_TRUNC) { - hf |= O_TRUNC; - } - - if (flags & NEWLIB_O_EXCL) { - hf |= O_EXCL; - } - - return hf; -} - -struct newlib_stat { - int16_t newlib_st_dev; /* device */ - uint16_t newlib_st_ino; /* inode */ - uint16_t newlib_st_mode; /* protection */ - uint16_t newlib_st_nlink; /* number of hard links */ - uint16_t newlib_st_uid; /* user ID of owner */ - uint16_t newlib_st_gid; /* group ID of owner */ - int16_t newlib_st_rdev; /* device type (if inode device) */ - int32_t newlib_st_size; /* total size, in bytes */ - int32_t newlib_st_atime; /* time of last access */ - uint32_t newlib_st_spare1; - int32_t newlib_st_mtime; /* time of last modification */ - uint32_t newlib_st_spare2; - int32_t newlib_st_ctime; /* time of last change */ - uint32_t newlib_st_spare3; -} QEMU_PACKED; - -static int translate_stat(CPULM32State *env, target_ulong addr, - struct stat *s) -{ - struct newlib_stat *p; - - p = lock_user(VERIFY_WRITE, addr, sizeof(struct newlib_stat), 0); - if (!p) { - return 0; - } - p->newlib_st_dev = cpu_to_be16(s->st_dev); - p->newlib_st_ino = cpu_to_be16(s->st_ino); - p->newlib_st_mode = cpu_to_be16(s->st_mode); - p->newlib_st_nlink = cpu_to_be16(s->st_nlink); - p->newlib_st_uid = cpu_to_be16(s->st_uid); - p->newlib_st_gid = cpu_to_be16(s->st_gid); - p->newlib_st_rdev = cpu_to_be16(s->st_rdev); - p->newlib_st_size = cpu_to_be32(s->st_size); - p->newlib_st_atime = cpu_to_be32(s->st_atime); - p->newlib_st_mtime = cpu_to_be32(s->st_mtime); - p->newlib_st_ctime = cpu_to_be32(s->st_ctime); - unlock_user(p, addr, sizeof(struct newlib_stat)); - - return 1; -} - -bool lm32_cpu_do_semihosting(CPUState *cs) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - - int ret = -1; - target_ulong nr, arg0, arg1, arg2; - void *p; - struct stat s; - - nr = env->regs[R_R8]; - arg0 = env->regs[R_R1]; - arg1 = env->regs[R_R2]; - arg2 = env->regs[R_R3]; - - switch (nr) { - case TARGET_SYS_exit: - /* void _exit(int rc) */ - exit(arg0); - - case TARGET_SYS_open: - /* int open(const char *pathname, int flags) */ - p = lock_user_string(arg0); - if (!p) { - ret = -1; - } else { - ret = open(p, translate_openflags(arg2)); - unlock_user(p, arg0, 0); - } - break; - - case TARGET_SYS_read: - /* ssize_t read(int fd, const void *buf, size_t count) */ - p = lock_user(VERIFY_WRITE, arg1, arg2, 0); - if (!p) { - ret = -1; - } else { - ret = read(arg0, p, arg2); - unlock_user(p, arg1, arg2); - } - break; - - case TARGET_SYS_write: - /* ssize_t write(int fd, const void *buf, size_t count) */ - p = lock_user(VERIFY_READ, arg1, arg2, 1); - if (!p) { - ret = -1; - } else { - ret = write(arg0, p, arg2); - unlock_user(p, arg1, 0); - } - break; - - case TARGET_SYS_close: - /* int close(int fd) */ - /* don't close stdin/stdout/stderr */ - if (arg0 > 2) { - ret = close(arg0); - } else { - ret = 0; - } - break; - - case TARGET_SYS_lseek: - /* off_t lseek(int fd, off_t offset, int whence */ - ret = lseek(arg0, arg1, arg2); - break; - - case TARGET_SYS_stat: - /* int stat(const char *path, struct stat *buf) */ - p = lock_user_string(arg0); - if (!p) { - ret = -1; - } else { - ret = stat(p, &s); - unlock_user(p, arg0, 0); - if (translate_stat(env, arg1, &s) == 0) { - ret = -1; - } - } - break; - - case TARGET_SYS_fstat: - /* int stat(int fd, struct stat *buf) */ - ret = fstat(arg0, &s); - if (ret == 0) { - if (translate_stat(env, arg1, &s) == 0) { - ret = -1; - } - } - break; - - default: - /* unhandled */ - return false; - } - - env->regs[R_R1] = ret; - return true; -} diff --git a/target/lm32/machine.c b/target/lm32/machine.c deleted file mode 100644 index 365eaa2e47..0000000000 --- a/target/lm32/machine.c +++ /dev/null @@ -1,33 +0,0 @@ -#include "qemu/osdep.h" -#include "cpu.h" -#include "migration/cpu.h" - -static const VMStateDescription vmstate_env = { - .name = "env", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, CPULM32State, 32), - VMSTATE_UINT32(pc, CPULM32State), - VMSTATE_UINT32(ie, CPULM32State), - VMSTATE_UINT32(icc, CPULM32State), - VMSTATE_UINT32(dcc, CPULM32State), - VMSTATE_UINT32(cc, CPULM32State), - VMSTATE_UINT32(eba, CPULM32State), - VMSTATE_UINT32(dc, CPULM32State), - VMSTATE_UINT32(deba, CPULM32State), - VMSTATE_UINT32_ARRAY(bp, CPULM32State, 4), - VMSTATE_UINT32_ARRAY(wp, CPULM32State, 4), - VMSTATE_END_OF_LIST() - } -}; - -const VMStateDescription vmstate_lm32_cpu = { - .name = "cpu", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(env, LM32CPU, 1, vmstate_env, CPULM32State), - VMSTATE_END_OF_LIST() - } -}; diff --git a/target/lm32/meson.build b/target/lm32/meson.build deleted file mode 100644 index ef0eef07f1..0000000000 --- a/target/lm32/meson.build +++ /dev/null @@ -1,15 +0,0 @@ -lm32_ss = ss.source_set() -lm32_ss.add(files( - 'cpu.c', - 'gdbstub.c', - 'helper.c', - 'lm32-semi.c', - 'op_helper.c', - 'translate.c', -)) - -lm32_softmmu_ss = ss.source_set() -lm32_softmmu_ss.add(files('machine.c')) - -target_arch += {'lm32': lm32_ss} -target_softmmu_arch += {'lm32': lm32_softmmu_ss} diff --git a/target/lm32/op_helper.c b/target/lm32/op_helper.c deleted file mode 100644 index e39fcd5647..0000000000 --- a/target/lm32/op_helper.c +++ /dev/null @@ -1,148 +0,0 @@ -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" -#include "qemu/host-utils.h" -#include "qemu/main-loop.h" -#include "sysemu/runstate.h" - -#include "hw/lm32/lm32_pic.h" -#include "hw/char/lm32_juart.h" - -#include "exec/exec-all.h" -#include "exec/cpu_ldst.h" - -#ifndef CONFIG_USER_ONLY -#endif - -#if !defined(CONFIG_USER_ONLY) -void raise_exception(CPULM32State *env, int index) -{ - CPUState *cs = env_cpu(env); - - cs->exception_index = index; - cpu_loop_exit(cs); -} - -void HELPER(raise_exception)(CPULM32State *env, uint32_t index) -{ - raise_exception(env, index); -} - -void HELPER(hlt)(CPULM32State *env) -{ - CPUState *cs = env_cpu(env); - - cs->halted = 1; - cs->exception_index = EXCP_HLT; - cpu_loop_exit(cs); -} - -void HELPER(ill)(CPULM32State *env) -{ -#ifndef CONFIG_USER_ONLY - CPUState *cs = env_cpu(env); - fprintf(stderr, "VM paused due to illegal instruction. " - "Connect a debugger or switch to the monitor console " - "to find out more.\n"); - vm_stop(RUN_STATE_PAUSED); - cs->halted = 1; - raise_exception(env, EXCP_HALTED); -#endif -} - -void HELPER(wcsr_bp)(CPULM32State *env, uint32_t bp, uint32_t idx) -{ - uint32_t addr = bp & ~1; - - assert(idx < 4); - - env->bp[idx] = bp; - lm32_breakpoint_remove(env, idx); - if (bp & 1) { - lm32_breakpoint_insert(env, idx, addr); - } -} - -void HELPER(wcsr_wp)(CPULM32State *env, uint32_t wp, uint32_t idx) -{ - lm32_wp_t wp_type; - - assert(idx < 4); - - env->wp[idx] = wp; - - wp_type = lm32_wp_type(env->dc, idx); - lm32_watchpoint_remove(env, idx); - if (wp_type != LM32_WP_DISABLED) { - lm32_watchpoint_insert(env, idx, wp, wp_type); - } -} - -void HELPER(wcsr_dc)(CPULM32State *env, uint32_t dc) -{ - uint32_t old_dc; - int i; - lm32_wp_t old_type; - lm32_wp_t new_type; - - old_dc = env->dc; - env->dc = dc; - - for (i = 0; i < 4; i++) { - old_type = lm32_wp_type(old_dc, i); - new_type = lm32_wp_type(dc, i); - - if (old_type != new_type) { - lm32_watchpoint_remove(env, i); - if (new_type != LM32_WP_DISABLED) { - lm32_watchpoint_insert(env, i, env->wp[i], new_type); - } - } - } -} - -void HELPER(wcsr_im)(CPULM32State *env, uint32_t im) -{ - qemu_mutex_lock_iothread(); - lm32_pic_set_im(env->pic_state, im); - qemu_mutex_unlock_iothread(); -} - -void HELPER(wcsr_ip)(CPULM32State *env, uint32_t im) -{ - qemu_mutex_lock_iothread(); - lm32_pic_set_ip(env->pic_state, im); - qemu_mutex_unlock_iothread(); -} - -void HELPER(wcsr_jtx)(CPULM32State *env, uint32_t jtx) -{ - lm32_juart_set_jtx(env->juart_state, jtx); -} - -void HELPER(wcsr_jrx)(CPULM32State *env, uint32_t jrx) -{ - lm32_juart_set_jrx(env->juart_state, jrx); -} - -uint32_t HELPER(rcsr_im)(CPULM32State *env) -{ - return lm32_pic_get_im(env->pic_state); -} - -uint32_t HELPER(rcsr_ip)(CPULM32State *env) -{ - return lm32_pic_get_ip(env->pic_state); -} - -uint32_t HELPER(rcsr_jtx)(CPULM32State *env) -{ - return lm32_juart_get_jtx(env->juart_state); -} - -uint32_t HELPER(rcsr_jrx)(CPULM32State *env) -{ - return lm32_juart_get_jrx(env->juart_state); -} -#endif - diff --git a/target/lm32/translate.c b/target/lm32/translate.c deleted file mode 100644 index 20c70d03f1..0000000000 --- a/target/lm32/translate.c +++ /dev/null @@ -1,1237 +0,0 @@ -/* - * LatticeMico32 main translation routines. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * 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/>. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "disas/disas.h" -#include "exec/helper-proto.h" -#include "exec/exec-all.h" -#include "exec/translator.h" -#include "tcg/tcg-op.h" -#include "qemu/qemu-print.h" - -#include "exec/cpu_ldst.h" -#include "hw/lm32/lm32_pic.h" - -#include "exec/helper-gen.h" - -#include "trace-tcg.h" -#include "exec/log.h" - - -#define DISAS_LM32 0 - -#define LOG_DIS(...) \ - do { \ - if (DISAS_LM32) { \ - qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__); \ - } \ - } while (0) - -#define EXTRACT_FIELD(src, start, end) \ - (((src) >> start) & ((1 << (end - start + 1)) - 1)) - -#define MEM_INDEX 0 - -/* is_jmp field values */ -#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ -#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ -#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */ - -static TCGv cpu_R[32]; -static TCGv cpu_pc; -static TCGv cpu_ie; -static TCGv cpu_icc; -static TCGv cpu_dcc; -static TCGv cpu_cc; -static TCGv cpu_cfg; -static TCGv cpu_eba; -static TCGv cpu_dc; -static TCGv cpu_deba; -static TCGv cpu_bp[4]; -static TCGv cpu_wp[4]; - -#include "exec/gen-icount.h" - -enum { - OP_FMT_RI, - OP_FMT_RR, - OP_FMT_CR, - OP_FMT_I -}; - -/* This is the state at translation time. */ -typedef struct DisasContext { - target_ulong pc; - - /* Decoder. */ - int format; - uint32_t ir; - uint8_t opcode; - uint8_t r0, r1, r2, csr; - uint16_t imm5; - uint16_t imm16; - uint32_t imm26; - - unsigned int delayed_branch; - unsigned int tb_flags, synced_flags; /* tb dependent flags. */ - int is_jmp; - - TranslationBlock *tb; - int singlestep_enabled; - - uint32_t features; - uint8_t num_breakpoints; - uint8_t num_watchpoints; -} DisasContext; - -static const char *regnames[] = { - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26/gp", "r27/fp", "r28/sp", "r29/ra", - "r30/ea", "r31/ba", "bp0", "bp1", "bp2", "bp3", "wp0", - "wp1", "wp2", "wp3" -}; - -static inline int zero_extend(unsigned int val, int width) -{ - return val & ((1 << width) - 1); -} - -static inline int sign_extend(unsigned int val, int width) -{ - int sval; - - /* LSL. */ - val <<= 32 - width; - sval = val; - /* ASR. */ - sval >>= 32 - width; - - return sval; -} - -static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index) -{ - TCGv_i32 tmp = tcg_const_i32(index); - - gen_helper_raise_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); -} - -static inline void t_gen_illegal_insn(DisasContext *dc) -{ - tcg_gen_movi_tl(cpu_pc, dc->pc); - gen_helper_ill(cpu_env); -} - -static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) -{ - if (unlikely(dc->singlestep_enabled)) { - return false; - } - -#ifndef CONFIG_USER_ONLY - return (dc->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); -#else - return true; -#endif -} - -static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) -{ - if (use_goto_tb(dc, dest)) { - tcg_gen_goto_tb(n); - tcg_gen_movi_tl(cpu_pc, dest); - tcg_gen_exit_tb(dc->tb, n); - } else { - tcg_gen_movi_tl(cpu_pc, dest); - if (dc->singlestep_enabled) { - t_gen_raise_exception(dc, EXCP_DEBUG); - } - tcg_gen_exit_tb(NULL, 0); - } -} - -static void dec_add(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - if (dc->r0 == R_R0) { - if (dc->r1 == R_R0 && dc->imm16 == 0) { - LOG_DIS("nop\n"); - } else { - LOG_DIS("mvi r%d, %d\n", dc->r1, sign_extend(dc->imm16, 16)); - } - } else { - LOG_DIS("addi r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16)); - } - } else { - LOG_DIS("add r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - if (dc->format == OP_FMT_RI) { - tcg_gen_addi_tl(cpu_R[dc->r1], cpu_R[dc->r0], - sign_extend(dc->imm16, 16)); - } else { - tcg_gen_add_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } -} - -static void dec_and(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("andi r%d, r%d, %d\n", dc->r1, dc->r0, - zero_extend(dc->imm16, 16)); - } else { - LOG_DIS("and r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - if (dc->format == OP_FMT_RI) { - tcg_gen_andi_tl(cpu_R[dc->r1], cpu_R[dc->r0], - zero_extend(dc->imm16, 16)); - } else { - if (dc->r0 == 0 && dc->r1 == 0 && dc->r2 == 0) { - tcg_gen_movi_tl(cpu_pc, dc->pc + 4); - gen_helper_hlt(cpu_env); - } else { - tcg_gen_and_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } - } -} - -static void dec_andhi(DisasContext *dc) -{ - LOG_DIS("andhi r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm16); - - tcg_gen_andi_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16)); -} - -static void dec_b(DisasContext *dc) -{ - if (dc->r0 == R_RA) { - LOG_DIS("ret\n"); - } else if (dc->r0 == R_EA) { - LOG_DIS("eret\n"); - } else if (dc->r0 == R_BA) { - LOG_DIS("bret\n"); - } else { - LOG_DIS("b r%d\n", dc->r0); - } - - /* restore IE.IE in case of an eret */ - if (dc->r0 == R_EA) { - TCGv t0 = tcg_temp_new(); - TCGLabel *l1 = gen_new_label(); - tcg_gen_andi_tl(t0, cpu_ie, IE_EIE); - tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_IE); - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_EIE, l1); - tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE); - gen_set_label(l1); - tcg_temp_free(t0); - } else if (dc->r0 == R_BA) { - TCGv t0 = tcg_temp_new(); - TCGLabel *l1 = gen_new_label(); - tcg_gen_andi_tl(t0, cpu_ie, IE_BIE); - tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_IE); - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_BIE, l1); - tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE); - gen_set_label(l1); - tcg_temp_free(t0); - } - tcg_gen_mov_tl(cpu_pc, cpu_R[dc->r0]); - - dc->is_jmp = DISAS_JUMP; -} - -static void dec_bi(DisasContext *dc) -{ - LOG_DIS("bi %d\n", sign_extend(dc->imm26 << 2, 26)); - - gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26))); - - dc->is_jmp = DISAS_TB_JUMP; -} - -static inline void gen_cond_branch(DisasContext *dc, int cond) -{ - TCGLabel *l1 = gen_new_label(); - tcg_gen_brcond_tl(cond, cpu_R[dc->r0], cpu_R[dc->r1], l1); - gen_goto_tb(dc, 0, dc->pc + 4); - gen_set_label(l1); - gen_goto_tb(dc, 1, dc->pc + (sign_extend(dc->imm16 << 2, 16))); - dc->is_jmp = DISAS_TB_JUMP; -} - -static void dec_be(DisasContext *dc) -{ - LOG_DIS("be r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16) * 4); - - gen_cond_branch(dc, TCG_COND_EQ); -} - -static void dec_bg(DisasContext *dc) -{ - LOG_DIS("bg r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16 * 4)); - - gen_cond_branch(dc, TCG_COND_GT); -} - -static void dec_bge(DisasContext *dc) -{ - LOG_DIS("bge r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16) * 4); - - gen_cond_branch(dc, TCG_COND_GE); -} - -static void dec_bgeu(DisasContext *dc) -{ - LOG_DIS("bgeu r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16) * 4); - - gen_cond_branch(dc, TCG_COND_GEU); -} - -static void dec_bgu(DisasContext *dc) -{ - LOG_DIS("bgu r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16) * 4); - - gen_cond_branch(dc, TCG_COND_GTU); -} - -static void dec_bne(DisasContext *dc) -{ - LOG_DIS("bne r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16) * 4); - - gen_cond_branch(dc, TCG_COND_NE); -} - -static void dec_call(DisasContext *dc) -{ - LOG_DIS("call r%d\n", dc->r0); - - tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4); - tcg_gen_mov_tl(cpu_pc, cpu_R[dc->r0]); - - dc->is_jmp = DISAS_JUMP; -} - -static void dec_calli(DisasContext *dc) -{ - LOG_DIS("calli %d\n", sign_extend(dc->imm26, 26) * 4); - - tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4); - gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26))); - - dc->is_jmp = DISAS_TB_JUMP; -} - -static inline void gen_compare(DisasContext *dc, int cond) -{ - int i; - - if (dc->format == OP_FMT_RI) { - switch (cond) { - case TCG_COND_GEU: - case TCG_COND_GTU: - i = zero_extend(dc->imm16, 16); - break; - default: - i = sign_extend(dc->imm16, 16); - break; - } - - tcg_gen_setcondi_tl(cond, cpu_R[dc->r1], cpu_R[dc->r0], i); - } else { - tcg_gen_setcond_tl(cond, cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } -} - -static void dec_cmpe(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("cmpei r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16)); - } else { - LOG_DIS("cmpe r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - gen_compare(dc, TCG_COND_EQ); -} - -static void dec_cmpg(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("cmpgi r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16)); - } else { - LOG_DIS("cmpg r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - gen_compare(dc, TCG_COND_GT); -} - -static void dec_cmpge(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("cmpgei r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16)); - } else { - LOG_DIS("cmpge r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - gen_compare(dc, TCG_COND_GE); -} - -static void dec_cmpgeu(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("cmpgeui r%d, r%d, %d\n", dc->r1, dc->r0, - zero_extend(dc->imm16, 16)); - } else { - LOG_DIS("cmpgeu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - gen_compare(dc, TCG_COND_GEU); -} - -static void dec_cmpgu(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("cmpgui r%d, r%d, %d\n", dc->r1, dc->r0, - zero_extend(dc->imm16, 16)); - } else { - LOG_DIS("cmpgu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - gen_compare(dc, TCG_COND_GTU); -} - -static void dec_cmpne(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("cmpnei r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16)); - } else { - LOG_DIS("cmpne r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - gen_compare(dc, TCG_COND_NE); -} - -static void dec_divu(DisasContext *dc) -{ - TCGLabel *l1; - - LOG_DIS("divu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - - if (!(dc->features & LM32_FEATURE_DIVIDE)) { - qemu_log_mask(LOG_GUEST_ERROR, "hardware divider is not available\n"); - t_gen_illegal_insn(dc); - return; - } - - l1 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[dc->r1], 0, l1); - tcg_gen_movi_tl(cpu_pc, dc->pc); - t_gen_raise_exception(dc, EXCP_DIVIDE_BY_ZERO); - gen_set_label(l1); - tcg_gen_divu_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); -} - -static void dec_lb(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("lb r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_ld8s(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_lbu(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("lbu r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_ld8u(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_lh(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("lh r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_ld16s(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_lhu(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("lhu r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_ld16u(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_lw(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("lw r%d, (r%d+%d)\n", dc->r1, dc->r0, sign_extend(dc->imm16, 16)); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_ld32s(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_modu(DisasContext *dc) -{ - TCGLabel *l1; - - LOG_DIS("modu r%d, r%d, %d\n", dc->r2, dc->r0, dc->r1); - - if (!(dc->features & LM32_FEATURE_DIVIDE)) { - qemu_log_mask(LOG_GUEST_ERROR, "hardware divider is not available\n"); - t_gen_illegal_insn(dc); - return; - } - - l1 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[dc->r1], 0, l1); - tcg_gen_movi_tl(cpu_pc, dc->pc); - t_gen_raise_exception(dc, EXCP_DIVIDE_BY_ZERO); - gen_set_label(l1); - tcg_gen_remu_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); -} - -static void dec_mul(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("muli r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16)); - } else { - LOG_DIS("mul r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - if (!(dc->features & LM32_FEATURE_MULTIPLY)) { - qemu_log_mask(LOG_GUEST_ERROR, - "hardware multiplier is not available\n"); - t_gen_illegal_insn(dc); - return; - } - - if (dc->format == OP_FMT_RI) { - tcg_gen_muli_tl(cpu_R[dc->r1], cpu_R[dc->r0], - sign_extend(dc->imm16, 16)); - } else { - tcg_gen_mul_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } -} - -static void dec_nor(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("nori r%d, r%d, %d\n", dc->r1, dc->r0, - zero_extend(dc->imm16, 16)); - } else { - LOG_DIS("nor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - if (dc->format == OP_FMT_RI) { - TCGv t0 = tcg_temp_new(); - tcg_gen_movi_tl(t0, zero_extend(dc->imm16, 16)); - tcg_gen_nor_tl(cpu_R[dc->r1], cpu_R[dc->r0], t0); - tcg_temp_free(t0); - } else { - tcg_gen_nor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } -} - -static void dec_or(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("ori r%d, r%d, %d\n", dc->r1, dc->r0, - zero_extend(dc->imm16, 16)); - } else { - if (dc->r1 == R_R0) { - LOG_DIS("mv r%d, r%d\n", dc->r2, dc->r0); - } else { - LOG_DIS("or r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - } - - if (dc->format == OP_FMT_RI) { - tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0], - zero_extend(dc->imm16, 16)); - } else { - tcg_gen_or_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } -} - -static void dec_orhi(DisasContext *dc) -{ - if (dc->r0 == R_R0) { - LOG_DIS("mvhi r%d, %d\n", dc->r1, dc->imm16); - } else { - LOG_DIS("orhi r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm16); - } - - tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16)); -} - -static void dec_scall(DisasContext *dc) -{ - switch (dc->imm5) { - case 2: - LOG_DIS("break\n"); - tcg_gen_movi_tl(cpu_pc, dc->pc); - t_gen_raise_exception(dc, EXCP_BREAKPOINT); - break; - case 7: - LOG_DIS("scall\n"); - tcg_gen_movi_tl(cpu_pc, dc->pc); - t_gen_raise_exception(dc, EXCP_SYSTEMCALL); - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, "invalid opcode @0x%x", dc->pc); - t_gen_illegal_insn(dc); - break; - } -} - -static void dec_rcsr(DisasContext *dc) -{ - LOG_DIS("rcsr r%d, %d\n", dc->r2, dc->csr); - - switch (dc->csr) { - case CSR_IE: - tcg_gen_mov_tl(cpu_R[dc->r2], cpu_ie); - break; - case CSR_IM: - gen_helper_rcsr_im(cpu_R[dc->r2], cpu_env); - break; - case CSR_IP: - gen_helper_rcsr_ip(cpu_R[dc->r2], cpu_env); - break; - case CSR_CC: - tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cc); - break; - case CSR_CFG: - tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cfg); - break; - case CSR_EBA: - tcg_gen_mov_tl(cpu_R[dc->r2], cpu_eba); - break; - case CSR_DC: - tcg_gen_mov_tl(cpu_R[dc->r2], cpu_dc); - break; - case CSR_DEBA: - tcg_gen_mov_tl(cpu_R[dc->r2], cpu_deba); - break; - case CSR_JTX: - gen_helper_rcsr_jtx(cpu_R[dc->r2], cpu_env); - break; - case CSR_JRX: - gen_helper_rcsr_jrx(cpu_R[dc->r2], cpu_env); - break; - case CSR_ICC: - case CSR_DCC: - case CSR_BP0: - case CSR_BP1: - case CSR_BP2: - case CSR_BP3: - case CSR_WP0: - case CSR_WP1: - case CSR_WP2: - case CSR_WP3: - qemu_log_mask(LOG_GUEST_ERROR, "invalid read access csr=%x\n", dc->csr); - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, "read_csr: unknown csr=%x\n", dc->csr); - break; - } -} - -static void dec_sb(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("sb (r%d+%d), r%d\n", dc->r0, dc->imm16, dc->r1); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_st8(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_sextb(DisasContext *dc) -{ - LOG_DIS("sextb r%d, r%d\n", dc->r2, dc->r0); - - if (!(dc->features & LM32_FEATURE_SIGN_EXTEND)) { - qemu_log_mask(LOG_GUEST_ERROR, - "hardware sign extender is not available\n"); - t_gen_illegal_insn(dc); - return; - } - - tcg_gen_ext8s_tl(cpu_R[dc->r2], cpu_R[dc->r0]); -} - -static void dec_sexth(DisasContext *dc) -{ - LOG_DIS("sexth r%d, r%d\n", dc->r2, dc->r0); - - if (!(dc->features & LM32_FEATURE_SIGN_EXTEND)) { - qemu_log_mask(LOG_GUEST_ERROR, - "hardware sign extender is not available\n"); - t_gen_illegal_insn(dc); - return; - } - - tcg_gen_ext16s_tl(cpu_R[dc->r2], cpu_R[dc->r0]); -} - -static void dec_sh(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("sh (r%d+%d), r%d\n", dc->r0, dc->imm16, dc->r1); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_st16(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_sl(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("sli r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5); - } else { - LOG_DIS("sl r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - if (!(dc->features & LM32_FEATURE_SHIFT)) { - qemu_log_mask(LOG_GUEST_ERROR, "hardware shifter is not available\n"); - t_gen_illegal_insn(dc); - return; - } - - if (dc->format == OP_FMT_RI) { - tcg_gen_shli_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5); - } else { - TCGv t0 = tcg_temp_new(); - tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f); - tcg_gen_shl_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0); - tcg_temp_free(t0); - } -} - -static void dec_sr(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("sri r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5); - } else { - LOG_DIS("sr r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - /* The real CPU (w/o hardware shifter) only supports right shift by exactly - * one bit */ - if (dc->format == OP_FMT_RI) { - if (!(dc->features & LM32_FEATURE_SHIFT) && (dc->imm5 != 1)) { - qemu_log_mask(LOG_GUEST_ERROR, - "hardware shifter is not available\n"); - t_gen_illegal_insn(dc); - return; - } - tcg_gen_sari_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5); - } else { - TCGLabel *l1 = gen_new_label(); - TCGLabel *l2 = gen_new_label(); - TCGv t0 = tcg_temp_local_new(); - tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f); - - if (!(dc->features & LM32_FEATURE_SHIFT)) { - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 1, l1); - t_gen_illegal_insn(dc); - tcg_gen_br(l2); - } - - gen_set_label(l1); - tcg_gen_sar_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0); - gen_set_label(l2); - - tcg_temp_free(t0); - } -} - -static void dec_sru(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("srui r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5); - } else { - LOG_DIS("sru r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - if (dc->format == OP_FMT_RI) { - if (!(dc->features & LM32_FEATURE_SHIFT) && (dc->imm5 != 1)) { - qemu_log_mask(LOG_GUEST_ERROR, - "hardware shifter is not available\n"); - t_gen_illegal_insn(dc); - return; - } - tcg_gen_shri_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5); - } else { - TCGLabel *l1 = gen_new_label(); - TCGLabel *l2 = gen_new_label(); - TCGv t0 = tcg_temp_local_new(); - tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f); - - if (!(dc->features & LM32_FEATURE_SHIFT)) { - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 1, l1); - t_gen_illegal_insn(dc); - tcg_gen_br(l2); - } - - gen_set_label(l1); - tcg_gen_shr_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0); - gen_set_label(l2); - - tcg_temp_free(t0); - } -} - -static void dec_sub(DisasContext *dc) -{ - LOG_DIS("sub r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - - tcg_gen_sub_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); -} - -static void dec_sw(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("sw (r%d+%d), r%d\n", dc->r0, sign_extend(dc->imm16, 16), dc->r1); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_st32(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_user(DisasContext *dc) -{ - LOG_DIS("user"); - - qemu_log_mask(LOG_GUEST_ERROR, "user instruction undefined\n"); - t_gen_illegal_insn(dc); -} - -static void dec_wcsr(DisasContext *dc) -{ - int no; - - LOG_DIS("wcsr %d, r%d\n", dc->csr, dc->r1); - - switch (dc->csr) { - case CSR_IE: - tcg_gen_mov_tl(cpu_ie, cpu_R[dc->r1]); - tcg_gen_movi_tl(cpu_pc, dc->pc + 4); - dc->is_jmp = DISAS_UPDATE; - break; - case CSR_IM: - /* mark as an io operation because it could cause an interrupt */ - if (tb_cflags(dc->tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_wcsr_im(cpu_env, cpu_R[dc->r1]); - tcg_gen_movi_tl(cpu_pc, dc->pc + 4); - dc->is_jmp = DISAS_UPDATE; - break; - case CSR_IP: - /* mark as an io operation because it could cause an interrupt */ - if (tb_cflags(dc->tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_wcsr_ip(cpu_env, cpu_R[dc->r1]); - tcg_gen_movi_tl(cpu_pc, dc->pc + 4); - dc->is_jmp = DISAS_UPDATE; - break; - case CSR_ICC: - /* TODO */ - break; - case CSR_DCC: - /* TODO */ - break; - case CSR_EBA: - tcg_gen_mov_tl(cpu_eba, cpu_R[dc->r1]); - break; - case CSR_DEBA: - tcg_gen_mov_tl(cpu_deba, cpu_R[dc->r1]); - break; - case CSR_JTX: - gen_helper_wcsr_jtx(cpu_env, cpu_R[dc->r1]); - break; - case CSR_JRX: - gen_helper_wcsr_jrx(cpu_env, cpu_R[dc->r1]); - break; - case CSR_DC: - gen_helper_wcsr_dc(cpu_env, cpu_R[dc->r1]); - break; - case CSR_BP0: - case CSR_BP1: - case CSR_BP2: - case CSR_BP3: - no = dc->csr - CSR_BP0; - if (dc->num_breakpoints <= no) { - qemu_log_mask(LOG_GUEST_ERROR, - "breakpoint #%i is not available\n", no); - t_gen_illegal_insn(dc); - break; - } - gen_helper_wcsr_bp(cpu_env, cpu_R[dc->r1], tcg_const_i32(no)); - break; - case CSR_WP0: - case CSR_WP1: - case CSR_WP2: - case CSR_WP3: - no = dc->csr - CSR_WP0; - if (dc->num_watchpoints <= no) { - qemu_log_mask(LOG_GUEST_ERROR, - "watchpoint #%i is not available\n", no); - t_gen_illegal_insn(dc); - break; - } - gen_helper_wcsr_wp(cpu_env, cpu_R[dc->r1], tcg_const_i32(no)); - break; - case CSR_CC: - case CSR_CFG: - qemu_log_mask(LOG_GUEST_ERROR, "invalid write access csr=%x\n", - dc->csr); - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, "write_csr: unknown csr=%x\n", - dc->csr); - break; - } -} - -static void dec_xnor(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("xnori r%d, r%d, %d\n", dc->r1, dc->r0, - zero_extend(dc->imm16, 16)); - } else { - if (dc->r1 == R_R0) { - LOG_DIS("not r%d, r%d\n", dc->r2, dc->r0); - } else { - LOG_DIS("xnor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - } - - if (dc->format == OP_FMT_RI) { - tcg_gen_xori_tl(cpu_R[dc->r1], cpu_R[dc->r0], - zero_extend(dc->imm16, 16)); - tcg_gen_not_tl(cpu_R[dc->r1], cpu_R[dc->r1]); - } else { - tcg_gen_eqv_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } -} - -static void dec_xor(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("xori r%d, r%d, %d\n", dc->r1, dc->r0, - zero_extend(dc->imm16, 16)); - } else { - LOG_DIS("xor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - if (dc->format == OP_FMT_RI) { - tcg_gen_xori_tl(cpu_R[dc->r1], cpu_R[dc->r0], - zero_extend(dc->imm16, 16)); - } else { - tcg_gen_xor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } -} - -static void dec_ill(DisasContext *dc) -{ - qemu_log_mask(LOG_GUEST_ERROR, "invalid opcode 0x%02x\n", dc->opcode); - t_gen_illegal_insn(dc); -} - -typedef void (*DecoderInfo)(DisasContext *dc); -static const DecoderInfo decinfo[] = { - dec_sru, dec_nor, dec_mul, dec_sh, dec_lb, dec_sr, dec_xor, dec_lh, - dec_and, dec_xnor, dec_lw, dec_lhu, dec_sb, dec_add, dec_or, dec_sl, - dec_lbu, dec_be, dec_bg, dec_bge, dec_bgeu, dec_bgu, dec_sw, dec_bne, - dec_andhi, dec_cmpe, dec_cmpg, dec_cmpge, dec_cmpgeu, dec_cmpgu, dec_orhi, - dec_cmpne, - dec_sru, dec_nor, dec_mul, dec_divu, dec_rcsr, dec_sr, dec_xor, dec_ill, - dec_and, dec_xnor, dec_ill, dec_scall, dec_sextb, dec_add, dec_or, dec_sl, - dec_b, dec_modu, dec_sub, dec_user, dec_wcsr, dec_ill, dec_call, dec_sexth, - dec_bi, dec_cmpe, dec_cmpg, dec_cmpge, dec_cmpgeu, dec_cmpgu, dec_calli, - dec_cmpne -}; - -static inline void decode(DisasContext *dc, uint32_t ir) -{ - dc->ir = ir; - LOG_DIS("%8.8x\t", dc->ir); - - dc->opcode = EXTRACT_FIELD(ir, 26, 31); - - dc->imm5 = EXTRACT_FIELD(ir, 0, 4); - dc->imm16 = EXTRACT_FIELD(ir, 0, 15); - dc->imm26 = EXTRACT_FIELD(ir, 0, 25); - - dc->csr = EXTRACT_FIELD(ir, 21, 25); - dc->r0 = EXTRACT_FIELD(ir, 21, 25); - dc->r1 = EXTRACT_FIELD(ir, 16, 20); - dc->r2 = EXTRACT_FIELD(ir, 11, 15); - - /* bit 31 seems to indicate insn type. */ - if (ir & (1 << 31)) { - dc->format = OP_FMT_RR; - } else { - dc->format = OP_FMT_RI; - } - - assert(ARRAY_SIZE(decinfo) == 64); - assert(dc->opcode < 64); - - decinfo[dc->opcode](dc); -} - -/* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) -{ - CPULM32State *env = cs->env_ptr; - LM32CPU *cpu = env_archcpu(env); - struct DisasContext ctx, *dc = &ctx; - uint32_t pc_start; - uint32_t page_start; - int num_insns; - - pc_start = tb->pc; - dc->features = cpu->features; - dc->num_breakpoints = cpu->num_breakpoints; - dc->num_watchpoints = cpu->num_watchpoints; - dc->tb = tb; - - dc->is_jmp = DISAS_NEXT; - dc->pc = pc_start; - dc->singlestep_enabled = cs->singlestep_enabled; - - if (pc_start & 3) { - qemu_log_mask(LOG_GUEST_ERROR, - "unaligned PC=%x. Ignoring lowest bits.\n", pc_start); - pc_start &= ~3; - } - - page_start = pc_start & TARGET_PAGE_MASK; - num_insns = 0; - - gen_tb_start(tb); - do { - tcg_gen_insn_start(dc->pc); - num_insns++; - - if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { - tcg_gen_movi_tl(cpu_pc, dc->pc); - t_gen_raise_exception(dc, EXCP_DEBUG); - dc->is_jmp = DISAS_UPDATE; - /* 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. */ - dc->pc += 4; - break; - } - - /* Pretty disas. */ - LOG_DIS("%8.8x:\t", dc->pc); - - if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) { - gen_io_start(); - } - - decode(dc, cpu_ldl_code(env, dc->pc)); - dc->pc += 4; - } while (!dc->is_jmp - && !tcg_op_buf_full() - && !cs->singlestep_enabled - && !singlestep - && (dc->pc - page_start < TARGET_PAGE_SIZE) - && num_insns < max_insns); - - - if (unlikely(cs->singlestep_enabled)) { - if (dc->is_jmp == DISAS_NEXT) { - tcg_gen_movi_tl(cpu_pc, dc->pc); - } - t_gen_raise_exception(dc, EXCP_DEBUG); - } else { - switch (dc->is_jmp) { - case DISAS_NEXT: - gen_goto_tb(dc, 1, dc->pc); - break; - default: - case DISAS_JUMP: - case DISAS_UPDATE: - /* indicate that the hash table must be used - to find the next TB */ - tcg_gen_exit_tb(NULL, 0); - break; - case DISAS_TB_JUMP: - /* nothing more to generate */ - break; - } - } - - gen_tb_end(tb, num_insns); - - tb->size = dc->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)) { - FILE *logfile = qemu_log_lock(); - qemu_log("\n"); - log_target_disas(cs, pc_start, dc->pc - pc_start); - qemu_log_unlock(logfile); - } -#endif -} - -void lm32_cpu_dump_state(CPUState *cs, FILE *f, int flags) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - int i; - - if (!env) { - return; - } - - qemu_fprintf(f, "IN: PC=%x %s\n", - env->pc, lookup_symbol(env->pc)); - - qemu_fprintf(f, "ie=%8.8x (IE=%x EIE=%x BIE=%x) im=%8.8x ip=%8.8x\n", - env->ie, - (env->ie & IE_IE) ? 1 : 0, - (env->ie & IE_EIE) ? 1 : 0, - (env->ie & IE_BIE) ? 1 : 0, - lm32_pic_get_im(env->pic_state), - lm32_pic_get_ip(env->pic_state)); - qemu_fprintf(f, "eba=%8.8x deba=%8.8x\n", - env->eba, - env->deba); - - for (i = 0; i < 32; i++) { - qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); - if ((i + 1) % 4 == 0) { - qemu_fprintf(f, "\n"); - } - } - qemu_fprintf(f, "\n\n"); -} - -void restore_state_to_opc(CPULM32State *env, TranslationBlock *tb, - target_ulong *data) -{ - env->pc = data[0]; -} - -void lm32_translate_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cpu_R); i++) { - cpu_R[i] = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, regs[i]), - regnames[i]); - } - - for (i = 0; i < ARRAY_SIZE(cpu_bp); i++) { - cpu_bp[i] = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, bp[i]), - regnames[32+i]); - } - - for (i = 0; i < ARRAY_SIZE(cpu_wp); i++) { - cpu_wp[i] = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, wp[i]), - regnames[36+i]); - } - - cpu_pc = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, pc), - "pc"); - cpu_ie = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, ie), - "ie"); - cpu_icc = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, icc), - "icc"); - cpu_dcc = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, dcc), - "dcc"); - cpu_cc = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, cc), - "cc"); - cpu_cfg = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, cfg), - "cfg"); - cpu_eba = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, eba), - "eba"); - cpu_dc = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, dc), - "dc"); - cpu_deba = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, deba), - "deba"); -} - diff --git a/target/meson.build b/target/meson.build index 0e2c4b69cb..2f6940255e 100644 --- a/target/meson.build +++ b/target/meson.build @@ -5,11 +5,9 @@ subdir('cris') subdir('hexagon') subdir('hppa') subdir('i386') -subdir('lm32') subdir('m68k') subdir('microblaze') subdir('mips') -subdir('moxie') subdir('nios2') subdir('openrisc') subdir('ppc') @@ -19,5 +17,4 @@ subdir('s390x') subdir('sh4') subdir('sparc') subdir('tricore') -subdir('unicore32') subdir('xtensa') diff --git a/target/moxie/cpu-param.h b/target/moxie/cpu-param.h deleted file mode 100644 index 9a40ef525c..0000000000 --- a/target/moxie/cpu-param.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Moxie cpu parameters for qemu. - * - * Copyright (c) 2008, 2010, 2013 Anthony Green - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#ifndef MOXIE_CPU_PARAM_H -#define MOXIE_CPU_PARAM_H 1 - -#define TARGET_LONG_BITS 32 -#define TARGET_PAGE_BITS 12 /* 4k */ -#define TARGET_PHYS_ADDR_SPACE_BITS 32 -#define TARGET_VIRT_ADDR_SPACE_BITS 32 -#define NB_MMU_MODES 1 - -#endif diff --git a/target/moxie/cpu.c b/target/moxie/cpu.c deleted file mode 100644 index 83bec34d36..0000000000 --- a/target/moxie/cpu.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * QEMU Moxie CPU - * - * Copyright (c) 2013 Anthony Green - * - * 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 program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "cpu.h" -#include "migration/vmstate.h" -#include "machine.h" - -static void moxie_cpu_set_pc(CPUState *cs, vaddr value) -{ - MoxieCPU *cpu = MOXIE_CPU(cs); - - cpu->env.pc = value; -} - -static bool moxie_cpu_has_work(CPUState *cs) -{ - return cs->interrupt_request & CPU_INTERRUPT_HARD; -} - -static void moxie_cpu_reset(DeviceState *dev) -{ - CPUState *s = CPU(dev); - MoxieCPU *cpu = MOXIE_CPU(s); - MoxieCPUClass *mcc = MOXIE_CPU_GET_CLASS(cpu); - CPUMoxieState *env = &cpu->env; - - mcc->parent_reset(dev); - - memset(env, 0, offsetof(CPUMoxieState, end_reset_fields)); - env->pc = 0x1000; -} - -static void moxie_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) -{ - info->mach = bfd_arch_moxie; - info->print_insn = print_insn_moxie; -} - -static void moxie_cpu_realizefn(DeviceState *dev, Error **errp) -{ - CPUState *cs = CPU(dev); - MoxieCPUClass *mcc = MOXIE_CPU_GET_CLASS(dev); - Error *local_err = NULL; - - cpu_exec_realizefn(cs, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - - qemu_init_vcpu(cs); - cpu_reset(cs); - - mcc->parent_realize(dev, errp); -} - -static void moxie_cpu_initfn(Object *obj) -{ - MoxieCPU *cpu = MOXIE_CPU(obj); - - cpu_set_cpustate_pointers(cpu); -} - -static ObjectClass *moxie_cpu_class_by_name(const char *cpu_model) -{ - ObjectClass *oc; - char *typename; - - typename = g_strdup_printf(MOXIE_CPU_TYPE_NAME("%s"), cpu_model); - oc = object_class_by_name(typename); - g_free(typename); - if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_MOXIE_CPU) || - object_class_is_abstract(oc))) { - return NULL; - } - return oc; -} - -#include "hw/core/tcg-cpu-ops.h" - -static struct TCGCPUOps moxie_tcg_ops = { - .initialize = moxie_translate_init, - .tlb_fill = moxie_cpu_tlb_fill, - -#ifndef CONFIG_USER_ONLY - .do_interrupt = moxie_cpu_do_interrupt, -#endif /* !CONFIG_USER_ONLY */ -}; - -static void moxie_cpu_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); - MoxieCPUClass *mcc = MOXIE_CPU_CLASS(oc); - - device_class_set_parent_realize(dc, moxie_cpu_realizefn, - &mcc->parent_realize); - device_class_set_parent_reset(dc, moxie_cpu_reset, &mcc->parent_reset); - - cc->class_by_name = moxie_cpu_class_by_name; - - cc->has_work = moxie_cpu_has_work; - cc->dump_state = moxie_cpu_dump_state; - cc->set_pc = moxie_cpu_set_pc; -#ifndef CONFIG_USER_ONLY - cc->get_phys_page_debug = moxie_cpu_get_phys_page_debug; - cc->vmsd = &vmstate_moxie_cpu; -#endif - cc->disas_set_info = moxie_cpu_disas_set_info; - cc->tcg_ops = &moxie_tcg_ops; -} - -static void moxielite_initfn(Object *obj) -{ - /* Set cpu feature flags */ -} - -static void moxie_any_initfn(Object *obj) -{ - /* Set cpu feature flags */ -} - -#define DEFINE_MOXIE_CPU_TYPE(cpu_model, initfn) \ - { \ - .parent = TYPE_MOXIE_CPU, \ - .instance_init = initfn, \ - .name = MOXIE_CPU_TYPE_NAME(cpu_model), \ - } - -static const TypeInfo moxie_cpus_type_infos[] = { - { /* base class should be registered first */ - .name = TYPE_MOXIE_CPU, - .parent = TYPE_CPU, - .instance_size = sizeof(MoxieCPU), - .instance_init = moxie_cpu_initfn, - .class_size = sizeof(MoxieCPUClass), - .class_init = moxie_cpu_class_init, - }, - DEFINE_MOXIE_CPU_TYPE("MoxieLite", moxielite_initfn), - DEFINE_MOXIE_CPU_TYPE("any", moxie_any_initfn), -}; - -DEFINE_TYPES(moxie_cpus_type_infos) diff --git a/target/moxie/cpu.h b/target/moxie/cpu.h deleted file mode 100644 index bd6ab66084..0000000000 --- a/target/moxie/cpu.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Moxie emulation - * - * Copyright (c) 2008, 2010, 2013 Anthony Green - * - * 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 program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef MOXIE_CPU_H -#define MOXIE_CPU_H - -#include "exec/cpu-defs.h" -#include "qom/object.h" - -#define MOXIE_EX_DIV0 0 -#define MOXIE_EX_BAD 1 -#define MOXIE_EX_IRQ 2 -#define MOXIE_EX_SWI 3 -#define MOXIE_EX_MMU_MISS 4 -#define MOXIE_EX_BREAK 16 - -typedef struct CPUMoxieState { - - uint32_t flags; /* general execution flags */ - uint32_t gregs[16]; /* general registers */ - uint32_t sregs[256]; /* special registers */ - uint32_t pc; /* program counter */ - /* Instead of saving the cc value, we save the cmp arguments - and compute cc on demand. */ - uint32_t cc_a; /* reg a for condition code calculation */ - uint32_t cc_b; /* reg b for condition code calculation */ - - void *irq[8]; - - /* Fields up to this point are cleared by a CPU reset */ - struct {} end_reset_fields; -} CPUMoxieState; - -#include "hw/core/cpu.h" - -#define TYPE_MOXIE_CPU "moxie-cpu" - -OBJECT_DECLARE_TYPE(MoxieCPU, MoxieCPUClass, - MOXIE_CPU) - -/** - * MoxieCPUClass: - * @parent_reset: The parent class' reset handler. - * - * A Moxie CPU model. - */ -struct MoxieCPUClass { - /*< private >*/ - CPUClass parent_class; - /*< public >*/ - - DeviceRealize parent_realize; - DeviceReset parent_reset; -}; - -/** - * MoxieCPU: - * @env: #CPUMoxieState - * - * A Moxie CPU. - */ -struct MoxieCPU { - /*< private >*/ - CPUState parent_obj; - /*< public >*/ - - CPUNegativeOffsetState neg; - CPUMoxieState env; -}; - - -void moxie_cpu_do_interrupt(CPUState *cs); -void moxie_cpu_dump_state(CPUState *cpu, FILE *f, int flags); -hwaddr moxie_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -void moxie_translate_init(void); -int cpu_moxie_signal_handler(int host_signum, void *pinfo, - void *puc); - -#define MOXIE_CPU_TYPE_SUFFIX "-" TYPE_MOXIE_CPU -#define MOXIE_CPU_TYPE_NAME(model) model MOXIE_CPU_TYPE_SUFFIX -#define CPU_RESOLVING_TYPE TYPE_MOXIE_CPU - -#define cpu_signal_handler cpu_moxie_signal_handler - -static inline int cpu_mmu_index(CPUMoxieState *env, bool ifetch) -{ - return 0; -} - -typedef CPUMoxieState CPUArchState; -typedef MoxieCPU ArchCPU; - -#include "exec/cpu-all.h" - -static inline void cpu_get_tb_cpu_state(CPUMoxieState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) -{ - *pc = env->pc; - *cs_base = 0; - *flags = 0; -} - -bool moxie_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr); - -#endif /* MOXIE_CPU_H */ diff --git a/target/moxie/helper.c b/target/moxie/helper.c deleted file mode 100644 index b1919f62b3..0000000000 --- a/target/moxie/helper.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Moxie helper routines. - * - * Copyright (c) 2008, 2009, 2010, 2013 Anthony Green - * - * 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 program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" - -#include "cpu.h" -#include "mmu.h" -#include "exec/exec-all.h" -#include "exec/cpu_ldst.h" -#include "qemu/host-utils.h" -#include "exec/helper-proto.h" - -void helper_raise_exception(CPUMoxieState *env, int ex) -{ - CPUState *cs = env_cpu(env); - - cs->exception_index = ex; - /* Stash the exception type. */ - env->sregs[2] = ex; - /* Stash the address where the exception occurred. */ - cpu_restore_state(cs, GETPC(), true); - env->sregs[5] = env->pc; - /* Jump to the exception handline routine. */ - env->pc = env->sregs[1]; - cpu_loop_exit(cs); -} - -uint32_t helper_div(CPUMoxieState *env, uint32_t a, uint32_t b) -{ - if (unlikely(b == 0)) { - helper_raise_exception(env, MOXIE_EX_DIV0); - return 0; - } - if (unlikely(a == INT_MIN && b == -1)) { - return INT_MIN; - } - - return (int32_t)a / (int32_t)b; -} - -uint32_t helper_udiv(CPUMoxieState *env, uint32_t a, uint32_t b) -{ - if (unlikely(b == 0)) { - helper_raise_exception(env, MOXIE_EX_DIV0); - return 0; - } - return a / b; -} - -void helper_debug(CPUMoxieState *env) -{ - CPUState *cs = env_cpu(env); - - cs->exception_index = EXCP_DEBUG; - cpu_loop_exit(cs); -} - -bool moxie_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr) -{ - MoxieCPU *cpu = MOXIE_CPU(cs); - CPUMoxieState *env = &cpu->env; - MoxieMMUResult res; - int prot, miss; - - address &= TARGET_PAGE_MASK; - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - miss = moxie_mmu_translate(&res, env, address, access_type, mmu_idx); - if (likely(!miss)) { - tlb_set_page(cs, address, res.phy, prot, mmu_idx, TARGET_PAGE_SIZE); - return true; - } - if (probe) { - return false; - } - - cs->exception_index = MOXIE_EX_MMU_MISS; - cpu_loop_exit_restore(cs, retaddr); -} - -void moxie_cpu_do_interrupt(CPUState *cs) -{ - switch (cs->exception_index) { - case MOXIE_EX_BREAK: - break; - default: - break; - } -} - -hwaddr moxie_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) -{ - MoxieCPU *cpu = MOXIE_CPU(cs); - uint32_t phy = addr; - MoxieMMUResult res; - int miss; - - miss = moxie_mmu_translate(&res, &cpu->env, addr, 0, 0); - if (!miss) { - phy = res.phy; - } - return phy; -} diff --git a/target/moxie/helper.h b/target/moxie/helper.h deleted file mode 100644 index d94ef7a17e..0000000000 --- a/target/moxie/helper.h +++ /dev/null @@ -1,5 +0,0 @@ -DEF_HELPER_2(raise_exception, void, env, int) -DEF_HELPER_1(debug, void, env) - -DEF_HELPER_FLAGS_3(div, TCG_CALL_NO_WG, i32, env, i32, i32) -DEF_HELPER_FLAGS_3(udiv, TCG_CALL_NO_WG, i32, env, i32, i32) diff --git a/target/moxie/machine.c b/target/moxie/machine.c deleted file mode 100644 index d0f177048c..0000000000 --- a/target/moxie/machine.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "qemu/osdep.h" -#include "cpu.h" -#include "machine.h" -#include "migration/cpu.h" - -const VMStateDescription vmstate_moxie_cpu = { - .name = "cpu", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(flags, CPUMoxieState), - VMSTATE_UINT32_ARRAY(gregs, CPUMoxieState, 16), - VMSTATE_UINT32_ARRAY(sregs, CPUMoxieState, 256), - VMSTATE_UINT32(pc, CPUMoxieState), - VMSTATE_UINT32(cc_a, CPUMoxieState), - VMSTATE_UINT32(cc_b, CPUMoxieState), - VMSTATE_END_OF_LIST() - } -}; diff --git a/target/moxie/machine.h b/target/moxie/machine.h deleted file mode 100644 index a1b72907ae..0000000000 --- a/target/moxie/machine.h +++ /dev/null @@ -1 +0,0 @@ -extern const VMStateDescription vmstate_moxie_cpu; diff --git a/target/moxie/meson.build b/target/moxie/meson.build deleted file mode 100644 index b4beb528cc..0000000000 --- a/target/moxie/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -moxie_ss = ss.source_set() -moxie_ss.add(files( - 'cpu.c', - 'helper.c', - 'machine.c', - 'machine.c', - 'translate.c', -)) - -moxie_softmmu_ss = ss.source_set() -moxie_softmmu_ss.add(files('mmu.c')) - -target_arch += {'moxie': moxie_ss} -target_softmmu_arch += {'moxie': moxie_softmmu_ss} diff --git a/target/moxie/mmu.c b/target/moxie/mmu.c deleted file mode 100644 index 87783a36f8..0000000000 --- a/target/moxie/mmu.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Moxie mmu emulation. - * - * Copyright (c) 2008, 2013 Anthony Green - * - * 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 program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" - -#include "cpu.h" -#include "mmu.h" - -int moxie_mmu_translate(MoxieMMUResult *res, - CPUMoxieState *env, uint32_t vaddr, - int rw, int mmu_idx) -{ - /* Perform no translation yet. */ - res->phy = vaddr; - return 0; -} diff --git a/target/moxie/mmu.h b/target/moxie/mmu.h deleted file mode 100644 index d80690f4d2..0000000000 --- a/target/moxie/mmu.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef TARGET_MOXIE_MMU_H -#define TARGET_MOXIE_MMU_H - -#define MOXIE_MMU_ERR_EXEC 0 -#define MOXIE_MMU_ERR_READ 1 -#define MOXIE_MMU_ERR_WRITE 2 -#define MOXIE_MMU_ERR_FLUSH 3 - -typedef struct { - uint32_t phy; - uint32_t pfn; - int cause_op; -} MoxieMMUResult; - -int moxie_mmu_translate(MoxieMMUResult *res, - CPUMoxieState *env, uint32_t vaddr, - int rw, int mmu_idx); - -#endif diff --git a/target/moxie/translate.c b/target/moxie/translate.c deleted file mode 100644 index 24a742b25e..0000000000 --- a/target/moxie/translate.c +++ /dev/null @@ -1,892 +0,0 @@ -/* - * Moxie emulation for qemu: main translation routines. - * - * Copyright (c) 2009, 2013 Anthony Green - * - * 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 program. If not, see <http://www.gnu.org/licenses/>. - */ - -/* For information on the Moxie architecture, see - * http://moxielogic.org/wiki - */ - -#include "qemu/osdep.h" - -#include "cpu.h" -#include "exec/exec-all.h" -#include "disas/disas.h" -#include "tcg/tcg-op.h" -#include "exec/cpu_ldst.h" -#include "qemu/qemu-print.h" - -#include "exec/helper-proto.h" -#include "exec/helper-gen.h" -#include "exec/log.h" - -/* This is the state at translation time. */ -typedef struct DisasContext { - TranslationBlock *tb; - target_ulong pc, saved_pc; - uint32_t opcode; - uint32_t fp_status; - /* Routine used to access memory */ - int memidx; - int bstate; - target_ulong btarget; - int singlestep_enabled; -} DisasContext; - -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 */ -}; - -static TCGv cpu_pc; -static TCGv cpu_gregs[16]; -static TCGv cc_a, cc_b; - -#include "exec/gen-icount.h" - -#define REG(x) (cpu_gregs[x]) - -/* Extract the signed 10-bit offset from a 16-bit branch - instruction. */ -static int extract_branch_offset(int opcode) -{ - return (((signed short)((opcode & ((1 << 10) - 1)) << 6)) >> 6) << 1; -} - -void moxie_cpu_dump_state(CPUState *cs, FILE *f, int flags) -{ - MoxieCPU *cpu = MOXIE_CPU(cs); - CPUMoxieState *env = &cpu->env; - int i; - qemu_fprintf(f, "pc=0x%08x\n", env->pc); - qemu_fprintf(f, "$fp=0x%08x $sp=0x%08x $r0=0x%08x $r1=0x%08x\n", - env->gregs[0], env->gregs[1], env->gregs[2], env->gregs[3]); - for (i = 4; i < 16; i += 4) { - qemu_fprintf(f, "$r%d=0x%08x $r%d=0x%08x $r%d=0x%08x $r%d=0x%08x\n", - i - 2, env->gregs[i], i - 1, env->gregs[i + 1], - i, env->gregs[i + 2], i + 1, env->gregs[i + 3]); - } - for (i = 4; i < 16; i += 4) { - qemu_fprintf(f, "sr%d=0x%08x sr%d=0x%08x sr%d=0x%08x sr%d=0x%08x\n", - i - 2, env->sregs[i], i - 1, env->sregs[i + 1], - i, env->sregs[i + 2], i + 1, env->sregs[i + 3]); - } -} - -void moxie_translate_init(void) -{ - int i; - static const char * const gregnames[16] = { - "$fp", "$sp", "$r0", "$r1", - "$r2", "$r3", "$r4", "$r5", - "$r6", "$r7", "$r8", "$r9", - "$r10", "$r11", "$r12", "$r13" - }; - - cpu_pc = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMoxieState, pc), "$pc"); - for (i = 0; i < 16; i++) - cpu_gregs[i] = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMoxieState, gregs[i]), - gregnames[i]); - - cc_a = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMoxieState, cc_a), "cc_a"); - cc_b = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMoxieState, cc_b), "cc_b"); -} - -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 inline void gen_goto_tb(CPUMoxieState *env, DisasContext *ctx, - int n, target_ulong dest) -{ - if (use_goto_tb(ctx, dest)) { - tcg_gen_goto_tb(n); - tcg_gen_movi_i32(cpu_pc, dest); - tcg_gen_exit_tb(ctx->tb, n); - } else { - tcg_gen_movi_i32(cpu_pc, dest); - if (ctx->singlestep_enabled) { - gen_helper_debug(cpu_env); - } - tcg_gen_exit_tb(NULL, 0); - } -} - -static int decode_opc(MoxieCPU *cpu, DisasContext *ctx) -{ - CPUMoxieState *env = &cpu->env; - - /* Local cache for the instruction opcode. */ - int opcode; - /* Set the default instruction length. */ - int length = 2; - - /* Examine the 16-bit opcode. */ - opcode = ctx->opcode; - - /* Decode instruction. */ - if (opcode & (1 << 15)) { - if (opcode & (1 << 14)) { - /* This is a Form 3 instruction. */ - int inst = (opcode >> 10 & 0xf); - -#define BRANCH(cond) \ - do { \ - TCGLabel *l1 = gen_new_label(); \ - tcg_gen_brcond_i32(cond, cc_a, cc_b, l1); \ - gen_goto_tb(env, ctx, 1, ctx->pc+2); \ - gen_set_label(l1); \ - gen_goto_tb(env, ctx, 0, extract_branch_offset(opcode) + ctx->pc+2); \ - ctx->bstate = BS_BRANCH; \ - } while (0) - - switch (inst) { - case 0x00: /* beq */ - BRANCH(TCG_COND_EQ); - break; - case 0x01: /* bne */ - BRANCH(TCG_COND_NE); - break; - case 0x02: /* blt */ - BRANCH(TCG_COND_LT); - break; - case 0x03: /* bgt */ - BRANCH(TCG_COND_GT); - break; - case 0x04: /* bltu */ - BRANCH(TCG_COND_LTU); - break; - case 0x05: /* bgtu */ - BRANCH(TCG_COND_GTU); - break; - case 0x06: /* bge */ - BRANCH(TCG_COND_GE); - break; - case 0x07: /* ble */ - BRANCH(TCG_COND_LE); - break; - case 0x08: /* bgeu */ - BRANCH(TCG_COND_GEU); - break; - case 0x09: /* bleu */ - BRANCH(TCG_COND_LEU); - break; - default: - { - TCGv temp = tcg_temp_new_i32(); - tcg_gen_movi_i32(cpu_pc, ctx->pc); - tcg_gen_movi_i32(temp, MOXIE_EX_BAD); - gen_helper_raise_exception(cpu_env, temp); - tcg_temp_free_i32(temp); - } - break; - } - } else { - /* This is a Form 2 instruction. */ - int inst = (opcode >> 12 & 0x3); - switch (inst) { - case 0x00: /* inc */ - { - int a = (opcode >> 8) & 0xf; - unsigned int v = (opcode & 0xff); - tcg_gen_addi_i32(REG(a), REG(a), v); - } - break; - case 0x01: /* dec */ - { - int a = (opcode >> 8) & 0xf; - unsigned int v = (opcode & 0xff); - tcg_gen_subi_i32(REG(a), REG(a), v); - } - break; - case 0x02: /* gsr */ - { - int a = (opcode >> 8) & 0xf; - unsigned v = (opcode & 0xff); - tcg_gen_ld_i32(REG(a), cpu_env, - offsetof(CPUMoxieState, sregs[v])); - } - break; - case 0x03: /* ssr */ - { - int a = (opcode >> 8) & 0xf; - unsigned v = (opcode & 0xff); - tcg_gen_st_i32(REG(a), cpu_env, - offsetof(CPUMoxieState, sregs[v])); - } - break; - default: - { - TCGv temp = tcg_temp_new_i32(); - tcg_gen_movi_i32(cpu_pc, ctx->pc); - tcg_gen_movi_i32(temp, MOXIE_EX_BAD); - gen_helper_raise_exception(cpu_env, temp); - tcg_temp_free_i32(temp); - } - break; - } - } - } else { - /* This is a Form 1 instruction. */ - int inst = opcode >> 8; - switch (inst) { - case 0x00: /* nop */ - break; - case 0x01: /* ldi.l (immediate) */ - { - int reg = (opcode >> 4) & 0xf; - int val = cpu_ldl_code(env, ctx->pc+2); - tcg_gen_movi_i32(REG(reg), val); - length = 6; - } - break; - case 0x02: /* mov (register-to-register) */ - { - int dest = (opcode >> 4) & 0xf; - int src = opcode & 0xf; - tcg_gen_mov_i32(REG(dest), REG(src)); - } - break; - case 0x03: /* jsra */ - { - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - - tcg_gen_movi_i32(t1, ctx->pc + 6); - - /* Make space for the static chain and return address. */ - tcg_gen_subi_i32(t2, REG(1), 8); - tcg_gen_mov_i32(REG(1), t2); - tcg_gen_qemu_st32(t1, REG(1), ctx->memidx); - - /* Push the current frame pointer. */ - tcg_gen_subi_i32(t2, REG(1), 4); - tcg_gen_mov_i32(REG(1), t2); - tcg_gen_qemu_st32(REG(0), REG(1), ctx->memidx); - - /* Set the pc and $fp. */ - tcg_gen_mov_i32(REG(0), REG(1)); - - gen_goto_tb(env, ctx, 0, cpu_ldl_code(env, ctx->pc+2)); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - - ctx->bstate = BS_BRANCH; - length = 6; - } - break; - case 0x04: /* ret */ - { - TCGv t1 = tcg_temp_new_i32(); - - /* The new $sp is the old $fp. */ - tcg_gen_mov_i32(REG(1), REG(0)); - - /* Pop the frame pointer. */ - tcg_gen_qemu_ld32u(REG(0), REG(1), ctx->memidx); - tcg_gen_addi_i32(t1, REG(1), 4); - tcg_gen_mov_i32(REG(1), t1); - - - /* Pop the return address and skip over the static chain - slot. */ - tcg_gen_qemu_ld32u(cpu_pc, REG(1), ctx->memidx); - tcg_gen_addi_i32(t1, REG(1), 8); - tcg_gen_mov_i32(REG(1), t1); - - tcg_temp_free_i32(t1); - - /* Jump... */ - tcg_gen_exit_tb(NULL, 0); - - ctx->bstate = BS_BRANCH; - } - break; - case 0x05: /* add.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_add_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x06: /* push */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv t1 = tcg_temp_new_i32(); - tcg_gen_subi_i32(t1, REG(a), 4); - tcg_gen_mov_i32(REG(a), t1); - tcg_gen_qemu_st32(REG(b), REG(a), ctx->memidx); - tcg_temp_free_i32(t1); - } - break; - case 0x07: /* pop */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - TCGv t1 = tcg_temp_new_i32(); - - tcg_gen_qemu_ld32u(REG(b), REG(a), ctx->memidx); - tcg_gen_addi_i32(t1, REG(a), 4); - tcg_gen_mov_i32(REG(a), t1); - tcg_temp_free_i32(t1); - } - break; - case 0x08: /* lda.l */ - { - int reg = (opcode >> 4) & 0xf; - - TCGv ptr = tcg_temp_new_i32(); - tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_ld32u(REG(reg), ptr, ctx->memidx); - tcg_temp_free_i32(ptr); - - length = 6; - } - break; - case 0x09: /* sta.l */ - { - int val = (opcode >> 4) & 0xf; - - TCGv ptr = tcg_temp_new_i32(); - tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_st32(REG(val), ptr, ctx->memidx); - tcg_temp_free_i32(ptr); - - length = 6; - } - break; - case 0x0a: /* ld.l (register indirect) */ - { - int src = opcode & 0xf; - int dest = (opcode >> 4) & 0xf; - - tcg_gen_qemu_ld32u(REG(dest), REG(src), ctx->memidx); - } - break; - case 0x0b: /* st.l */ - { - int dest = (opcode >> 4) & 0xf; - int val = opcode & 0xf; - - tcg_gen_qemu_st32(REG(val), REG(dest), ctx->memidx); - } - break; - case 0x0c: /* ldo.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_ld32u(t2, t1, ctx->memidx); - tcg_gen_mov_i32(REG(a), t2); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - - length = 6; - } - break; - case 0x0d: /* sto.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_st32(REG(b), t1, ctx->memidx); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - - length = 6; - } - break; - case 0x0e: /* cmp */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_mov_i32(cc_a, REG(a)); - tcg_gen_mov_i32(cc_b, REG(b)); - } - break; - case 0x19: /* jsr */ - { - int fnreg = (opcode >> 4) & 0xf; - - /* Load the stack pointer into T0. */ - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - - tcg_gen_movi_i32(t1, ctx->pc+2); - - /* Make space for the static chain and return address. */ - tcg_gen_subi_i32(t2, REG(1), 8); - tcg_gen_mov_i32(REG(1), t2); - tcg_gen_qemu_st32(t1, REG(1), ctx->memidx); - - /* Push the current frame pointer. */ - tcg_gen_subi_i32(t2, REG(1), 4); - tcg_gen_mov_i32(REG(1), t2); - tcg_gen_qemu_st32(REG(0), REG(1), ctx->memidx); - - /* Set the pc and $fp. */ - tcg_gen_mov_i32(REG(0), REG(1)); - tcg_gen_mov_i32(cpu_pc, REG(fnreg)); - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - tcg_gen_exit_tb(NULL, 0); - ctx->bstate = BS_BRANCH; - } - break; - case 0x1a: /* jmpa */ - { - tcg_gen_movi_i32(cpu_pc, cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_exit_tb(NULL, 0); - ctx->bstate = BS_BRANCH; - length = 6; - } - break; - case 0x1b: /* ldi.b (immediate) */ - { - int reg = (opcode >> 4) & 0xf; - int val = cpu_ldl_code(env, ctx->pc+2); - tcg_gen_movi_i32(REG(reg), val); - length = 6; - } - break; - case 0x1c: /* ld.b (register indirect) */ - { - int src = opcode & 0xf; - int dest = (opcode >> 4) & 0xf; - - tcg_gen_qemu_ld8u(REG(dest), REG(src), ctx->memidx); - } - break; - case 0x1d: /* lda.b */ - { - int reg = (opcode >> 4) & 0xf; - - TCGv ptr = tcg_temp_new_i32(); - tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_ld8u(REG(reg), ptr, ctx->memidx); - tcg_temp_free_i32(ptr); - - length = 6; - } - break; - case 0x1e: /* st.b */ - { - int dest = (opcode >> 4) & 0xf; - int val = opcode & 0xf; - - tcg_gen_qemu_st8(REG(val), REG(dest), ctx->memidx); - } - break; - case 0x1f: /* sta.b */ - { - int val = (opcode >> 4) & 0xf; - - TCGv ptr = tcg_temp_new_i32(); - tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_st8(REG(val), ptr, ctx->memidx); - tcg_temp_free_i32(ptr); - - length = 6; - } - break; - case 0x20: /* ldi.s (immediate) */ - { - int reg = (opcode >> 4) & 0xf; - int val = cpu_ldl_code(env, ctx->pc+2); - tcg_gen_movi_i32(REG(reg), val); - length = 6; - } - break; - case 0x21: /* ld.s (register indirect) */ - { - int src = opcode & 0xf; - int dest = (opcode >> 4) & 0xf; - - tcg_gen_qemu_ld16u(REG(dest), REG(src), ctx->memidx); - } - break; - case 0x22: /* lda.s */ - { - int reg = (opcode >> 4) & 0xf; - - TCGv ptr = tcg_temp_new_i32(); - tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_ld16u(REG(reg), ptr, ctx->memidx); - tcg_temp_free_i32(ptr); - - length = 6; - } - break; - case 0x23: /* st.s */ - { - int dest = (opcode >> 4) & 0xf; - int val = opcode & 0xf; - - tcg_gen_qemu_st16(REG(val), REG(dest), ctx->memidx); - } - break; - case 0x24: /* sta.s */ - { - int val = (opcode >> 4) & 0xf; - - TCGv ptr = tcg_temp_new_i32(); - tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_st16(REG(val), ptr, ctx->memidx); - tcg_temp_free_i32(ptr); - - length = 6; - } - break; - case 0x25: /* jmp */ - { - int reg = (opcode >> 4) & 0xf; - tcg_gen_mov_i32(cpu_pc, REG(reg)); - tcg_gen_exit_tb(NULL, 0); - ctx->bstate = BS_BRANCH; - } - break; - case 0x26: /* and */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_and_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x27: /* lshr */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv sv = tcg_temp_new_i32(); - tcg_gen_andi_i32(sv, REG(b), 0x1f); - tcg_gen_shr_i32(REG(a), REG(a), sv); - tcg_temp_free_i32(sv); - } - break; - case 0x28: /* ashl */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv sv = tcg_temp_new_i32(); - tcg_gen_andi_i32(sv, REG(b), 0x1f); - tcg_gen_shl_i32(REG(a), REG(a), sv); - tcg_temp_free_i32(sv); - } - break; - case 0x29: /* sub.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_sub_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x2a: /* neg */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_neg_i32(REG(a), REG(b)); - } - break; - case 0x2b: /* or */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_or_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x2c: /* not */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_not_i32(REG(a), REG(b)); - } - break; - case 0x2d: /* ashr */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv sv = tcg_temp_new_i32(); - tcg_gen_andi_i32(sv, REG(b), 0x1f); - tcg_gen_sar_i32(REG(a), REG(a), sv); - tcg_temp_free_i32(sv); - } - break; - case 0x2e: /* xor */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_xor_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x2f: /* mul.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_mul_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x30: /* swi */ - { - int val = cpu_ldl_code(env, ctx->pc+2); - - TCGv temp = tcg_temp_new_i32(); - tcg_gen_movi_i32(temp, val); - tcg_gen_st_i32(temp, cpu_env, - offsetof(CPUMoxieState, sregs[3])); - tcg_gen_movi_i32(cpu_pc, ctx->pc); - tcg_gen_movi_i32(temp, MOXIE_EX_SWI); - gen_helper_raise_exception(cpu_env, temp); - tcg_temp_free_i32(temp); - - length = 6; - } - break; - case 0x31: /* div.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - tcg_gen_movi_i32(cpu_pc, ctx->pc); - gen_helper_div(REG(a), cpu_env, REG(a), REG(b)); - } - break; - case 0x32: /* udiv.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - tcg_gen_movi_i32(cpu_pc, ctx->pc); - gen_helper_udiv(REG(a), cpu_env, REG(a), REG(b)); - } - break; - case 0x33: /* mod.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - tcg_gen_rem_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x34: /* umod.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - tcg_gen_remu_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x35: /* brk */ - { - TCGv temp = tcg_temp_new_i32(); - tcg_gen_movi_i32(cpu_pc, ctx->pc); - tcg_gen_movi_i32(temp, MOXIE_EX_BREAK); - gen_helper_raise_exception(cpu_env, temp); - tcg_temp_free_i32(temp); - } - break; - case 0x36: /* ldo.b */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_ld8u(t2, t1, ctx->memidx); - tcg_gen_mov_i32(REG(a), t2); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - - length = 6; - } - break; - case 0x37: /* sto.b */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_st8(REG(b), t1, ctx->memidx); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - - length = 6; - } - break; - case 0x38: /* ldo.s */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_ld16u(t2, t1, ctx->memidx); - tcg_gen_mov_i32(REG(a), t2); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - - length = 6; - } - break; - case 0x39: /* sto.s */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_st16(REG(b), t1, ctx->memidx); - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - - length = 6; - } - break; - default: - { - TCGv temp = tcg_temp_new_i32(); - tcg_gen_movi_i32(cpu_pc, ctx->pc); - tcg_gen_movi_i32(temp, MOXIE_EX_BAD); - gen_helper_raise_exception(cpu_env, temp); - tcg_temp_free_i32(temp); - } - break; - } - } - - return length; -} - -/* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) -{ - CPUMoxieState *env = cs->env_ptr; - MoxieCPU *cpu = env_archcpu(env); - DisasContext ctx; - target_ulong pc_start; - int num_insns; - - pc_start = tb->pc; - ctx.pc = pc_start; - ctx.saved_pc = -1; - ctx.tb = tb; - ctx.memidx = 0; - ctx.singlestep_enabled = 0; - ctx.bstate = BS_NONE; - num_insns = 0; - - gen_tb_start(tb); - do { - tcg_gen_insn_start(ctx.pc); - num_insns++; - - if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) { - tcg_gen_movi_i32(cpu_pc, ctx.pc); - gen_helper_debug(cpu_env); - ctx.bstate = BS_EXCP; - /* 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; - goto done_generating; - } - - ctx.opcode = cpu_lduw_code(env, ctx.pc); - ctx.pc += decode_opc(cpu, &ctx); - - if (num_insns >= max_insns) { - break; - } - if (cs->singlestep_enabled) { - break; - } - if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) { - break; - } - } while (ctx.bstate == BS_NONE && !tcg_op_buf_full()); - - if (cs->singlestep_enabled) { - tcg_gen_movi_tl(cpu_pc, ctx.pc); - gen_helper_debug(cpu_env); - } else { - switch (ctx.bstate) { - case BS_STOP: - case BS_NONE: - gen_goto_tb(env, &ctx, 0, ctx.pc); - break; - case BS_EXCP: - tcg_gen_exit_tb(NULL, 0); - break; - case BS_BRANCH: - default: - break; - } - } - done_generating: - gen_tb_end(tb, num_insns); - - tb->size = ctx.pc - pc_start; - tb->icount = num_insns; -} - -void restore_state_to_opc(CPUMoxieState *env, TranslationBlock *tb, - target_ulong *data) -{ - env->pc = data[0]; -} diff --git a/target/unicore32/cpu-param.h b/target/unicore32/cpu-param.h deleted file mode 100644 index 94d8a5daa1..0000000000 --- a/target/unicore32/cpu-param.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * UniCore32 cpu parameters for qemu. - * - * Copyright (C) 2010-2012 Guan Xuetao - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef UNICORE32_CPU_PARAM_H -#define UNICORE32_CPU_PARAM_H 1 - -#define TARGET_LONG_BITS 32 -#define TARGET_PAGE_BITS 12 -#define TARGET_PHYS_ADDR_SPACE_BITS 32 -#define TARGET_VIRT_ADDR_SPACE_BITS 32 -#define NB_MMU_MODES 2 - -#endif diff --git a/target/unicore32/cpu-qom.h b/target/unicore32/cpu-qom.h deleted file mode 100644 index 43621e7479..0000000000 --- a/target/unicore32/cpu-qom.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * QEMU UniCore32 CPU - * - * Copyright (c) 2012 SUSE LINUX Products GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or (at your option) any - * later version. See the COPYING file in the top-level directory. - */ -#ifndef QEMU_UC32_CPU_QOM_H -#define QEMU_UC32_CPU_QOM_H - -#include "hw/core/cpu.h" -#include "qom/object.h" - -#define TYPE_UNICORE32_CPU "unicore32-cpu" - -OBJECT_DECLARE_TYPE(UniCore32CPU, UniCore32CPUClass, - UNICORE32_CPU) - -/** - * UniCore32CPUClass: - * @parent_realize: The parent class' realize handler. - * - * A UniCore32 CPU model. - */ -struct UniCore32CPUClass { - /*< private >*/ - CPUClass parent_class; - /*< public >*/ - - DeviceRealize parent_realize; -}; - - -#endif diff --git a/target/unicore32/cpu.c b/target/unicore32/cpu.c deleted file mode 100644 index 0258884f84..0000000000 --- a/target/unicore32/cpu.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * QEMU UniCore32 CPU - * - * Copyright (c) 2010-2012 Guan Xuetao - * Copyright (c) 2012 SUSE LINUX Products GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Contributions from 2012-04-01 on are considered under GPL version 2, - * or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "cpu.h" -#include "migration/vmstate.h" -#include "exec/exec-all.h" - -static void uc32_cpu_set_pc(CPUState *cs, vaddr value) -{ - UniCore32CPU *cpu = UNICORE32_CPU(cs); - - cpu->env.regs[31] = value; -} - -static bool uc32_cpu_has_work(CPUState *cs) -{ - return cs->interrupt_request & - (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB); -} - -static inline void set_feature(CPUUniCore32State *env, int feature) -{ - env->features |= feature; -} - -/* CPU models */ - -static ObjectClass *uc32_cpu_class_by_name(const char *cpu_model) -{ - ObjectClass *oc; - char *typename; - - typename = g_strdup_printf(UNICORE32_CPU_TYPE_NAME("%s"), cpu_model); - oc = object_class_by_name(typename); - g_free(typename); - if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_UNICORE32_CPU) || - object_class_is_abstract(oc))) { - oc = NULL; - } - return oc; -} - -static void unicore_ii_cpu_initfn(Object *obj) -{ - UniCore32CPU *cpu = UNICORE32_CPU(obj); - CPUUniCore32State *env = &cpu->env; - - env->cp0.c0_cpuid = 0x4d000863; - env->cp0.c0_cachetype = 0x0d152152; - env->cp0.c1_sys = 0x2000; - env->cp0.c2_base = 0x0; - env->cp0.c3_faultstatus = 0x0; - env->cp0.c4_faultaddr = 0x0; - env->ucf64.xregs[UC32_UCF64_FPSCR] = 0; - - set_feature(env, UC32_HWCAP_CMOV); - set_feature(env, UC32_HWCAP_UCF64); -} - -static void uc32_any_cpu_initfn(Object *obj) -{ - UniCore32CPU *cpu = UNICORE32_CPU(obj); - CPUUniCore32State *env = &cpu->env; - - env->cp0.c0_cpuid = 0xffffffff; - env->ucf64.xregs[UC32_UCF64_FPSCR] = 0; - - set_feature(env, UC32_HWCAP_CMOV); - set_feature(env, UC32_HWCAP_UCF64); -} - -static void uc32_cpu_realizefn(DeviceState *dev, Error **errp) -{ - CPUState *cs = CPU(dev); - UniCore32CPUClass *ucc = UNICORE32_CPU_GET_CLASS(dev); - Error *local_err = NULL; - - cpu_exec_realizefn(cs, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - - qemu_init_vcpu(cs); - - ucc->parent_realize(dev, errp); -} - -static void uc32_cpu_initfn(Object *obj) -{ - UniCore32CPU *cpu = UNICORE32_CPU(obj); - CPUUniCore32State *env = &cpu->env; - - cpu_set_cpustate_pointers(cpu); - -#ifdef CONFIG_USER_ONLY - env->uncached_asr = ASR_MODE_USER; - env->regs[31] = 0; -#else - env->uncached_asr = ASR_MODE_PRIV; - env->regs[31] = 0x03000000; -#endif -} - -static const VMStateDescription vmstate_uc32_cpu = { - .name = "cpu", - .unmigratable = 1, -}; - -#include "hw/core/tcg-cpu-ops.h" - -static struct TCGCPUOps uc32_tcg_ops = { - .initialize = uc32_translate_init, - .cpu_exec_interrupt = uc32_cpu_exec_interrupt, - .tlb_fill = uc32_cpu_tlb_fill, - -#ifndef CONFIG_USER_ONLY - .do_interrupt = uc32_cpu_do_interrupt, -#endif /* !CONFIG_USER_ONLY */ -}; - -static void uc32_cpu_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); - UniCore32CPUClass *ucc = UNICORE32_CPU_CLASS(oc); - - device_class_set_parent_realize(dc, uc32_cpu_realizefn, - &ucc->parent_realize); - - cc->class_by_name = uc32_cpu_class_by_name; - cc->has_work = uc32_cpu_has_work; - cc->dump_state = uc32_cpu_dump_state; - cc->set_pc = uc32_cpu_set_pc; - cc->get_phys_page_debug = uc32_cpu_get_phys_page_debug; - dc->vmsd = &vmstate_uc32_cpu; - cc->tcg_ops = &uc32_tcg_ops; -} - -#define DEFINE_UNICORE32_CPU_TYPE(cpu_model, initfn) \ - { \ - .parent = TYPE_UNICORE32_CPU, \ - .instance_init = initfn, \ - .name = UNICORE32_CPU_TYPE_NAME(cpu_model), \ - } - -static const TypeInfo uc32_cpu_type_infos[] = { - { - .name = TYPE_UNICORE32_CPU, - .parent = TYPE_CPU, - .instance_size = sizeof(UniCore32CPU), - .instance_init = uc32_cpu_initfn, - .abstract = true, - .class_size = sizeof(UniCore32CPUClass), - .class_init = uc32_cpu_class_init, - }, - DEFINE_UNICORE32_CPU_TYPE("UniCore-II", unicore_ii_cpu_initfn), - DEFINE_UNICORE32_CPU_TYPE("any", uc32_any_cpu_initfn), -}; - -DEFINE_TYPES(uc32_cpu_type_infos) diff --git a/target/unicore32/cpu.h b/target/unicore32/cpu.h deleted file mode 100644 index 7a32e086ed..0000000000 --- a/target/unicore32/cpu.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * UniCore32 virtual CPU header - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or (at your option) any - * later version. See the COPYING file in the top-level directory. - */ - -#ifndef UNICORE32_CPU_H -#define UNICORE32_CPU_H - -#include "cpu-qom.h" -#include "exec/cpu-defs.h" - -typedef struct CPUUniCore32State { - /* Regs for current mode. */ - uint32_t regs[32]; - /* Frequently accessed ASR bits are stored separately for efficiently. - This contains all the other bits. Use asr_{read,write} to access - the whole ASR. */ - uint32_t uncached_asr; - uint32_t bsr; - - /* Banked registers. */ - uint32_t banked_bsr[6]; - uint32_t banked_r29[6]; - uint32_t banked_r30[6]; - - /* asr flag cache for faster execution */ - uint32_t CF; /* 0 or 1 */ - uint32_t VF; /* V is the bit 31. All other bits are undefined */ - uint32_t NF; /* N is bit 31. All other bits are undefined. */ - uint32_t ZF; /* Z set if zero. */ - - /* System control coprocessor (cp0) */ - struct { - uint32_t c0_cpuid; - uint32_t c0_cachetype; - uint32_t c1_sys; /* System control register. */ - uint32_t c2_base; /* MMU translation table base. */ - uint32_t c3_faultstatus; /* Fault status registers. */ - uint32_t c4_faultaddr; /* Fault address registers. */ - uint32_t c5_cacheop; /* Cache operation registers. */ - uint32_t c6_tlbop; /* TLB operation registers. */ - } cp0; - - /* UniCore-F64 coprocessor state. */ - struct { - float64 regs[16]; - uint32_t xregs[32]; - float_status fp_status; - } ucf64; - - /* Internal CPU feature flags. */ - uint32_t features; - -} CPUUniCore32State; - -/** - * UniCore32CPU: - * @env: #CPUUniCore32State - * - * A UniCore32 CPU. - */ -struct UniCore32CPU { - /*< private >*/ - CPUState parent_obj; - /*< public >*/ - - CPUNegativeOffsetState neg; - CPUUniCore32State env; -}; - - -void uc32_cpu_do_interrupt(CPUState *cpu); -bool uc32_cpu_exec_interrupt(CPUState *cpu, int int_req); -void uc32_cpu_dump_state(CPUState *cpu, FILE *f, int flags); -hwaddr uc32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); - -#define ASR_M (0x1f) -#define ASR_MODE_USER (0x10) -#define ASR_MODE_INTR (0x12) -#define ASR_MODE_PRIV (0x13) -#define ASR_MODE_TRAP (0x17) -#define ASR_MODE_EXTN (0x1b) -#define ASR_MODE_SUSR (0x1f) -#define ASR_I (1 << 7) -#define ASR_V (1 << 28) -#define ASR_C (1 << 29) -#define ASR_Z (1 << 30) -#define ASR_N (1 << 31) -#define ASR_NZCV (ASR_N | ASR_Z | ASR_C | ASR_V) -#define ASR_RESERVED (~(ASR_M | ASR_I | ASR_NZCV)) - -#define UC32_EXCP_PRIV (1) -#define UC32_EXCP_ITRAP (2) -#define UC32_EXCP_DTRAP (3) -#define UC32_EXCP_INTR (4) - -/* Return the current ASR value. */ -target_ulong cpu_asr_read(CPUUniCore32State *env1); -/* Set the ASR. Note that some bits of mask must be all-set or all-clear. */ -void cpu_asr_write(CPUUniCore32State *env1, target_ulong val, target_ulong mask); - -/* UniCore-F64 system registers. */ -#define UC32_UCF64_FPSCR (31) -#define UCF64_FPSCR_MASK (0x27ffffff) -#define UCF64_FPSCR_RND_MASK (0x7) -#define UCF64_FPSCR_RND(r) (((r) >> 0) & UCF64_FPSCR_RND_MASK) -#define UCF64_FPSCR_TRAPEN_MASK (0x7f) -#define UCF64_FPSCR_TRAPEN(r) (((r) >> 10) & UCF64_FPSCR_TRAPEN_MASK) -#define UCF64_FPSCR_FLAG_MASK (0x3ff) -#define UCF64_FPSCR_FLAG(r) (((r) >> 17) & UCF64_FPSCR_FLAG_MASK) -#define UCF64_FPSCR_FLAG_ZERO (1 << 17) -#define UCF64_FPSCR_FLAG_INFINITY (1 << 18) -#define UCF64_FPSCR_FLAG_INVALID (1 << 19) -#define UCF64_FPSCR_FLAG_UNDERFLOW (1 << 20) -#define UCF64_FPSCR_FLAG_OVERFLOW (1 << 21) -#define UCF64_FPSCR_FLAG_INEXACT (1 << 22) -#define UCF64_FPSCR_FLAG_HUGEINT (1 << 23) -#define UCF64_FPSCR_FLAG_DENORMAL (1 << 24) -#define UCF64_FPSCR_FLAG_UNIMP (1 << 25) -#define UCF64_FPSCR_FLAG_DIVZERO (1 << 26) - -#define UC32_HWCAP_CMOV 4 /* 1 << 2 */ -#define UC32_HWCAP_UCF64 8 /* 1 << 3 */ - -#define cpu_signal_handler uc32_cpu_signal_handler - -int uc32_cpu_signal_handler(int host_signum, void *pinfo, void *puc); - -/* MMU modes definitions */ -#define MMU_USER_IDX 1 -static inline int cpu_mmu_index(CPUUniCore32State *env, bool ifetch) -{ - return (env->uncached_asr & ASR_M) == ASR_MODE_USER ? 1 : 0; -} - -typedef CPUUniCore32State CPUArchState; -typedef UniCore32CPU ArchCPU; - -#include "exec/cpu-all.h" - -#define UNICORE32_CPU_TYPE_SUFFIX "-" TYPE_UNICORE32_CPU -#define UNICORE32_CPU_TYPE_NAME(model) model UNICORE32_CPU_TYPE_SUFFIX -#define CPU_RESOLVING_TYPE TYPE_UNICORE32_CPU - -static inline void cpu_get_tb_cpu_state(CPUUniCore32State *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) -{ - *pc = env->regs[31]; - *cs_base = 0; - *flags = 0; - if ((env->uncached_asr & ASR_M) != ASR_MODE_USER) { - *flags |= (1 << 6); - } -} - -bool uc32_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr); -void uc32_translate_init(void); -void switch_mode(CPUUniCore32State *, int); - -#endif /* UNICORE32_CPU_H */ diff --git a/target/unicore32/helper.c b/target/unicore32/helper.c deleted file mode 100644 index 704393c27f..0000000000 --- a/target/unicore32/helper.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Contributions from 2012-04-01 on are considered under GPL version 2, - * or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "cpu.h" -#include "exec/exec-all.h" -#include "exec/helper-proto.h" -#include "semihosting/console.h" - -#undef DEBUG_UC32 - -#ifdef DEBUG_UC32 -#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif - -#ifndef CONFIG_USER_ONLY -void helper_cp0_set(CPUUniCore32State *env, uint32_t val, uint32_t creg, - uint32_t cop) -{ - /* - * movc pp.nn, rn, #imm9 - * rn: UCOP_REG_D - * nn: UCOP_REG_N - * 1: sys control reg. - * 2: page table base reg. - * 3: data fault status reg. - * 4: insn fault status reg. - * 5: cache op. reg. - * 6: tlb op. reg. - * imm9: split UCOP_IMM10 with bit5 is 0 - */ - switch (creg) { - case 1: - if (cop != 0) { - goto unrecognized; - } - env->cp0.c1_sys = val; - break; - case 2: - if (cop != 0) { - goto unrecognized; - } - env->cp0.c2_base = val; - break; - case 3: - if (cop != 0) { - goto unrecognized; - } - env->cp0.c3_faultstatus = val; - break; - case 4: - if (cop != 0) { - goto unrecognized; - } - env->cp0.c4_faultaddr = val; - break; - case 5: - switch (cop) { - case 28: - DPRINTF("Invalidate Entire I&D cache\n"); - return; - case 20: - DPRINTF("Invalidate Entire Icache\n"); - return; - case 12: - DPRINTF("Invalidate Entire Dcache\n"); - return; - case 10: - DPRINTF("Clean Entire Dcache\n"); - return; - case 14: - DPRINTF("Flush Entire Dcache\n"); - return; - case 13: - DPRINTF("Invalidate Dcache line\n"); - return; - case 11: - DPRINTF("Clean Dcache line\n"); - return; - case 15: - DPRINTF("Flush Dcache line\n"); - return; - } - break; - case 6: - if ((cop <= 6) && (cop >= 2)) { - /* invalid all tlb */ - tlb_flush(env_cpu(env)); - return; - } - break; - default: - goto unrecognized; - } - return; -unrecognized: - qemu_log_mask(LOG_GUEST_ERROR, - "Wrong register (%d) or wrong operation (%d) in cp0_set!\n", - creg, cop); -} - -uint32_t helper_cp0_get(CPUUniCore32State *env, uint32_t creg, uint32_t cop) -{ - /* - * movc rd, pp.nn, #imm9 - * rd: UCOP_REG_D - * nn: UCOP_REG_N - * 0: cpuid and cachetype - * 1: sys control reg. - * 2: page table base reg. - * 3: data fault status reg. - * 4: insn fault status reg. - * imm9: split UCOP_IMM10 with bit5 is 0 - */ - switch (creg) { - case 0: - switch (cop) { - case 0: - return env->cp0.c0_cpuid; - case 1: - return env->cp0.c0_cachetype; - } - break; - case 1: - if (cop == 0) { - return env->cp0.c1_sys; - } - break; - case 2: - if (cop == 0) { - return env->cp0.c2_base; - } - break; - case 3: - if (cop == 0) { - return env->cp0.c3_faultstatus; - } - break; - case 4: - if (cop == 0) { - return env->cp0.c4_faultaddr; - } - break; - } - qemu_log_mask(LOG_GUEST_ERROR, - "Wrong register (%d) or wrong operation (%d) in cp0_set!\n", - creg, cop); - return 0; -} - -void helper_cp1_putc(target_ulong regval) -{ - const char c = regval; - - qemu_semihosting_log_out(&c, sizeof(c)); -} -#endif /* !CONFIG_USER_ONLY */ - -bool uc32_cpu_exec_interrupt(CPUState *cs, int interrupt_request) -{ - if (interrupt_request & CPU_INTERRUPT_HARD) { - UniCore32CPU *cpu = UNICORE32_CPU(cs); - CPUUniCore32State *env = &cpu->env; - - if (!(env->uncached_asr & ASR_I)) { - cs->exception_index = UC32_EXCP_INTR; - uc32_cpu_do_interrupt(cs); - return true; - } - } - return false; -} diff --git a/target/unicore32/helper.h b/target/unicore32/helper.h deleted file mode 100644 index a4a5d45d1d..0000000000 --- a/target/unicore32/helper.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or (at your option) any - * later version. See the COPYING file in the top-level directory. - */ - -#ifndef CONFIG_USER_ONLY -DEF_HELPER_4(cp0_set, void, env, i32, i32, i32) -DEF_HELPER_3(cp0_get, i32, env, i32, i32) -DEF_HELPER_1(cp1_putc, void, i32) -#endif - -DEF_HELPER_2(exception, void, env, i32) - -DEF_HELPER_3(asr_write, void, env, i32, i32) -DEF_HELPER_1(asr_read, i32, env) - -DEF_HELPER_2(get_user_reg, i32, env, i32) -DEF_HELPER_3(set_user_reg, void, env, i32, i32) - -DEF_HELPER_3(add_cc, i32, env, i32, i32) -DEF_HELPER_3(adc_cc, i32, env, i32, i32) -DEF_HELPER_3(sub_cc, i32, env, i32, i32) -DEF_HELPER_3(sbc_cc, i32, env, i32, i32) - -DEF_HELPER_2(shl, i32, i32, i32) -DEF_HELPER_2(shr, i32, i32, i32) -DEF_HELPER_2(sar, i32, i32, i32) -DEF_HELPER_3(shl_cc, i32, env, i32, i32) -DEF_HELPER_3(shr_cc, i32, env, i32, i32) -DEF_HELPER_3(sar_cc, i32, env, i32, i32) -DEF_HELPER_3(ror_cc, i32, env, i32, i32) - -DEF_HELPER_1(ucf64_get_fpscr, i32, env) -DEF_HELPER_2(ucf64_set_fpscr, void, env, i32) - -DEF_HELPER_3(ucf64_adds, f32, f32, f32, env) -DEF_HELPER_3(ucf64_addd, f64, f64, f64, env) -DEF_HELPER_3(ucf64_subs, f32, f32, f32, env) -DEF_HELPER_3(ucf64_subd, f64, f64, f64, env) -DEF_HELPER_3(ucf64_muls, f32, f32, f32, env) -DEF_HELPER_3(ucf64_muld, f64, f64, f64, env) -DEF_HELPER_3(ucf64_divs, f32, f32, f32, env) -DEF_HELPER_3(ucf64_divd, f64, f64, f64, env) -DEF_HELPER_1(ucf64_negs, f32, f32) -DEF_HELPER_1(ucf64_negd, f64, f64) -DEF_HELPER_1(ucf64_abss, f32, f32) -DEF_HELPER_1(ucf64_absd, f64, f64) -DEF_HELPER_4(ucf64_cmps, void, f32, f32, i32, env) -DEF_HELPER_4(ucf64_cmpd, void, f64, f64, i32, env) - -DEF_HELPER_2(ucf64_sf2df, f64, f32, env) -DEF_HELPER_2(ucf64_df2sf, f32, f64, env) - -DEF_HELPER_2(ucf64_si2sf, f32, f32, env) -DEF_HELPER_2(ucf64_si2df, f64, f32, env) - -DEF_HELPER_2(ucf64_sf2si, f32, f32, env) -DEF_HELPER_2(ucf64_df2si, f32, f64, env) diff --git a/target/unicore32/meson.build b/target/unicore32/meson.build deleted file mode 100644 index 0fa78772eb..0000000000 --- a/target/unicore32/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -unicore32_ss = ss.source_set() -unicore32_ss.add(files( - 'cpu.c', - 'helper.c', - 'op_helper.c', - 'translate.c', - 'ucf64_helper.c', -), curses) - -unicore32_softmmu_ss = ss.source_set() -unicore32_softmmu_ss.add(files('softmmu.c')) - -target_arch += {'unicore32': unicore32_ss} -target_softmmu_arch += {'unicore32': unicore32_softmmu_ss} diff --git a/target/unicore32/op_helper.c b/target/unicore32/op_helper.c deleted file mode 100644 index eeaa78601a..0000000000 --- a/target/unicore32/op_helper.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * UniCore32 helper routines - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or (at your option) any - * later version. See the COPYING file in the top-level directory. - */ -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" -#include "exec/exec-all.h" -#include "exec/cpu_ldst.h" - -#define SIGNBIT (uint32_t)0x80000000 -#define SIGNBIT64 ((uint64_t)1 << 63) - -void HELPER(exception)(CPUUniCore32State *env, uint32_t excp) -{ - CPUState *cs = env_cpu(env); - - cs->exception_index = excp; - cpu_loop_exit(cs); -} - -static target_ulong asr_read(CPUUniCore32State *env) -{ - int ZF; - ZF = (env->ZF == 0); - return env->uncached_asr | (env->NF & 0x80000000) | (ZF << 30) | - (env->CF << 29) | ((env->VF & 0x80000000) >> 3); -} - -target_ulong cpu_asr_read(CPUUniCore32State *env) -{ - return asr_read(env); -} - -target_ulong HELPER(asr_read)(CPUUniCore32State *env) -{ - return asr_read(env); -} - -static void asr_write(CPUUniCore32State *env, target_ulong val, - target_ulong mask) -{ - if (mask & ASR_NZCV) { - env->ZF = (~val) & ASR_Z; - env->NF = val; - env->CF = (val >> 29) & 1; - env->VF = (val << 3) & 0x80000000; - } - - if ((env->uncached_asr ^ val) & mask & ASR_M) { - switch_mode(env, val & ASR_M); - } - mask &= ~ASR_NZCV; - env->uncached_asr = (env->uncached_asr & ~mask) | (val & mask); -} - -void cpu_asr_write(CPUUniCore32State *env, target_ulong val, target_ulong mask) -{ - asr_write(env, val, mask); -} - -void HELPER(asr_write)(CPUUniCore32State *env, target_ulong val, - target_ulong mask) -{ - asr_write(env, val, mask); -} - -/* Access to user mode registers from privileged modes. */ -uint32_t HELPER(get_user_reg)(CPUUniCore32State *env, uint32_t regno) -{ - uint32_t val; - - if (regno == 29) { - val = env->banked_r29[0]; - } else if (regno == 30) { - val = env->banked_r30[0]; - } else { - val = env->regs[regno]; - } - return val; -} - -void HELPER(set_user_reg)(CPUUniCore32State *env, uint32_t regno, uint32_t val) -{ - if (regno == 29) { - env->banked_r29[0] = val; - } else if (regno == 30) { - env->banked_r30[0] = val; - } else { - env->regs[regno] = val; - } -} - -/* ??? Flag setting arithmetic is awkward because we need to do comparisons. - The only way to do that in TCG is a conditional branch, which clobbers - all our temporaries. For now implement these as helper functions. */ - -uint32_t HELPER(add_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b) -{ - uint32_t result; - result = a + b; - env->NF = env->ZF = result; - env->CF = result < a; - env->VF = (a ^ b ^ -1) & (a ^ result); - return result; -} - -uint32_t HELPER(adc_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b) -{ - uint32_t result; - if (!env->CF) { - result = a + b; - env->CF = result < a; - } else { - result = a + b + 1; - env->CF = result <= a; - } - env->VF = (a ^ b ^ -1) & (a ^ result); - env->NF = env->ZF = result; - return result; -} - -uint32_t HELPER(sub_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b) -{ - uint32_t result; - result = a - b; - env->NF = env->ZF = result; - env->CF = a >= b; - env->VF = (a ^ b) & (a ^ result); - return result; -} - -uint32_t HELPER(sbc_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b) -{ - uint32_t result; - if (!env->CF) { - result = a - b - 1; - env->CF = a > b; - } else { - result = a - b; - env->CF = a >= b; - } - env->VF = (a ^ b) & (a ^ result); - env->NF = env->ZF = result; - return result; -} - -/* Similarly for variable shift instructions. */ - -uint32_t HELPER(shl)(uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) { - return 0; - } - return x << shift; -} - -uint32_t HELPER(shr)(uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) { - return 0; - } - return (uint32_t)x >> shift; -} - -uint32_t HELPER(sar)(uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) { - shift = 31; - } - return (int32_t)x >> shift; -} - -uint32_t HELPER(shl_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) { - if (shift == 32) { - env->CF = x & 1; - } else { - env->CF = 0; - } - return 0; - } else if (shift != 0) { - env->CF = (x >> (32 - shift)) & 1; - return x << shift; - } - return x; -} - -uint32_t HELPER(shr_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) { - if (shift == 32) { - env->CF = (x >> 31) & 1; - } else { - env->CF = 0; - } - return 0; - } else if (shift != 0) { - env->CF = (x >> (shift - 1)) & 1; - return x >> shift; - } - return x; -} - -uint32_t HELPER(sar_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) { - env->CF = (x >> 31) & 1; - return (int32_t)x >> 31; - } else if (shift != 0) { - env->CF = (x >> (shift - 1)) & 1; - return (int32_t)x >> shift; - } - return x; -} - -uint32_t HELPER(ror_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i) -{ - int shift1, shift; - shift1 = i & 0xff; - shift = shift1 & 0x1f; - if (shift == 0) { - if (shift1 != 0) { - env->CF = (x >> 31) & 1; - } - return x; - } else { - env->CF = (x >> (shift - 1)) & 1; - return ((uint32_t)x >> shift) | (x << (32 - shift)); - } -} diff --git a/target/unicore32/softmmu.c b/target/unicore32/softmmu.c deleted file mode 100644 index cbdaa500b7..0000000000 --- a/target/unicore32/softmmu.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Softmmu related functions - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ -#ifdef CONFIG_USER_ONLY -#error This file only exist under softmmu circumstance -#endif - -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/exec-all.h" -#include "qemu/error-report.h" - -#undef DEBUG_UC32 - -#ifdef DEBUG_UC32 -#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif - -#define SUPERPAGE_SIZE (1 << 22) -#define UC32_PAGETABLE_READ (1 << 8) -#define UC32_PAGETABLE_WRITE (1 << 7) -#define UC32_PAGETABLE_EXEC (1 << 6) -#define UC32_PAGETABLE_EXIST (1 << 2) -#define PAGETABLE_TYPE(x) ((x) & 3) - - -/* Map CPU modes onto saved register banks. */ -static inline int bank_number(CPUUniCore32State *env, int mode) -{ - switch (mode) { - case ASR_MODE_USER: - case ASR_MODE_SUSR: - return 0; - case ASR_MODE_PRIV: - return 1; - case ASR_MODE_TRAP: - return 2; - case ASR_MODE_EXTN: - return 3; - case ASR_MODE_INTR: - return 4; - } - cpu_abort(env_cpu(env), "Bad mode %x\n", mode); - return -1; -} - -void switch_mode(CPUUniCore32State *env, int mode) -{ - int old_mode; - int i; - - old_mode = env->uncached_asr & ASR_M; - if (mode == old_mode) { - return; - } - - i = bank_number(env, old_mode); - env->banked_r29[i] = env->regs[29]; - env->banked_r30[i] = env->regs[30]; - env->banked_bsr[i] = env->bsr; - - i = bank_number(env, mode); - env->regs[29] = env->banked_r29[i]; - env->regs[30] = env->banked_r30[i]; - env->bsr = env->banked_bsr[i]; -} - -/* Handle a CPU exception. */ -void uc32_cpu_do_interrupt(CPUState *cs) -{ - UniCore32CPU *cpu = UNICORE32_CPU(cs); - CPUUniCore32State *env = &cpu->env; - uint32_t addr; - int new_mode; - - switch (cs->exception_index) { - case UC32_EXCP_PRIV: - new_mode = ASR_MODE_PRIV; - addr = 0x08; - break; - case UC32_EXCP_ITRAP: - DPRINTF("itrap happened at %x\n", env->regs[31]); - new_mode = ASR_MODE_TRAP; - addr = 0x0c; - break; - case UC32_EXCP_DTRAP: - DPRINTF("dtrap happened at %x\n", env->regs[31]); - new_mode = ASR_MODE_TRAP; - addr = 0x10; - break; - case UC32_EXCP_INTR: - new_mode = ASR_MODE_INTR; - addr = 0x18; - break; - default: - cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); - return; - } - /* High vectors. */ - if (env->cp0.c1_sys & (1 << 13)) { - addr += 0xffff0000; - } - - switch_mode(env, new_mode); - env->bsr = cpu_asr_read(env); - env->uncached_asr = (env->uncached_asr & ~ASR_M) | new_mode; - env->uncached_asr |= ASR_I; - /* The PC already points to the proper instruction. */ - env->regs[30] = env->regs[31]; - env->regs[31] = addr; - cs->interrupt_request |= CPU_INTERRUPT_EXITTB; -} - -static int get_phys_addr_ucv2(CPUUniCore32State *env, uint32_t address, - int access_type, int is_user, uint32_t *phys_ptr, int *prot, - target_ulong *page_size) -{ - CPUState *cs = env_cpu(env); - int code; - uint32_t table; - uint32_t desc; - uint32_t phys_addr; - - /* Pagetable walk. */ - /* Lookup l1 descriptor. */ - table = env->cp0.c2_base & 0xfffff000; - table |= (address >> 20) & 0xffc; - desc = ldl_phys(cs->as, table); - code = 0; - switch (PAGETABLE_TYPE(desc)) { - case 3: - /* Superpage */ - if (!(desc & UC32_PAGETABLE_EXIST)) { - code = 0x0b; /* superpage miss */ - goto do_fault; - } - phys_addr = (desc & 0xffc00000) | (address & 0x003fffff); - *page_size = SUPERPAGE_SIZE; - break; - case 0: - /* Lookup l2 entry. */ - if (is_user) { - DPRINTF("PGD address %x, desc %x\n", table, desc); - } - if (!(desc & UC32_PAGETABLE_EXIST)) { - code = 0x05; /* second pagetable miss */ - goto do_fault; - } - table = (desc & 0xfffff000) | ((address >> 10) & 0xffc); - desc = ldl_phys(cs->as, table); - /* 4k page. */ - if (is_user) { - DPRINTF("PTE address %x, desc %x\n", table, desc); - } - if (!(desc & UC32_PAGETABLE_EXIST)) { - code = 0x08; /* page miss */ - goto do_fault; - } - switch (PAGETABLE_TYPE(desc)) { - case 0: - phys_addr = (desc & 0xfffff000) | (address & 0xfff); - *page_size = TARGET_PAGE_SIZE; - break; - default: - cpu_abort(cs, "wrong page type!"); - } - break; - default: - cpu_abort(cs, "wrong page type!"); - } - - *phys_ptr = phys_addr; - *prot = 0; - /* Check access permissions. */ - if (desc & UC32_PAGETABLE_READ) { - *prot |= PAGE_READ; - } else { - if (is_user && (access_type == 0)) { - code = 0x11; /* access unreadable area */ - goto do_fault; - } - } - - if (desc & UC32_PAGETABLE_WRITE) { - *prot |= PAGE_WRITE; - } else { - if (is_user && (access_type == 1)) { - code = 0x12; /* access unwritable area */ - goto do_fault; - } - } - - if (desc & UC32_PAGETABLE_EXEC) { - *prot |= PAGE_EXEC; - } else { - if (is_user && (access_type == 2)) { - code = 0x13; /* access unexecutable area */ - goto do_fault; - } - } - -do_fault: - return code; -} - -bool uc32_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr) -{ - UniCore32CPU *cpu = UNICORE32_CPU(cs); - CPUUniCore32State *env = &cpu->env; - uint32_t phys_addr; - target_ulong page_size; - int prot; - int ret, is_user; - - ret = 1; - is_user = mmu_idx == MMU_USER_IDX; - - if ((env->cp0.c1_sys & 1) == 0) { - /* MMU disabled. */ - phys_addr = address; - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - page_size = TARGET_PAGE_SIZE; - ret = 0; - } else { - if ((address & (1 << 31)) || (is_user)) { - ret = get_phys_addr_ucv2(env, address, access_type, is_user, - &phys_addr, &prot, &page_size); - if (is_user) { - DPRINTF("user space access: ret %x, address %" VADDR_PRIx ", " - "access_type %x, phys_addr %x, prot %x\n", - ret, address, access_type, phys_addr, prot); - } - } else { - /*IO memory */ - phys_addr = address | (1 << 31); - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - page_size = TARGET_PAGE_SIZE; - ret = 0; - } - } - - if (ret == 0) { - /* Map a single page. */ - phys_addr &= TARGET_PAGE_MASK; - address &= TARGET_PAGE_MASK; - tlb_set_page(cs, address, phys_addr, prot, mmu_idx, page_size); - return true; - } - - if (probe) { - return false; - } - - env->cp0.c3_faultstatus = ret; - env->cp0.c4_faultaddr = address; - if (access_type == 2) { - cs->exception_index = UC32_EXCP_ITRAP; - } else { - cs->exception_index = UC32_EXCP_DTRAP; - } - cpu_loop_exit_restore(cs, retaddr); -} - -hwaddr uc32_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) -{ - error_report("function uc32_cpu_get_phys_page_debug not " - "implemented, aborting"); - return -1; -} diff --git a/target/unicore32/translate.c b/target/unicore32/translate.c deleted file mode 100644 index 370709c9ea..0000000000 --- a/target/unicore32/translate.c +++ /dev/null @@ -1,2083 +0,0 @@ -/* - * UniCore32 translation - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or (at your option) any - * later version. See the COPYING file in the top-level directory. - */ -#include "qemu/osdep.h" - -#include "cpu.h" -#include "disas/disas.h" -#include "exec/exec-all.h" -#include "tcg/tcg-op.h" -#include "qemu/log.h" -#include "exec/cpu_ldst.h" -#include "exec/translator.h" -#include "qemu/qemu-print.h" - -#include "exec/helper-proto.h" -#include "exec/helper-gen.h" - -#include "trace-tcg.h" -#include "exec/log.h" - - -/* internal defines */ -typedef struct DisasContext { - target_ulong pc; - int is_jmp; - /* Nonzero if this instruction has been conditionally skipped. */ - int condjmp; - /* The label that will be jumped to when the instruction is skipped. */ - TCGLabel *condlabel; - TranslationBlock *tb; - int singlestep_enabled; -#ifndef CONFIG_USER_ONLY - int user; -#endif -} DisasContext; - -#ifndef CONFIG_USER_ONLY -#define IS_USER(s) (s->user) -#else -#define IS_USER(s) 1 -#endif - -/* is_jmp field values */ -#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ -#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ -#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */ -/* These instructions trap after executing, so defer them until after the - conditional executions state has been updated. */ -#define DISAS_SYSCALL DISAS_TARGET_3 - -static TCGv_i32 cpu_R[32]; - -/* FIXME: These should be removed. */ -static TCGv cpu_F0s, cpu_F1s; -static TCGv_i64 cpu_F0d, cpu_F1d; - -#include "exec/gen-icount.h" - -static const char *regnames[] = { - "r00", "r01", "r02", "r03", "r04", "r05", "r06", "r07", - "r08", "r09", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "r29", "r30", "pc" }; - -/* initialize TCG globals. */ -void uc32_translate_init(void) -{ - int i; - - for (i = 0; i < 32; i++) { - cpu_R[i] = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUUniCore32State, regs[i]), regnames[i]); - } -} - -static int num_temps; - -/* Allocate a temporary variable. */ -static TCGv_i32 new_tmp(void) -{ - num_temps++; - return tcg_temp_new_i32(); -} - -/* Release a temporary variable. */ -static void dead_tmp(TCGv tmp) -{ - tcg_temp_free(tmp); - num_temps--; -} - -static inline TCGv load_cpu_offset(int offset) -{ - TCGv tmp = new_tmp(); - tcg_gen_ld_i32(tmp, cpu_env, offset); - return tmp; -} - -#define load_cpu_field(name) load_cpu_offset(offsetof(CPUUniCore32State, name)) - -static inline void store_cpu_offset(TCGv var, int offset) -{ - tcg_gen_st_i32(var, cpu_env, offset); - dead_tmp(var); -} - -#define store_cpu_field(var, name) \ - store_cpu_offset(var, offsetof(CPUUniCore32State, name)) - -/* Set a variable to the value of a CPU register. */ -static void load_reg_var(DisasContext *s, TCGv var, int reg) -{ - if (reg == 31) { - uint32_t addr; - /* normaly, since we updated PC */ - addr = (long)s->pc; - tcg_gen_movi_i32(var, addr); - } else { - tcg_gen_mov_i32(var, cpu_R[reg]); - } -} - -/* Create a new temporary and set it to the value of a CPU register. */ -static inline TCGv load_reg(DisasContext *s, int reg) -{ - TCGv tmp = new_tmp(); - load_reg_var(s, tmp, reg); - return tmp; -} - -/* Set a CPU register. The source must be a temporary and will be - marked as dead. */ -static void store_reg(DisasContext *s, int reg, TCGv var) -{ - if (reg == 31) { - tcg_gen_andi_i32(var, var, ~3); - s->is_jmp = DISAS_JUMP; - } - tcg_gen_mov_i32(cpu_R[reg], var); - dead_tmp(var); -} - -/* Value extensions. */ -#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var) -#define gen_uxth(var) tcg_gen_ext16u_i32(var, var) -#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var) -#define gen_sxth(var) tcg_gen_ext16s_i32(var, var) - -#define UCOP_REG_M (((insn) >> 0) & 0x1f) -#define UCOP_REG_N (((insn) >> 19) & 0x1f) -#define UCOP_REG_D (((insn) >> 14) & 0x1f) -#define UCOP_REG_S (((insn) >> 9) & 0x1f) -#define UCOP_REG_LO (((insn) >> 14) & 0x1f) -#define UCOP_REG_HI (((insn) >> 9) & 0x1f) -#define UCOP_SH_OP (((insn) >> 6) & 0x03) -#define UCOP_SH_IM (((insn) >> 9) & 0x1f) -#define UCOP_OPCODES (((insn) >> 25) & 0x0f) -#define UCOP_IMM_9 (((insn) >> 0) & 0x1ff) -#define UCOP_IMM10 (((insn) >> 0) & 0x3ff) -#define UCOP_IMM14 (((insn) >> 0) & 0x3fff) -#define UCOP_COND (((insn) >> 25) & 0x0f) -#define UCOP_CMOV_COND (((insn) >> 19) & 0x0f) -#define UCOP_CPNUM (((insn) >> 10) & 0x0f) -#define UCOP_UCF64_FMT (((insn) >> 24) & 0x03) -#define UCOP_UCF64_FUNC (((insn) >> 6) & 0x0f) -#define UCOP_UCF64_COND (((insn) >> 6) & 0x0f) - -#define UCOP_SET(i) ((insn) & (1 << (i))) -#define UCOP_SET_P UCOP_SET(28) -#define UCOP_SET_U UCOP_SET(27) -#define UCOP_SET_B UCOP_SET(26) -#define UCOP_SET_W UCOP_SET(25) -#define UCOP_SET_L UCOP_SET(24) -#define UCOP_SET_S UCOP_SET(24) - -#define ILLEGAL cpu_abort(env_cpu(env), \ - "Illegal UniCore32 instruction %x at line %d!", \ - insn, __LINE__) - -#ifndef CONFIG_USER_ONLY -static void disas_cp0_insn(CPUUniCore32State *env, DisasContext *s, - uint32_t insn) -{ - TCGv tmp, tmp2, tmp3; - if ((insn & 0xfe000000) == 0xe0000000) { - tmp2 = new_tmp(); - tmp3 = new_tmp(); - tcg_gen_movi_i32(tmp2, UCOP_REG_N); - tcg_gen_movi_i32(tmp3, UCOP_IMM10); - if (UCOP_SET_L) { - tmp = new_tmp(); - gen_helper_cp0_get(tmp, cpu_env, tmp2, tmp3); - store_reg(s, UCOP_REG_D, tmp); - } else { - tmp = load_reg(s, UCOP_REG_D); - gen_helper_cp0_set(cpu_env, tmp, tmp2, tmp3); - dead_tmp(tmp); - } - dead_tmp(tmp2); - dead_tmp(tmp3); - return; - } - ILLEGAL; -} - -static void disas_ocd_insn(CPUUniCore32State *env, DisasContext *s, - uint32_t insn) -{ - TCGv tmp; - - if ((insn & 0xff003fff) == 0xe1000400) { - /* - * movc rd, pp.nn, #imm9 - * rd: UCOP_REG_D - * nn: UCOP_REG_N (must be 0) - * imm9: 0 - */ - if (UCOP_REG_N == 0) { - tmp = new_tmp(); - tcg_gen_movi_i32(tmp, 0); - store_reg(s, UCOP_REG_D, tmp); - return; - } else { - ILLEGAL; - } - } - if ((insn & 0xff003fff) == 0xe0000401) { - /* - * movc pp.nn, rn, #imm9 - * rn: UCOP_REG_D - * nn: UCOP_REG_N (must be 1) - * imm9: 1 - */ - if (UCOP_REG_N == 1) { - tmp = load_reg(s, UCOP_REG_D); - gen_helper_cp1_putc(tmp); - dead_tmp(tmp); - return; - } else { - ILLEGAL; - } - } - ILLEGAL; -} -#endif - -static inline void gen_set_asr(TCGv var, uint32_t mask) -{ - TCGv tmp_mask = tcg_const_i32(mask); - gen_helper_asr_write(cpu_env, var, tmp_mask); - tcg_temp_free_i32(tmp_mask); -} -/* Set NZCV flags from the high 4 bits of var. */ -#define gen_set_nzcv(var) gen_set_asr(var, ASR_NZCV) - -static void gen_exception(int excp) -{ - TCGv tmp = new_tmp(); - tcg_gen_movi_i32(tmp, excp); - gen_helper_exception(cpu_env, tmp); - dead_tmp(tmp); -} - -#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, CF)) - -/* Set CF to the top bit of var. */ -static void gen_set_CF_bit31(TCGv var) -{ - TCGv tmp = new_tmp(); - tcg_gen_shri_i32(tmp, var, 31); - gen_set_CF(tmp); - dead_tmp(tmp); -} - -/* Set N and Z flags from var. */ -static inline void gen_logic_CC(TCGv var) -{ - tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, NF)); - tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, ZF)); -} - -/* dest = T0 + T1 + CF. */ -static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1) -{ - TCGv tmp; - tcg_gen_add_i32(dest, t0, t1); - tmp = load_cpu_field(CF); - tcg_gen_add_i32(dest, dest, tmp); - dead_tmp(tmp); -} - -/* dest = T0 - T1 + CF - 1. */ -static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1) -{ - TCGv tmp; - tcg_gen_sub_i32(dest, t0, t1); - tmp = load_cpu_field(CF); - tcg_gen_add_i32(dest, dest, tmp); - tcg_gen_subi_i32(dest, dest, 1); - dead_tmp(tmp); -} - -static void shifter_out_im(TCGv var, int shift) -{ - TCGv tmp = new_tmp(); - if (shift == 0) { - tcg_gen_andi_i32(tmp, var, 1); - } else { - tcg_gen_shri_i32(tmp, var, shift); - if (shift != 31) { - tcg_gen_andi_i32(tmp, tmp, 1); - } - } - gen_set_CF(tmp); - dead_tmp(tmp); -} - -/* Shift by immediate. Includes special handling for shift == 0. */ -static inline void gen_uc32_shift_im(TCGv var, int shiftop, int shift, - int flags) -{ - switch (shiftop) { - case 0: /* LSL */ - if (shift != 0) { - if (flags) { - shifter_out_im(var, 32 - shift); - } - tcg_gen_shli_i32(var, var, shift); - } - break; - case 1: /* LSR */ - if (shift == 0) { - if (flags) { - tcg_gen_shri_i32(var, var, 31); - gen_set_CF(var); - } - tcg_gen_movi_i32(var, 0); - } else { - if (flags) { - shifter_out_im(var, shift - 1); - } - tcg_gen_shri_i32(var, var, shift); - } - break; - case 2: /* ASR */ - if (shift == 0) { - shift = 32; - } - if (flags) { - shifter_out_im(var, shift - 1); - } - if (shift == 32) { - shift = 31; - } - tcg_gen_sari_i32(var, var, shift); - break; - case 3: /* ROR/RRX */ - if (shift != 0) { - if (flags) { - shifter_out_im(var, shift - 1); - } - tcg_gen_rotri_i32(var, var, shift); break; - } else { - TCGv tmp = load_cpu_field(CF); - if (flags) { - shifter_out_im(var, 0); - } - tcg_gen_shri_i32(var, var, 1); - tcg_gen_shli_i32(tmp, tmp, 31); - tcg_gen_or_i32(var, var, tmp); - dead_tmp(tmp); - } - } -}; - -static inline void gen_uc32_shift_reg(TCGv var, int shiftop, - TCGv shift, int flags) -{ - if (flags) { - switch (shiftop) { - case 0: - gen_helper_shl_cc(var, cpu_env, var, shift); - break; - case 1: - gen_helper_shr_cc(var, cpu_env, var, shift); - break; - case 2: - gen_helper_sar_cc(var, cpu_env, var, shift); - break; - case 3: - gen_helper_ror_cc(var, cpu_env, var, shift); - break; - } - } else { - switch (shiftop) { - case 0: - gen_helper_shl(var, var, shift); - break; - case 1: - gen_helper_shr(var, var, shift); - break; - case 2: - gen_helper_sar(var, var, shift); - break; - case 3: - tcg_gen_andi_i32(shift, shift, 0x1f); - tcg_gen_rotr_i32(var, var, shift); - break; - } - } - dead_tmp(shift); -} - -static void gen_test_cc(int cc, TCGLabel *label) -{ - TCGv tmp; - TCGv tmp2; - TCGLabel *inv; - - switch (cc) { - case 0: /* eq: Z */ - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); - break; - case 1: /* ne: !Z */ - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); - break; - case 2: /* cs: C */ - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); - break; - case 3: /* cc: !C */ - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); - break; - case 4: /* mi: N */ - tmp = load_cpu_field(NF); - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); - break; - case 5: /* pl: !N */ - tmp = load_cpu_field(NF); - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); - break; - case 6: /* vs: V */ - tmp = load_cpu_field(VF); - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); - break; - case 7: /* vc: !V */ - tmp = load_cpu_field(VF); - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); - break; - case 8: /* hi: C && !Z */ - inv = gen_new_label(); - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); - dead_tmp(tmp); - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); - gen_set_label(inv); - break; - case 9: /* ls: !C || Z */ - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); - dead_tmp(tmp); - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); - break; - case 10: /* ge: N == V -> N ^ V == 0 */ - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - dead_tmp(tmp2); - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); - break; - case 11: /* lt: N != V -> N ^ V != 0 */ - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - dead_tmp(tmp2); - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); - break; - case 12: /* gt: !Z && N == V */ - inv = gen_new_label(); - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); - dead_tmp(tmp); - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - dead_tmp(tmp2); - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); - gen_set_label(inv); - break; - case 13: /* le: Z || N != V */ - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); - dead_tmp(tmp); - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - dead_tmp(tmp2); - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); - break; - default: - fprintf(stderr, "Bad condition code 0x%x\n", cc); - abort(); - } - dead_tmp(tmp); -} - -static const uint8_t table_logic_cc[16] = { - 1, /* and */ 1, /* xor */ 0, /* sub */ 0, /* rsb */ - 0, /* add */ 0, /* adc */ 0, /* sbc */ 0, /* rsc */ - 1, /* andl */ 1, /* xorl */ 0, /* cmp */ 0, /* cmn */ - 1, /* orr */ 1, /* mov */ 1, /* bic */ 1, /* mvn */ -}; - -/* Set PC state from an immediate address. */ -static inline void gen_bx_im(DisasContext *s, uint32_t addr) -{ - s->is_jmp = DISAS_UPDATE; - tcg_gen_movi_i32(cpu_R[31], addr & ~3); -} - -/* Set PC state from var. var is marked as dead. */ -static inline void gen_bx(DisasContext *s, TCGv var) -{ - s->is_jmp = DISAS_UPDATE; - tcg_gen_andi_i32(cpu_R[31], var, ~3); - dead_tmp(var); -} - -static inline void store_reg_bx(DisasContext *s, int reg, TCGv var) -{ - store_reg(s, reg, var); -} - -static inline TCGv gen_ld8s(TCGv addr, int index) -{ - TCGv tmp = new_tmp(); - tcg_gen_qemu_ld8s(tmp, addr, index); - return tmp; -} - -static inline TCGv gen_ld8u(TCGv addr, int index) -{ - TCGv tmp = new_tmp(); - tcg_gen_qemu_ld8u(tmp, addr, index); - return tmp; -} - -static inline TCGv gen_ld16s(TCGv addr, int index) -{ - TCGv tmp = new_tmp(); - tcg_gen_qemu_ld16s(tmp, addr, index); - return tmp; -} - -static inline TCGv gen_ld16u(TCGv addr, int index) -{ - TCGv tmp = new_tmp(); - tcg_gen_qemu_ld16u(tmp, addr, index); - return tmp; -} - -static inline TCGv gen_ld32(TCGv addr, int index) -{ - TCGv tmp = new_tmp(); - tcg_gen_qemu_ld32u(tmp, addr, index); - return tmp; -} - -static inline void gen_st8(TCGv val, TCGv addr, int index) -{ - tcg_gen_qemu_st8(val, addr, index); - dead_tmp(val); -} - -static inline void gen_st16(TCGv val, TCGv addr, int index) -{ - tcg_gen_qemu_st16(val, addr, index); - dead_tmp(val); -} - -static inline void gen_st32(TCGv val, TCGv addr, int index) -{ - tcg_gen_qemu_st32(val, addr, index); - dead_tmp(val); -} - -static inline void gen_set_pc_im(uint32_t val) -{ - tcg_gen_movi_i32(cpu_R[31], val); -} - -/* Force a TB lookup after an instruction that changes the CPU state. */ -static inline void gen_lookup_tb(DisasContext *s) -{ - tcg_gen_movi_i32(cpu_R[31], s->pc & ~1); - s->is_jmp = DISAS_UPDATE; -} - -static inline void gen_add_data_offset(DisasContext *s, unsigned int insn, - TCGv var) -{ - int val; - TCGv offset; - - if (UCOP_SET(29)) { - /* immediate */ - val = UCOP_IMM14; - if (!UCOP_SET_U) { - val = -val; - } - if (val != 0) { - tcg_gen_addi_i32(var, var, val); - } - } else { - /* shift/register */ - offset = load_reg(s, UCOP_REG_M); - gen_uc32_shift_im(offset, UCOP_SH_OP, UCOP_SH_IM, 0); - if (!UCOP_SET_U) { - tcg_gen_sub_i32(var, var, offset); - } else { - tcg_gen_add_i32(var, var, offset); - } - dead_tmp(offset); - } -} - -static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn, - TCGv var) -{ - int val; - TCGv offset; - - if (UCOP_SET(26)) { - /* immediate */ - val = (insn & 0x1f) | ((insn >> 4) & 0x3e0); - if (!UCOP_SET_U) { - val = -val; - } - if (val != 0) { - tcg_gen_addi_i32(var, var, val); - } - } else { - /* register */ - offset = load_reg(s, UCOP_REG_M); - if (!UCOP_SET_U) { - tcg_gen_sub_i32(var, var, offset); - } else { - tcg_gen_add_i32(var, var, offset); - } - dead_tmp(offset); - } -} - -static inline long ucf64_reg_offset(int reg) -{ - if (reg & 1) { - return offsetof(CPUUniCore32State, ucf64.regs[reg >> 1]) - + offsetof(CPU_DoubleU, l.upper); - } else { - return offsetof(CPUUniCore32State, ucf64.regs[reg >> 1]) - + offsetof(CPU_DoubleU, l.lower); - } -} - -#define ucf64_gen_ld32(reg) load_cpu_offset(ucf64_reg_offset(reg)) -#define ucf64_gen_st32(var, reg) store_cpu_offset(var, ucf64_reg_offset(reg)) - -/* UniCore-F64 single load/store I_offset */ -static void do_ucf64_ldst_i(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - int offset; - TCGv tmp; - TCGv addr; - - addr = load_reg(s, UCOP_REG_N); - if (!UCOP_SET_P && !UCOP_SET_W) { - ILLEGAL; - } - - if (UCOP_SET_P) { - offset = UCOP_IMM10 << 2; - if (!UCOP_SET_U) { - offset = -offset; - } - if (offset != 0) { - tcg_gen_addi_i32(addr, addr, offset); - } - } - - if (UCOP_SET_L) { /* load */ - tmp = gen_ld32(addr, IS_USER(s)); - ucf64_gen_st32(tmp, UCOP_REG_D); - } else { /* store */ - tmp = ucf64_gen_ld32(UCOP_REG_D); - gen_st32(tmp, addr, IS_USER(s)); - } - - if (!UCOP_SET_P) { - offset = UCOP_IMM10 << 2; - if (!UCOP_SET_U) { - offset = -offset; - } - if (offset != 0) { - tcg_gen_addi_i32(addr, addr, offset); - } - } - if (UCOP_SET_W) { - store_reg(s, UCOP_REG_N, addr); - } else { - dead_tmp(addr); - } -} - -/* UniCore-F64 load/store multiple words */ -static void do_ucf64_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - unsigned int i; - int j, n, freg; - TCGv tmp; - TCGv addr; - - if (UCOP_REG_D != 0) { - ILLEGAL; - } - if (UCOP_REG_N == 31) { - ILLEGAL; - } - if ((insn << 24) == 0) { - ILLEGAL; - } - - addr = load_reg(s, UCOP_REG_N); - - n = 0; - for (i = 0; i < 8; i++) { - if (UCOP_SET(i)) { - n++; - } - } - - if (UCOP_SET_U) { - if (UCOP_SET_P) { /* pre increment */ - tcg_gen_addi_i32(addr, addr, 4); - } /* unnecessary to do anything when post increment */ - } else { - if (UCOP_SET_P) { /* pre decrement */ - tcg_gen_addi_i32(addr, addr, -(n * 4)); - } else { /* post decrement */ - if (n != 1) { - tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); - } - } - } - - freg = ((insn >> 8) & 3) << 3; /* freg should be 0, 8, 16, 24 */ - - for (i = 0, j = 0; i < 8; i++, freg++) { - if (!UCOP_SET(i)) { - continue; - } - - if (UCOP_SET_L) { /* load */ - tmp = gen_ld32(addr, IS_USER(s)); - ucf64_gen_st32(tmp, freg); - } else { /* store */ - tmp = ucf64_gen_ld32(freg); - gen_st32(tmp, addr, IS_USER(s)); - } - - j++; - /* unnecessary to add after the last transfer */ - if (j != n) { - tcg_gen_addi_i32(addr, addr, 4); - } - } - - if (UCOP_SET_W) { /* write back */ - if (UCOP_SET_U) { - if (!UCOP_SET_P) { /* post increment */ - tcg_gen_addi_i32(addr, addr, 4); - } /* unnecessary to do anything when pre increment */ - } else { - if (UCOP_SET_P) { - /* pre decrement */ - if (n != 1) { - tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); - } - } else { - /* post decrement */ - tcg_gen_addi_i32(addr, addr, -(n * 4)); - } - } - store_reg(s, UCOP_REG_N, addr); - } else { - dead_tmp(addr); - } -} - -/* UniCore-F64 mrc/mcr */ -static void do_ucf64_trans(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - TCGv tmp; - - if ((insn & 0xfe0003ff) == 0xe2000000) { - /* control register */ - if ((UCOP_REG_N != UC32_UCF64_FPSCR) || (UCOP_REG_D == 31)) { - ILLEGAL; - } - if (UCOP_SET(24)) { - /* CFF */ - tmp = new_tmp(); - gen_helper_ucf64_get_fpscr(tmp, cpu_env); - store_reg(s, UCOP_REG_D, tmp); - } else { - /* CTF */ - tmp = load_reg(s, UCOP_REG_D); - gen_helper_ucf64_set_fpscr(cpu_env, tmp); - dead_tmp(tmp); - gen_lookup_tb(s); - } - return; - } - if ((insn & 0xfe0003ff) == 0xe0000000) { - /* general register */ - if (UCOP_REG_D == 31) { - ILLEGAL; - } - if (UCOP_SET(24)) { /* MFF */ - tmp = ucf64_gen_ld32(UCOP_REG_N); - store_reg(s, UCOP_REG_D, tmp); - } else { /* MTF */ - tmp = load_reg(s, UCOP_REG_D); - ucf64_gen_st32(tmp, UCOP_REG_N); - } - return; - } - if ((insn & 0xfb000000) == 0xe9000000) { - /* MFFC */ - if (UCOP_REG_D != 31) { - ILLEGAL; - } - if (UCOP_UCF64_COND & 0x8) { - ILLEGAL; - } - - tmp = new_tmp(); - tcg_gen_movi_i32(tmp, UCOP_UCF64_COND); - if (UCOP_SET(26)) { - tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N)); - tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, tmp, cpu_env); - } else { - tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N)); - tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, tmp, cpu_env); - } - dead_tmp(tmp); - return; - } - ILLEGAL; -} - -/* UniCore-F64 convert instructions */ -static void do_ucf64_fcvt(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - if (UCOP_UCF64_FMT == 3) { - ILLEGAL; - } - if (UCOP_REG_N != 0) { - ILLEGAL; - } - switch (UCOP_UCF64_FUNC) { - case 0: /* cvt.s */ - switch (UCOP_UCF64_FMT) { - case 1 /* d */: - tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_df2sf(cpu_F0s, cpu_F0d, cpu_env); - tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); - break; - case 2 /* w */: - tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_si2sf(cpu_F0s, cpu_F0s, cpu_env); - tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); - break; - default /* s */: - ILLEGAL; - break; - } - break; - case 1: /* cvt.d */ - switch (UCOP_UCF64_FMT) { - case 0 /* s */: - tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_sf2df(cpu_F0d, cpu_F0s, cpu_env); - tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D)); - break; - case 2 /* w */: - tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_si2df(cpu_F0d, cpu_F0s, cpu_env); - tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D)); - break; - default /* d */: - ILLEGAL; - break; - } - break; - case 4: /* cvt.w */ - switch (UCOP_UCF64_FMT) { - case 0 /* s */: - tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_sf2si(cpu_F0s, cpu_F0s, cpu_env); - tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); - break; - case 1 /* d */: - tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_df2si(cpu_F0s, cpu_F0d, cpu_env); - tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); - break; - default /* w */: - ILLEGAL; - break; - } - break; - default: - ILLEGAL; - } -} - -/* UniCore-F64 compare instructions */ -static void do_ucf64_fcmp(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - if (UCOP_SET(25)) { - ILLEGAL; - } - if (UCOP_REG_D != 0) { - ILLEGAL; - } - - ILLEGAL; /* TODO */ - if (UCOP_SET(24)) { - tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N)); - tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - /* gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, cpu_env); */ - } else { - tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N)); - tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - /* gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, cpu_env); */ - } -} - -#define gen_helper_ucf64_movs(x, y) do { } while (0) -#define gen_helper_ucf64_movd(x, y) do { } while (0) - -#define UCF64_OP1(name) do { \ - if (UCOP_REG_N != 0) { \ - ILLEGAL; \ - } \ - switch (UCOP_UCF64_FMT) { \ - case 0 /* s */: \ - tcg_gen_ld_i32(cpu_F0s, cpu_env, \ - ucf64_reg_offset(UCOP_REG_M)); \ - gen_helper_ucf64_##name##s(cpu_F0s, cpu_F0s); \ - tcg_gen_st_i32(cpu_F0s, cpu_env, \ - ucf64_reg_offset(UCOP_REG_D)); \ - break; \ - case 1 /* d */: \ - tcg_gen_ld_i64(cpu_F0d, cpu_env, \ - ucf64_reg_offset(UCOP_REG_M)); \ - gen_helper_ucf64_##name##d(cpu_F0d, cpu_F0d); \ - tcg_gen_st_i64(cpu_F0d, cpu_env, \ - ucf64_reg_offset(UCOP_REG_D)); \ - break; \ - case 2 /* w */: \ - ILLEGAL; \ - break; \ - } \ - } while (0) - -#define UCF64_OP2(name) do { \ - switch (UCOP_UCF64_FMT) { \ - case 0 /* s */: \ - tcg_gen_ld_i32(cpu_F0s, cpu_env, \ - ucf64_reg_offset(UCOP_REG_N)); \ - tcg_gen_ld_i32(cpu_F1s, cpu_env, \ - ucf64_reg_offset(UCOP_REG_M)); \ - gen_helper_ucf64_##name##s(cpu_F0s, \ - cpu_F0s, cpu_F1s, cpu_env); \ - tcg_gen_st_i32(cpu_F0s, cpu_env, \ - ucf64_reg_offset(UCOP_REG_D)); \ - break; \ - case 1 /* d */: \ - tcg_gen_ld_i64(cpu_F0d, cpu_env, \ - ucf64_reg_offset(UCOP_REG_N)); \ - tcg_gen_ld_i64(cpu_F1d, cpu_env, \ - ucf64_reg_offset(UCOP_REG_M)); \ - gen_helper_ucf64_##name##d(cpu_F0d, \ - cpu_F0d, cpu_F1d, cpu_env); \ - tcg_gen_st_i64(cpu_F0d, cpu_env, \ - ucf64_reg_offset(UCOP_REG_D)); \ - break; \ - case 2 /* w */: \ - ILLEGAL; \ - break; \ - } \ - } while (0) - -/* UniCore-F64 data processing */ -static void do_ucf64_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - if (UCOP_UCF64_FMT == 3) { - ILLEGAL; - } - switch (UCOP_UCF64_FUNC) { - case 0: /* add */ - UCF64_OP2(add); - break; - case 1: /* sub */ - UCF64_OP2(sub); - break; - case 2: /* mul */ - UCF64_OP2(mul); - break; - case 4: /* div */ - UCF64_OP2(div); - break; - case 5: /* abs */ - UCF64_OP1(abs); - break; - case 6: /* mov */ - UCF64_OP1(mov); - break; - case 7: /* neg */ - UCF64_OP1(neg); - break; - default: - ILLEGAL; - } -} - -/* Disassemble an F64 instruction */ -static void disas_ucf64_insn(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - if (!UCOP_SET(29)) { - if (UCOP_SET(26)) { - do_ucf64_ldst_m(env, s, insn); - } else { - do_ucf64_ldst_i(env, s, insn); - } - } else { - if (UCOP_SET(5)) { - switch ((insn >> 26) & 0x3) { - case 0: - do_ucf64_datap(env, s, insn); - break; - case 1: - ILLEGAL; - break; - case 2: - do_ucf64_fcvt(env, s, insn); - break; - case 3: - do_ucf64_fcmp(env, s, insn); - break; - } - } else { - do_ucf64_trans(env, s, insn); - } - } -} - -static inline bool use_goto_tb(DisasContext *s, uint32_t dest) -{ -#ifndef CONFIG_USER_ONLY - return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); -#else - return true; -#endif -} - -static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest) -{ - if (use_goto_tb(s, dest)) { - tcg_gen_goto_tb(n); - gen_set_pc_im(dest); - tcg_gen_exit_tb(s->tb, n); - } else { - gen_set_pc_im(dest); - tcg_gen_exit_tb(NULL, 0); - } -} - -static inline void gen_jmp(DisasContext *s, uint32_t dest) -{ - if (unlikely(s->singlestep_enabled)) { - /* An indirect jump so that we still trigger the debug exception. */ - gen_bx_im(s, dest); - } else { - gen_goto_tb(s, 0, dest); - s->is_jmp = DISAS_TB_JUMP; - } -} - -/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */ -static int gen_set_psr(DisasContext *s, uint32_t mask, int bsr, TCGv t0) -{ - TCGv tmp; - if (bsr) { - /* ??? This is also undefined in system mode. */ - if (IS_USER(s)) { - return 1; - } - - tmp = load_cpu_field(bsr); - tcg_gen_andi_i32(tmp, tmp, ~mask); - tcg_gen_andi_i32(t0, t0, mask); - tcg_gen_or_i32(tmp, tmp, t0); - store_cpu_field(tmp, bsr); - } else { - gen_set_asr(t0, mask); - } - dead_tmp(t0); - gen_lookup_tb(s); - return 0; -} - -/* Generate an old-style exception return. Marks pc as dead. */ -static void gen_exception_return(DisasContext *s, TCGv pc) -{ - TCGv tmp; - store_reg(s, 31, pc); - tmp = load_cpu_field(bsr); - gen_set_asr(tmp, 0xffffffff); - dead_tmp(tmp); - s->is_jmp = DISAS_UPDATE; -} - -static void disas_coproc_insn(CPUUniCore32State *env, DisasContext *s, - uint32_t insn) -{ - switch (UCOP_CPNUM) { -#ifndef CONFIG_USER_ONLY - case 0: - disas_cp0_insn(env, s, insn); - break; - case 1: - disas_ocd_insn(env, s, insn); - break; -#endif - case 2: - disas_ucf64_insn(env, s, insn); - break; - default: - /* Unknown coprocessor. */ - cpu_abort(env_cpu(env), "Unknown coprocessor!"); - } -} - -/* data processing instructions */ -static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - TCGv tmp; - TCGv tmp2; - int logic_cc; - - if (UCOP_OPCODES == 0x0f || UCOP_OPCODES == 0x0d) { - if (UCOP_SET(23)) { /* CMOV instructions */ - if ((UCOP_CMOV_COND == 0xe) || (UCOP_CMOV_COND == 0xf)) { - ILLEGAL; - } - /* if not always execute, we generate a conditional jump to - next instruction */ - s->condlabel = gen_new_label(); - gen_test_cc(UCOP_CMOV_COND ^ 1, s->condlabel); - s->condjmp = 1; - } - } - - logic_cc = table_logic_cc[UCOP_OPCODES] & (UCOP_SET_S >> 24); - - if (UCOP_SET(29)) { - unsigned int val; - /* immediate operand */ - val = UCOP_IMM_9; - if (UCOP_SH_IM) { - val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM)); - } - tmp2 = new_tmp(); - tcg_gen_movi_i32(tmp2, val); - if (logic_cc && UCOP_SH_IM) { - gen_set_CF_bit31(tmp2); - } - } else { - /* register */ - tmp2 = load_reg(s, UCOP_REG_M); - if (UCOP_SET(5)) { - tmp = load_reg(s, UCOP_REG_S); - gen_uc32_shift_reg(tmp2, UCOP_SH_OP, tmp, logic_cc); - } else { - gen_uc32_shift_im(tmp2, UCOP_SH_OP, UCOP_SH_IM, logic_cc); - } - } - - if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) { - tmp = load_reg(s, UCOP_REG_N); - } else { - tmp = NULL; - } - - switch (UCOP_OPCODES) { - case 0x00: - tcg_gen_and_i32(tmp, tmp, tmp2); - if (logic_cc) { - gen_logic_CC(tmp); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x01: - tcg_gen_xor_i32(tmp, tmp, tmp2); - if (logic_cc) { - gen_logic_CC(tmp); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x02: - if (UCOP_SET_S && UCOP_REG_D == 31) { - /* SUBS r31, ... is used for exception return. */ - if (IS_USER(s)) { - ILLEGAL; - } - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); - gen_exception_return(s, tmp); - } else { - if (UCOP_SET_S) { - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); - } else { - tcg_gen_sub_i32(tmp, tmp, tmp2); - } - store_reg_bx(s, UCOP_REG_D, tmp); - } - break; - case 0x03: - if (UCOP_SET_S) { - gen_helper_sub_cc(tmp, cpu_env, tmp2, tmp); - } else { - tcg_gen_sub_i32(tmp, tmp2, tmp); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x04: - if (UCOP_SET_S) { - gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); - } else { - tcg_gen_add_i32(tmp, tmp, tmp2); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x05: - if (UCOP_SET_S) { - gen_helper_adc_cc(tmp, cpu_env, tmp, tmp2); - } else { - gen_add_carry(tmp, tmp, tmp2); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x06: - if (UCOP_SET_S) { - gen_helper_sbc_cc(tmp, cpu_env, tmp, tmp2); - } else { - gen_sub_carry(tmp, tmp, tmp2); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x07: - if (UCOP_SET_S) { - gen_helper_sbc_cc(tmp, cpu_env, tmp2, tmp); - } else { - gen_sub_carry(tmp, tmp2, tmp); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x08: - if (UCOP_SET_S) { - tcg_gen_and_i32(tmp, tmp, tmp2); - gen_logic_CC(tmp); - } - dead_tmp(tmp); - break; - case 0x09: - if (UCOP_SET_S) { - tcg_gen_xor_i32(tmp, tmp, tmp2); - gen_logic_CC(tmp); - } - dead_tmp(tmp); - break; - case 0x0a: - if (UCOP_SET_S) { - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); - } - dead_tmp(tmp); - break; - case 0x0b: - if (UCOP_SET_S) { - gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); - } - dead_tmp(tmp); - break; - case 0x0c: - tcg_gen_or_i32(tmp, tmp, tmp2); - if (logic_cc) { - gen_logic_CC(tmp); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x0d: - if (logic_cc && UCOP_REG_D == 31) { - /* MOVS r31, ... is used for exception return. */ - if (IS_USER(s)) { - ILLEGAL; - } - gen_exception_return(s, tmp2); - } else { - if (logic_cc) { - gen_logic_CC(tmp2); - } - store_reg_bx(s, UCOP_REG_D, tmp2); - } - break; - case 0x0e: - tcg_gen_andc_i32(tmp, tmp, tmp2); - if (logic_cc) { - gen_logic_CC(tmp); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - default: - case 0x0f: - tcg_gen_not_i32(tmp2, tmp2); - if (logic_cc) { - gen_logic_CC(tmp2); - } - store_reg_bx(s, UCOP_REG_D, tmp2); - break; - } - if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) { - dead_tmp(tmp2); - } -} - -/* multiply */ -static void do_mult(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - TCGv tmp, tmp2, tmp3, tmp4; - - if (UCOP_SET(27)) { - /* 64 bit mul */ - tmp = load_reg(s, UCOP_REG_M); - tmp2 = load_reg(s, UCOP_REG_N); - if (UCOP_SET(26)) { - tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2); - } else { - tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2); - } - if (UCOP_SET(25)) { /* mult accumulate */ - tmp3 = load_reg(s, UCOP_REG_LO); - tmp4 = load_reg(s, UCOP_REG_HI); - tcg_gen_add2_i32(tmp, tmp2, tmp, tmp2, tmp3, tmp4); - dead_tmp(tmp3); - dead_tmp(tmp4); - } - store_reg(s, UCOP_REG_LO, tmp); - store_reg(s, UCOP_REG_HI, tmp2); - } else { - /* 32 bit mul */ - tmp = load_reg(s, UCOP_REG_M); - tmp2 = load_reg(s, UCOP_REG_N); - tcg_gen_mul_i32(tmp, tmp, tmp2); - dead_tmp(tmp2); - if (UCOP_SET(25)) { - /* Add */ - tmp2 = load_reg(s, UCOP_REG_S); - tcg_gen_add_i32(tmp, tmp, tmp2); - dead_tmp(tmp2); - } - if (UCOP_SET_S) { - gen_logic_CC(tmp); - } - store_reg(s, UCOP_REG_D, tmp); - } -} - -/* miscellaneous instructions */ -static void do_misc(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - unsigned int val; - TCGv tmp; - - if ((insn & 0xffffffe0) == 0x10ffc120) { - /* Trivial implementation equivalent to bx. */ - tmp = load_reg(s, UCOP_REG_M); - gen_bx(s, tmp); - return; - } - - if ((insn & 0xfbffc000) == 0x30ffc000) { - /* PSR = immediate */ - val = UCOP_IMM_9; - if (UCOP_SH_IM) { - val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM)); - } - tmp = new_tmp(); - tcg_gen_movi_i32(tmp, val); - if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) { - ILLEGAL; - } - return; - } - - if ((insn & 0xfbffffe0) == 0x12ffc020) { - /* PSR.flag = reg */ - tmp = load_reg(s, UCOP_REG_M); - if (gen_set_psr(s, ASR_NZCV, UCOP_SET_B, tmp)) { - ILLEGAL; - } - return; - } - - if ((insn & 0xfbffffe0) == 0x10ffc020) { - /* PSR = reg */ - tmp = load_reg(s, UCOP_REG_M); - if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) { - ILLEGAL; - } - return; - } - - if ((insn & 0xfbf83fff) == 0x10f80000) { - /* reg = PSR */ - if (UCOP_SET_B) { - if (IS_USER(s)) { - ILLEGAL; - } - tmp = load_cpu_field(bsr); - } else { - tmp = new_tmp(); - gen_helper_asr_read(tmp, cpu_env); - } - store_reg(s, UCOP_REG_D, tmp); - return; - } - - if ((insn & 0xfbf83fe0) == 0x12f80120) { - /* clz */ - tmp = load_reg(s, UCOP_REG_M); - if (UCOP_SET(26)) { - /* clo */ - tcg_gen_not_i32(tmp, tmp); - } - tcg_gen_clzi_i32(tmp, tmp, 32); - store_reg(s, UCOP_REG_D, tmp); - return; - } - - /* otherwise */ - ILLEGAL; -} - -/* load/store I_offset and R_offset */ -static void do_ldst_ir(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - unsigned int mmu_idx; - TCGv tmp; - TCGv tmp2; - - tmp2 = load_reg(s, UCOP_REG_N); - mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W)); - - /* immediate */ - if (UCOP_SET_P) { - gen_add_data_offset(s, insn, tmp2); - } - - if (UCOP_SET_L) { - /* load */ - if (UCOP_SET_B) { - tmp = gen_ld8u(tmp2, mmu_idx); - } else { - tmp = gen_ld32(tmp2, mmu_idx); - } - } else { - /* store */ - tmp = load_reg(s, UCOP_REG_D); - if (UCOP_SET_B) { - gen_st8(tmp, tmp2, mmu_idx); - } else { - gen_st32(tmp, tmp2, mmu_idx); - } - } - if (!UCOP_SET_P) { - gen_add_data_offset(s, insn, tmp2); - store_reg(s, UCOP_REG_N, tmp2); - } else if (UCOP_SET_W) { - store_reg(s, UCOP_REG_N, tmp2); - } else { - dead_tmp(tmp2); - } - if (UCOP_SET_L) { - /* Complete the load. */ - if (UCOP_REG_D == 31) { - gen_bx(s, tmp); - } else { - store_reg(s, UCOP_REG_D, tmp); - } - } -} - -/* SWP instruction */ -static void do_swap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - TCGv addr; - TCGv tmp; - TCGv tmp2; - - if ((insn & 0xff003fe0) != 0x40000120) { - ILLEGAL; - } - - /* ??? This is not really atomic. However we know - we never have multiple CPUs running in parallel, - so it is good enough. */ - addr = load_reg(s, UCOP_REG_N); - tmp = load_reg(s, UCOP_REG_M); - if (UCOP_SET_B) { - tmp2 = gen_ld8u(addr, IS_USER(s)); - gen_st8(tmp, addr, IS_USER(s)); - } else { - tmp2 = gen_ld32(addr, IS_USER(s)); - gen_st32(tmp, addr, IS_USER(s)); - } - dead_tmp(addr); - store_reg(s, UCOP_REG_D, tmp2); -} - -/* load/store hw/sb */ -static void do_ldst_hwsb(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - TCGv addr; - TCGv tmp; - - if (UCOP_SH_OP == 0) { - do_swap(env, s, insn); - return; - } - - addr = load_reg(s, UCOP_REG_N); - if (UCOP_SET_P) { - gen_add_datah_offset(s, insn, addr); - } - - if (UCOP_SET_L) { /* load */ - switch (UCOP_SH_OP) { - case 1: - tmp = gen_ld16u(addr, IS_USER(s)); - break; - case 2: - tmp = gen_ld8s(addr, IS_USER(s)); - break; - default: /* see do_swap */ - case 3: - tmp = gen_ld16s(addr, IS_USER(s)); - break; - } - } else { /* store */ - if (UCOP_SH_OP != 1) { - ILLEGAL; - } - tmp = load_reg(s, UCOP_REG_D); - gen_st16(tmp, addr, IS_USER(s)); - } - /* Perform base writeback before the loaded value to - ensure correct behavior with overlapping index registers. */ - if (!UCOP_SET_P) { - gen_add_datah_offset(s, insn, addr); - store_reg(s, UCOP_REG_N, addr); - } else if (UCOP_SET_W) { - store_reg(s, UCOP_REG_N, addr); - } else { - dead_tmp(addr); - } - if (UCOP_SET_L) { - /* Complete the load. */ - store_reg(s, UCOP_REG_D, tmp); - } -} - -/* load/store multiple words */ -static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - unsigned int val, i, mmu_idx; - int j, n, reg, user, loaded_base; - TCGv tmp; - TCGv tmp2; - TCGv addr; - TCGv loaded_var; - - if (UCOP_SET(7)) { - ILLEGAL; - } - /* XXX: store correct base if write back */ - user = 0; - if (UCOP_SET_B) { /* S bit in instruction table */ - if (IS_USER(s)) { - ILLEGAL; /* only usable in supervisor mode */ - } - if (UCOP_SET(18) == 0) { /* pc reg */ - user = 1; - } - } - - mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W)); - addr = load_reg(s, UCOP_REG_N); - - /* compute total size */ - loaded_base = 0; - loaded_var = NULL; - n = 0; - for (i = 0; i < 6; i++) { - if (UCOP_SET(i)) { - n++; - } - } - for (i = 9; i < 19; i++) { - if (UCOP_SET(i)) { - n++; - } - } - /* XXX: test invalid n == 0 case ? */ - if (UCOP_SET_U) { - if (UCOP_SET_P) { - /* pre increment */ - tcg_gen_addi_i32(addr, addr, 4); - } else { - /* post increment */ - } - } else { - if (UCOP_SET_P) { - /* pre decrement */ - tcg_gen_addi_i32(addr, addr, -(n * 4)); - } else { - /* post decrement */ - if (n != 1) { - tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); - } - } - } - - j = 0; - reg = UCOP_SET(6) ? 16 : 0; - for (i = 0; i < 19; i++, reg++) { - if (i == 6) { - i = i + 3; - } - if (UCOP_SET(i)) { - if (UCOP_SET_L) { /* load */ - tmp = gen_ld32(addr, mmu_idx); - if (reg == 31) { - gen_bx(s, tmp); - } else if (user) { - tmp2 = tcg_const_i32(reg); - gen_helper_set_user_reg(cpu_env, tmp2, tmp); - tcg_temp_free_i32(tmp2); - dead_tmp(tmp); - } else if (reg == UCOP_REG_N) { - loaded_var = tmp; - loaded_base = 1; - } else { - store_reg(s, reg, tmp); - } - } else { /* store */ - if (reg == 31) { - /* special case: r31 = PC + 4 */ - val = (long)s->pc; - tmp = new_tmp(); - tcg_gen_movi_i32(tmp, val); - } else if (user) { - tmp = new_tmp(); - tmp2 = tcg_const_i32(reg); - gen_helper_get_user_reg(tmp, cpu_env, tmp2); - tcg_temp_free_i32(tmp2); - } else { - tmp = load_reg(s, reg); - } - gen_st32(tmp, addr, mmu_idx); - } - j++; - /* no need to add after the last transfer */ - if (j != n) { - tcg_gen_addi_i32(addr, addr, 4); - } - } - } - if (UCOP_SET_W) { /* write back */ - if (UCOP_SET_U) { - if (UCOP_SET_P) { - /* pre increment */ - } else { - /* post increment */ - tcg_gen_addi_i32(addr, addr, 4); - } - } else { - if (UCOP_SET_P) { - /* pre decrement */ - if (n != 1) { - tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); - } - } else { - /* post decrement */ - tcg_gen_addi_i32(addr, addr, -(n * 4)); - } - } - store_reg(s, UCOP_REG_N, addr); - } else { - dead_tmp(addr); - } - if (loaded_base) { - store_reg(s, UCOP_REG_N, loaded_var); - } - if (UCOP_SET_B && !user) { - /* Restore ASR from BSR. */ - tmp = load_cpu_field(bsr); - gen_set_asr(tmp, 0xffffffff); - dead_tmp(tmp); - s->is_jmp = DISAS_UPDATE; - } -} - -/* branch (and link) */ -static void do_branch(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - unsigned int val; - int32_t offset; - TCGv tmp; - - if (UCOP_COND == 0xf) { - ILLEGAL; - } - - if (UCOP_COND != 0xe) { - /* if not always execute, we generate a conditional jump to - next instruction */ - s->condlabel = gen_new_label(); - gen_test_cc(UCOP_COND ^ 1, s->condlabel); - s->condjmp = 1; - } - - val = (int32_t)s->pc; - if (UCOP_SET_L) { - tmp = new_tmp(); - tcg_gen_movi_i32(tmp, val); - store_reg(s, 30, tmp); - } - offset = (((int32_t)insn << 8) >> 8); - val += (offset << 2); /* unicore is pc+4 */ - gen_jmp(s, val); -} - -static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s) -{ - unsigned int insn; - - insn = cpu_ldl_code(env, s->pc); - s->pc += 4; - - /* UniCore instructions class: - * AAAB BBBC xxxx xxxx xxxx xxxD xxEx xxxx - * AAA : see switch case - * BBBB : opcodes or cond or PUBW - * C : S OR L - * D : 8 - * E : 5 - */ - switch (insn >> 29) { - case 0x0: - if (UCOP_SET(5) && UCOP_SET(8) && !UCOP_SET(28)) { - do_mult(env, s, insn); - break; - } - - if (UCOP_SET(8)) { - do_misc(env, s, insn); - break; - } - /* fallthrough */ - case 0x1: - if (((UCOP_OPCODES >> 2) == 2) && !UCOP_SET_S) { - do_misc(env, s, insn); - break; - } - do_datap(env, s, insn); - break; - - case 0x2: - if (UCOP_SET(8) && UCOP_SET(5)) { - do_ldst_hwsb(env, s, insn); - break; - } - if (UCOP_SET(8) || UCOP_SET(5)) { - ILLEGAL; - } - /* fallthrough */ - case 0x3: - do_ldst_ir(env, s, insn); - break; - - case 0x4: - if (UCOP_SET(8)) { - ILLEGAL; /* extended instructions */ - } - do_ldst_m(env, s, insn); - break; - case 0x5: - do_branch(env, s, insn); - break; - case 0x6: - /* Coprocessor. */ - disas_coproc_insn(env, s, insn); - break; - case 0x7: - if (!UCOP_SET(28)) { - disas_coproc_insn(env, s, insn); - break; - } - if ((insn & 0xff000000) == 0xff000000) { /* syscall */ - gen_set_pc_im(s->pc); - s->is_jmp = DISAS_SYSCALL; - break; - } - ILLEGAL; - } -} - -/* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) -{ - CPUUniCore32State *env = cs->env_ptr; - DisasContext dc1, *dc = &dc1; - target_ulong pc_start; - uint32_t page_start; - int num_insns; - - /* generate intermediate code */ - num_temps = 0; - - pc_start = tb->pc; - - dc->tb = tb; - - dc->is_jmp = DISAS_NEXT; - dc->pc = pc_start; - dc->singlestep_enabled = cs->singlestep_enabled; - dc->condjmp = 0; - cpu_F0s = tcg_temp_new_i32(); - cpu_F1s = tcg_temp_new_i32(); - cpu_F0d = tcg_temp_new_i64(); - cpu_F1d = tcg_temp_new_i64(); - page_start = pc_start & TARGET_PAGE_MASK; - num_insns = 0; - -#ifndef CONFIG_USER_ONLY - if ((env->uncached_asr & ASR_M) == ASR_MODE_USER) { - dc->user = 1; - } else { - dc->user = 0; - } -#endif - - gen_tb_start(tb); - do { - tcg_gen_insn_start(dc->pc); - num_insns++; - - if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { - gen_set_pc_im(dc->pc); - gen_exception(EXCP_DEBUG); - dc->is_jmp = DISAS_JUMP; - /* 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. */ - dc->pc += 4; - goto done_generating; - } - - if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) { - gen_io_start(); - } - - disas_uc32_insn(env, dc); - - if (num_temps) { - fprintf(stderr, "Internal resource leak before %08x\n", dc->pc); - num_temps = 0; - } - - if (dc->condjmp && !dc->is_jmp) { - gen_set_label(dc->condlabel); - dc->condjmp = 0; - } - /* Translation stops when a conditional branch is encountered. - * Otherwise the subsequent code could get translated several times. - * Also stop translation when a page boundary is reached. This - * ensures prefetch aborts occur at the right place. */ - } while (!dc->is_jmp && !tcg_op_buf_full() && - !cs->singlestep_enabled && - !singlestep && - dc->pc - page_start < TARGET_PAGE_SIZE && - num_insns < max_insns); - - if (tb_cflags(tb) & CF_LAST_IO) { - if (dc->condjmp) { - /* FIXME: This can theoretically happen with self-modifying - code. */ - cpu_abort(cs, "IO on conditional branch instruction"); - } - } - - /* At this stage dc->condjmp will only be set when the skipped - instruction was a conditional branch or trap, and the PC has - already been written. */ - if (unlikely(cs->singlestep_enabled)) { - /* Make sure the pc is updated, and raise a debug exception. */ - if (dc->condjmp) { - if (dc->is_jmp == DISAS_SYSCALL) { - gen_exception(UC32_EXCP_PRIV); - } else { - gen_exception(EXCP_DEBUG); - } - gen_set_label(dc->condlabel); - } - if (dc->condjmp || !dc->is_jmp) { - gen_set_pc_im(dc->pc); - dc->condjmp = 0; - } - if (dc->is_jmp == DISAS_SYSCALL && !dc->condjmp) { - gen_exception(UC32_EXCP_PRIV); - } else { - gen_exception(EXCP_DEBUG); - } - } else { - /* While branches must always occur at the end of an IT block, - there are a few other things that can cause us to terminate - the TB in the middel of an IT block: - - Exception generating instructions (bkpt, swi, undefined). - - Page boundaries. - - Hardware watchpoints. - Hardware breakpoints have already been handled and skip this code. - */ - switch (dc->is_jmp) { - case DISAS_NEXT: - gen_goto_tb(dc, 1, dc->pc); - break; - default: - case DISAS_JUMP: - case DISAS_UPDATE: - /* indicate that the hash table must be used to find the next TB */ - tcg_gen_exit_tb(NULL, 0); - break; - case DISAS_TB_JUMP: - /* nothing more to generate */ - break; - case DISAS_SYSCALL: - gen_exception(UC32_EXCP_PRIV); - break; - } - if (dc->condjmp) { - gen_set_label(dc->condlabel); - gen_goto_tb(dc, 1, dc->pc); - dc->condjmp = 0; - } - } - -done_generating: - gen_tb_end(tb, num_insns); - -#ifdef DEBUG_DISAS - if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) - && qemu_log_in_addr_range(pc_start)) { - FILE *logfile = qemu_log_lock(); - qemu_log("----------------\n"); - qemu_log("IN: %s\n", lookup_symbol(pc_start)); - log_target_disas(cs, pc_start, dc->pc - pc_start); - qemu_log("\n"); - qemu_log_unlock(logfile); - } -#endif - tb->size = dc->pc - pc_start; - tb->icount = num_insns; -} - -static const char *cpu_mode_names[16] = { - "USER", "REAL", "INTR", "PRIV", "UM14", "UM15", "UM16", "TRAP", - "UM18", "UM19", "UM1A", "EXTN", "UM1C", "UM1D", "UM1E", "SUSR" -}; - -#undef UCF64_DUMP_STATE -#ifdef UCF64_DUMP_STATE -static void cpu_dump_state_ucf64(CPUUniCore32State *env, int flags) -{ - int i; - union { - uint32_t i; - float s; - } s0, s1; - CPU_DoubleU d; - /* ??? This assumes float64 and double have the same layout. - Oh well, it's only debug dumps. */ - union { - float64 f64; - double d; - } d0; - - for (i = 0; i < 16; i++) { - d.d = env->ucf64.regs[i]; - s0.i = d.l.lower; - s1.i = d.l.upper; - d0.f64 = d.d; - qemu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g)", - i * 2, (int)s0.i, s0.s, - i * 2 + 1, (int)s1.i, s1.s); - qemu_fprintf(f, " d%02d=%" PRIx64 "(%8g)\n", - i, (uint64_t)d0.f64, d0.d); - } - qemu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]); -} -#else -#define cpu_dump_state_ucf64(env, file, pr, flags) do { } while (0) -#endif - -void uc32_cpu_dump_state(CPUState *cs, FILE *f, int flags) -{ - UniCore32CPU *cpu = UNICORE32_CPU(cs); - CPUUniCore32State *env = &cpu->env; - int i; - uint32_t psr; - - for (i = 0; i < 32; i++) { - qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]); - if ((i % 4) == 3) { - qemu_fprintf(f, "\n"); - } else { - qemu_fprintf(f, " "); - } - } - psr = cpu_asr_read(env); - qemu_fprintf(f, "PSR=%08x %c%c%c%c %s\n", - psr, - psr & (1 << 31) ? 'N' : '-', - psr & (1 << 30) ? 'Z' : '-', - psr & (1 << 29) ? 'C' : '-', - psr & (1 << 28) ? 'V' : '-', - cpu_mode_names[psr & 0xf]); - - if (flags & CPU_DUMP_FPU) { - cpu_dump_state_ucf64(env, f, cpu_fprintf, flags); - } -} - -void restore_state_to_opc(CPUUniCore32State *env, TranslationBlock *tb, - target_ulong *data) -{ - env->regs[31] = data[0]; -} diff --git a/target/unicore32/ucf64_helper.c b/target/unicore32/ucf64_helper.c deleted file mode 100644 index 12a91900f6..0000000000 --- a/target/unicore32/ucf64_helper.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * UniCore-F64 simulation helpers for QEMU. - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" -#include "fpu/softfloat.h" - -/* - * The convention used for UniCore-F64 instructions: - * Single precition routines have a "s" suffix - * Double precision routines have a "d" suffix. - */ - -/* Convert host exception flags to f64 form. */ -static inline int ucf64_exceptbits_from_host(int host_bits) -{ - int target_bits = 0; - - if (host_bits & float_flag_invalid) { - target_bits |= UCF64_FPSCR_FLAG_INVALID; - } - if (host_bits & float_flag_divbyzero) { - target_bits |= UCF64_FPSCR_FLAG_DIVZERO; - } - if (host_bits & float_flag_overflow) { - target_bits |= UCF64_FPSCR_FLAG_OVERFLOW; - } - if (host_bits & float_flag_underflow) { - target_bits |= UCF64_FPSCR_FLAG_UNDERFLOW; - } - if (host_bits & float_flag_inexact) { - target_bits |= UCF64_FPSCR_FLAG_INEXACT; - } - return target_bits; -} - -uint32_t HELPER(ucf64_get_fpscr)(CPUUniCore32State *env) -{ - int i; - uint32_t fpscr; - - fpscr = (env->ucf64.xregs[UC32_UCF64_FPSCR] & UCF64_FPSCR_MASK); - i = get_float_exception_flags(&env->ucf64.fp_status); - fpscr |= ucf64_exceptbits_from_host(i); - return fpscr; -} - -/* Convert ucf64 exception flags to target form. */ -static inline int ucf64_exceptbits_to_host(int target_bits) -{ - int host_bits = 0; - - if (target_bits & UCF64_FPSCR_FLAG_INVALID) { - host_bits |= float_flag_invalid; - } - if (target_bits & UCF64_FPSCR_FLAG_DIVZERO) { - host_bits |= float_flag_divbyzero; - } - if (target_bits & UCF64_FPSCR_FLAG_OVERFLOW) { - host_bits |= float_flag_overflow; - } - if (target_bits & UCF64_FPSCR_FLAG_UNDERFLOW) { - host_bits |= float_flag_underflow; - } - if (target_bits & UCF64_FPSCR_FLAG_INEXACT) { - host_bits |= float_flag_inexact; - } - return host_bits; -} - -void HELPER(ucf64_set_fpscr)(CPUUniCore32State *env, uint32_t val) -{ - UniCore32CPU *cpu = env_archcpu(env); - int i; - uint32_t changed; - - changed = env->ucf64.xregs[UC32_UCF64_FPSCR]; - env->ucf64.xregs[UC32_UCF64_FPSCR] = (val & UCF64_FPSCR_MASK); - - changed ^= val; - if (changed & (UCF64_FPSCR_RND_MASK)) { - i = UCF64_FPSCR_RND(val); - switch (i) { - case 0: - i = float_round_nearest_even; - break; - case 1: - i = float_round_to_zero; - break; - case 2: - i = float_round_up; - break; - case 3: - i = float_round_down; - break; - default: /* 100 and 101 not implement */ - cpu_abort(CPU(cpu), "Unsupported UniCore-F64 round mode"); - } - set_float_rounding_mode(i, &env->ucf64.fp_status); - } - - i = ucf64_exceptbits_to_host(UCF64_FPSCR_TRAPEN(val)); - set_float_exception_flags(i, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_adds)(float32 a, float32 b, CPUUniCore32State *env) -{ - return float32_add(a, b, &env->ucf64.fp_status); -} - -float64 HELPER(ucf64_addd)(float64 a, float64 b, CPUUniCore32State *env) -{ - return float64_add(a, b, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_subs)(float32 a, float32 b, CPUUniCore32State *env) -{ - return float32_sub(a, b, &env->ucf64.fp_status); -} - -float64 HELPER(ucf64_subd)(float64 a, float64 b, CPUUniCore32State *env) -{ - return float64_sub(a, b, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_muls)(float32 a, float32 b, CPUUniCore32State *env) -{ - return float32_mul(a, b, &env->ucf64.fp_status); -} - -float64 HELPER(ucf64_muld)(float64 a, float64 b, CPUUniCore32State *env) -{ - return float64_mul(a, b, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_divs)(float32 a, float32 b, CPUUniCore32State *env) -{ - return float32_div(a, b, &env->ucf64.fp_status); -} - -float64 HELPER(ucf64_divd)(float64 a, float64 b, CPUUniCore32State *env) -{ - return float64_div(a, b, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_negs)(float32 a) -{ - return float32_chs(a); -} - -float64 HELPER(ucf64_negd)(float64 a) -{ - return float64_chs(a); -} - -float32 HELPER(ucf64_abss)(float32 a) -{ - return float32_abs(a); -} - -float64 HELPER(ucf64_absd)(float64 a) -{ - return float64_abs(a); -} - -void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c, - CPUUniCore32State *env) -{ - FloatRelation flag = float32_compare_quiet(a, b, &env->ucf64.fp_status); - env->CF = 0; - switch (c & 0x7) { - case 0: /* F */ - break; - case 1: /* UN */ - if (flag == 2) { - env->CF = 1; - } - break; - case 2: /* EQ */ - if (flag == 0) { - env->CF = 1; - } - break; - case 3: /* UEQ */ - if ((flag == 0) || (flag == 2)) { - env->CF = 1; - } - break; - case 4: /* OLT */ - if (flag == -1) { - env->CF = 1; - } - break; - case 5: /* ULT */ - if ((flag == -1) || (flag == 2)) { - env->CF = 1; - } - break; - case 6: /* OLE */ - if ((flag == -1) || (flag == 0)) { - env->CF = 1; - } - break; - case 7: /* ULE */ - if (flag != 1) { - env->CF = 1; - } - break; - } - env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29) - | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff); -} - -void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c, - CPUUniCore32State *env) -{ - FloatRelation flag = float64_compare_quiet(a, b, &env->ucf64.fp_status); - env->CF = 0; - switch (c & 0x7) { - case 0: /* F */ - break; - case 1: /* UN */ - if (flag == 2) { - env->CF = 1; - } - break; - case 2: /* EQ */ - if (flag == 0) { - env->CF = 1; - } - break; - case 3: /* UEQ */ - if ((flag == 0) || (flag == 2)) { - env->CF = 1; - } - break; - case 4: /* OLT */ - if (flag == -1) { - env->CF = 1; - } - break; - case 5: /* ULT */ - if ((flag == -1) || (flag == 2)) { - env->CF = 1; - } - break; - case 6: /* OLE */ - if ((flag == -1) || (flag == 0)) { - env->CF = 1; - } - break; - case 7: /* ULE */ - if (flag != 1) { - env->CF = 1; - } - break; - } - env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29) - | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff); -} - -/* Helper routines to perform bitwise copies between float and int. */ -static inline float32 ucf64_itos(uint32_t i) -{ - union { - uint32_t i; - float32 s; - } v; - - v.i = i; - return v.s; -} - -static inline uint32_t ucf64_stoi(float32 s) -{ - union { - uint32_t i; - float32 s; - } v; - - v.s = s; - return v.i; -} - -/* Integer to float conversion. */ -float32 HELPER(ucf64_si2sf)(float32 x, CPUUniCore32State *env) -{ - return int32_to_float32(ucf64_stoi(x), &env->ucf64.fp_status); -} - -float64 HELPER(ucf64_si2df)(float32 x, CPUUniCore32State *env) -{ - return int32_to_float64(ucf64_stoi(x), &env->ucf64.fp_status); -} - -/* Float to integer conversion. */ -float32 HELPER(ucf64_sf2si)(float32 x, CPUUniCore32State *env) -{ - return ucf64_itos(float32_to_int32(x, &env->ucf64.fp_status)); -} - -float32 HELPER(ucf64_df2si)(float64 x, CPUUniCore32State *env) -{ - return ucf64_itos(float64_to_int32(x, &env->ucf64.fp_status)); -} - -/* floating point conversion */ -float64 HELPER(ucf64_sf2df)(float32 x, CPUUniCore32State *env) -{ - return float32_to_float64(x, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_df2sf)(float64 x, CPUUniCore32State *env) -{ - return float64_to_float32(x, &env->ucf64.fp_status); -} |