diff options
author | Thomas Huth <thuth@redhat.com> | 2016-10-11 08:56:52 +0200 |
---|---|---|
committer | Thomas Huth <thuth@redhat.com> | 2016-12-20 21:52:12 +0100 |
commit | fcf5ef2ab52c621a4617ebbef36bf43b4003f4c0 (patch) | |
tree | 2b450d96b01455df8ed908bf8f26ddc388a03380 /target-lm32 | |
parent | 82ecffa8c050bf5bbc13329e9b65eac1caa5b55c (diff) | |
download | qemu-fcf5ef2ab52c621a4617ebbef36bf43b4003f4c0.zip qemu-fcf5ef2ab52c621a4617ebbef36bf43b4003f4c0.tar.gz qemu-fcf5ef2ab52c621a4617ebbef36bf43b4003f4c0.tar.bz2 |
Move target-* CPU file into a target/ folder
We've currently got 18 architectures in QEMU, and thus 18 target-xxx
folders in the root folder of the QEMU source tree. More architectures
(e.g. RISC-V, AVR) are likely to be included soon, too, so the main
folder of the QEMU sources slowly gets quite overcrowded with the
target-xxx folders.
To disburden the main folder a little bit, let's move the target-xxx
folders into a dedicated target/ folder, so that target-xxx/ simply
becomes target/xxx/ instead.
Acked-by: Laurent Vivier <laurent@vivier.eu> [m68k part]
Acked-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> [tricore part]
Acked-by: Michael Walle <michael@walle.cc> [lm32 part]
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com> [s390x part]
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com> [s390x part]
Acked-by: Eduardo Habkost <ehabkost@redhat.com> [i386 part]
Acked-by: Artyom Tarasenko <atar4qemu@gmail.com> [sparc part]
Acked-by: Richard Henderson <rth@twiddle.net> [alpha part]
Acked-by: Max Filippov <jcmvbkbc@gmail.com> [xtensa part]
Reviewed-by: David Gibson <david@gibson.dropbear.id.au> [ppc part]
Acked-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> [crisµblaze part]
Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn> [unicore32 part]
Signed-off-by: Thomas Huth <thuth@redhat.com>
Diffstat (limited to 'target-lm32')
-rw-r--r-- | target-lm32/Makefile.objs | 4 | ||||
-rw-r--r-- | target-lm32/README | 45 | ||||
-rw-r--r-- | target-lm32/TODO | 1 | ||||
-rw-r--r-- | target-lm32/cpu-qom.h | 52 | ||||
-rw-r--r-- | target-lm32/cpu.c | 328 | ||||
-rw-r--r-- | target-lm32/cpu.h | 274 | ||||
-rw-r--r-- | target-lm32/gdbstub.c | 93 | ||||
-rw-r--r-- | target-lm32/helper.c | 237 | ||||
-rw-r--r-- | target-lm32/helper.h | 14 | ||||
-rw-r--r-- | target-lm32/lm32-semi.c | 212 | ||||
-rw-r--r-- | target-lm32/machine.c | 36 | ||||
-rw-r--r-- | target-lm32/op_helper.c | 162 | ||||
-rw-r--r-- | target-lm32/translate.c | 1254 |
13 files changed, 0 insertions, 2712 deletions
diff --git a/target-lm32/Makefile.objs b/target-lm32/Makefile.objs deleted file mode 100644 index c3e1bd6..0000000 --- a/target-lm32/Makefile.objs +++ /dev/null @@ -1,4 +0,0 @@ -obj-y += translate.o op_helper.o helper.o cpu.o -obj-y += gdbstub.o -obj-y += lm32-semi.o -obj-$(CONFIG_SOFTMMU) += machine.o diff --git a/target-lm32/README b/target-lm32/README deleted file mode 100644 index ba3508a..0000000 --- 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 e163c42..0000000 --- a/target-lm32/TODO +++ /dev/null @@ -1 +0,0 @@ -* linux-user emulation diff --git a/target-lm32/cpu-qom.h b/target-lm32/cpu-qom.h deleted file mode 100644 index b423d25..0000000 --- a/target-lm32/cpu-qom.h +++ /dev/null @@ -1,52 +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 "qom/cpu.h" - -#define TYPE_LM32_CPU "lm32-cpu" - -#define LM32_CPU_CLASS(klass) \ - OBJECT_CLASS_CHECK(LM32CPUClass, (klass), TYPE_LM32_CPU) -#define LM32_CPU(obj) \ - OBJECT_CHECK(LM32CPU, (obj), TYPE_LM32_CPU) -#define LM32_CPU_GET_CLASS(obj) \ - OBJECT_GET_CLASS(LM32CPUClass, (obj), TYPE_LM32_CPU) - -/** - * LM32CPUClass: - * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. - * - * A LatticeMico32 CPU model. - */ -typedef struct LM32CPUClass { - /*< private >*/ - CPUClass parent_class; - /*< public >*/ - - DeviceRealize parent_realize; - void (*parent_reset)(CPUState *cpu); -} LM32CPUClass; - -typedef struct LM32CPU LM32CPU; - -#endif diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c deleted file mode 100644 index 8d939a7..0000000 --- a/target-lm32/cpu.c +++ /dev/null @@ -1,328 +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 "cpu.h" -#include "qemu-common.h" -#include "exec/exec-all.h" - - -static void lm32_cpu_set_pc(CPUState *cs, vaddr value) -{ - LM32CPU *cpu = LM32_CPU(cs); - - cpu->env.pc = value; -} - -/* Sort alphabetically by type name. */ -static gint lm32_cpu_list_compare(gconstpointer a, gconstpointer b) -{ - ObjectClass *class_a = (ObjectClass *)a; - ObjectClass *class_b = (ObjectClass *)b; - const char *name_a, *name_b; - - name_a = object_class_get_name(class_a); - name_b = object_class_get_name(class_b); - return strcmp(name_a, name_b); -} - -static void lm32_cpu_list_entry(gpointer data, gpointer user_data) -{ - ObjectClass *oc = data; - CPUListState *s = user_data; - const char *typename = object_class_get_name(oc); - char *name; - - name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_LM32_CPU)); - (*s->cpu_fprintf)(s->file, " %s\n", name); - g_free(name); -} - - -void lm32_cpu_list(FILE *f, fprintf_function cpu_fprintf) -{ - CPUListState s = { - .file = f, - .cpu_fprintf = cpu_fprintf, - }; - GSList *list; - - list = object_class_get_list(TYPE_LM32_CPU, false); - list = g_slist_sort(list, lm32_cpu_list_compare); - (*cpu_fprintf)(f, "Available CPUs:\n"); - g_slist_foreach(list, lm32_cpu_list_entry, &s); - 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; -} - -/* CPUClass::reset() */ -static void lm32_cpu_reset(CPUState *s) -{ - LM32CPU *cpu = LM32_CPU(s); - LM32CPUClass *lcc = LM32_CPU_GET_CLASS(cpu); - CPULM32State *env = &cpu->env; - - lcc->parent_reset(s); - - /* reset cpu state */ - memset(env, 0, offsetof(CPULM32State, eba)); - - lm32_cpu_init_cfg_reg(cpu); - tlb_flush(s, 1); -} - -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) -{ - CPUState *cs = CPU(obj); - LM32CPU *cpu = LM32_CPU(obj); - CPULM32State *env = &cpu->env; - static bool tcg_initialized; - - cs->env_ptr = env; - - env->flags = 0; - - if (tcg_enabled() && !tcg_initialized) { - tcg_initialized = true; - lm32_translate_init(); - } -} - -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; -} - -typedef struct LM32CPUInfo { - const char *name; - void (*initfn)(Object *obj); -} LM32CPUInfo; - -static const LM32CPUInfo lm32_cpus[] = { - { - .name = "lm32-basic", - .initfn = lm32_basic_cpu_initfn, - }, - { - .name = "lm32-standard", - .initfn = lm32_standard_cpu_initfn, - }, - { - .name = "lm32-full", - .initfn = lm32_full_cpu_initfn, - }, -}; - -static ObjectClass *lm32_cpu_class_by_name(const char *cpu_model) -{ - ObjectClass *oc; - char *typename; - - if (cpu_model == NULL) { - return NULL; - } - - typename = g_strdup_printf("%s-" TYPE_LM32_CPU, 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; -} - -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); - - lcc->parent_realize = dc->realize; - dc->realize = lm32_cpu_realizefn; - - lcc->parent_reset = cc->reset; - cc->reset = lm32_cpu_reset; - - cc->class_by_name = lm32_cpu_class_by_name; - cc->has_work = lm32_cpu_has_work; - cc->do_interrupt = lm32_cpu_do_interrupt; - cc->cpu_exec_interrupt = lm32_cpu_exec_interrupt; - 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; -#ifdef CONFIG_USER_ONLY - cc->handle_mmu_fault = lm32_cpu_handle_mmu_fault; -#else - 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->debug_excp_handler = lm32_debug_excp_handler; - cc->disas_set_info = lm32_cpu_disas_set_info; -} - -static void lm32_register_cpu_type(const LM32CPUInfo *info) -{ - TypeInfo type_info = { - .parent = TYPE_LM32_CPU, - .instance_init = info->initfn, - }; - - type_info.name = g_strdup_printf("%s-" TYPE_LM32_CPU, info->name); - type_register(&type_info); - g_free((void *)type_info.name); -} - -static const TypeInfo lm32_cpu_type_info = { - .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, -}; - -static void lm32_cpu_register_types(void) -{ - int i; - - type_register_static(&lm32_cpu_type_info); - for (i = 0; i < ARRAY_SIZE(lm32_cpus); i++) { - lm32_register_cpu_type(&lm32_cpus[i]); - } -} - -type_init(lm32_cpu_register_types) diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h deleted file mode 100644 index d8a3515..0000000 --- a/target-lm32/cpu.h +++ /dev/null @@ -1,274 +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 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 - -#define TARGET_LONG_BITS 32 - -#define CPUArchState struct CPULM32State - -#include "qemu-common.h" -#include "cpu-qom.h" -#include "exec/cpu-defs.h" -struct CPULM32State; -typedef struct CPULM32State CPULM32State; - -#define NB_MMU_MODES 1 -#define TARGET_PAGE_BITS 12 -static inline int cpu_mmu_index(CPULM32State *env, bool ifetch) -{ - return 0; -} - -#define TARGET_PHYS_ADDR_SPACE_BITS 32 -#define TARGET_VIRT_ADDR_SPACE_BITS 32 - -/* 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]; - - CPU_COMMON - - /* 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 >*/ - - CPULM32State env; - - uint32_t revision; - uint8_t num_interrupts; - uint8_t num_breakpoints; - uint8_t num_watchpoints; - uint32_t features; -}; - -static inline LM32CPU *lm32_env_get_cpu(CPULM32State *env) -{ - return container_of(env, LM32CPU, env); -} - -#define ENV_GET_CPU(e) CPU(lm32_env_get_cpu(e)) - -#define ENV_OFFSET offsetof(LM32CPU, env) - -#ifndef CONFIG_USER_ONLY -extern const struct 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, fprintf_function cpu_fprintf, - int flags); -hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -int lm32_cpu_gdb_read_register(CPUState *cpu, uint8_t *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; -} - -LM32CPU *cpu_lm32_init(const char *cpu_model); -/* 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(FILE *f, fprintf_function cpu_fprintf); -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 cpu_init(cpu_model) CPU(cpu_lm32_init(cpu_model)) - -#define cpu_list lm32_cpu_list -#define cpu_signal_handler cpu_lm32_signal_handler - -int lm32_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw, - int mmu_idx); - -#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 cf929dd..0000000 --- a/target-lm32/gdbstub.c +++ /dev/null @@ -1,93 +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 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "cpu.h" -#include "exec/gdbstub.h" -#include "hw/lm32/lm32_pic.h" - -int lm32_cpu_gdb_read_register(CPUState *cs, uint8_t *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 891da18..0000000 --- a/target-lm32/helper.c +++ /dev/null @@ -1,237 +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 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 "sysemu/sysemu.h" -#include "exec/semihost.h" -#include "exec/log.h" - -int lm32_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, - int mmu_idx) -{ - 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 0; -} - -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) -{ - LM32CPU *cpu = lm32_env_get_cpu(env); - - cpu_breakpoint_insert(CPU(cpu), address, BP_CPU, - &env->cpu_breakpoint[idx]); -} - -void lm32_breakpoint_remove(CPULM32State *env, int idx) -{ - LM32CPU *cpu = lm32_env_get_cpu(env); - - if (!env->cpu_breakpoint[idx]) { - return; - } - - cpu_breakpoint_remove_by_ref(CPU(cpu), 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) -{ - LM32CPU *cpu = lm32_env_get_cpu(env); - 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(CPU(cpu), address, 1, flags, - &env->cpu_watchpoint[idx]); - } -} - -void lm32_watchpoint_remove(CPULM32State *env, int idx) -{ - LM32CPU *cpu = lm32_env_get_cpu(env); - - if (!env->cpu_watchpoint[idx]) { - return; - } - - cpu_watchpoint_remove_by_ref(CPU(cpu), env->cpu_watchpoint[idx]); - env->cpu_watchpoint[idx] = NULL; -} - -static bool check_watchpoints(CPULM32State *env) -{ - LM32CPU *cpu = lm32_env_get_cpu(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; -} - -LM32CPU *cpu_lm32_init(const char *cpu_model) -{ - return LM32_CPU(cpu_generic_init(TYPE_LM32_CPU, cpu_model)); -} - -/* 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 445578c..0000000 --- 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 20f1a1c..0000000 --- a/target-lm32/lm32-semi.c +++ /dev/null @@ -1,212 +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 "qemu/log.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 3c258a4..0000000 --- a/target-lm32/machine.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/hw.h" -#include "hw/boards.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/op_helper.c b/target-lm32/op_helper.c deleted file mode 100644 index 2177c8a..0000000 --- a/target-lm32/op_helper.c +++ /dev/null @@ -1,162 +0,0 @@ -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" -#include "qemu/host-utils.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 -#include "sysemu/sysemu.h" -#endif - -#if !defined(CONFIG_USER_ONLY) -void raise_exception(CPULM32State *env, int index) -{ - CPUState *cs = CPU(lm32_env_get_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 = CPU(lm32_env_get_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 = CPU(lm32_env_get_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) -{ - lm32_pic_set_im(env->pic_state, im); -} - -void HELPER(wcsr_ip)(CPULM32State *env, uint32_t im) -{ - lm32_pic_set_ip(env->pic_state, im); -} - -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); -} - -/* Try to fill the TLB and return an exception if error. If retaddr is - * NULL, it means that the function was called in C code (i.e. not - * from generated code or from helper.c) - */ -void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr) -{ - int ret; - - ret = lm32_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); - if (unlikely(ret)) { - if (retaddr) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } - cpu_loop_exit(cs); - } -} -#endif - diff --git a/target-lm32/translate.c b/target-lm32/translate.c deleted file mode 100644 index 692882f..0000000 --- a/target-lm32/translate.c +++ /dev/null @@ -1,1254 +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 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 "tcg-op.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 - -static TCGv_env cpu_env; -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; - - struct 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((uintptr_t)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(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 (dc->tb->cflags & 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); - if (dc->tb->cflags & CF_USE_ICOUNT) { - gen_io_end(); - } - dc->is_jmp = DISAS_UPDATE; - break; - case CSR_IP: - /* mark as an io operation because it could cause an interrupt */ - if (dc->tb->cflags & 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); - if (dc->tb->cflags & CF_USE_ICOUNT) { - gen_io_end(); - } - 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(CPULM32State *env, struct TranslationBlock *tb) -{ - LM32CPU *cpu = lm32_env_get_cpu(env); - CPUState *cs = CPU(cpu); - struct DisasContext ctx, *dc = &ctx; - uint32_t pc_start; - uint32_t next_page_start; - int num_insns; - int max_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; - } - - next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; - num_insns = 0; - max_insns = tb->cflags & CF_COUNT_MASK; - if (max_insns == 0) { - max_insns = CF_COUNT_MASK; - } - if (max_insns > TCG_MAX_INSNS) { - max_insns = TCG_MAX_INSNS; - } - - gen_tb_start(tb); - 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 & 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 < next_page_start) - && num_insns < max_insns); - - if (tb->cflags & CF_LAST_IO) { - gen_io_end(); - } - - 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(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)) { - qemu_log_lock(); - qemu_log("\n"); - log_target_disas(cs, pc_start, dc->pc - pc_start, 0); - qemu_log("\nisize=%d osize=%d\n", - dc->pc - pc_start, tcg_op_buf_count()); - qemu_log_unlock(); - } -#endif -} - -void lm32_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - int i; - - if (!env || !f) { - return; - } - - cpu_fprintf(f, "IN: PC=%x %s\n", - env->pc, lookup_symbol(env->pc)); - - cpu_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)); - cpu_fprintf(f, "eba=%8.8x deba=%8.8x\n", - env->eba, - env->deba); - - for (i = 0; i < 32; i++) { - cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); - if ((i + 1) % 4 == 0) { - cpu_fprintf(f, "\n"); - } - } - cpu_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; - - cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); - tcg_ctx.tcg_env = cpu_env; - - 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"); -} - |