mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-06 01:03:55 -06:00
Move target-* CPU file into a target/ folder
We've currently got 18 architectures in QEMU, and thus 18 target-xxx folders in the root folder of the QEMU source tree. More architectures (e.g. RISC-V, AVR) are likely to be included soon, too, so the main folder of the QEMU sources slowly gets quite overcrowded with the target-xxx folders. To disburden the main folder a little bit, let's move the target-xxx folders into a dedicated target/ folder, so that target-xxx/ simply becomes target/xxx/ instead. Acked-by: Laurent Vivier <laurent@vivier.eu> [m68k part] Acked-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> [tricore part] Acked-by: Michael Walle <michael@walle.cc> [lm32 part] Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com> [s390x part] Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com> [s390x part] Acked-by: Eduardo Habkost <ehabkost@redhat.com> [i386 part] Acked-by: Artyom Tarasenko <atar4qemu@gmail.com> [sparc part] Acked-by: Richard Henderson <rth@twiddle.net> [alpha part] Acked-by: Max Filippov <jcmvbkbc@gmail.com> [xtensa part] Reviewed-by: David Gibson <david@gibson.dropbear.id.au> [ppc part] Acked-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> [crisµblaze part] Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn> [unicore32 part] Signed-off-by: Thomas Huth <thuth@redhat.com>
This commit is contained in:
parent
82ecffa8c0
commit
fcf5ef2ab5
369 changed files with 78 additions and 80 deletions
5
target/openrisc/Makefile.objs
Normal file
5
target/openrisc/Makefile.objs
Normal file
|
@ -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
|
278
target/openrisc/cpu.c
Normal file
278
target/openrisc/cpu.c
Normal file
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* 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 "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "cpu.h"
|
||||
#include "qemu-common.h"
|
||||
#include "exec/exec-all.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);
|
||||
Error *local_err = NULL;
|
||||
|
||||
cpu_exec_realizefn(cs, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_init_vcpu(cs);
|
||||
cpu_reset(cs);
|
||||
|
||||
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;
|
||||
|
||||
#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)
|
411
target/openrisc/cpu.h
Normal file
411
target/openrisc/cpu.h
Normal file
|
@ -0,0 +1,411 @@
|
|||
/*
|
||||
* 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 OPENRISC_CPU_H
|
||||
#define OPENRISC_CPU_H
|
||||
|
||||
#define TARGET_LONG_BITS 32
|
||||
|
||||
#define CPUArchState struct CPUOpenRISCState
|
||||
|
||||
/* cpu_openrisc_map_address_* in CPUOpenRISCTLBContext need this decl. */
|
||||
struct OpenRISCCPU;
|
||||
|
||||
#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);
|
||||
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_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, uint32_t *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, bool ifetch)
|
||||
{
|
||||
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
|
||||
|
||||
#endif /* OPENRISC_CPU_H */
|
31
target/openrisc/exception.c
Normal file
31
target/openrisc/exception.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.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);
|
||||
}
|
28
target/openrisc/exception.h
Normal file
28
target/openrisc/exception.h
Normal file
|
@ -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 TARGET_OPENRISC_EXCEPTION_H
|
||||
#define TARGET_OPENRISC_EXCEPTION_H
|
||||
|
||||
#include "cpu.h"
|
||||
#include "qemu-common.h"
|
||||
|
||||
void QEMU_NORETURN raise_exception(OpenRISCCPU *cpu, uint32_t excp);
|
||||
|
||||
#endif /* TARGET_OPENRISC_EXCEPTION_H */
|
30
target/openrisc/exception_helper.c
Normal file
30
target/openrisc/exception_helper.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 "qemu/osdep.h"
|
||||
#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);
|
||||
}
|
301
target/openrisc/fpu_helper.c
Normal file
301
target/openrisc/fpu_helper.c
Normal file
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
* 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 "qemu/osdep.h"
|
||||
#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
|
84
target/openrisc/gdbstub.c
Normal file
84
target/openrisc/gdbstub.c
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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 "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.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;
|
||||
}
|
66
target/openrisc/helper.h
Normal file
66
target/openrisc/helper.h
Normal file
|
@ -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)
|
80
target/openrisc/int_helper.c
Normal file
80
target/openrisc/int_helper.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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 "qemu/osdep.h"
|
||||
#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;
|
||||
}
|
87
target/openrisc/interrupt.c
Normal file
87
target/openrisc/interrupt.c
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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 "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.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;
|
||||
}
|
60
target/openrisc/interrupt_helper.c
Normal file
60
target/openrisc/interrupt_helper.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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 "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.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;
|
||||
}
|
54
target/openrisc/machine.c
Normal file
54
target/openrisc/machine.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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 "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/boards.h"
|
||||
#include "migration/cpu.h"
|
||||
|
||||
static const VMStateDescription vmstate_env = {
|
||||
.name = "env",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(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()
|
||||
}
|
||||
};
|
238
target/openrisc/mmu.c
Normal file
238
target/openrisc/mmu.c
Normal file
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* 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 "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.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
|
44
target/openrisc/mmu_helper.c
Normal file
44
target/openrisc/mmu_helper.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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 "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = openrisc_cpu_handle_mmu_fault(cs, addr, access_type, 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
|
288
target/openrisc/sys_helper.c
Normal file
288
target/openrisc/sys_helper.c
Normal file
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* 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 "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.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;
|
||||
}
|
1783
target/openrisc/translate.c
Normal file
1783
target/openrisc/translate.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue