summaryrefslogtreecommitdiffstats
path: root/qemu/target-openrisc
diff options
context:
space:
mode:
authorYang Zhang <yang.z.zhang@intel.com>2015-08-28 09:58:54 +0800
committerYang Zhang <yang.z.zhang@intel.com>2015-09-01 12:44:00 +0800
commite44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch)
tree66b09f592c55df2878107a468a91d21506104d3f /qemu/target-openrisc
parent9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff)
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/target-openrisc')
-rw-r--r--qemu/target-openrisc/Makefile.objs5
-rw-r--r--qemu/target-openrisc/cpu.c269
-rw-r--r--qemu/target-openrisc/cpu.h418
-rw-r--r--qemu/target-openrisc/exception.c29
-rw-r--r--qemu/target-openrisc/exception.h28
-rw-r--r--qemu/target-openrisc/exception_helper.c29
-rw-r--r--qemu/target-openrisc/fpu_helper.c300
-rw-r--r--qemu/target-openrisc/gdbstub.c83
-rw-r--r--qemu/target-openrisc/helper.h66
-rw-r--r--qemu/target-openrisc/int_helper.c79
-rw-r--r--qemu/target-openrisc/interrupt.c85
-rw-r--r--qemu/target-openrisc/interrupt_helper.c58
-rw-r--r--qemu/target-openrisc/machine.c50
-rw-r--r--qemu/target-openrisc/mmu.c236
-rw-r--r--qemu/target-openrisc/mmu_helper.c42
-rw-r--r--qemu/target-openrisc/sys_helper.c286
-rw-r--r--qemu/target-openrisc/translate.c1810
17 files changed, 3873 insertions, 0 deletions
diff --git a/qemu/target-openrisc/Makefile.objs b/qemu/target-openrisc/Makefile.objs
new file mode 100644
index 000000000..397d01650
--- /dev/null
+++ b/qemu/target-openrisc/Makefile.objs
@@ -0,0 +1,5 @@
+obj-$(CONFIG_SOFTMMU) += machine.o
+obj-y += cpu.o exception.o interrupt.o mmu.o translate.o
+obj-y += exception_helper.o fpu_helper.o int_helper.o \
+ interrupt_helper.o mmu_helper.o sys_helper.o
+obj-y += gdbstub.o
diff --git a/qemu/target-openrisc/cpu.c b/qemu/target-openrisc/cpu.c
new file mode 100644
index 000000000..d97f3c03c
--- /dev/null
+++ b/qemu/target-openrisc/cpu.c
@@ -0,0 +1,269 @@
+/*
+ * QEMU OpenRISC CPU
+ *
+ * Copyright (c) 2012 Jia Liu <proljc@gmail.com>
+ *
+ * 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 "cpu.h"
+#include "qemu-common.h"
+
+static void openrisc_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+
+ cpu->env.pc = value;
+}
+
+static bool openrisc_cpu_has_work(CPUState *cs)
+{
+ return cs->interrupt_request & (CPU_INTERRUPT_HARD |
+ CPU_INTERRUPT_TIMER);
+}
+
+/* CPUClass::reset() */
+static void openrisc_cpu_reset(CPUState *s)
+{
+ OpenRISCCPU *cpu = OPENRISC_CPU(s);
+ OpenRISCCPUClass *occ = OPENRISC_CPU_GET_CLASS(cpu);
+
+ occ->parent_reset(s);
+
+#ifndef CONFIG_USER_ONLY
+ memset(&cpu->env, 0, offsetof(CPUOpenRISCState, tlb));
+#else
+ memset(&cpu->env, 0, offsetof(CPUOpenRISCState, irq));
+#endif
+
+ tlb_flush(s, 1);
+ /*tb_flush(&cpu->env); FIXME: Do we need it? */
+
+ cpu->env.pc = 0x100;
+ cpu->env.sr = SR_FO | SR_SM;
+ s->exception_index = -1;
+
+ cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP;
+ cpu->env.cpucfgr = CPUCFGR_OB32S | CPUCFGR_OF32S;
+ cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2)) | (DMMUCFGR_NTS & (6 << 2));
+ cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2)) | (IMMUCFGR_NTS & (6 << 2));
+
+#ifndef CONFIG_USER_ONLY
+ cpu->env.picmr = 0x00000000;
+ cpu->env.picsr = 0x00000000;
+
+ cpu->env.ttmr = 0x00000000;
+ cpu->env.ttcr = 0x00000000;
+#endif
+}
+
+static inline void set_feature(OpenRISCCPU *cpu, int feature)
+{
+ cpu->feature |= feature;
+ cpu->env.cpucfgr = cpu->feature;
+}
+
+static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp)
+{
+ CPUState *cs = CPU(dev);
+ OpenRISCCPUClass *occ = OPENRISC_CPU_GET_CLASS(dev);
+
+ qemu_init_vcpu(cs);
+ cpu_reset(cs);
+
+ occ->parent_realize(dev, errp);
+}
+
+static void openrisc_cpu_initfn(Object *obj)
+{
+ CPUState *cs = CPU(obj);
+ OpenRISCCPU *cpu = OPENRISC_CPU(obj);
+ static int inited;
+
+ cs->env_ptr = &cpu->env;
+ cpu_exec_init(cs, &error_abort);
+
+#ifndef CONFIG_USER_ONLY
+ cpu_openrisc_mmu_init(cpu);
+#endif
+
+ if (tcg_enabled() && !inited) {
+ inited = 1;
+ openrisc_translate_init();
+ }
+}
+
+/* CPU models */
+
+static ObjectClass *openrisc_cpu_class_by_name(const char *cpu_model)
+{
+ ObjectClass *oc;
+ char *typename;
+
+ if (cpu_model == NULL) {
+ return NULL;
+ }
+
+ typename = g_strdup_printf("%s-" TYPE_OPENRISC_CPU, cpu_model);
+ oc = object_class_by_name(typename);
+ g_free(typename);
+ if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_OPENRISC_CPU) ||
+ object_class_is_abstract(oc))) {
+ return NULL;
+ }
+ return oc;
+}
+
+static void or1200_initfn(Object *obj)
+{
+ OpenRISCCPU *cpu = OPENRISC_CPU(obj);
+
+ set_feature(cpu, OPENRISC_FEATURE_OB32S);
+ set_feature(cpu, OPENRISC_FEATURE_OF32S);
+}
+
+static void openrisc_any_initfn(Object *obj)
+{
+ OpenRISCCPU *cpu = OPENRISC_CPU(obj);
+
+ set_feature(cpu, OPENRISC_FEATURE_OB32S);
+}
+
+typedef struct OpenRISCCPUInfo {
+ const char *name;
+ void (*initfn)(Object *obj);
+} OpenRISCCPUInfo;
+
+static const OpenRISCCPUInfo openrisc_cpus[] = {
+ { .name = "or1200", .initfn = or1200_initfn },
+ { .name = "any", .initfn = openrisc_any_initfn },
+};
+
+static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
+{
+ OpenRISCCPUClass *occ = OPENRISC_CPU_CLASS(oc);
+ CPUClass *cc = CPU_CLASS(occ);
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ occ->parent_realize = dc->realize;
+ dc->realize = openrisc_cpu_realizefn;
+
+ occ->parent_reset = cc->reset;
+ cc->reset = openrisc_cpu_reset;
+
+ cc->class_by_name = openrisc_cpu_class_by_name;
+ cc->has_work = openrisc_cpu_has_work;
+ cc->do_interrupt = openrisc_cpu_do_interrupt;
+ cc->cpu_exec_interrupt = openrisc_cpu_exec_interrupt;
+ cc->dump_state = openrisc_cpu_dump_state;
+ cc->set_pc = openrisc_cpu_set_pc;
+ cc->gdb_read_register = openrisc_cpu_gdb_read_register;
+ cc->gdb_write_register = openrisc_cpu_gdb_write_register;
+#ifdef CONFIG_USER_ONLY
+ cc->handle_mmu_fault = openrisc_cpu_handle_mmu_fault;
+#else
+ cc->get_phys_page_debug = openrisc_cpu_get_phys_page_debug;
+ dc->vmsd = &vmstate_openrisc_cpu;
+#endif
+ cc->gdb_num_core_regs = 32 + 3;
+}
+
+static void cpu_register(const OpenRISCCPUInfo *info)
+{
+ TypeInfo type_info = {
+ .parent = TYPE_OPENRISC_CPU,
+ .instance_size = sizeof(OpenRISCCPU),
+ .instance_init = info->initfn,
+ .class_size = sizeof(OpenRISCCPUClass),
+ };
+
+ type_info.name = g_strdup_printf("%s-" TYPE_OPENRISC_CPU, info->name);
+ type_register(&type_info);
+ g_free((void *)type_info.name);
+}
+
+static const TypeInfo openrisc_cpu_type_info = {
+ .name = TYPE_OPENRISC_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(OpenRISCCPU),
+ .instance_init = openrisc_cpu_initfn,
+ .abstract = true,
+ .class_size = sizeof(OpenRISCCPUClass),
+ .class_init = openrisc_cpu_class_init,
+};
+
+static void openrisc_cpu_register_types(void)
+{
+ int i;
+
+ type_register_static(&openrisc_cpu_type_info);
+ for (i = 0; i < ARRAY_SIZE(openrisc_cpus); i++) {
+ cpu_register(&openrisc_cpus[i]);
+ }
+}
+
+OpenRISCCPU *cpu_openrisc_init(const char *cpu_model)
+{
+ return OPENRISC_CPU(cpu_generic_init(TYPE_OPENRISC_CPU, cpu_model));
+}
+
+/* Sort alphabetically by type name, except for "any". */
+static gint openrisc_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);
+ if (strcmp(name_a, "any-" TYPE_OPENRISC_CPU) == 0) {
+ return 1;
+ } else if (strcmp(name_b, "any-" TYPE_OPENRISC_CPU) == 0) {
+ return -1;
+ } else {
+ return strcmp(name_a, name_b);
+ }
+}
+
+static void openrisc_cpu_list_entry(gpointer data, gpointer user_data)
+{
+ ObjectClass *oc = data;
+ CPUListState *s = user_data;
+ const char *typename;
+ char *name;
+
+ typename = object_class_get_name(oc);
+ name = g_strndup(typename,
+ strlen(typename) - strlen("-" TYPE_OPENRISC_CPU));
+ (*s->cpu_fprintf)(s->file, " %s\n",
+ name);
+ g_free(name);
+}
+
+void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf)
+{
+ CPUListState s = {
+ .file = f,
+ .cpu_fprintf = cpu_fprintf,
+ };
+ GSList *list;
+
+ list = object_class_get_list(TYPE_OPENRISC_CPU, false);
+ list = g_slist_sort(list, openrisc_cpu_list_compare);
+ (*cpu_fprintf)(f, "Available CPUs:\n");
+ g_slist_foreach(list, openrisc_cpu_list_entry, &s);
+ g_slist_free(list);
+}
+
+type_init(openrisc_cpu_register_types)
diff --git a/qemu/target-openrisc/cpu.h b/qemu/target-openrisc/cpu.h
new file mode 100644
index 000000000..36c4f20e2
--- /dev/null
+++ b/qemu/target-openrisc/cpu.h
@@ -0,0 +1,418 @@
+/*
+ * OpenRISC virtual CPU header.
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ *
+ * 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 CPU_OPENRISC_H
+#define CPU_OPENRISC_H
+
+#define TARGET_LONG_BITS 32
+#define ELF_MACHINE EM_OPENRISC
+
+#define CPUArchState struct CPUOpenRISCState
+
+/* cpu_openrisc_map_address_* in CPUOpenRISCTLBContext need this decl. */
+struct OpenRISCCPU;
+
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/cpu-defs.h"
+#include "fpu/softfloat.h"
+#include "qom/cpu.h"
+
+#define TYPE_OPENRISC_CPU "or32-cpu"
+
+#define OPENRISC_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(OpenRISCCPUClass, (klass), TYPE_OPENRISC_CPU)
+#define OPENRISC_CPU(obj) \
+ OBJECT_CHECK(OpenRISCCPU, (obj), TYPE_OPENRISC_CPU)
+#define OPENRISC_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(OpenRISCCPUClass, (obj), TYPE_OPENRISC_CPU)
+
+/**
+ * OpenRISCCPUClass:
+ * @parent_realize: The parent class' realize handler.
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A OpenRISC CPU model.
+ */
+typedef struct OpenRISCCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ DeviceRealize parent_realize;
+ void (*parent_reset)(CPUState *cpu);
+} OpenRISCCPUClass;
+
+#define NB_MMU_MODES 3
+
+enum {
+ MMU_NOMMU_IDX = 0,
+ MMU_SUPERVISOR_IDX = 1,
+ MMU_USER_IDX = 2,
+};
+
+#define TARGET_PAGE_BITS 13
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+
+#define SET_FP_CAUSE(reg, v) do {\
+ (reg) = ((reg) & ~(0x3f << 12)) | \
+ ((v & 0x3f) << 12);\
+ } while (0)
+#define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f)
+#define UPDATE_FP_FLAGS(reg, v) do {\
+ (reg) |= ((v & 0x1f) << 2);\
+ } while (0)
+
+/* Version Register */
+#define SPR_VR 0xFFFF003F
+
+/* Internal flags, delay slot flag */
+#define D_FLAG 1
+
+/* Interrupt */
+#define NR_IRQS 32
+
+/* Unit presece register */
+enum {
+ UPR_UP = (1 << 0),
+ UPR_DCP = (1 << 1),
+ UPR_ICP = (1 << 2),
+ UPR_DMP = (1 << 3),
+ UPR_IMP = (1 << 4),
+ UPR_MP = (1 << 5),
+ UPR_DUP = (1 << 6),
+ UPR_PCUR = (1 << 7),
+ UPR_PMP = (1 << 8),
+ UPR_PICP = (1 << 9),
+ UPR_TTP = (1 << 10),
+ UPR_CUP = (255 << 24),
+};
+
+/* CPU configure register */
+enum {
+ CPUCFGR_NSGF = (15 << 0),
+ CPUCFGR_CGF = (1 << 4),
+ CPUCFGR_OB32S = (1 << 5),
+ CPUCFGR_OB64S = (1 << 6),
+ CPUCFGR_OF32S = (1 << 7),
+ CPUCFGR_OF64S = (1 << 8),
+ CPUCFGR_OV64S = (1 << 9),
+};
+
+/* DMMU configure register */
+enum {
+ DMMUCFGR_NTW = (3 << 0),
+ DMMUCFGR_NTS = (7 << 2),
+ DMMUCFGR_NAE = (7 << 5),
+ DMMUCFGR_CRI = (1 << 8),
+ DMMUCFGR_PRI = (1 << 9),
+ DMMUCFGR_TEIRI = (1 << 10),
+ DMMUCFGR_HTR = (1 << 11),
+};
+
+/* IMMU configure register */
+enum {
+ IMMUCFGR_NTW = (3 << 0),
+ IMMUCFGR_NTS = (7 << 2),
+ IMMUCFGR_NAE = (7 << 5),
+ IMMUCFGR_CRI = (1 << 8),
+ IMMUCFGR_PRI = (1 << 9),
+ IMMUCFGR_TEIRI = (1 << 10),
+ IMMUCFGR_HTR = (1 << 11),
+};
+
+/* Float point control status register */
+enum {
+ FPCSR_FPEE = 1,
+ FPCSR_RM = (3 << 1),
+ FPCSR_OVF = (1 << 3),
+ FPCSR_UNF = (1 << 4),
+ FPCSR_SNF = (1 << 5),
+ FPCSR_QNF = (1 << 6),
+ FPCSR_ZF = (1 << 7),
+ FPCSR_IXF = (1 << 8),
+ FPCSR_IVF = (1 << 9),
+ FPCSR_INF = (1 << 10),
+ FPCSR_DZF = (1 << 11),
+};
+
+/* Exceptions indices */
+enum {
+ EXCP_RESET = 0x1,
+ EXCP_BUSERR = 0x2,
+ EXCP_DPF = 0x3,
+ EXCP_IPF = 0x4,
+ EXCP_TICK = 0x5,
+ EXCP_ALIGN = 0x6,
+ EXCP_ILLEGAL = 0x7,
+ EXCP_INT = 0x8,
+ EXCP_DTLBMISS = 0x9,
+ EXCP_ITLBMISS = 0xa,
+ EXCP_RANGE = 0xb,
+ EXCP_SYSCALL = 0xc,
+ EXCP_FPE = 0xd,
+ EXCP_TRAP = 0xe,
+ EXCP_NR,
+};
+
+/* Supervisor register */
+enum {
+ SR_SM = (1 << 0),
+ SR_TEE = (1 << 1),
+ SR_IEE = (1 << 2),
+ SR_DCE = (1 << 3),
+ SR_ICE = (1 << 4),
+ SR_DME = (1 << 5),
+ SR_IME = (1 << 6),
+ SR_LEE = (1 << 7),
+ SR_CE = (1 << 8),
+ SR_F = (1 << 9),
+ SR_CY = (1 << 10),
+ SR_OV = (1 << 11),
+ SR_OVE = (1 << 12),
+ SR_DSX = (1 << 13),
+ SR_EPH = (1 << 14),
+ SR_FO = (1 << 15),
+ SR_SUMRA = (1 << 16),
+ SR_SCE = (1 << 17),
+};
+
+/* OpenRISC Hardware Capabilities */
+enum {
+ OPENRISC_FEATURE_NSGF = (15 << 0),
+ OPENRISC_FEATURE_CGF = (1 << 4),
+ OPENRISC_FEATURE_OB32S = (1 << 5),
+ OPENRISC_FEATURE_OB64S = (1 << 6),
+ OPENRISC_FEATURE_OF32S = (1 << 7),
+ OPENRISC_FEATURE_OF64S = (1 << 8),
+ OPENRISC_FEATURE_OV64S = (1 << 9),
+};
+
+/* Tick Timer Mode Register */
+enum {
+ TTMR_TP = (0xfffffff),
+ TTMR_IP = (1 << 28),
+ TTMR_IE = (1 << 29),
+ TTMR_M = (3 << 30),
+};
+
+/* Timer Mode */
+enum {
+ TIMER_NONE = (0 << 30),
+ TIMER_INTR = (1 << 30),
+ TIMER_SHOT = (2 << 30),
+ TIMER_CONT = (3 << 30),
+};
+
+/* TLB size */
+enum {
+ DTLB_WAYS = 1,
+ DTLB_SIZE = 64,
+ DTLB_MASK = (DTLB_SIZE-1),
+ ITLB_WAYS = 1,
+ ITLB_SIZE = 64,
+ ITLB_MASK = (ITLB_SIZE-1),
+};
+
+/* TLB prot */
+enum {
+ URE = (1 << 6),
+ UWE = (1 << 7),
+ SRE = (1 << 8),
+ SWE = (1 << 9),
+
+ SXE = (1 << 6),
+ UXE = (1 << 7),
+};
+
+/* check if tlb available */
+enum {
+ TLBRET_INVALID = -3,
+ TLBRET_NOMATCH = -2,
+ TLBRET_BADADDR = -1,
+ TLBRET_MATCH = 0
+};
+
+typedef struct OpenRISCTLBEntry {
+ uint32_t mr;
+ uint32_t tr;
+} OpenRISCTLBEntry;
+
+#ifndef CONFIG_USER_ONLY
+typedef struct CPUOpenRISCTLBContext {
+ OpenRISCTLBEntry itlb[ITLB_WAYS][ITLB_SIZE];
+ OpenRISCTLBEntry dtlb[DTLB_WAYS][DTLB_SIZE];
+
+ int (*cpu_openrisc_map_address_code)(struct OpenRISCCPU *cpu,
+ hwaddr *physical,
+ int *prot,
+ target_ulong address, int rw);
+ int (*cpu_openrisc_map_address_data)(struct OpenRISCCPU *cpu,
+ hwaddr *physical,
+ int *prot,
+ target_ulong address, int rw);
+} CPUOpenRISCTLBContext;
+#endif
+
+typedef struct CPUOpenRISCState {
+ target_ulong gpr[32]; /* General registers */
+ target_ulong pc; /* Program counter */
+ target_ulong npc; /* Next PC */
+ target_ulong ppc; /* Prev PC */
+ target_ulong jmp_pc; /* Jump PC */
+
+ target_ulong machi; /* Multiply register MACHI */
+ target_ulong maclo; /* Multiply register MACLO */
+
+ target_ulong fpmaddhi; /* Multiply and add float register FPMADDHI */
+ target_ulong fpmaddlo; /* Multiply and add float register FPMADDLO */
+
+ target_ulong epcr; /* Exception PC register */
+ target_ulong eear; /* Exception EA register */
+
+ uint32_t sr; /* Supervisor register */
+ uint32_t vr; /* Version register */
+ uint32_t upr; /* Unit presence register */
+ uint32_t cpucfgr; /* CPU configure register */
+ uint32_t dmmucfgr; /* DMMU configure register */
+ uint32_t immucfgr; /* IMMU configure register */
+ uint32_t esr; /* Exception supervisor register */
+ uint32_t fpcsr; /* Float register */
+ float_status fp_status;
+
+ uint32_t flags; /* cpu_flags, we only use it for exception
+ in solt so far. */
+ uint32_t btaken; /* the SR_F bit */
+
+ CPU_COMMON
+
+ /* Fields from here on are preserved across CPU reset. */
+#ifndef CONFIG_USER_ONLY
+ CPUOpenRISCTLBContext * tlb;
+
+ QEMUTimer *timer;
+ uint32_t ttmr; /* Timer tick mode register */
+ uint32_t ttcr; /* Timer tick count register */
+
+ uint32_t picmr; /* Interrupt mask register */
+ uint32_t picsr; /* Interrupt contrl register*/
+#endif
+ void *irq[32]; /* Interrupt irq input */
+} CPUOpenRISCState;
+
+/**
+ * OpenRISCCPU:
+ * @env: #CPUOpenRISCState
+ *
+ * A OpenRISC CPU.
+ */
+typedef struct OpenRISCCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUOpenRISCState env;
+
+ uint32_t feature; /* CPU Capabilities */
+} OpenRISCCPU;
+
+static inline OpenRISCCPU *openrisc_env_get_cpu(CPUOpenRISCState *env)
+{
+ return container_of(env, OpenRISCCPU, env);
+}
+
+#define ENV_GET_CPU(e) CPU(openrisc_env_get_cpu(e))
+
+#define ENV_OFFSET offsetof(OpenRISCCPU, env)
+
+OpenRISCCPU *cpu_openrisc_init(const char *cpu_model);
+
+void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf);
+int cpu_openrisc_exec(CPUState *cpu);
+void openrisc_cpu_do_interrupt(CPUState *cpu);
+bool openrisc_cpu_exec_interrupt(CPUState *cpu, int int_req);
+void openrisc_cpu_dump_state(CPUState *cpu, FILE *f,
+ fprintf_function cpu_fprintf, int flags);
+hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int openrisc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int openrisc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+void openrisc_translate_init(void);
+int openrisc_cpu_handle_mmu_fault(CPUState *cpu, vaddr address,
+ int rw, int mmu_idx);
+int cpu_openrisc_signal_handler(int host_signum, void *pinfo, void *puc);
+
+#define cpu_list cpu_openrisc_list
+#define cpu_exec cpu_openrisc_exec
+#define cpu_gen_code cpu_openrisc_gen_code
+#define cpu_signal_handler cpu_openrisc_signal_handler
+
+#ifndef CONFIG_USER_ONLY
+extern const struct VMStateDescription vmstate_openrisc_cpu;
+
+/* hw/openrisc_pic.c */
+void cpu_openrisc_pic_init(OpenRISCCPU *cpu);
+
+/* hw/openrisc_timer.c */
+void cpu_openrisc_clock_init(OpenRISCCPU *cpu);
+void cpu_openrisc_count_update(OpenRISCCPU *cpu);
+void cpu_openrisc_timer_update(OpenRISCCPU *cpu);
+void cpu_openrisc_count_start(OpenRISCCPU *cpu);
+void cpu_openrisc_count_stop(OpenRISCCPU *cpu);
+
+void cpu_openrisc_mmu_init(OpenRISCCPU *cpu);
+int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu,
+ hwaddr *physical,
+ int *prot, target_ulong address, int rw);
+int cpu_openrisc_get_phys_code(OpenRISCCPU *cpu,
+ hwaddr *physical,
+ int *prot, target_ulong address, int rw);
+int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
+ hwaddr *physical,
+ int *prot, target_ulong address, int rw);
+#endif
+
+#define cpu_init(cpu_model) CPU(cpu_openrisc_init(cpu_model))
+
+#include "exec/cpu-all.h"
+
+static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env,
+ target_ulong *pc,
+ target_ulong *cs_base, int *flags)
+{
+ *pc = env->pc;
+ *cs_base = 0;
+ /* D_FLAG -- branch instruction exception */
+ *flags = (env->flags & D_FLAG);
+}
+
+static inline int cpu_mmu_index(CPUOpenRISCState *env)
+{
+ if (!(env->sr & SR_IME)) {
+ return MMU_NOMMU_IDX;
+ }
+ return (env->sr & SR_SM) == 0 ? MMU_USER_IDX : MMU_SUPERVISOR_IDX;
+}
+
+#define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_INT_0
+
+#include "exec/exec-all.h"
+
+#endif /* CPU_OPENRISC_H */
diff --git a/qemu/target-openrisc/exception.c b/qemu/target-openrisc/exception.c
new file mode 100644
index 000000000..74652a58f
--- /dev/null
+++ b/qemu/target-openrisc/exception.c
@@ -0,0 +1,29 @@
+/*
+ * OpenRISC exception.
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ *
+ * 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 "cpu.h"
+#include "exception.h"
+
+void QEMU_NORETURN raise_exception(OpenRISCCPU *cpu, uint32_t excp)
+{
+ CPUState *cs = CPU(cpu);
+
+ cs->exception_index = excp;
+ cpu_loop_exit(cs);
+}
diff --git a/qemu/target-openrisc/exception.h b/qemu/target-openrisc/exception.h
new file mode 100644
index 000000000..4b64430df
--- /dev/null
+++ b/qemu/target-openrisc/exception.h
@@ -0,0 +1,28 @@
+/*
+ * OpenRISC exception header.
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ *
+ * 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 QEMU_OPENRISC_EXCP_H
+#define QEMU_OPENRISC_EXCP_H
+
+#include "cpu.h"
+#include "qemu-common.h"
+
+void QEMU_NORETURN raise_exception(OpenRISCCPU *cpu, uint32_t excp);
+
+#endif /* QEMU_OPENRISC_EXCP_H */
diff --git a/qemu/target-openrisc/exception_helper.c b/qemu/target-openrisc/exception_helper.c
new file mode 100644
index 000000000..6093953c9
--- /dev/null
+++ b/qemu/target-openrisc/exception_helper.c
@@ -0,0 +1,29 @@
+/*
+ * OpenRISC exception helper routines
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ *
+ * 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 "cpu.h"
+#include "exec/helper-proto.h"
+#include "exception.h"
+
+void HELPER(exception)(CPUOpenRISCState *env, uint32_t excp)
+{
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
+
+ raise_exception(cpu, excp);
+}
diff --git a/qemu/target-openrisc/fpu_helper.c b/qemu/target-openrisc/fpu_helper.c
new file mode 100644
index 000000000..c94ed35af
--- /dev/null
+++ b/qemu/target-openrisc/fpu_helper.c
@@ -0,0 +1,300 @@
+/*
+ * OpenRISC float helper routines
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ * Feng Gao <gf91597@gmail.com>
+ *
+ * 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 "cpu.h"
+#include "exec/helper-proto.h"
+#include "exception.h"
+
+static inline uint32_t ieee_ex_to_openrisc(OpenRISCCPU *cpu, int fexcp)
+{
+ int ret = 0;
+ if (fexcp) {
+ if (fexcp & float_flag_invalid) {
+ cpu->env.fpcsr |= FPCSR_IVF;
+ ret = 1;
+ }
+ if (fexcp & float_flag_overflow) {
+ cpu->env.fpcsr |= FPCSR_OVF;
+ ret = 1;
+ }
+ if (fexcp & float_flag_underflow) {
+ cpu->env.fpcsr |= FPCSR_UNF;
+ ret = 1;
+ }
+ if (fexcp & float_flag_divbyzero) {
+ cpu->env.fpcsr |= FPCSR_DZF;
+ ret = 1;
+ }
+ if (fexcp & float_flag_inexact) {
+ cpu->env.fpcsr |= FPCSR_IXF;
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+static inline void update_fpcsr(OpenRISCCPU *cpu)
+{
+ int tmp = ieee_ex_to_openrisc(cpu,
+ get_float_exception_flags(&cpu->env.fp_status));
+
+ SET_FP_CAUSE(cpu->env.fpcsr, tmp);
+ if ((GET_FP_ENABLE(cpu->env.fpcsr) & tmp) &&
+ (cpu->env.fpcsr & FPCSR_FPEE)) {
+ helper_exception(&cpu->env, EXCP_FPE);
+ } else {
+ UPDATE_FP_FLAGS(cpu->env.fpcsr, tmp);
+ }
+}
+
+uint64_t HELPER(itofd)(CPUOpenRISCState *env, uint64_t val)
+{
+ uint64_t itofd;
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
+
+ set_float_exception_flags(0, &cpu->env.fp_status);
+ itofd = int32_to_float64(val, &cpu->env.fp_status);
+ update_fpcsr(cpu);
+
+ return itofd;
+}
+
+uint32_t HELPER(itofs)(CPUOpenRISCState *env, uint32_t val)
+{
+ uint32_t itofs;
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
+
+ set_float_exception_flags(0, &cpu->env.fp_status);
+ itofs = int32_to_float32(val, &cpu->env.fp_status);
+ update_fpcsr(cpu);
+
+ return itofs;
+}
+
+uint64_t HELPER(ftoid)(CPUOpenRISCState *env, uint64_t val)
+{
+ uint64_t ftoid;
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
+
+ set_float_exception_flags(0, &cpu->env.fp_status);
+ ftoid = float32_to_int64(val, &cpu->env.fp_status);
+ update_fpcsr(cpu);
+
+ return ftoid;
+}
+
+uint32_t HELPER(ftois)(CPUOpenRISCState *env, uint32_t val)
+{
+ uint32_t ftois;
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
+
+ set_float_exception_flags(0, &cpu->env.fp_status);
+ ftois = float32_to_int32(val, &cpu->env.fp_status);
+ update_fpcsr(cpu);
+
+ return ftois;
+}
+
+#define FLOAT_OP(name, p) void helper_float_##_##p(void)
+
+#define FLOAT_CALC(name) \
+uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \
+ uint64_t fdt0, uint64_t fdt1) \
+{ \
+ uint64_t result; \
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
+ set_float_exception_flags(0, &cpu->env.fp_status); \
+ result = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status); \
+ update_fpcsr(cpu); \
+ return result; \
+} \
+ \
+uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \
+ uint32_t fdt0, uint32_t fdt1) \
+{ \
+ uint32_t result; \
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
+ set_float_exception_flags(0, &cpu->env.fp_status); \
+ result = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status); \
+ update_fpcsr(cpu); \
+ return result; \
+} \
+
+FLOAT_CALC(add)
+FLOAT_CALC(sub)
+FLOAT_CALC(mul)
+FLOAT_CALC(div)
+FLOAT_CALC(rem)
+#undef FLOAT_CALC
+
+#define FLOAT_TERNOP(name1, name2) \
+uint64_t helper_float_ ## name1 ## name2 ## _d(CPUOpenRISCState *env, \
+ uint64_t fdt0, \
+ uint64_t fdt1) \
+{ \
+ uint64_t result, temp, hi, lo; \
+ uint32_t val1, val2; \
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
+ hi = env->fpmaddhi; \
+ lo = env->fpmaddlo; \
+ set_float_exception_flags(0, &cpu->env.fp_status); \
+ result = float64_ ## name1(fdt0, fdt1, &cpu->env.fp_status); \
+ lo &= 0xffffffff; \
+ hi &= 0xffffffff; \
+ temp = (hi << 32) | lo; \
+ result = float64_ ## name2(result, temp, &cpu->env.fp_status); \
+ val1 = result >> 32; \
+ val2 = (uint32_t) (result & 0xffffffff); \
+ update_fpcsr(cpu); \
+ cpu->env.fpmaddlo = val2; \
+ cpu->env.fpmaddhi = val1; \
+ return 0; \
+} \
+ \
+uint32_t helper_float_ ## name1 ## name2 ## _s(CPUOpenRISCState *env, \
+ uint32_t fdt0, uint32_t fdt1) \
+{ \
+ uint64_t result, temp, hi, lo; \
+ uint32_t val1, val2; \
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
+ hi = cpu->env.fpmaddhi; \
+ lo = cpu->env.fpmaddlo; \
+ set_float_exception_flags(0, &cpu->env.fp_status); \
+ result = float64_ ## name1(fdt0, fdt1, &cpu->env.fp_status); \
+ temp = (hi << 32) | lo; \
+ result = float64_ ## name2(result, temp, &cpu->env.fp_status); \
+ val1 = result >> 32; \
+ val2 = (uint32_t) (result & 0xffffffff); \
+ update_fpcsr(cpu); \
+ cpu->env.fpmaddlo = val2; \
+ cpu->env.fpmaddhi = val1; \
+ return 0; \
+}
+
+FLOAT_TERNOP(mul, add)
+#undef FLOAT_TERNOP
+
+
+#define FLOAT_CMP(name) \
+uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \
+ uint64_t fdt0, uint64_t fdt1) \
+{ \
+ int res; \
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
+ set_float_exception_flags(0, &cpu->env.fp_status); \
+ res = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status); \
+ update_fpcsr(cpu); \
+ return res; \
+} \
+ \
+uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \
+ uint32_t fdt0, uint32_t fdt1)\
+{ \
+ int res; \
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
+ set_float_exception_flags(0, &cpu->env.fp_status); \
+ res = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status); \
+ update_fpcsr(cpu); \
+ return res; \
+}
+
+FLOAT_CMP(le)
+FLOAT_CMP(eq)
+FLOAT_CMP(lt)
+#undef FLOAT_CMP
+
+
+#define FLOAT_CMPNE(name) \
+uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \
+ uint64_t fdt0, uint64_t fdt1) \
+{ \
+ int res; \
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
+ set_float_exception_flags(0, &cpu->env.fp_status); \
+ res = !float64_eq_quiet(fdt0, fdt1, &cpu->env.fp_status); \
+ update_fpcsr(cpu); \
+ return res; \
+} \
+ \
+uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \
+ uint32_t fdt0, uint32_t fdt1) \
+{ \
+ int res; \
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
+ set_float_exception_flags(0, &cpu->env.fp_status); \
+ res = !float32_eq_quiet(fdt0, fdt1, &cpu->env.fp_status); \
+ update_fpcsr(cpu); \
+ return res; \
+}
+
+FLOAT_CMPNE(ne)
+#undef FLOAT_CMPNE
+
+#define FLOAT_CMPGT(name) \
+uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \
+ uint64_t fdt0, uint64_t fdt1) \
+{ \
+ int res; \
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
+ set_float_exception_flags(0, &cpu->env.fp_status); \
+ res = !float64_le(fdt0, fdt1, &cpu->env.fp_status); \
+ update_fpcsr(cpu); \
+ return res; \
+} \
+ \
+uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \
+ uint32_t fdt0, uint32_t fdt1) \
+{ \
+ int res; \
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
+ set_float_exception_flags(0, &cpu->env.fp_status); \
+ res = !float32_le(fdt0, fdt1, &cpu->env.fp_status); \
+ update_fpcsr(cpu); \
+ return res; \
+}
+FLOAT_CMPGT(gt)
+#undef FLOAT_CMPGT
+
+#define FLOAT_CMPGE(name) \
+uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \
+ uint64_t fdt0, uint64_t fdt1) \
+{ \
+ int res; \
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
+ set_float_exception_flags(0, &cpu->env.fp_status); \
+ res = !float64_lt(fdt0, fdt1, &cpu->env.fp_status); \
+ update_fpcsr(cpu); \
+ return res; \
+} \
+ \
+uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \
+ uint32_t fdt0, uint32_t fdt1) \
+{ \
+ int res; \
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
+ set_float_exception_flags(0, &cpu->env.fp_status); \
+ res = !float32_lt(fdt0, fdt1, &cpu->env.fp_status); \
+ update_fpcsr(cpu); \
+ return res; \
+}
+
+FLOAT_CMPGE(ge)
+#undef FLOAT_CMPGE
diff --git a/qemu/target-openrisc/gdbstub.c b/qemu/target-openrisc/gdbstub.c
new file mode 100644
index 000000000..18bcc4616
--- /dev/null
+++ b/qemu/target-openrisc/gdbstub.c
@@ -0,0 +1,83 @@
+/*
+ * OpenRISC 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 "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int openrisc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+ CPUOpenRISCState *env = &cpu->env;
+
+ if (n < 32) {
+ return gdb_get_reg32(mem_buf, env->gpr[n]);
+ } else {
+ switch (n) {
+ case 32: /* PPC */
+ return gdb_get_reg32(mem_buf, env->ppc);
+
+ case 33: /* NPC */
+ return gdb_get_reg32(mem_buf, env->npc);
+
+ case 34: /* SR */
+ return gdb_get_reg32(mem_buf, env->sr);
+
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+int openrisc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+ CPUClass *cc = CPU_GET_CLASS(cs);
+ CPUOpenRISCState *env = &cpu->env;
+ uint32_t tmp;
+
+ if (n > cc->gdb_num_core_regs) {
+ return 0;
+ }
+
+ tmp = ldl_p(mem_buf);
+
+ if (n < 32) {
+ env->gpr[n] = tmp;
+ } else {
+ switch (n) {
+ case 32: /* PPC */
+ env->ppc = tmp;
+ break;
+
+ case 33: /* NPC */
+ env->npc = tmp;
+ break;
+
+ case 34: /* SR */
+ env->sr = tmp;
+ break;
+
+ default:
+ break;
+ }
+ }
+ return 4;
+}
diff --git a/qemu/target-openrisc/helper.h b/qemu/target-openrisc/helper.h
new file mode 100644
index 000000000..f53fa2134
--- /dev/null
+++ b/qemu/target-openrisc/helper.h
@@ -0,0 +1,66 @@
+/*
+ * OpenRISC helper defines
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ *
+ * 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/>.
+ */
+
+/* exception */
+DEF_HELPER_FLAGS_2(exception, 0, void, env, i32)
+
+/* float */
+DEF_HELPER_FLAGS_2(itofd, 0, i64, env, i64)
+DEF_HELPER_FLAGS_2(itofs, 0, i32, env, i32)
+DEF_HELPER_FLAGS_2(ftoid, 0, i64, env, i64)
+DEF_HELPER_FLAGS_2(ftois, 0, i32, env, i32)
+
+#define FOP_MADD(op) \
+DEF_HELPER_FLAGS_3(float_ ## op ## _s, 0, i32, env, i32, i32) \
+DEF_HELPER_FLAGS_3(float_ ## op ## _d, 0, i64, env, i64, i64)
+FOP_MADD(muladd)
+#undef FOP_MADD
+
+#define FOP_CALC(op) \
+DEF_HELPER_FLAGS_3(float_ ## op ## _s, 0, i32, env, i32, i32) \
+DEF_HELPER_FLAGS_3(float_ ## op ## _d, 0, i64, env, i64, i64)
+FOP_CALC(add)
+FOP_CALC(sub)
+FOP_CALC(mul)
+FOP_CALC(div)
+FOP_CALC(rem)
+#undef FOP_CALC
+
+#define FOP_CMP(op) \
+DEF_HELPER_FLAGS_3(float_ ## op ## _s, 0, i32, env, i32, i32) \
+DEF_HELPER_FLAGS_3(float_ ## op ## _d, 0, i64, env, i64, i64)
+FOP_CMP(eq)
+FOP_CMP(lt)
+FOP_CMP(le)
+FOP_CMP(ne)
+FOP_CMP(gt)
+FOP_CMP(ge)
+#undef FOP_CMP
+
+/* int */
+DEF_HELPER_FLAGS_1(ff1, 0, tl, tl)
+DEF_HELPER_FLAGS_1(fl1, 0, tl, tl)
+DEF_HELPER_FLAGS_3(mul32, 0, i32, env, i32, i32)
+
+/* interrupt */
+DEF_HELPER_FLAGS_1(rfe, 0, void, env)
+
+/* sys */
+DEF_HELPER_FLAGS_4(mtspr, 0, void, env, tl, tl, tl)
+DEF_HELPER_FLAGS_4(mfspr, 0, tl, env, tl, tl, tl)
diff --git a/qemu/target-openrisc/int_helper.c b/qemu/target-openrisc/int_helper.c
new file mode 100644
index 000000000..6e27aebd9
--- /dev/null
+++ b/qemu/target-openrisc/int_helper.c
@@ -0,0 +1,79 @@
+/*
+ * OpenRISC int helper routines
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ * Feng Gao <gf91597@gmail.com>
+ *
+ * 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 "cpu.h"
+#include "exec/helper-proto.h"
+#include "exception.h"
+#include "qemu/host-utils.h"
+
+target_ulong HELPER(ff1)(target_ulong x)
+{
+/*#ifdef TARGET_OPENRISC64
+ return x ? ctz64(x) + 1 : 0;
+#else*/
+ return x ? ctz32(x) + 1 : 0;
+/*#endif*/
+}
+
+target_ulong HELPER(fl1)(target_ulong x)
+{
+/* not used yet, open it when we need or64. */
+/*#ifdef TARGET_OPENRISC64
+ return 64 - clz64(x);
+#else*/
+ return 32 - clz32(x);
+/*#endif*/
+}
+
+uint32_t HELPER(mul32)(CPUOpenRISCState *env,
+ uint32_t ra, uint32_t rb)
+{
+ uint64_t result;
+ uint32_t high, cy;
+
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
+
+ result = (uint64_t)ra * rb;
+ /* regisiers in or32 is 32bit, so 32 is NOT a magic number.
+ or64 is not handled in this function, and not implement yet,
+ TARGET_LONG_BITS for or64 is 64, it will break this function,
+ so, we didn't use TARGET_LONG_BITS here. */
+ high = result >> 32;
+ cy = result >> (32 - 1);
+
+ if ((cy & 0x1) == 0x0) {
+ if (high == 0x0) {
+ return result;
+ }
+ }
+
+ if ((cy & 0x1) == 0x1) {
+ if (high == 0xffffffff) {
+ return result;
+ }
+ }
+
+ cpu->env.sr |= (SR_OV | SR_CY);
+ if (cpu->env.sr & SR_OVE) {
+ raise_exception(cpu, EXCP_RANGE);
+ }
+
+ return result;
+}
diff --git a/qemu/target-openrisc/interrupt.c b/qemu/target-openrisc/interrupt.c
new file mode 100644
index 000000000..e480cfd1b
--- /dev/null
+++ b/qemu/target-openrisc/interrupt.c
@@ -0,0 +1,85 @@
+/*
+ * OpenRISC interrupt.
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ *
+ * 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 "cpu.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+#include "qemu/host-utils.h"
+#ifndef CONFIG_USER_ONLY
+#include "hw/loader.h"
+#endif
+
+void openrisc_cpu_do_interrupt(CPUState *cs)
+{
+#ifndef CONFIG_USER_ONLY
+ OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+ CPUOpenRISCState *env = &cpu->env;
+
+ env->epcr = env->pc;
+ if (env->flags & D_FLAG) {
+ env->flags &= ~D_FLAG;
+ env->sr |= SR_DSX;
+ env->epcr -= 4;
+ }
+ if (cs->exception_index == EXCP_SYSCALL) {
+ env->epcr += 4;
+ }
+
+ /* For machine-state changed between user-mode and supervisor mode,
+ we need flush TLB when we enter&exit EXCP. */
+ tlb_flush(cs, 1);
+
+ env->esr = env->sr;
+ env->sr &= ~SR_DME;
+ env->sr &= ~SR_IME;
+ env->sr |= SR_SM;
+ env->sr &= ~SR_IEE;
+ env->sr &= ~SR_TEE;
+ env->tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu;
+ env->tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu;
+
+ if (cs->exception_index > 0 && cs->exception_index < EXCP_NR) {
+ env->pc = (cs->exception_index << 8);
+ } else {
+ cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
+ }
+#endif
+
+ cs->exception_index = -1;
+}
+
+bool openrisc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
+{
+ OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+ CPUOpenRISCState *env = &cpu->env;
+ int idx = -1;
+
+ if ((interrupt_request & CPU_INTERRUPT_HARD) && (env->sr & SR_IEE)) {
+ idx = EXCP_INT;
+ }
+ if ((interrupt_request & CPU_INTERRUPT_TIMER) && (env->sr & SR_TEE)) {
+ idx = EXCP_TICK;
+ }
+ if (idx >= 0) {
+ cs->exception_index = idx;
+ openrisc_cpu_do_interrupt(cs);
+ return true;
+ }
+ return false;
+}
diff --git a/qemu/target-openrisc/interrupt_helper.c b/qemu/target-openrisc/interrupt_helper.c
new file mode 100644
index 000000000..55a780c7b
--- /dev/null
+++ b/qemu/target-openrisc/interrupt_helper.c
@@ -0,0 +1,58 @@
+/*
+ * OpenRISC interrupt helper routines
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ * Feng Gao <gf91597@gmail.com>
+ *
+ * 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 "cpu.h"
+#include "exec/helper-proto.h"
+
+void HELPER(rfe)(CPUOpenRISCState *env)
+{
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
+ CPUState *cs = CPU(cpu);
+#ifndef CONFIG_USER_ONLY
+ int need_flush_tlb = (cpu->env.sr & (SR_SM | SR_IME | SR_DME)) ^
+ (cpu->env.esr & (SR_SM | SR_IME | SR_DME));
+#endif
+ cpu->env.pc = cpu->env.epcr;
+ cpu->env.npc = cpu->env.epcr;
+ cpu->env.sr = cpu->env.esr;
+
+#ifndef CONFIG_USER_ONLY
+ if (cpu->env.sr & SR_DME) {
+ cpu->env.tlb->cpu_openrisc_map_address_data =
+ &cpu_openrisc_get_phys_data;
+ } else {
+ cpu->env.tlb->cpu_openrisc_map_address_data =
+ &cpu_openrisc_get_phys_nommu;
+ }
+
+ if (cpu->env.sr & SR_IME) {
+ cpu->env.tlb->cpu_openrisc_map_address_code =
+ &cpu_openrisc_get_phys_code;
+ } else {
+ cpu->env.tlb->cpu_openrisc_map_address_code =
+ &cpu_openrisc_get_phys_nommu;
+ }
+
+ if (need_flush_tlb) {
+ tlb_flush(cs, 1);
+ }
+#endif
+ cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
diff --git a/qemu/target-openrisc/machine.c b/qemu/target-openrisc/machine.c
new file mode 100644
index 000000000..9f66a9cef
--- /dev/null
+++ b/qemu/target-openrisc/machine.c
@@ -0,0 +1,50 @@
+/*
+ * OpenRISC Machine
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ *
+ * 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 "hw/hw.h"
+#include "hw/boards.h"
+
+static const VMStateDescription vmstate_env = {
+ .name = "env",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(gpr, CPUOpenRISCState, 32),
+ VMSTATE_UINT32(sr, CPUOpenRISCState),
+ VMSTATE_UINT32(epcr, CPUOpenRISCState),
+ VMSTATE_UINT32(eear, CPUOpenRISCState),
+ VMSTATE_UINT32(esr, CPUOpenRISCState),
+ VMSTATE_UINT32(fpcsr, CPUOpenRISCState),
+ VMSTATE_UINT32(pc, CPUOpenRISCState),
+ VMSTATE_UINT32(npc, CPUOpenRISCState),
+ VMSTATE_UINT32(ppc, CPUOpenRISCState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+const VMStateDescription vmstate_openrisc_cpu = {
+ .name = "cpu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_CPU(),
+ VMSTATE_STRUCT(env, OpenRISCCPU, 1, vmstate_env, CPUOpenRISCState),
+ VMSTATE_END_OF_LIST()
+ }
+};
diff --git a/qemu/target-openrisc/mmu.c b/qemu/target-openrisc/mmu.c
new file mode 100644
index 000000000..750a93636
--- /dev/null
+++ b/qemu/target-openrisc/mmu.c
@@ -0,0 +1,236 @@
+/*
+ * OpenRISC MMU.
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ * Zhizhou Zhang <etouzh@gmail.com>
+ *
+ * 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 "cpu.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+#include "qemu/host-utils.h"
+#ifndef CONFIG_USER_ONLY
+#include "hw/loader.h"
+#endif
+
+#ifndef CONFIG_USER_ONLY
+int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu,
+ hwaddr *physical,
+ int *prot, target_ulong address, int rw)
+{
+ *physical = address;
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return TLBRET_MATCH;
+}
+
+int cpu_openrisc_get_phys_code(OpenRISCCPU *cpu,
+ hwaddr *physical,
+ int *prot, target_ulong address, int rw)
+{
+ int vpn = address >> TARGET_PAGE_BITS;
+ int idx = vpn & ITLB_MASK;
+ int right = 0;
+
+ if ((cpu->env.tlb->itlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
+ return TLBRET_NOMATCH;
+ }
+ if (!(cpu->env.tlb->itlb[0][idx].mr & 1)) {
+ return TLBRET_INVALID;
+ }
+
+ if (cpu->env.sr & SR_SM) { /* supervisor mode */
+ if (cpu->env.tlb->itlb[0][idx].tr & SXE) {
+ right |= PAGE_EXEC;
+ }
+ } else {
+ if (cpu->env.tlb->itlb[0][idx].tr & UXE) {
+ right |= PAGE_EXEC;
+ }
+ }
+
+ if ((rw & 2) && ((right & PAGE_EXEC) == 0)) {
+ return TLBRET_BADADDR;
+ }
+
+ *physical = (cpu->env.tlb->itlb[0][idx].tr & TARGET_PAGE_MASK) |
+ (address & (TARGET_PAGE_SIZE-1));
+ *prot = right;
+ return TLBRET_MATCH;
+}
+
+int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
+ hwaddr *physical,
+ int *prot, target_ulong address, int rw)
+{
+ int vpn = address >> TARGET_PAGE_BITS;
+ int idx = vpn & DTLB_MASK;
+ int right = 0;
+
+ if ((cpu->env.tlb->dtlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
+ return TLBRET_NOMATCH;
+ }
+ if (!(cpu->env.tlb->dtlb[0][idx].mr & 1)) {
+ return TLBRET_INVALID;
+ }
+
+ if (cpu->env.sr & SR_SM) { /* supervisor mode */
+ if (cpu->env.tlb->dtlb[0][idx].tr & SRE) {
+ right |= PAGE_READ;
+ }
+ if (cpu->env.tlb->dtlb[0][idx].tr & SWE) {
+ right |= PAGE_WRITE;
+ }
+ } else {
+ if (cpu->env.tlb->dtlb[0][idx].tr & URE) {
+ right |= PAGE_READ;
+ }
+ if (cpu->env.tlb->dtlb[0][idx].tr & UWE) {
+ right |= PAGE_WRITE;
+ }
+ }
+
+ if (!(rw & 1) && ((right & PAGE_READ) == 0)) {
+ return TLBRET_BADADDR;
+ }
+ if ((rw & 1) && ((right & PAGE_WRITE) == 0)) {
+ return TLBRET_BADADDR;
+ }
+
+ *physical = (cpu->env.tlb->dtlb[0][idx].tr & TARGET_PAGE_MASK) |
+ (address & (TARGET_PAGE_SIZE-1));
+ *prot = right;
+ return TLBRET_MATCH;
+}
+
+static int cpu_openrisc_get_phys_addr(OpenRISCCPU *cpu,
+ hwaddr *physical,
+ int *prot, target_ulong address,
+ int rw)
+{
+ int ret = TLBRET_MATCH;
+
+ if (rw == 2) { /* ITLB */
+ *physical = 0;
+ ret = cpu->env.tlb->cpu_openrisc_map_address_code(cpu, physical,
+ prot, address, rw);
+ } else { /* DTLB */
+ ret = cpu->env.tlb->cpu_openrisc_map_address_data(cpu, physical,
+ prot, address, rw);
+ }
+
+ return ret;
+}
+#endif
+
+static void cpu_openrisc_raise_mmu_exception(OpenRISCCPU *cpu,
+ target_ulong address,
+ int rw, int tlb_error)
+{
+ CPUState *cs = CPU(cpu);
+ int exception = 0;
+
+ switch (tlb_error) {
+ default:
+ if (rw == 2) {
+ exception = EXCP_IPF;
+ } else {
+ exception = EXCP_DPF;
+ }
+ break;
+#ifndef CONFIG_USER_ONLY
+ case TLBRET_BADADDR:
+ if (rw == 2) {
+ exception = EXCP_IPF;
+ } else {
+ exception = EXCP_DPF;
+ }
+ break;
+ case TLBRET_INVALID:
+ case TLBRET_NOMATCH:
+ /* No TLB match for a mapped address */
+ if (rw == 2) {
+ exception = EXCP_ITLBMISS;
+ } else {
+ exception = EXCP_DTLBMISS;
+ }
+ break;
+#endif
+ }
+
+ cs->exception_index = exception;
+ cpu->env.eear = address;
+}
+
+#ifndef CONFIG_USER_ONLY
+int openrisc_cpu_handle_mmu_fault(CPUState *cs,
+ vaddr address, int rw, int mmu_idx)
+{
+ OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+ int ret = 0;
+ hwaddr physical = 0;
+ int prot = 0;
+
+ ret = cpu_openrisc_get_phys_addr(cpu, &physical, &prot,
+ address, rw);
+
+ if (ret == TLBRET_MATCH) {
+ tlb_set_page(cs, address & TARGET_PAGE_MASK,
+ physical & TARGET_PAGE_MASK, prot,
+ mmu_idx, TARGET_PAGE_SIZE);
+ ret = 0;
+ } else if (ret < 0) {
+ cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
+ ret = 1;
+ }
+
+ return ret;
+}
+#else
+int openrisc_cpu_handle_mmu_fault(CPUState *cs,
+ vaddr address, int rw, int mmu_idx)
+{
+ OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+ int ret = 0;
+
+ cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
+ ret = 1;
+
+ return ret;
+}
+#endif
+
+#ifndef CONFIG_USER_ONLY
+hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
+{
+ OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+ hwaddr phys_addr;
+ int prot;
+
+ if (cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0)) {
+ return -1;
+ }
+
+ return phys_addr;
+}
+
+void cpu_openrisc_mmu_init(OpenRISCCPU *cpu)
+{
+ cpu->env.tlb = g_malloc0(sizeof(CPUOpenRISCTLBContext));
+
+ cpu->env.tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu;
+ cpu->env.tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu;
+}
+#endif
diff --git a/qemu/target-openrisc/mmu_helper.c b/qemu/target-openrisc/mmu_helper.c
new file mode 100644
index 000000000..ee1c6f611
--- /dev/null
+++ b/qemu/target-openrisc/mmu_helper.c
@@ -0,0 +1,42 @@
+/*
+ * OpenRISC MMU helper routines
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ * Zhizhou Zhang <etouzh@gmail.com>
+ *
+ * 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 "cpu.h"
+#include "exec/cpu_ldst.h"
+
+#ifndef CONFIG_USER_ONLY
+
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write,
+ int mmu_idx, uintptr_t retaddr)
+{
+ int ret;
+
+ ret = openrisc_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
+
+ if (ret) {
+ if (retaddr) {
+ /* now we have a real cpu fault. */
+ cpu_restore_state(cs, retaddr);
+ }
+ /* Raise Exception. */
+ cpu_loop_exit(cs);
+ }
+}
+#endif
diff --git a/qemu/target-openrisc/sys_helper.c b/qemu/target-openrisc/sys_helper.c
new file mode 100644
index 000000000..53ca6bcef
--- /dev/null
+++ b/qemu/target-openrisc/sys_helper.c
@@ -0,0 +1,286 @@
+/*
+ * OpenRISC system instructions helper routines
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ * Zhizhou Zhang <etouzh@gmail.com>
+ *
+ * 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 "cpu.h"
+#include "exec/helper-proto.h"
+
+#define TO_SPR(group, number) (((group) << 11) + (number))
+
+void HELPER(mtspr)(CPUOpenRISCState *env,
+ target_ulong ra, target_ulong rb, target_ulong offset)
+{
+#ifndef CONFIG_USER_ONLY
+ int spr = (ra | offset);
+ int idx;
+
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
+ CPUState *cs = CPU(cpu);
+
+ switch (spr) {
+ case TO_SPR(0, 0): /* VR */
+ env->vr = rb;
+ break;
+
+ case TO_SPR(0, 16): /* NPC */
+ env->npc = rb;
+ break;
+
+ case TO_SPR(0, 17): /* SR */
+ if ((env->sr & (SR_IME | SR_DME | SR_SM)) ^
+ (rb & (SR_IME | SR_DME | SR_SM))) {
+ tlb_flush(cs, 1);
+ }
+ env->sr = rb;
+ env->sr |= SR_FO; /* FO is const equal to 1 */
+ if (env->sr & SR_DME) {
+ env->tlb->cpu_openrisc_map_address_data =
+ &cpu_openrisc_get_phys_data;
+ } else {
+ env->tlb->cpu_openrisc_map_address_data =
+ &cpu_openrisc_get_phys_nommu;
+ }
+
+ if (env->sr & SR_IME) {
+ env->tlb->cpu_openrisc_map_address_code =
+ &cpu_openrisc_get_phys_code;
+ } else {
+ env->tlb->cpu_openrisc_map_address_code =
+ &cpu_openrisc_get_phys_nommu;
+ }
+ break;
+
+ case TO_SPR(0, 18): /* PPC */
+ env->ppc = rb;
+ break;
+
+ case TO_SPR(0, 32): /* EPCR */
+ env->epcr = rb;
+ break;
+
+ case TO_SPR(0, 48): /* EEAR */
+ env->eear = rb;
+ break;
+
+ case TO_SPR(0, 64): /* ESR */
+ env->esr = rb;
+ break;
+ case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */
+ idx = spr - TO_SPR(1, 512);
+ if (!(rb & 1)) {
+ tlb_flush_page(cs, env->tlb->dtlb[0][idx].mr & TARGET_PAGE_MASK);
+ }
+ env->tlb->dtlb[0][idx].mr = rb;
+ break;
+
+ case TO_SPR(1, 640) ... TO_SPR(1, 640+DTLB_SIZE-1): /* DTLBW0TR 0-127 */
+ idx = spr - TO_SPR(1, 640);
+ env->tlb->dtlb[0][idx].tr = rb;
+ break;
+ case TO_SPR(1, 768) ... TO_SPR(1, 895): /* DTLBW1MR 0-127 */
+ case TO_SPR(1, 896) ... TO_SPR(1, 1023): /* DTLBW1TR 0-127 */
+ case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */
+ case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */
+ case TO_SPR(1, 1280) ... TO_SPR(1, 1407): /* DTLBW3MR 0-127 */
+ case TO_SPR(1, 1408) ... TO_SPR(1, 1535): /* DTLBW3TR 0-127 */
+ break;
+ case TO_SPR(2, 512) ... TO_SPR(2, 512+ITLB_SIZE-1): /* ITLBW0MR 0-127 */
+ idx = spr - TO_SPR(2, 512);
+ if (!(rb & 1)) {
+ tlb_flush_page(cs, env->tlb->itlb[0][idx].mr & TARGET_PAGE_MASK);
+ }
+ env->tlb->itlb[0][idx].mr = rb;
+ break;
+
+ case TO_SPR(2, 640) ... TO_SPR(2, 640+ITLB_SIZE-1): /* ITLBW0TR 0-127 */
+ idx = spr - TO_SPR(2, 640);
+ env->tlb->itlb[0][idx].tr = rb;
+ break;
+ case TO_SPR(2, 768) ... TO_SPR(2, 895): /* ITLBW1MR 0-127 */
+ case TO_SPR(2, 896) ... TO_SPR(2, 1023): /* ITLBW1TR 0-127 */
+ case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */
+ case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */
+ case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
+ case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
+ break;
+ case TO_SPR(9, 0): /* PICMR */
+ env->picmr |= rb;
+ break;
+ case TO_SPR(9, 2): /* PICSR */
+ env->picsr &= ~rb;
+ break;
+ case TO_SPR(10, 0): /* TTMR */
+ {
+ if ((env->ttmr & TTMR_M) ^ (rb & TTMR_M)) {
+ switch (rb & TTMR_M) {
+ case TIMER_NONE:
+ cpu_openrisc_count_stop(cpu);
+ break;
+ case TIMER_INTR:
+ case TIMER_SHOT:
+ case TIMER_CONT:
+ cpu_openrisc_count_start(cpu);
+ break;
+ default:
+ break;
+ }
+ }
+
+ int ip = env->ttmr & TTMR_IP;
+
+ if (rb & TTMR_IP) { /* Keep IP bit. */
+ env->ttmr = (rb & ~TTMR_IP) | ip;
+ } else { /* Clear IP bit. */
+ env->ttmr = rb & ~TTMR_IP;
+ cs->interrupt_request &= ~CPU_INTERRUPT_TIMER;
+ }
+
+ cpu_openrisc_timer_update(cpu);
+ }
+ break;
+
+ case TO_SPR(10, 1): /* TTCR */
+ env->ttcr = rb;
+ if (env->ttmr & TIMER_NONE) {
+ return;
+ }
+ cpu_openrisc_timer_update(cpu);
+ break;
+ default:
+
+ break;
+ }
+#endif
+}
+
+target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
+ target_ulong rd, target_ulong ra, uint32_t offset)
+{
+#ifndef CONFIG_USER_ONLY
+ int spr = (ra | offset);
+ int idx;
+
+ OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
+
+ switch (spr) {
+ case TO_SPR(0, 0): /* VR */
+ return env->vr & SPR_VR;
+
+ case TO_SPR(0, 1): /* UPR */
+ return env->upr; /* TT, DM, IM, UP present */
+
+ case TO_SPR(0, 2): /* CPUCFGR */
+ return env->cpucfgr;
+
+ case TO_SPR(0, 3): /* DMMUCFGR */
+ return env->dmmucfgr; /* 1Way, 64 entries */
+
+ case TO_SPR(0, 4): /* IMMUCFGR */
+ return env->immucfgr;
+
+ case TO_SPR(0, 16): /* NPC */
+ return env->npc;
+
+ case TO_SPR(0, 17): /* SR */
+ return env->sr;
+
+ case TO_SPR(0, 18): /* PPC */
+ return env->ppc;
+
+ case TO_SPR(0, 32): /* EPCR */
+ return env->epcr;
+
+ case TO_SPR(0, 48): /* EEAR */
+ return env->eear;
+
+ case TO_SPR(0, 64): /* ESR */
+ return env->esr;
+
+ case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */
+ idx = spr - TO_SPR(1, 512);
+ return env->tlb->dtlb[0][idx].mr;
+
+ case TO_SPR(1, 640) ... TO_SPR(1, 640+DTLB_SIZE-1): /* DTLBW0TR 0-127 */
+ idx = spr - TO_SPR(1, 640);
+ return env->tlb->dtlb[0][idx].tr;
+
+ case TO_SPR(1, 768) ... TO_SPR(1, 895): /* DTLBW1MR 0-127 */
+ case TO_SPR(1, 896) ... TO_SPR(1, 1023): /* DTLBW1TR 0-127 */
+ case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */
+ case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */
+ case TO_SPR(1, 1280) ... TO_SPR(1, 1407): /* DTLBW3MR 0-127 */
+ case TO_SPR(1, 1408) ... TO_SPR(1, 1535): /* DTLBW3TR 0-127 */
+ break;
+
+ case TO_SPR(2, 512) ... TO_SPR(2, 512+ITLB_SIZE-1): /* ITLBW0MR 0-127 */
+ idx = spr - TO_SPR(2, 512);
+ return env->tlb->itlb[0][idx].mr;
+
+ case TO_SPR(2, 640) ... TO_SPR(2, 640+ITLB_SIZE-1): /* ITLBW0TR 0-127 */
+ idx = spr - TO_SPR(2, 640);
+ return env->tlb->itlb[0][idx].tr;
+
+ case TO_SPR(2, 768) ... TO_SPR(2, 895): /* ITLBW1MR 0-127 */
+ case TO_SPR(2, 896) ... TO_SPR(2, 1023): /* ITLBW1TR 0-127 */
+ case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */
+ case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */
+ case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
+ case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
+ break;
+
+ case TO_SPR(9, 0): /* PICMR */
+ return env->picmr;
+
+ case TO_SPR(9, 2): /* PICSR */
+ return env->picsr;
+
+ case TO_SPR(10, 0): /* TTMR */
+ return env->ttmr;
+
+ case TO_SPR(10, 1): /* TTCR */
+ cpu_openrisc_count_update(cpu);
+ return env->ttcr;
+
+ default:
+ break;
+ }
+#endif
+
+/*If we later need to add tracepoints (or debug printfs) for the return
+value, it may be useful to structure the code like this:
+
+target_ulong ret = 0;
+
+switch() {
+case x:
+ ret = y;
+ break;
+case z:
+ ret = 42;
+ break;
+...
+}
+
+later something like trace_spr_read(ret);
+
+return ret;*/
+
+ /* for rd is passed in, if rd unchanged, just keep it back. */
+ return rd;
+}
diff --git a/qemu/target-openrisc/translate.c b/qemu/target-openrisc/translate.c
new file mode 100644
index 000000000..a62cbf401
--- /dev/null
+++ b/qemu/target-openrisc/translate.c
@@ -0,0 +1,1810 @@
+/*
+ * OpenRISC translation
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ * Feng Gao <gf91597@gmail.com>
+ *
+ * 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 "cpu.h"
+#include "exec/exec-all.h"
+#include "disas/disas.h"
+#include "tcg-op.h"
+#include "qemu-common.h"
+#include "qemu/log.h"
+#include "config.h"
+#include "qemu/bitops.h"
+#include "exec/cpu_ldst.h"
+
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
+
+#include "trace-tcg.h"
+
+
+#define OPENRISC_DISAS
+
+#ifdef OPENRISC_DISAS
+# define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
+#else
+# define LOG_DIS(...) do { } while (0)
+#endif
+
+typedef struct DisasContext {
+ TranslationBlock *tb;
+ target_ulong pc, ppc, npc;
+ uint32_t tb_flags, synced_flags, flags;
+ uint32_t is_jmp;
+ uint32_t mem_idx;
+ int singlestep_enabled;
+ uint32_t delayed_branch;
+} DisasContext;
+
+static TCGv_ptr cpu_env;
+static TCGv cpu_sr;
+static TCGv cpu_R[32];
+static TCGv cpu_pc;
+static TCGv jmp_pc; /* l.jr/l.jalr temp pc */
+static TCGv cpu_npc;
+static TCGv cpu_ppc;
+static TCGv_i32 env_btaken; /* bf/bnf , F flag taken */
+static TCGv_i32 fpcsr;
+static TCGv machi, maclo;
+static TCGv fpmaddhi, fpmaddlo;
+static TCGv_i32 env_flags;
+#include "exec/gen-icount.h"
+
+void openrisc_translate_init(void)
+{
+ static const char * const 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", "r27", "r28", "r29", "r30", "r31",
+ };
+ int i;
+
+ cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+ cpu_sr = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUOpenRISCState, sr), "sr");
+ env_flags = tcg_global_mem_new_i32(TCG_AREG0,
+ offsetof(CPUOpenRISCState, flags),
+ "flags");
+ cpu_pc = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUOpenRISCState, pc), "pc");
+ cpu_npc = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUOpenRISCState, npc), "npc");
+ cpu_ppc = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUOpenRISCState, ppc), "ppc");
+ jmp_pc = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUOpenRISCState, jmp_pc), "jmp_pc");
+ env_btaken = tcg_global_mem_new_i32(TCG_AREG0,
+ offsetof(CPUOpenRISCState, btaken),
+ "btaken");
+ fpcsr = tcg_global_mem_new_i32(TCG_AREG0,
+ offsetof(CPUOpenRISCState, fpcsr),
+ "fpcsr");
+ machi = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUOpenRISCState, machi),
+ "machi");
+ maclo = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUOpenRISCState, maclo),
+ "maclo");
+ fpmaddhi = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUOpenRISCState, fpmaddhi),
+ "fpmaddhi");
+ fpmaddlo = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUOpenRISCState, fpmaddlo),
+ "fpmaddlo");
+ for (i = 0; i < 32; i++) {
+ cpu_R[i] = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUOpenRISCState, gpr[i]),
+ regnames[i]);
+ }
+}
+
+/* Writeback SR_F translation space to execution space. */
+static inline void wb_SR_F(void)
+{
+ TCGLabel *label = gen_new_label();
+ tcg_gen_andi_tl(cpu_sr, cpu_sr, ~SR_F);
+ tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, label);
+ tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_F);
+ gen_set_label(label);
+}
+
+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 <<= TARGET_LONG_BITS - width;
+ sval = val;
+ /* ASR. */
+ sval >>= TARGET_LONG_BITS - width;
+ return sval;
+}
+
+static inline void gen_sync_flags(DisasContext *dc)
+{
+ /* Sync the tb dependent flag between translate and runtime. */
+ if (dc->tb_flags != dc->synced_flags) {
+ tcg_gen_movi_tl(env_flags, dc->tb_flags);
+ dc->synced_flags = dc->tb_flags;
+ }
+}
+
+static void gen_exception(DisasContext *dc, unsigned int excp)
+{
+ TCGv_i32 tmp = tcg_const_i32(excp);
+ gen_helper_exception(cpu_env, tmp);
+ tcg_temp_free_i32(tmp);
+}
+
+static void gen_illegal_exception(DisasContext *dc)
+{
+ tcg_gen_movi_tl(cpu_pc, dc->pc);
+ gen_exception(dc, EXCP_ILLEGAL);
+ dc->is_jmp = DISAS_UPDATE;
+}
+
+/* not used yet, open it when we need or64. */
+/*#ifdef TARGET_OPENRISC64
+static void check_ob64s(DisasContext *dc)
+{
+ if (!(dc->flags & CPUCFGR_OB64S)) {
+ gen_illegal_exception(dc);
+ }
+}
+
+static void check_of64s(DisasContext *dc)
+{
+ if (!(dc->flags & CPUCFGR_OF64S)) {
+ gen_illegal_exception(dc);
+ }
+}
+
+static void check_ov64s(DisasContext *dc)
+{
+ if (!(dc->flags & CPUCFGR_OV64S)) {
+ gen_illegal_exception(dc);
+ }
+}
+#endif*/
+
+static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
+{
+ TranslationBlock *tb;
+ tb = dc->tb;
+ if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
+ likely(!dc->singlestep_enabled)) {
+ tcg_gen_movi_tl(cpu_pc, dest);
+ tcg_gen_goto_tb(n);
+ tcg_gen_exit_tb((uintptr_t)tb + n);
+ } else {
+ tcg_gen_movi_tl(cpu_pc, dest);
+ if (dc->singlestep_enabled) {
+ gen_exception(dc, EXCP_DEBUG);
+ }
+ tcg_gen_exit_tb(0);
+ }
+}
+
+static void gen_jump(DisasContext *dc, uint32_t imm, uint32_t reg, uint32_t op0)
+{
+ target_ulong tmp_pc;
+ /* N26, 26bits imm */
+ tmp_pc = sign_extend((imm<<2), 26) + dc->pc;
+
+ switch (op0) {
+ case 0x00: /* l.j */
+ tcg_gen_movi_tl(jmp_pc, tmp_pc);
+ break;
+ case 0x01: /* l.jal */
+ tcg_gen_movi_tl(cpu_R[9], (dc->pc + 8));
+ tcg_gen_movi_tl(jmp_pc, tmp_pc);
+ break;
+ case 0x03: /* l.bnf */
+ case 0x04: /* l.bf */
+ {
+ TCGLabel *lab = gen_new_label();
+ TCGv sr_f = tcg_temp_new();
+ tcg_gen_movi_tl(jmp_pc, dc->pc+8);
+ tcg_gen_andi_tl(sr_f, cpu_sr, SR_F);
+ tcg_gen_brcondi_i32(op0 == 0x03 ? TCG_COND_EQ : TCG_COND_NE,
+ sr_f, SR_F, lab);
+ tcg_gen_movi_tl(jmp_pc, tmp_pc);
+ gen_set_label(lab);
+ tcg_temp_free(sr_f);
+ }
+ break;
+ case 0x11: /* l.jr */
+ tcg_gen_mov_tl(jmp_pc, cpu_R[reg]);
+ break;
+ case 0x12: /* l.jalr */
+ tcg_gen_movi_tl(cpu_R[9], (dc->pc + 8));
+ tcg_gen_mov_tl(jmp_pc, cpu_R[reg]);
+ break;
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+
+ dc->delayed_branch = 2;
+ dc->tb_flags |= D_FLAG;
+ gen_sync_flags(dc);
+}
+
+
+static void dec_calc(DisasContext *dc, uint32_t insn)
+{
+ uint32_t op0, op1, op2;
+ uint32_t ra, rb, rd;
+ op0 = extract32(insn, 0, 4);
+ op1 = extract32(insn, 8, 2);
+ op2 = extract32(insn, 6, 2);
+ ra = extract32(insn, 16, 5);
+ rb = extract32(insn, 11, 5);
+ rd = extract32(insn, 21, 5);
+
+ switch (op0) {
+ case 0x0000:
+ switch (op1) {
+ case 0x00: /* l.add */
+ LOG_DIS("l.add r%d, r%d, r%d\n", rd, ra, rb);
+ {
+ TCGLabel *lab = gen_new_label();
+ TCGv_i64 ta = tcg_temp_new_i64();
+ TCGv_i64 tb = tcg_temp_new_i64();
+ TCGv_i64 td = tcg_temp_local_new_i64();
+ TCGv_i32 res = tcg_temp_local_new_i32();
+ TCGv_i32 sr_ove = tcg_temp_local_new_i32();
+ tcg_gen_extu_i32_i64(ta, cpu_R[ra]);
+ tcg_gen_extu_i32_i64(tb, cpu_R[rb]);
+ tcg_gen_add_i64(td, ta, tb);
+ tcg_gen_trunc_i64_i32(res, td);
+ tcg_gen_shri_i64(td, td, 31);
+ tcg_gen_andi_i64(td, td, 0x3);
+ /* Jump to lab when no overflow. */
+ tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab);
+ tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab);
+ tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY));
+ tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE);
+ tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab);
+ gen_exception(dc, EXCP_RANGE);
+ gen_set_label(lab);
+ tcg_gen_mov_i32(cpu_R[rd], res);
+ tcg_temp_free_i64(ta);
+ tcg_temp_free_i64(tb);
+ tcg_temp_free_i64(td);
+ tcg_temp_free_i32(res);
+ tcg_temp_free_i32(sr_ove);
+ }
+ break;
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x0001: /* l.addc */
+ switch (op1) {
+ case 0x00:
+ LOG_DIS("l.addc r%d, r%d, r%d\n", rd, ra, rb);
+ {
+ TCGLabel *lab = gen_new_label();
+ TCGv_i64 ta = tcg_temp_new_i64();
+ TCGv_i64 tb = tcg_temp_new_i64();
+ TCGv_i64 tcy = tcg_temp_local_new_i64();
+ TCGv_i64 td = tcg_temp_local_new_i64();
+ TCGv_i32 res = tcg_temp_local_new_i32();
+ TCGv_i32 sr_cy = tcg_temp_local_new_i32();
+ TCGv_i32 sr_ove = tcg_temp_local_new_i32();
+ tcg_gen_extu_i32_i64(ta, cpu_R[ra]);
+ tcg_gen_extu_i32_i64(tb, cpu_R[rb]);
+ tcg_gen_andi_i32(sr_cy, cpu_sr, SR_CY);
+ tcg_gen_extu_i32_i64(tcy, sr_cy);
+ tcg_gen_shri_i64(tcy, tcy, 10);
+ tcg_gen_add_i64(td, ta, tb);
+ tcg_gen_add_i64(td, td, tcy);
+ tcg_gen_trunc_i64_i32(res, td);
+ tcg_gen_shri_i64(td, td, 32);
+ tcg_gen_andi_i64(td, td, 0x3);
+ /* Jump to lab when no overflow. */
+ tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab);
+ tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab);
+ tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY));
+ tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE);
+ tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab);
+ gen_exception(dc, EXCP_RANGE);
+ gen_set_label(lab);
+ tcg_gen_mov_i32(cpu_R[rd], res);
+ tcg_temp_free_i64(ta);
+ tcg_temp_free_i64(tb);
+ tcg_temp_free_i64(tcy);
+ tcg_temp_free_i64(td);
+ tcg_temp_free_i32(res);
+ tcg_temp_free_i32(sr_cy);
+ tcg_temp_free_i32(sr_ove);
+ }
+ break;
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x0002: /* l.sub */
+ switch (op1) {
+ case 0x00:
+ LOG_DIS("l.sub r%d, r%d, r%d\n", rd, ra, rb);
+ {
+ TCGLabel *lab = gen_new_label();
+ TCGv_i64 ta = tcg_temp_new_i64();
+ TCGv_i64 tb = tcg_temp_new_i64();
+ TCGv_i64 td = tcg_temp_local_new_i64();
+ TCGv_i32 res = tcg_temp_local_new_i32();
+ TCGv_i32 sr_ove = tcg_temp_local_new_i32();
+
+ tcg_gen_extu_i32_i64(ta, cpu_R[ra]);
+ tcg_gen_extu_i32_i64(tb, cpu_R[rb]);
+ tcg_gen_sub_i64(td, ta, tb);
+ tcg_gen_trunc_i64_i32(res, td);
+ tcg_gen_shri_i64(td, td, 31);
+ tcg_gen_andi_i64(td, td, 0x3);
+ /* Jump to lab when no overflow. */
+ tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab);
+ tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab);
+ tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY));
+ tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE);
+ tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab);
+ gen_exception(dc, EXCP_RANGE);
+ gen_set_label(lab);
+ tcg_gen_mov_i32(cpu_R[rd], res);
+ tcg_temp_free_i64(ta);
+ tcg_temp_free_i64(tb);
+ tcg_temp_free_i64(td);
+ tcg_temp_free_i32(res);
+ tcg_temp_free_i32(sr_ove);
+ }
+ break;
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x0003: /* l.and */
+ switch (op1) {
+ case 0x00:
+ LOG_DIS("l.and r%d, r%d, r%d\n", rd, ra, rb);
+ tcg_gen_and_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+ break;
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x0004: /* l.or */
+ switch (op1) {
+ case 0x00:
+ LOG_DIS("l.or r%d, r%d, r%d\n", rd, ra, rb);
+ tcg_gen_or_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+ break;
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x0005:
+ switch (op1) {
+ case 0x00: /* l.xor */
+ LOG_DIS("l.xor r%d, r%d, r%d\n", rd, ra, rb);
+ tcg_gen_xor_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+ break;
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x0006:
+ switch (op1) {
+ case 0x03: /* l.mul */
+ LOG_DIS("l.mul r%d, r%d, r%d\n", rd, ra, rb);
+ if (ra != 0 && rb != 0) {
+ gen_helper_mul32(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+ } else {
+ tcg_gen_movi_tl(cpu_R[rd], 0x0);
+ }
+ break;
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x0009:
+ switch (op1) {
+ case 0x03: /* l.div */
+ LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb);
+ {
+ TCGLabel *lab0 = gen_new_label();
+ TCGLabel *lab1 = gen_new_label();
+ TCGLabel *lab2 = gen_new_label();
+ TCGLabel *lab3 = gen_new_label();
+ TCGv_i32 sr_ove = tcg_temp_local_new_i32();
+ if (rb == 0) {
+ tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY));
+ tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
+ tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab0);
+ gen_exception(dc, EXCP_RANGE);
+ gen_set_label(lab0);
+ } else {
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_R[rb],
+ 0x00000000, lab1);
+ tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[ra],
+ 0x80000000, lab2);
+ tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[rb],
+ 0xffffffff, lab2);
+ gen_set_label(lab1);
+ tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY));
+ tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
+ tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab3);
+ gen_exception(dc, EXCP_RANGE);
+ gen_set_label(lab2);
+ tcg_gen_div_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+ gen_set_label(lab3);
+ }
+ tcg_temp_free_i32(sr_ove);
+ }
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x000a:
+ switch (op1) {
+ case 0x03: /* l.divu */
+ LOG_DIS("l.divu r%d, r%d, r%d\n", rd, ra, rb);
+ {
+ TCGLabel *lab0 = gen_new_label();
+ TCGLabel *lab1 = gen_new_label();
+ TCGLabel *lab2 = gen_new_label();
+ TCGv_i32 sr_ove = tcg_temp_local_new_i32();
+ if (rb == 0) {
+ tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY));
+ tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
+ tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab0);
+ gen_exception(dc, EXCP_RANGE);
+ gen_set_label(lab0);
+ } else {
+ tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[rb],
+ 0x00000000, lab1);
+ tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY));
+ tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
+ tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab2);
+ gen_exception(dc, EXCP_RANGE);
+ gen_set_label(lab1);
+ tcg_gen_divu_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+ gen_set_label(lab2);
+ }
+ tcg_temp_free_i32(sr_ove);
+ }
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x000b:
+ switch (op1) {
+ case 0x03: /* l.mulu */
+ LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb);
+ if (rb != 0 && ra != 0) {
+ TCGv_i64 result = tcg_temp_local_new_i64();
+ TCGv_i64 tra = tcg_temp_local_new_i64();
+ TCGv_i64 trb = tcg_temp_local_new_i64();
+ TCGv_i64 high = tcg_temp_new_i64();
+ TCGv_i32 sr_ove = tcg_temp_local_new_i32();
+ TCGLabel *lab = gen_new_label();
+ /* Calculate each result. */
+ tcg_gen_extu_i32_i64(tra, cpu_R[ra]);
+ tcg_gen_extu_i32_i64(trb, cpu_R[rb]);
+ tcg_gen_mul_i64(result, tra, trb);
+ tcg_temp_free_i64(tra);
+ tcg_temp_free_i64(trb);
+ tcg_gen_shri_i64(high, result, TARGET_LONG_BITS);
+ /* Overflow or not. */
+ tcg_gen_brcondi_i64(TCG_COND_EQ, high, 0x00000000, lab);
+ tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY));
+ tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
+ tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
+ gen_exception(dc, EXCP_RANGE);
+ gen_set_label(lab);
+ tcg_temp_free_i64(high);
+ tcg_gen_trunc_i64_tl(cpu_R[rd], result);
+ tcg_temp_free_i64(result);
+ tcg_temp_free_i32(sr_ove);
+ } else {
+ tcg_gen_movi_tl(cpu_R[rd], 0);
+ }
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x000e:
+ switch (op1) {
+ case 0x00: /* l.cmov */
+ LOG_DIS("l.cmov r%d, r%d, r%d\n", rd, ra, rb);
+ {
+ TCGLabel *lab = gen_new_label();
+ TCGv res = tcg_temp_local_new();
+ TCGv sr_f = tcg_temp_new();
+ tcg_gen_andi_tl(sr_f, cpu_sr, SR_F);
+ tcg_gen_mov_tl(res, cpu_R[rb]);
+ tcg_gen_brcondi_tl(TCG_COND_NE, sr_f, SR_F, lab);
+ tcg_gen_mov_tl(res, cpu_R[ra]);
+ gen_set_label(lab);
+ tcg_gen_mov_tl(cpu_R[rd], res);
+ tcg_temp_free(sr_f);
+ tcg_temp_free(res);
+ }
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x000f:
+ switch (op1) {
+ case 0x00: /* l.ff1 */
+ LOG_DIS("l.ff1 r%d, r%d, r%d\n", rd, ra, rb);
+ gen_helper_ff1(cpu_R[rd], cpu_R[ra]);
+ break;
+ case 0x01: /* l.fl1 */
+ LOG_DIS("l.fl1 r%d, r%d, r%d\n", rd, ra, rb);
+ gen_helper_fl1(cpu_R[rd], cpu_R[ra]);
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x0008:
+ switch (op1) {
+ case 0x00:
+ switch (op2) {
+ case 0x00: /* l.sll */
+ LOG_DIS("l.sll r%d, r%d, r%d\n", rd, ra, rb);
+ tcg_gen_shl_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+ break;
+ case 0x01: /* l.srl */
+ LOG_DIS("l.srl r%d, r%d, r%d\n", rd, ra, rb);
+ tcg_gen_shr_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+ break;
+ case 0x02: /* l.sra */
+ LOG_DIS("l.sra r%d, r%d, r%d\n", rd, ra, rb);
+ tcg_gen_sar_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+ break;
+ case 0x03: /* l.ror */
+ LOG_DIS("l.ror r%d, r%d, r%d\n", rd, ra, rb);
+ tcg_gen_rotr_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x000c:
+ switch (op1) {
+ case 0x00:
+ switch (op2) {
+ case 0x00: /* l.exths */
+ LOG_DIS("l.exths r%d, r%d\n", rd, ra);
+ tcg_gen_ext16s_tl(cpu_R[rd], cpu_R[ra]);
+ break;
+ case 0x01: /* l.extbs */
+ LOG_DIS("l.extbs r%d, r%d\n", rd, ra);
+ tcg_gen_ext8s_tl(cpu_R[rd], cpu_R[ra]);
+ break;
+ case 0x02: /* l.exthz */
+ LOG_DIS("l.exthz r%d, r%d\n", rd, ra);
+ tcg_gen_ext16u_tl(cpu_R[rd], cpu_R[ra]);
+ break;
+ case 0x03: /* l.extbz */
+ LOG_DIS("l.extbz r%d, r%d\n", rd, ra);
+ tcg_gen_ext8u_tl(cpu_R[rd], cpu_R[ra]);
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x000d:
+ switch (op1) {
+ case 0x00:
+ switch (op2) {
+ case 0x00: /* l.extws */
+ LOG_DIS("l.extws r%d, r%d\n", rd, ra);
+ tcg_gen_ext32s_tl(cpu_R[rd], cpu_R[ra]);
+ break;
+ case 0x01: /* l.extwz */
+ LOG_DIS("l.extwz r%d, r%d\n", rd, ra);
+ tcg_gen_ext32u_tl(cpu_R[rd], cpu_R[ra]);
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+}
+
+static void dec_misc(DisasContext *dc, uint32_t insn)
+{
+ uint32_t op0, op1;
+ uint32_t ra, rb, rd;
+#ifdef OPENRISC_DISAS
+ uint32_t L6, K5;
+#endif
+ uint32_t I16, I5, I11, N26, tmp;
+ TCGMemOp mop;
+
+ op0 = extract32(insn, 26, 6);
+ op1 = extract32(insn, 24, 2);
+ ra = extract32(insn, 16, 5);
+ rb = extract32(insn, 11, 5);
+ rd = extract32(insn, 21, 5);
+#ifdef OPENRISC_DISAS
+ L6 = extract32(insn, 5, 6);
+ K5 = extract32(insn, 0, 5);
+#endif
+ I16 = extract32(insn, 0, 16);
+ I5 = extract32(insn, 21, 5);
+ I11 = extract32(insn, 0, 11);
+ N26 = extract32(insn, 0, 26);
+ tmp = (I5<<11) + I11;
+
+ switch (op0) {
+ case 0x00: /* l.j */
+ LOG_DIS("l.j %d\n", N26);
+ gen_jump(dc, N26, 0, op0);
+ break;
+
+ case 0x01: /* l.jal */
+ LOG_DIS("l.jal %d\n", N26);
+ gen_jump(dc, N26, 0, op0);
+ break;
+
+ case 0x03: /* l.bnf */
+ LOG_DIS("l.bnf %d\n", N26);
+ gen_jump(dc, N26, 0, op0);
+ break;
+
+ case 0x04: /* l.bf */
+ LOG_DIS("l.bf %d\n", N26);
+ gen_jump(dc, N26, 0, op0);
+ break;
+
+ case 0x05:
+ switch (op1) {
+ case 0x01: /* l.nop */
+ LOG_DIS("l.nop %d\n", I16);
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ break;
+
+ case 0x11: /* l.jr */
+ LOG_DIS("l.jr r%d\n", rb);
+ gen_jump(dc, 0, rb, op0);
+ break;
+
+ case 0x12: /* l.jalr */
+ LOG_DIS("l.jalr r%d\n", rb);
+ gen_jump(dc, 0, rb, op0);
+ break;
+
+ case 0x13: /* l.maci */
+ LOG_DIS("l.maci %d, r%d, %d\n", I5, ra, I11);
+ {
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ TCGv_i64 t2 = tcg_temp_new_i64();
+ TCGv_i32 dst = tcg_temp_new_i32();
+ TCGv ttmp = tcg_const_tl(tmp);
+ tcg_gen_mul_tl(dst, cpu_R[ra], ttmp);
+ tcg_gen_ext_i32_i64(t1, dst);
+ tcg_gen_concat_i32_i64(t2, maclo, machi);
+ tcg_gen_add_i64(t2, t2, t1);
+ tcg_gen_trunc_i64_i32(maclo, t2);
+ tcg_gen_shri_i64(t2, t2, 32);
+ tcg_gen_trunc_i64_i32(machi, t2);
+ tcg_temp_free_i32(dst);
+ tcg_temp_free(ttmp);
+ tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(t2);
+ }
+ break;
+
+ case 0x09: /* l.rfe */
+ LOG_DIS("l.rfe\n");
+ {
+#if defined(CONFIG_USER_ONLY)
+ return;
+#else
+ if (dc->mem_idx == MMU_USER_IDX) {
+ gen_illegal_exception(dc);
+ return;
+ }
+ gen_helper_rfe(cpu_env);
+ dc->is_jmp = DISAS_UPDATE;
+#endif
+ }
+ break;
+
+ case 0x1c: /* l.cust1 */
+ LOG_DIS("l.cust1\n");
+ break;
+
+ case 0x1d: /* l.cust2 */
+ LOG_DIS("l.cust2\n");
+ break;
+
+ case 0x1e: /* l.cust3 */
+ LOG_DIS("l.cust3\n");
+ break;
+
+ case 0x1f: /* l.cust4 */
+ LOG_DIS("l.cust4\n");
+ break;
+
+ case 0x3c: /* l.cust5 */
+ LOG_DIS("l.cust5 r%d, r%d, r%d, %d, %d\n", rd, ra, rb, L6, K5);
+ break;
+
+ case 0x3d: /* l.cust6 */
+ LOG_DIS("l.cust6\n");
+ break;
+
+ case 0x3e: /* l.cust7 */
+ LOG_DIS("l.cust7\n");
+ break;
+
+ case 0x3f: /* l.cust8 */
+ LOG_DIS("l.cust8\n");
+ break;
+
+/* not used yet, open it when we need or64. */
+/*#ifdef TARGET_OPENRISC64
+ case 0x20: l.ld
+ LOG_DIS("l.ld r%d, r%d, %d\n", rd, ra, I16);
+ check_ob64s(dc);
+ mop = MO_TEQ;
+ goto do_load;
+#endif*/
+
+ case 0x21: /* l.lwz */
+ LOG_DIS("l.lwz r%d, r%d, %d\n", rd, ra, I16);
+ mop = MO_TEUL;
+ goto do_load;
+
+ case 0x22: /* l.lws */
+ LOG_DIS("l.lws r%d, r%d, %d\n", rd, ra, I16);
+ mop = MO_TESL;
+ goto do_load;
+
+ case 0x23: /* l.lbz */
+ LOG_DIS("l.lbz r%d, r%d, %d\n", rd, ra, I16);
+ mop = MO_UB;
+ goto do_load;
+
+ case 0x24: /* l.lbs */
+ LOG_DIS("l.lbs r%d, r%d, %d\n", rd, ra, I16);
+ mop = MO_SB;
+ goto do_load;
+
+ case 0x25: /* l.lhz */
+ LOG_DIS("l.lhz r%d, r%d, %d\n", rd, ra, I16);
+ mop = MO_TEUW;
+ goto do_load;
+
+ case 0x26: /* l.lhs */
+ LOG_DIS("l.lhs r%d, r%d, %d\n", rd, ra, I16);
+ mop = MO_TESW;
+ goto do_load;
+
+ do_load:
+ {
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16));
+ tcg_gen_qemu_ld_tl(cpu_R[rd], t0, dc->mem_idx, mop);
+ tcg_temp_free(t0);
+ }
+ break;
+
+ case 0x27: /* l.addi */
+ LOG_DIS("l.addi r%d, r%d, %d\n", rd, ra, I16);
+ {
+ if (I16 == 0) {
+ tcg_gen_mov_tl(cpu_R[rd], cpu_R[ra]);
+ } else {
+ TCGLabel *lab = gen_new_label();
+ TCGv_i64 ta = tcg_temp_new_i64();
+ TCGv_i64 td = tcg_temp_local_new_i64();
+ TCGv_i32 res = tcg_temp_local_new_i32();
+ TCGv_i32 sr_ove = tcg_temp_local_new_i32();
+ tcg_gen_extu_i32_i64(ta, cpu_R[ra]);
+ tcg_gen_addi_i64(td, ta, sign_extend(I16, 16));
+ tcg_gen_trunc_i64_i32(res, td);
+ tcg_gen_shri_i64(td, td, 32);
+ tcg_gen_andi_i64(td, td, 0x3);
+ /* Jump to lab when no overflow. */
+ tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab);
+ tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab);
+ tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY));
+ tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE);
+ tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab);
+ gen_exception(dc, EXCP_RANGE);
+ gen_set_label(lab);
+ tcg_gen_mov_i32(cpu_R[rd], res);
+ tcg_temp_free_i64(ta);
+ tcg_temp_free_i64(td);
+ tcg_temp_free_i32(res);
+ tcg_temp_free_i32(sr_ove);
+ }
+ }
+ break;
+
+ case 0x28: /* l.addic */
+ LOG_DIS("l.addic r%d, r%d, %d\n", rd, ra, I16);
+ {
+ TCGLabel *lab = gen_new_label();
+ TCGv_i64 ta = tcg_temp_new_i64();
+ TCGv_i64 td = tcg_temp_local_new_i64();
+ TCGv_i64 tcy = tcg_temp_local_new_i64();
+ TCGv_i32 res = tcg_temp_local_new_i32();
+ TCGv_i32 sr_cy = tcg_temp_local_new_i32();
+ TCGv_i32 sr_ove = tcg_temp_local_new_i32();
+ tcg_gen_extu_i32_i64(ta, cpu_R[ra]);
+ tcg_gen_andi_i32(sr_cy, cpu_sr, SR_CY);
+ tcg_gen_shri_i32(sr_cy, sr_cy, 10);
+ tcg_gen_extu_i32_i64(tcy, sr_cy);
+ tcg_gen_addi_i64(td, ta, sign_extend(I16, 16));
+ tcg_gen_add_i64(td, td, tcy);
+ tcg_gen_trunc_i64_i32(res, td);
+ tcg_gen_shri_i64(td, td, 32);
+ tcg_gen_andi_i64(td, td, 0x3);
+ /* Jump to lab when no overflow. */
+ tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab);
+ tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab);
+ tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY));
+ tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE);
+ tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab);
+ gen_exception(dc, EXCP_RANGE);
+ gen_set_label(lab);
+ tcg_gen_mov_i32(cpu_R[rd], res);
+ tcg_temp_free_i64(ta);
+ tcg_temp_free_i64(td);
+ tcg_temp_free_i64(tcy);
+ tcg_temp_free_i32(res);
+ tcg_temp_free_i32(sr_cy);
+ tcg_temp_free_i32(sr_ove);
+ }
+ break;
+
+ case 0x29: /* l.andi */
+ LOG_DIS("l.andi r%d, r%d, %d\n", rd, ra, I16);
+ tcg_gen_andi_tl(cpu_R[rd], cpu_R[ra], zero_extend(I16, 16));
+ break;
+
+ case 0x2a: /* l.ori */
+ LOG_DIS("l.ori r%d, r%d, %d\n", rd, ra, I16);
+ tcg_gen_ori_tl(cpu_R[rd], cpu_R[ra], zero_extend(I16, 16));
+ break;
+
+ case 0x2b: /* l.xori */
+ LOG_DIS("l.xori r%d, r%d, %d\n", rd, ra, I16);
+ tcg_gen_xori_tl(cpu_R[rd], cpu_R[ra], sign_extend(I16, 16));
+ break;
+
+ case 0x2c: /* l.muli */
+ LOG_DIS("l.muli r%d, r%d, %d\n", rd, ra, I16);
+ if (ra != 0 && I16 != 0) {
+ TCGv_i32 im = tcg_const_i32(I16);
+ gen_helper_mul32(cpu_R[rd], cpu_env, cpu_R[ra], im);
+ tcg_temp_free_i32(im);
+ } else {
+ tcg_gen_movi_tl(cpu_R[rd], 0x0);
+ }
+ break;
+
+ case 0x2d: /* l.mfspr */
+ LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
+ {
+#if defined(CONFIG_USER_ONLY)
+ return;
+#else
+ TCGv_i32 ti = tcg_const_i32(I16);
+ if (dc->mem_idx == MMU_USER_IDX) {
+ gen_illegal_exception(dc);
+ return;
+ }
+ gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
+ tcg_temp_free_i32(ti);
+#endif
+ }
+ break;
+
+ case 0x30: /* l.mtspr */
+ LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
+ {
+#if defined(CONFIG_USER_ONLY)
+ return;
+#else
+ TCGv_i32 im = tcg_const_i32(tmp);
+ if (dc->mem_idx == MMU_USER_IDX) {
+ gen_illegal_exception(dc);
+ return;
+ }
+ gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
+ tcg_temp_free_i32(im);
+#endif
+ }
+ break;
+
+/* not used yet, open it when we need or64. */
+/*#ifdef TARGET_OPENRISC64
+ case 0x34: l.sd
+ LOG_DIS("l.sd %d, r%d, r%d, %d\n", I5, ra, rb, I11);
+ check_ob64s(dc);
+ mop = MO_TEQ;
+ goto do_store;
+#endif*/
+
+ case 0x35: /* l.sw */
+ LOG_DIS("l.sw %d, r%d, r%d, %d\n", I5, ra, rb, I11);
+ mop = MO_TEUL;
+ goto do_store;
+
+ case 0x36: /* l.sb */
+ LOG_DIS("l.sb %d, r%d, r%d, %d\n", I5, ra, rb, I11);
+ mop = MO_UB;
+ goto do_store;
+
+ case 0x37: /* l.sh */
+ LOG_DIS("l.sh %d, r%d, r%d, %d\n", I5, ra, rb, I11);
+ mop = MO_TEUW;
+ goto do_store;
+
+ do_store:
+ {
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(tmp, 16));
+ tcg_gen_qemu_st_tl(cpu_R[rb], t0, dc->mem_idx, mop);
+ tcg_temp_free(t0);
+ }
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+}
+
+static void dec_mac(DisasContext *dc, uint32_t insn)
+{
+ uint32_t op0;
+ uint32_t ra, rb;
+ op0 = extract32(insn, 0, 4);
+ ra = extract32(insn, 16, 5);
+ rb = extract32(insn, 11, 5);
+
+ switch (op0) {
+ case 0x0001: /* l.mac */
+ LOG_DIS("l.mac r%d, r%d\n", ra, rb);
+ {
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ TCGv_i64 t2 = tcg_temp_new_i64();
+ tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
+ tcg_gen_ext_i32_i64(t1, t0);
+ tcg_gen_concat_i32_i64(t2, maclo, machi);
+ tcg_gen_add_i64(t2, t2, t1);
+ tcg_gen_trunc_i64_i32(maclo, t2);
+ tcg_gen_shri_i64(t2, t2, 32);
+ tcg_gen_trunc_i64_i32(machi, t2);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(t2);
+ }
+ break;
+
+ case 0x0002: /* l.msb */
+ LOG_DIS("l.msb r%d, r%d\n", ra, rb);
+ {
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ TCGv_i64 t2 = tcg_temp_new_i64();
+ tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
+ tcg_gen_ext_i32_i64(t1, t0);
+ tcg_gen_concat_i32_i64(t2, maclo, machi);
+ tcg_gen_sub_i64(t2, t2, t1);
+ tcg_gen_trunc_i64_i32(maclo, t2);
+ tcg_gen_shri_i64(t2, t2, 32);
+ tcg_gen_trunc_i64_i32(machi, t2);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(t2);
+ }
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+}
+
+static void dec_logic(DisasContext *dc, uint32_t insn)
+{
+ uint32_t op0;
+ uint32_t rd, ra, L6;
+ op0 = extract32(insn, 6, 2);
+ rd = extract32(insn, 21, 5);
+ ra = extract32(insn, 16, 5);
+ L6 = extract32(insn, 0, 6);
+
+ switch (op0) {
+ case 0x00: /* l.slli */
+ LOG_DIS("l.slli r%d, r%d, %d\n", rd, ra, L6);
+ tcg_gen_shli_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f));
+ break;
+
+ case 0x01: /* l.srli */
+ LOG_DIS("l.srli r%d, r%d, %d\n", rd, ra, L6);
+ tcg_gen_shri_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f));
+ break;
+
+ case 0x02: /* l.srai */
+ LOG_DIS("l.srai r%d, r%d, %d\n", rd, ra, L6);
+ tcg_gen_sari_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f)); break;
+
+ case 0x03: /* l.rori */
+ LOG_DIS("l.rori r%d, r%d, %d\n", rd, ra, L6);
+ tcg_gen_rotri_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f));
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+}
+
+static void dec_M(DisasContext *dc, uint32_t insn)
+{
+ uint32_t op0;
+ uint32_t rd;
+ uint32_t K16;
+ op0 = extract32(insn, 16, 1);
+ rd = extract32(insn, 21, 5);
+ K16 = extract32(insn, 0, 16);
+
+ switch (op0) {
+ case 0x0: /* l.movhi */
+ LOG_DIS("l.movhi r%d, %d\n", rd, K16);
+ tcg_gen_movi_tl(cpu_R[rd], (K16 << 16));
+ break;
+
+ case 0x1: /* l.macrc */
+ LOG_DIS("l.macrc r%d\n", rd);
+ tcg_gen_mov_tl(cpu_R[rd], maclo);
+ tcg_gen_movi_tl(maclo, 0x0);
+ tcg_gen_movi_tl(machi, 0x0);
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+}
+
+static void dec_comp(DisasContext *dc, uint32_t insn)
+{
+ uint32_t op0;
+ uint32_t ra, rb;
+
+ op0 = extract32(insn, 21, 5);
+ ra = extract32(insn, 16, 5);
+ rb = extract32(insn, 11, 5);
+
+ tcg_gen_movi_i32(env_btaken, 0x0);
+ /* unsigned integers */
+ tcg_gen_ext32u_tl(cpu_R[ra], cpu_R[ra]);
+ tcg_gen_ext32u_tl(cpu_R[rb], cpu_R[rb]);
+
+ switch (op0) {
+ case 0x0: /* l.sfeq */
+ LOG_DIS("l.sfeq r%d, r%d\n", ra, rb);
+ tcg_gen_setcond_tl(TCG_COND_EQ, env_btaken, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x1: /* l.sfne */
+ LOG_DIS("l.sfne r%d, r%d\n", ra, rb);
+ tcg_gen_setcond_tl(TCG_COND_NE, env_btaken, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x2: /* l.sfgtu */
+ LOG_DIS("l.sfgtu r%d, r%d\n", ra, rb);
+ tcg_gen_setcond_tl(TCG_COND_GTU, env_btaken, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x3: /* l.sfgeu */
+ LOG_DIS("l.sfgeu r%d, r%d\n", ra, rb);
+ tcg_gen_setcond_tl(TCG_COND_GEU, env_btaken, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x4: /* l.sfltu */
+ LOG_DIS("l.sfltu r%d, r%d\n", ra, rb);
+ tcg_gen_setcond_tl(TCG_COND_LTU, env_btaken, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x5: /* l.sfleu */
+ LOG_DIS("l.sfleu r%d, r%d\n", ra, rb);
+ tcg_gen_setcond_tl(TCG_COND_LEU, env_btaken, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0xa: /* l.sfgts */
+ LOG_DIS("l.sfgts r%d, r%d\n", ra, rb);
+ tcg_gen_setcond_tl(TCG_COND_GT, env_btaken, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0xb: /* l.sfges */
+ LOG_DIS("l.sfges r%d, r%d\n", ra, rb);
+ tcg_gen_setcond_tl(TCG_COND_GE, env_btaken, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0xc: /* l.sflts */
+ LOG_DIS("l.sflts r%d, r%d\n", ra, rb);
+ tcg_gen_setcond_tl(TCG_COND_LT, env_btaken, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0xd: /* l.sfles */
+ LOG_DIS("l.sfles r%d, r%d\n", ra, rb);
+ tcg_gen_setcond_tl(TCG_COND_LE, env_btaken, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ wb_SR_F();
+}
+
+static void dec_compi(DisasContext *dc, uint32_t insn)
+{
+ uint32_t op0;
+ uint32_t ra, I16;
+
+ op0 = extract32(insn, 21, 5);
+ ra = extract32(insn, 16, 5);
+ I16 = extract32(insn, 0, 16);
+
+ tcg_gen_movi_i32(env_btaken, 0x0);
+ I16 = sign_extend(I16, 16);
+
+ switch (op0) {
+ case 0x0: /* l.sfeqi */
+ LOG_DIS("l.sfeqi r%d, %d\n", ra, I16);
+ tcg_gen_setcondi_tl(TCG_COND_EQ, env_btaken, cpu_R[ra], I16);
+ break;
+
+ case 0x1: /* l.sfnei */
+ LOG_DIS("l.sfnei r%d, %d\n", ra, I16);
+ tcg_gen_setcondi_tl(TCG_COND_NE, env_btaken, cpu_R[ra], I16);
+ break;
+
+ case 0x2: /* l.sfgtui */
+ LOG_DIS("l.sfgtui r%d, %d\n", ra, I16);
+ tcg_gen_setcondi_tl(TCG_COND_GTU, env_btaken, cpu_R[ra], I16);
+ break;
+
+ case 0x3: /* l.sfgeui */
+ LOG_DIS("l.sfgeui r%d, %d\n", ra, I16);
+ tcg_gen_setcondi_tl(TCG_COND_GEU, env_btaken, cpu_R[ra], I16);
+ break;
+
+ case 0x4: /* l.sfltui */
+ LOG_DIS("l.sfltui r%d, %d\n", ra, I16);
+ tcg_gen_setcondi_tl(TCG_COND_LTU, env_btaken, cpu_R[ra], I16);
+ break;
+
+ case 0x5: /* l.sfleui */
+ LOG_DIS("l.sfleui r%d, %d\n", ra, I16);
+ tcg_gen_setcondi_tl(TCG_COND_LEU, env_btaken, cpu_R[ra], I16);
+ break;
+
+ case 0xa: /* l.sfgtsi */
+ LOG_DIS("l.sfgtsi r%d, %d\n", ra, I16);
+ tcg_gen_setcondi_tl(TCG_COND_GT, env_btaken, cpu_R[ra], I16);
+ break;
+
+ case 0xb: /* l.sfgesi */
+ LOG_DIS("l.sfgesi r%d, %d\n", ra, I16);
+ tcg_gen_setcondi_tl(TCG_COND_GE, env_btaken, cpu_R[ra], I16);
+ break;
+
+ case 0xc: /* l.sfltsi */
+ LOG_DIS("l.sfltsi r%d, %d\n", ra, I16);
+ tcg_gen_setcondi_tl(TCG_COND_LT, env_btaken, cpu_R[ra], I16);
+ break;
+
+ case 0xd: /* l.sflesi */
+ LOG_DIS("l.sflesi r%d, %d\n", ra, I16);
+ tcg_gen_setcondi_tl(TCG_COND_LE, env_btaken, cpu_R[ra], I16);
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ wb_SR_F();
+}
+
+static void dec_sys(DisasContext *dc, uint32_t insn)
+{
+ uint32_t op0;
+#ifdef OPENRISC_DISAS
+ uint32_t K16;
+#endif
+ op0 = extract32(insn, 16, 10);
+#ifdef OPENRISC_DISAS
+ K16 = extract32(insn, 0, 16);
+#endif
+
+ switch (op0) {
+ case 0x000: /* l.sys */
+ LOG_DIS("l.sys %d\n", K16);
+ tcg_gen_movi_tl(cpu_pc, dc->pc);
+ gen_exception(dc, EXCP_SYSCALL);
+ dc->is_jmp = DISAS_UPDATE;
+ break;
+
+ case 0x100: /* l.trap */
+ LOG_DIS("l.trap %d\n", K16);
+#if defined(CONFIG_USER_ONLY)
+ return;
+#else
+ if (dc->mem_idx == MMU_USER_IDX) {
+ gen_illegal_exception(dc);
+ return;
+ }
+ tcg_gen_movi_tl(cpu_pc, dc->pc);
+ gen_exception(dc, EXCP_TRAP);
+#endif
+ break;
+
+ case 0x300: /* l.csync */
+ LOG_DIS("l.csync\n");
+#if defined(CONFIG_USER_ONLY)
+ return;
+#else
+ if (dc->mem_idx == MMU_USER_IDX) {
+ gen_illegal_exception(dc);
+ return;
+ }
+#endif
+ break;
+
+ case 0x200: /* l.msync */
+ LOG_DIS("l.msync\n");
+#if defined(CONFIG_USER_ONLY)
+ return;
+#else
+ if (dc->mem_idx == MMU_USER_IDX) {
+ gen_illegal_exception(dc);
+ return;
+ }
+#endif
+ break;
+
+ case 0x270: /* l.psync */
+ LOG_DIS("l.psync\n");
+#if defined(CONFIG_USER_ONLY)
+ return;
+#else
+ if (dc->mem_idx == MMU_USER_IDX) {
+ gen_illegal_exception(dc);
+ return;
+ }
+#endif
+ break;
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+}
+
+static void dec_float(DisasContext *dc, uint32_t insn)
+{
+ uint32_t op0;
+ uint32_t ra, rb, rd;
+ op0 = extract32(insn, 0, 8);
+ ra = extract32(insn, 16, 5);
+ rb = extract32(insn, 11, 5);
+ rd = extract32(insn, 21, 5);
+
+ switch (op0) {
+ case 0x00: /* lf.add.s */
+ LOG_DIS("lf.add.s r%d, r%d, r%d\n", rd, ra, rb);
+ gen_helper_float_add_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x01: /* lf.sub.s */
+ LOG_DIS("lf.sub.s r%d, r%d, r%d\n", rd, ra, rb);
+ gen_helper_float_sub_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+
+ case 0x02: /* lf.mul.s */
+ LOG_DIS("lf.mul.s r%d, r%d, r%d\n", rd, ra, rb);
+ if (ra != 0 && rb != 0) {
+ gen_helper_float_mul_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+ } else {
+ tcg_gen_ori_tl(fpcsr, fpcsr, FPCSR_ZF);
+ tcg_gen_movi_i32(cpu_R[rd], 0x0);
+ }
+ break;
+
+ case 0x03: /* lf.div.s */
+ LOG_DIS("lf.div.s r%d, r%d, r%d\n", rd, ra, rb);
+ gen_helper_float_div_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x04: /* lf.itof.s */
+ LOG_DIS("lf.itof r%d, r%d\n", rd, ra);
+ gen_helper_itofs(cpu_R[rd], cpu_env, cpu_R[ra]);
+ break;
+
+ case 0x05: /* lf.ftoi.s */
+ LOG_DIS("lf.ftoi r%d, r%d\n", rd, ra);
+ gen_helper_ftois(cpu_R[rd], cpu_env, cpu_R[ra]);
+ break;
+
+ case 0x06: /* lf.rem.s */
+ LOG_DIS("lf.rem.s r%d, r%d, r%d\n", rd, ra, rb);
+ gen_helper_float_rem_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x07: /* lf.madd.s */
+ LOG_DIS("lf.madd.s r%d, r%d, r%d\n", rd, ra, rb);
+ gen_helper_float_muladd_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x08: /* lf.sfeq.s */
+ LOG_DIS("lf.sfeq.s r%d, r%d\n", ra, rb);
+ gen_helper_float_eq_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x09: /* lf.sfne.s */
+ LOG_DIS("lf.sfne.s r%d, r%d\n", ra, rb);
+ gen_helper_float_ne_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x0a: /* lf.sfgt.s */
+ LOG_DIS("lf.sfgt.s r%d, r%d\n", ra, rb);
+ gen_helper_float_gt_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x0b: /* lf.sfge.s */
+ LOG_DIS("lf.sfge.s r%d, r%d\n", ra, rb);
+ gen_helper_float_ge_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x0c: /* lf.sflt.s */
+ LOG_DIS("lf.sflt.s r%d, r%d\n", ra, rb);
+ gen_helper_float_lt_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x0d: /* lf.sfle.s */
+ LOG_DIS("lf.sfle.s r%d, r%d\n", ra, rb);
+ gen_helper_float_le_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+/* not used yet, open it when we need or64. */
+/*#ifdef TARGET_OPENRISC64
+ case 0x10: lf.add.d
+ LOG_DIS("lf.add.d r%d, r%d, r%d\n", rd, ra, rb);
+ check_of64s(dc);
+ gen_helper_float_add_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x11: lf.sub.d
+ LOG_DIS("lf.sub.d r%d, r%d, r%d\n", rd, ra, rb);
+ check_of64s(dc);
+ gen_helper_float_sub_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x12: lf.mul.d
+ LOG_DIS("lf.mul.d r%d, r%d, r%d\n", rd, ra, rb);
+ check_of64s(dc);
+ if (ra != 0 && rb != 0) {
+ gen_helper_float_mul_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+ } else {
+ tcg_gen_ori_tl(fpcsr, fpcsr, FPCSR_ZF);
+ tcg_gen_movi_i64(cpu_R[rd], 0x0);
+ }
+ break;
+
+ case 0x13: lf.div.d
+ LOG_DIS("lf.div.d r%d, r%d, r%d\n", rd, ra, rb);
+ check_of64s(dc);
+ gen_helper_float_div_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x14: lf.itof.d
+ LOG_DIS("lf.itof r%d, r%d\n", rd, ra);
+ check_of64s(dc);
+ gen_helper_itofd(cpu_R[rd], cpu_env, cpu_R[ra]);
+ break;
+
+ case 0x15: lf.ftoi.d
+ LOG_DIS("lf.ftoi r%d, r%d\n", rd, ra);
+ check_of64s(dc);
+ gen_helper_ftoid(cpu_R[rd], cpu_env, cpu_R[ra]);
+ break;
+
+ case 0x16: lf.rem.d
+ LOG_DIS("lf.rem.d r%d, r%d, r%d\n", rd, ra, rb);
+ check_of64s(dc);
+ gen_helper_float_rem_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x17: lf.madd.d
+ LOG_DIS("lf.madd.d r%d, r%d, r%d\n", rd, ra, rb);
+ check_of64s(dc);
+ gen_helper_float_muladd_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x18: lf.sfeq.d
+ LOG_DIS("lf.sfeq.d r%d, r%d\n", ra, rb);
+ check_of64s(dc);
+ gen_helper_float_eq_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x1a: lf.sfgt.d
+ LOG_DIS("lf.sfgt.d r%d, r%d\n", ra, rb);
+ check_of64s(dc);
+ gen_helper_float_gt_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x1b: lf.sfge.d
+ LOG_DIS("lf.sfge.d r%d, r%d\n", ra, rb);
+ check_of64s(dc);
+ gen_helper_float_ge_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x19: lf.sfne.d
+ LOG_DIS("lf.sfne.d r%d, r%d\n", ra, rb);
+ check_of64s(dc);
+ gen_helper_float_ne_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x1c: lf.sflt.d
+ LOG_DIS("lf.sflt.d r%d, r%d\n", ra, rb);
+ check_of64s(dc);
+ gen_helper_float_lt_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+
+ case 0x1d: lf.sfle.d
+ LOG_DIS("lf.sfle.d r%d, r%d\n", ra, rb);
+ check_of64s(dc);
+ gen_helper_float_le_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+ break;
+#endif*/
+
+ default:
+ gen_illegal_exception(dc);
+ break;
+ }
+ wb_SR_F();
+}
+
+static void disas_openrisc_insn(DisasContext *dc, OpenRISCCPU *cpu)
+{
+ uint32_t op0;
+ uint32_t insn;
+ insn = cpu_ldl_code(&cpu->env, dc->pc);
+ op0 = extract32(insn, 26, 6);
+
+ switch (op0) {
+ case 0x06:
+ dec_M(dc, insn);
+ break;
+
+ case 0x08:
+ dec_sys(dc, insn);
+ break;
+
+ case 0x2e:
+ dec_logic(dc, insn);
+ break;
+
+ case 0x2f:
+ dec_compi(dc, insn);
+ break;
+
+ case 0x31:
+ dec_mac(dc, insn);
+ break;
+
+ case 0x32:
+ dec_float(dc, insn);
+ break;
+
+ case 0x38:
+ dec_calc(dc, insn);
+ break;
+
+ case 0x39:
+ dec_comp(dc, insn);
+ break;
+
+ default:
+ dec_misc(dc, insn);
+ break;
+ }
+}
+
+static void check_breakpoint(OpenRISCCPU *cpu, DisasContext *dc)
+{
+ CPUState *cs = CPU(cpu);
+ CPUBreakpoint *bp;
+
+ if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+ QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
+ if (bp->pc == dc->pc) {
+ tcg_gen_movi_tl(cpu_pc, dc->pc);
+ gen_exception(dc, EXCP_DEBUG);
+ dc->is_jmp = DISAS_UPDATE;
+ }
+ }
+ }
+}
+
+static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu,
+ TranslationBlock *tb,
+ int search_pc)
+{
+ CPUState *cs = CPU(cpu);
+ struct DisasContext ctx, *dc = &ctx;
+ uint32_t pc_start;
+ int j, k;
+ uint32_t next_page_start;
+ int num_insns;
+ int max_insns;
+
+ pc_start = tb->pc;
+ dc->tb = tb;
+
+ dc->is_jmp = DISAS_NEXT;
+ dc->ppc = pc_start;
+ dc->pc = pc_start;
+ dc->flags = cpu->env.cpucfgr;
+ dc->mem_idx = cpu_mmu_index(&cpu->env);
+ dc->synced_flags = dc->tb_flags = tb->flags;
+ dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
+ dc->singlestep_enabled = cs->singlestep_enabled;
+ if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+ qemu_log("-----------------------------------------\n");
+ log_cpu_state(CPU(cpu), 0);
+ }
+
+ next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+ k = -1;
+ num_insns = 0;
+ max_insns = tb->cflags & CF_COUNT_MASK;
+
+ if (max_insns == 0) {
+ max_insns = CF_COUNT_MASK;
+ }
+
+ gen_tb_start(tb);
+
+ do {
+ check_breakpoint(cpu, dc);
+ if (search_pc) {
+ j = tcg_op_buf_count();
+ if (k < j) {
+ k++;
+ while (k < j) {
+ tcg_ctx.gen_opc_instr_start[k++] = 0;
+ }
+ }
+ tcg_ctx.gen_opc_pc[k] = dc->pc;
+ tcg_ctx.gen_opc_instr_start[k] = 1;
+ tcg_ctx.gen_opc_icount[k] = num_insns;
+ }
+
+ if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
+ tcg_gen_debug_insn_start(dc->pc);
+ }
+
+ if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
+ gen_io_start();
+ }
+ dc->ppc = dc->pc - 4;
+ dc->npc = dc->pc + 4;
+ tcg_gen_movi_tl(cpu_ppc, dc->ppc);
+ tcg_gen_movi_tl(cpu_npc, dc->npc);
+ disas_openrisc_insn(dc, cpu);
+ dc->pc = dc->npc;
+ num_insns++;
+ /* delay slot */
+ if (dc->delayed_branch) {
+ dc->delayed_branch--;
+ if (!dc->delayed_branch) {
+ dc->tb_flags &= ~D_FLAG;
+ gen_sync_flags(dc);
+ tcg_gen_mov_tl(cpu_pc, jmp_pc);
+ tcg_gen_mov_tl(cpu_npc, jmp_pc);
+ tcg_gen_movi_tl(jmp_pc, 0);
+ tcg_gen_exit_tb(0);
+ dc->is_jmp = DISAS_JUMP;
+ break;
+ }
+ }
+ } 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 (dc->is_jmp == DISAS_NEXT) {
+ dc->is_jmp = DISAS_UPDATE;
+ tcg_gen_movi_tl(cpu_pc, dc->pc);
+ }
+ if (unlikely(cs->singlestep_enabled)) {
+ if (dc->is_jmp == DISAS_NEXT) {
+ tcg_gen_movi_tl(cpu_pc, dc->pc);
+ }
+ gen_exception(dc, EXCP_DEBUG);
+ } else {
+ switch (dc->is_jmp) {
+ case DISAS_NEXT:
+ gen_goto_tb(dc, 0, dc->pc);
+ break;
+ default:
+ case DISAS_JUMP:
+ break;
+ 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);
+
+ if (search_pc) {
+ j = tcg_op_buf_count();
+ k++;
+ while (k <= j) {
+ tcg_ctx.gen_opc_instr_start[k++] = 0;
+ }
+ } else {
+ tb->size = dc->pc - pc_start;
+ tb->icount = num_insns;
+ }
+
+#ifdef DEBUG_DISAS
+ if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+ 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());
+ }
+#endif
+}
+
+void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
+{
+ gen_intermediate_code_internal(openrisc_env_get_cpu(env), tb, 0);
+}
+
+void gen_intermediate_code_pc(CPUOpenRISCState *env,
+ struct TranslationBlock *tb)
+{
+ gen_intermediate_code_internal(openrisc_env_get_cpu(env), tb, 1);
+}
+
+void openrisc_cpu_dump_state(CPUState *cs, FILE *f,
+ fprintf_function cpu_fprintf,
+ int flags)
+{
+ OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+ CPUOpenRISCState *env = &cpu->env;
+ int i;
+
+ cpu_fprintf(f, "PC=%08x\n", env->pc);
+ for (i = 0; i < 32; ++i) {
+ cpu_fprintf(f, "R%02d=%08x%c", i, env->gpr[i],
+ (i % 4) == 3 ? '\n' : ' ');
+ }
+}
+
+void restore_state_to_opc(CPUOpenRISCState *env, TranslationBlock *tb,
+ int pc_pos)
+{
+ env->pc = tcg_ctx.gen_opc_pc[pc_pos];
+}