Browse Source
The CRIS target is deprecated since v9.0 (commit c7bbef4023
"docs: mark CRIS support as deprecated").
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Acked-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Message-ID: <20240904143603.52934-14-philmd@linaro.org>
pull/273/head
29 changed files with 9 additions and 7306 deletions
@ -1,2 +0,0 @@ |
|||||
config CRIS |
|
||||
bool |
|
||||
@ -1,16 +0,0 @@ |
|||||
/*
|
|
||||
* CRIS cpu parameters for qemu. |
|
||||
* |
|
||||
* Copyright (c) 2007 AXIS Communications AB |
|
||||
* SPDX-License-Identifier: LGPL-2.0+ |
|
||||
*/ |
|
||||
|
|
||||
#ifndef CRIS_CPU_PARAM_H |
|
||||
#define CRIS_CPU_PARAM_H |
|
||||
|
|
||||
#define TARGET_LONG_BITS 32 |
|
||||
#define TARGET_PAGE_BITS 13 |
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 32 |
|
||||
#define TARGET_VIRT_ADDR_SPACE_BITS 32 |
|
||||
|
|
||||
#endif |
|
||||
@ -1,32 +0,0 @@ |
|||||
/*
|
|
||||
* QEMU CRIS CPU QOM header (target agnostic) |
|
||||
* |
|
||||
* Copyright (c) 2012 SUSE LINUX Products GmbH |
|
||||
* |
|
||||
* This library is free software; you can redistribute it and/or |
|
||||
* modify it under the terms of the GNU Lesser General Public |
|
||||
* License as published by the Free Software Foundation; either |
|
||||
* version 2.1 of the License, or (at your option) any later version. |
|
||||
* |
|
||||
* This library is distributed in the hope that it will be useful, |
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
||||
* Lesser General Public License for more details. |
|
||||
* |
|
||||
* You should have received a copy of the GNU Lesser General Public |
|
||||
* License along with this library; if not, see |
|
||||
* <http://www.gnu.org/licenses/lgpl-2.1.html>
|
|
||||
*/ |
|
||||
#ifndef QEMU_CRIS_CPU_QOM_H |
|
||||
#define QEMU_CRIS_CPU_QOM_H |
|
||||
|
|
||||
#include "hw/core/cpu.h" |
|
||||
|
|
||||
#define TYPE_CRIS_CPU "cris-cpu" |
|
||||
|
|
||||
OBJECT_DECLARE_CPU_TYPE(CRISCPU, CRISCPUClass, CRIS_CPU) |
|
||||
|
|
||||
#define CRIS_CPU_TYPE_SUFFIX "-" TYPE_CRIS_CPU |
|
||||
#define CRIS_CPU_TYPE_NAME(name) (name CRIS_CPU_TYPE_SUFFIX) |
|
||||
|
|
||||
#endif |
|
||||
@ -1,323 +0,0 @@ |
|||||
/*
|
|
||||
* QEMU CRIS CPU |
|
||||
* |
|
||||
* Copyright (c) 2008 AXIS Communications AB |
|
||||
* Written by Edgar E. Iglesias. |
|
||||
* |
|
||||
* Copyright (c) 2012 SUSE LINUX Products GmbH |
|
||||
* |
|
||||
* This library is free software; you can redistribute it and/or |
|
||||
* modify it under the terms of the GNU Lesser General Public |
|
||||
* License as published by the Free Software Foundation; either |
|
||||
* version 2.1 of the License, or (at your option) any later version. |
|
||||
* |
|
||||
* This library is distributed in the hope that it will be useful, |
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
||||
* Lesser General Public License for more details. |
|
||||
* |
|
||||
* You should have received a copy of the GNU Lesser General Public |
|
||||
* License along with this library; if not, see |
|
||||
* <http://www.gnu.org/licenses/lgpl-2.1.html>
|
|
||||
*/ |
|
||||
|
|
||||
#include "qemu/osdep.h" |
|
||||
#include "qapi/error.h" |
|
||||
#include "qemu/qemu-print.h" |
|
||||
#include "cpu.h" |
|
||||
#include "mmu.h" |
|
||||
|
|
||||
|
|
||||
static void cris_cpu_set_pc(CPUState *cs, vaddr value) |
|
||||
{ |
|
||||
CRISCPU *cpu = CRIS_CPU(cs); |
|
||||
|
|
||||
cpu->env.pc = value; |
|
||||
} |
|
||||
|
|
||||
static vaddr cris_cpu_get_pc(CPUState *cs) |
|
||||
{ |
|
||||
CRISCPU *cpu = CRIS_CPU(cs); |
|
||||
|
|
||||
return cpu->env.pc; |
|
||||
} |
|
||||
|
|
||||
static void cris_restore_state_to_opc(CPUState *cs, |
|
||||
const TranslationBlock *tb, |
|
||||
const uint64_t *data) |
|
||||
{ |
|
||||
CRISCPU *cpu = CRIS_CPU(cs); |
|
||||
|
|
||||
cpu->env.pc = data[0]; |
|
||||
} |
|
||||
|
|
||||
static bool cris_cpu_has_work(CPUState *cs) |
|
||||
{ |
|
||||
return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); |
|
||||
} |
|
||||
|
|
||||
static int cris_cpu_mmu_index(CPUState *cs, bool ifetch) |
|
||||
{ |
|
||||
return !!(cpu_env(cs)->pregs[PR_CCS] & U_FLAG); |
|
||||
} |
|
||||
|
|
||||
static void cris_cpu_reset_hold(Object *obj, ResetType type) |
|
||||
{ |
|
||||
CPUState *cs = CPU(obj); |
|
||||
CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(obj); |
|
||||
CPUCRISState *env = cpu_env(cs); |
|
||||
uint32_t vr; |
|
||||
|
|
||||
if (ccc->parent_phases.hold) { |
|
||||
ccc->parent_phases.hold(obj, type); |
|
||||
} |
|
||||
|
|
||||
vr = env->pregs[PR_VR]; |
|
||||
memset(env, 0, offsetof(CPUCRISState, end_reset_fields)); |
|
||||
env->pregs[PR_VR] = vr; |
|
||||
|
|
||||
#if defined(CONFIG_USER_ONLY) |
|
||||
/* start in user mode with interrupts enabled. */ |
|
||||
env->pregs[PR_CCS] |= U_FLAG | I_FLAG | P_FLAG; |
|
||||
#else |
|
||||
cris_mmu_init(env); |
|
||||
env->pregs[PR_CCS] = 0; |
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
static ObjectClass *cris_cpu_class_by_name(const char *cpu_model) |
|
||||
{ |
|
||||
ObjectClass *oc; |
|
||||
char *typename; |
|
||||
|
|
||||
#if defined(CONFIG_USER_ONLY) |
|
||||
if (strcasecmp(cpu_model, "any") == 0) { |
|
||||
return object_class_by_name(CRIS_CPU_TYPE_NAME("crisv32")); |
|
||||
} |
|
||||
#endif |
|
||||
|
|
||||
typename = g_strdup_printf(CRIS_CPU_TYPE_NAME("%s"), cpu_model); |
|
||||
oc = object_class_by_name(typename); |
|
||||
g_free(typename); |
|
||||
|
|
||||
return oc; |
|
||||
} |
|
||||
|
|
||||
static void cris_cpu_realizefn(DeviceState *dev, Error **errp) |
|
||||
{ |
|
||||
CPUState *cs = CPU(dev); |
|
||||
CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(dev); |
|
||||
Error *local_err = NULL; |
|
||||
|
|
||||
cpu_exec_realizefn(cs, &local_err); |
|
||||
if (local_err != NULL) { |
|
||||
error_propagate(errp, local_err); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
cpu_reset(cs); |
|
||||
qemu_init_vcpu(cs); |
|
||||
|
|
||||
ccc->parent_realize(dev, errp); |
|
||||
} |
|
||||
|
|
||||
#ifndef CONFIG_USER_ONLY |
|
||||
static void cris_cpu_set_irq(void *opaque, int irq, int level) |
|
||||
{ |
|
||||
CRISCPU *cpu = opaque; |
|
||||
CPUState *cs = CPU(cpu); |
|
||||
int type = irq == CRIS_CPU_IRQ ? CPU_INTERRUPT_HARD : CPU_INTERRUPT_NMI; |
|
||||
|
|
||||
if (irq == CRIS_CPU_IRQ) { |
|
||||
/*
|
|
||||
* The PIC passes us the vector for the IRQ as the value it sends |
|
||||
* over the qemu_irq line |
|
||||
*/ |
|
||||
cpu->env.interrupt_vector = level; |
|
||||
} |
|
||||
|
|
||||
if (level) { |
|
||||
cpu_interrupt(cs, type); |
|
||||
} else { |
|
||||
cpu_reset_interrupt(cs, type); |
|
||||
} |
|
||||
} |
|
||||
#endif |
|
||||
|
|
||||
static void cris_disas_set_info(CPUState *cpu, disassemble_info *info) |
|
||||
{ |
|
||||
if (cpu_env(cpu)->pregs[PR_VR] != 32) { |
|
||||
info->mach = bfd_mach_cris_v0_v10; |
|
||||
info->print_insn = print_insn_crisv10; |
|
||||
} else { |
|
||||
info->mach = bfd_mach_cris_v32; |
|
||||
info->print_insn = print_insn_crisv32; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
static void cris_cpu_initfn(Object *obj) |
|
||||
{ |
|
||||
CRISCPU *cpu = CRIS_CPU(obj); |
|
||||
CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(obj); |
|
||||
CPUCRISState *env = &cpu->env; |
|
||||
|
|
||||
env->pregs[PR_VR] = ccc->vr; |
|
||||
|
|
||||
#ifndef CONFIG_USER_ONLY |
|
||||
/* IRQ and NMI lines. */ |
|
||||
qdev_init_gpio_in(DEVICE(cpu), cris_cpu_set_irq, 2); |
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
#ifndef CONFIG_USER_ONLY |
|
||||
#include "hw/core/sysemu-cpu-ops.h" |
|
||||
|
|
||||
static const struct SysemuCPUOps cris_sysemu_ops = { |
|
||||
.get_phys_page_debug = cris_cpu_get_phys_page_debug, |
|
||||
}; |
|
||||
#endif |
|
||||
|
|
||||
#include "hw/core/tcg-cpu-ops.h" |
|
||||
|
|
||||
static const TCGCPUOps crisv10_tcg_ops = { |
|
||||
.initialize = cris_initialize_crisv10_tcg, |
|
||||
.restore_state_to_opc = cris_restore_state_to_opc, |
|
||||
|
|
||||
#ifndef CONFIG_USER_ONLY |
|
||||
.tlb_fill = cris_cpu_tlb_fill, |
|
||||
.cpu_exec_interrupt = cris_cpu_exec_interrupt, |
|
||||
.cpu_exec_halt = cris_cpu_has_work, |
|
||||
.do_interrupt = crisv10_cpu_do_interrupt, |
|
||||
#endif /* !CONFIG_USER_ONLY */ |
|
||||
}; |
|
||||
|
|
||||
static const TCGCPUOps crisv32_tcg_ops = { |
|
||||
.initialize = cris_initialize_tcg, |
|
||||
.restore_state_to_opc = cris_restore_state_to_opc, |
|
||||
|
|
||||
#ifndef CONFIG_USER_ONLY |
|
||||
.tlb_fill = cris_cpu_tlb_fill, |
|
||||
.cpu_exec_interrupt = cris_cpu_exec_interrupt, |
|
||||
.cpu_exec_halt = cris_cpu_has_work, |
|
||||
.do_interrupt = cris_cpu_do_interrupt, |
|
||||
#endif /* !CONFIG_USER_ONLY */ |
|
||||
}; |
|
||||
|
|
||||
static void crisv8_cpu_class_init(ObjectClass *oc, void *data) |
|
||||
{ |
|
||||
CPUClass *cc = CPU_CLASS(oc); |
|
||||
CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); |
|
||||
|
|
||||
ccc->vr = 8; |
|
||||
cc->gdb_read_register = crisv10_cpu_gdb_read_register; |
|
||||
cc->tcg_ops = &crisv10_tcg_ops; |
|
||||
} |
|
||||
|
|
||||
static void crisv9_cpu_class_init(ObjectClass *oc, void *data) |
|
||||
{ |
|
||||
CPUClass *cc = CPU_CLASS(oc); |
|
||||
CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); |
|
||||
|
|
||||
ccc->vr = 9; |
|
||||
cc->gdb_read_register = crisv10_cpu_gdb_read_register; |
|
||||
cc->tcg_ops = &crisv10_tcg_ops; |
|
||||
} |
|
||||
|
|
||||
static void crisv10_cpu_class_init(ObjectClass *oc, void *data) |
|
||||
{ |
|
||||
CPUClass *cc = CPU_CLASS(oc); |
|
||||
CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); |
|
||||
|
|
||||
ccc->vr = 10; |
|
||||
cc->gdb_read_register = crisv10_cpu_gdb_read_register; |
|
||||
cc->tcg_ops = &crisv10_tcg_ops; |
|
||||
} |
|
||||
|
|
||||
static void crisv11_cpu_class_init(ObjectClass *oc, void *data) |
|
||||
{ |
|
||||
CPUClass *cc = CPU_CLASS(oc); |
|
||||
CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); |
|
||||
|
|
||||
ccc->vr = 11; |
|
||||
cc->gdb_read_register = crisv10_cpu_gdb_read_register; |
|
||||
cc->tcg_ops = &crisv10_tcg_ops; |
|
||||
} |
|
||||
|
|
||||
static void crisv17_cpu_class_init(ObjectClass *oc, void *data) |
|
||||
{ |
|
||||
CPUClass *cc = CPU_CLASS(oc); |
|
||||
CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); |
|
||||
|
|
||||
ccc->vr = 17; |
|
||||
cc->gdb_read_register = crisv10_cpu_gdb_read_register; |
|
||||
cc->tcg_ops = &crisv10_tcg_ops; |
|
||||
} |
|
||||
|
|
||||
static void crisv32_cpu_class_init(ObjectClass *oc, void *data) |
|
||||
{ |
|
||||
CPUClass *cc = CPU_CLASS(oc); |
|
||||
CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); |
|
||||
|
|
||||
ccc->vr = 32; |
|
||||
cc->tcg_ops = &crisv32_tcg_ops; |
|
||||
} |
|
||||
|
|
||||
static void cris_cpu_class_init(ObjectClass *oc, void *data) |
|
||||
{ |
|
||||
DeviceClass *dc = DEVICE_CLASS(oc); |
|
||||
CPUClass *cc = CPU_CLASS(oc); |
|
||||
CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); |
|
||||
ResettableClass *rc = RESETTABLE_CLASS(oc); |
|
||||
|
|
||||
device_class_set_parent_realize(dc, cris_cpu_realizefn, |
|
||||
&ccc->parent_realize); |
|
||||
|
|
||||
resettable_class_set_parent_phases(rc, NULL, cris_cpu_reset_hold, NULL, |
|
||||
&ccc->parent_phases); |
|
||||
|
|
||||
cc->class_by_name = cris_cpu_class_by_name; |
|
||||
cc->has_work = cris_cpu_has_work; |
|
||||
cc->mmu_index = cris_cpu_mmu_index; |
|
||||
cc->dump_state = cris_cpu_dump_state; |
|
||||
cc->set_pc = cris_cpu_set_pc; |
|
||||
cc->get_pc = cris_cpu_get_pc; |
|
||||
cc->gdb_read_register = cris_cpu_gdb_read_register; |
|
||||
cc->gdb_write_register = cris_cpu_gdb_write_register; |
|
||||
#ifndef CONFIG_USER_ONLY |
|
||||
dc->vmsd = &vmstate_cris_cpu; |
|
||||
cc->sysemu_ops = &cris_sysemu_ops; |
|
||||
#endif |
|
||||
|
|
||||
cc->gdb_num_core_regs = 49; |
|
||||
cc->gdb_stop_before_watchpoint = true; |
|
||||
|
|
||||
cc->disas_set_info = cris_disas_set_info; |
|
||||
} |
|
||||
|
|
||||
#define DEFINE_CRIS_CPU_TYPE(cpu_model, initfn) \ |
|
||||
{ \ |
|
||||
.parent = TYPE_CRIS_CPU, \ |
|
||||
.class_init = initfn, \ |
|
||||
.name = CRIS_CPU_TYPE_NAME(cpu_model), \ |
|
||||
} |
|
||||
|
|
||||
static const TypeInfo cris_cpu_model_type_infos[] = { |
|
||||
{ |
|
||||
.name = TYPE_CRIS_CPU, |
|
||||
.parent = TYPE_CPU, |
|
||||
.instance_size = sizeof(CRISCPU), |
|
||||
.instance_align = __alignof(CRISCPU), |
|
||||
.instance_init = cris_cpu_initfn, |
|
||||
.abstract = true, |
|
||||
.class_size = sizeof(CRISCPUClass), |
|
||||
.class_init = cris_cpu_class_init, |
|
||||
}, |
|
||||
DEFINE_CRIS_CPU_TYPE("crisv8", crisv8_cpu_class_init), |
|
||||
DEFINE_CRIS_CPU_TYPE("crisv9", crisv9_cpu_class_init), |
|
||||
DEFINE_CRIS_CPU_TYPE("crisv10", crisv10_cpu_class_init), |
|
||||
DEFINE_CRIS_CPU_TYPE("crisv11", crisv11_cpu_class_init), |
|
||||
DEFINE_CRIS_CPU_TYPE("crisv17", crisv17_cpu_class_init), |
|
||||
DEFINE_CRIS_CPU_TYPE("crisv32", crisv32_cpu_class_init), |
|
||||
}; |
|
||||
|
|
||||
DEFINE_TYPES(cris_cpu_model_type_infos) |
|
||||
@ -1,286 +0,0 @@ |
|||||
/*
|
|
||||
* CRIS virtual CPU header |
|
||||
* |
|
||||
* Copyright (c) 2007 AXIS Communications AB |
|
||||
* Written by Edgar E. Iglesias |
|
||||
* |
|
||||
* This library is free software; you can redistribute it and/or |
|
||||
* modify it under the terms of the GNU Lesser General Public |
|
||||
* License as published by the Free Software Foundation; either |
|
||||
* version 2.1 of the License, or (at your option) any later version. |
|
||||
* |
|
||||
* This library is distributed in the hope that it will be useful, |
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
||||
* 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 CRIS_CPU_H |
|
||||
#define CRIS_CPU_H |
|
||||
|
|
||||
#include "cpu-qom.h" |
|
||||
#include "exec/cpu-defs.h" |
|
||||
|
|
||||
#define EXCP_NMI 1 |
|
||||
#define EXCP_GURU 2 |
|
||||
#define EXCP_BUSFAULT 3 |
|
||||
#define EXCP_IRQ 4 |
|
||||
#define EXCP_BREAK 5 |
|
||||
|
|
||||
/* CRIS-specific interrupt pending bits. */ |
|
||||
#define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_3 |
|
||||
|
|
||||
/* CRUS CPU device objects interrupt lines. */ |
|
||||
/* PIC passes the vector for the IRQ as the value of it sends over qemu_irq */ |
|
||||
#define CRIS_CPU_IRQ 0 |
|
||||
#define CRIS_CPU_NMI 1 |
|
||||
|
|
||||
/* Register aliases. R0 - R15 */ |
|
||||
#define R_FP 8 |
|
||||
#define R_SP 14 |
|
||||
#define R_ACR 15 |
|
||||
|
|
||||
/* Support regs, P0 - P15 */ |
|
||||
#define PR_BZ 0 |
|
||||
#define PR_VR 1 |
|
||||
#define PR_PID 2 |
|
||||
#define PR_SRS 3 |
|
||||
#define PR_WZ 4 |
|
||||
#define PR_EXS 5 |
|
||||
#define PR_EDA 6 |
|
||||
#define PR_PREFIX 6 /* On CRISv10 P6 is reserved, we use it as prefix. */ |
|
||||
#define PR_MOF 7 |
|
||||
#define PR_DZ 8 |
|
||||
#define PR_EBP 9 |
|
||||
#define PR_ERP 10 |
|
||||
#define PR_SRP 11 |
|
||||
#define PR_NRP 12 |
|
||||
#define PR_CCS 13 |
|
||||
#define PR_USP 14 |
|
||||
#define PRV10_BRP 14 |
|
||||
#define PR_SPC 15 |
|
||||
|
|
||||
/* CPU flags. */ |
|
||||
#define Q_FLAG 0x80000000 |
|
||||
#define M_FLAG_V32 0x40000000 |
|
||||
#define PFIX_FLAG 0x800 /* CRISv10 Only. */ |
|
||||
#define F_FLAG_V10 0x400 |
|
||||
#define P_FLAG_V10 0x200 |
|
||||
#define S_FLAG 0x200 |
|
||||
#define R_FLAG 0x100 |
|
||||
#define P_FLAG 0x80 |
|
||||
#define M_FLAG_V10 0x80 |
|
||||
#define U_FLAG 0x40 |
|
||||
#define I_FLAG 0x20 |
|
||||
#define X_FLAG 0x10 |
|
||||
#define N_FLAG 0x08 |
|
||||
#define Z_FLAG 0x04 |
|
||||
#define V_FLAG 0x02 |
|
||||
#define C_FLAG 0x01 |
|
||||
#define ALU_FLAGS 0x1F |
|
||||
|
|
||||
/* Condition codes. */ |
|
||||
#define CC_CC 0 |
|
||||
#define CC_CS 1 |
|
||||
#define CC_NE 2 |
|
||||
#define CC_EQ 3 |
|
||||
#define CC_VC 4 |
|
||||
#define CC_VS 5 |
|
||||
#define CC_PL 6 |
|
||||
#define CC_MI 7 |
|
||||
#define CC_LS 8 |
|
||||
#define CC_HI 9 |
|
||||
#define CC_GE 10 |
|
||||
#define CC_LT 11 |
|
||||
#define CC_GT 12 |
|
||||
#define CC_LE 13 |
|
||||
#define CC_A 14 |
|
||||
#define CC_P 15 |
|
||||
|
|
||||
typedef struct { |
|
||||
uint32_t hi; |
|
||||
uint32_t lo; |
|
||||
} TLBSet; |
|
||||
|
|
||||
typedef struct CPUArchState { |
|
||||
uint32_t regs[16]; |
|
||||
/* P0 - P15 are referred to as special registers in the docs. */ |
|
||||
uint32_t pregs[16]; |
|
||||
|
|
||||
/* Pseudo register for the PC. Not directly accessible on CRIS. */ |
|
||||
uint32_t pc; |
|
||||
|
|
||||
/* Pseudo register for the kernel stack. */ |
|
||||
uint32_t ksp; |
|
||||
|
|
||||
/* Branch. */ |
|
||||
int dslot; |
|
||||
int btaken; |
|
||||
uint32_t btarget; |
|
||||
|
|
||||
/* Condition flag tracking. */ |
|
||||
uint32_t cc_op; |
|
||||
uint32_t cc_mask; |
|
||||
uint32_t cc_dest; |
|
||||
uint32_t cc_src; |
|
||||
uint32_t cc_result; |
|
||||
/* size of the operation, 1 = byte, 2 = word, 4 = dword. */ |
|
||||
int cc_size; |
|
||||
/* X flag at the time of cc snapshot. */ |
|
||||
int cc_x; |
|
||||
|
|
||||
/* CRIS has certain insns that lockout interrupts. */ |
|
||||
int locked_irq; |
|
||||
int interrupt_vector; |
|
||||
int fault_vector; |
|
||||
int trap_vector; |
|
||||
|
|
||||
/* FIXME: add a check in the translator to avoid writing to support
|
|
||||
register sets beyond the 4th. The ISA allows up to 256! but in |
|
||||
practice there is no core that implements more than 4. |
|
||||
|
|
||||
Support function registers are used to control units close to the |
|
||||
core. Accesses do not pass down the normal hierarchy. |
|
||||
*/ |
|
||||
uint32_t sregs[4][16]; |
|
||||
|
|
||||
/* Linear feedback shift reg in the mmu. Used to provide pseudo
|
|
||||
randomness for the 'hint' the mmu gives to sw for choosing valid |
|
||||
sets on TLB refills. */ |
|
||||
uint32_t mmu_rand_lfsr; |
|
||||
|
|
||||
/*
|
|
||||
* We just store the stores to the tlbset here for later evaluation |
|
||||
* when the hw needs access to them. |
|
||||
* |
|
||||
* One for I and another for D. |
|
||||
*/ |
|
||||
TLBSet tlbsets[2][4][16]; |
|
||||
|
|
||||
/* Fields up to this point are cleared by a CPU reset */ |
|
||||
struct {} end_reset_fields; |
|
||||
|
|
||||
/* Members from load_info on are preserved across resets. */ |
|
||||
void *load_info; |
|
||||
} CPUCRISState; |
|
||||
|
|
||||
/**
|
|
||||
* CRISCPU: |
|
||||
* @env: #CPUCRISState |
|
||||
* |
|
||||
* A CRIS CPU. |
|
||||
*/ |
|
||||
struct ArchCPU { |
|
||||
CPUState parent_obj; |
|
||||
|
|
||||
CPUCRISState env; |
|
||||
}; |
|
||||
|
|
||||
/**
|
|
||||
* CRISCPUClass: |
|
||||
* @parent_realize: The parent class' realize handler. |
|
||||
* @parent_phases: The parent class' reset phase handlers. |
|
||||
* @vr: Version Register value. |
|
||||
* |
|
||||
* A CRIS CPU model. |
|
||||
*/ |
|
||||
struct CRISCPUClass { |
|
||||
CPUClass parent_class; |
|
||||
|
|
||||
DeviceRealize parent_realize; |
|
||||
ResettablePhases parent_phases; |
|
||||
|
|
||||
uint32_t vr; |
|
||||
}; |
|
||||
|
|
||||
#ifndef CONFIG_USER_ONLY |
|
||||
extern const VMStateDescription vmstate_cris_cpu; |
|
||||
|
|
||||
void cris_cpu_do_interrupt(CPUState *cpu); |
|
||||
void crisv10_cpu_do_interrupt(CPUState *cpu); |
|
||||
bool cris_cpu_exec_interrupt(CPUState *cpu, int int_req); |
|
||||
|
|
||||
bool cris_cpu_tlb_fill(CPUState *cs, vaddr address, int size, |
|
||||
MMUAccessType access_type, int mmu_idx, |
|
||||
bool probe, uintptr_t retaddr); |
|
||||
hwaddr cris_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); |
|
||||
#endif |
|
||||
|
|
||||
void cris_cpu_dump_state(CPUState *cs, FILE *f, int flags); |
|
||||
|
|
||||
int crisv10_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); |
|
||||
int cris_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); |
|
||||
int cris_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); |
|
||||
|
|
||||
void cris_initialize_tcg(void); |
|
||||
void cris_initialize_crisv10_tcg(void); |
|
||||
|
|
||||
/* Instead of computing the condition codes after each CRIS instruction,
|
|
||||
* QEMU just stores one operand (called CC_SRC), the result |
|
||||
* (called CC_DEST) and the type of operation (called CC_OP). When the |
|
||||
* condition codes are needed, the condition codes can be calculated |
|
||||
* using this information. Condition codes are not generated if they |
|
||||
* are only needed for conditional branches. |
|
||||
*/ |
|
||||
enum { |
|
||||
CC_OP_DYNAMIC, /* Use env->cc_op */ |
|
||||
CC_OP_FLAGS, |
|
||||
CC_OP_CMP, |
|
||||
CC_OP_MOVE, |
|
||||
CC_OP_ADD, |
|
||||
CC_OP_ADDC, |
|
||||
CC_OP_MCP, |
|
||||
CC_OP_ADDU, |
|
||||
CC_OP_SUB, |
|
||||
CC_OP_SUBU, |
|
||||
CC_OP_NEG, |
|
||||
CC_OP_BTST, |
|
||||
CC_OP_MULS, |
|
||||
CC_OP_MULU, |
|
||||
CC_OP_DSTEP, |
|
||||
CC_OP_MSTEP, |
|
||||
CC_OP_BOUND, |
|
||||
|
|
||||
CC_OP_OR, |
|
||||
CC_OP_AND, |
|
||||
CC_OP_XOR, |
|
||||
CC_OP_LSL, |
|
||||
CC_OP_LSR, |
|
||||
CC_OP_ASR, |
|
||||
CC_OP_LZ |
|
||||
}; |
|
||||
|
|
||||
/* CRIS uses 8k pages. */ |
|
||||
#define MMAP_SHIFT TARGET_PAGE_BITS |
|
||||
|
|
||||
#define CPU_RESOLVING_TYPE TYPE_CRIS_CPU |
|
||||
|
|
||||
/* MMU modes definitions */ |
|
||||
#define MMU_USER_IDX 1 |
|
||||
|
|
||||
/* Support function regs. */ |
|
||||
#define SFR_RW_GC_CFG 0][0 |
|
||||
#define SFR_RW_MM_CFG env->pregs[PR_SRS]][0 |
|
||||
#define SFR_RW_MM_KBASE_LO env->pregs[PR_SRS]][1 |
|
||||
#define SFR_RW_MM_KBASE_HI env->pregs[PR_SRS]][2 |
|
||||
#define SFR_R_MM_CAUSE env->pregs[PR_SRS]][3 |
|
||||
#define SFR_RW_MM_TLB_SEL env->pregs[PR_SRS]][4 |
|
||||
#define SFR_RW_MM_TLB_LO env->pregs[PR_SRS]][5 |
|
||||
#define SFR_RW_MM_TLB_HI env->pregs[PR_SRS]][6 |
|
||||
|
|
||||
#include "exec/cpu-all.h" |
|
||||
|
|
||||
static inline void cpu_get_tb_cpu_state(CPUCRISState *env, vaddr *pc, |
|
||||
uint64_t *cs_base, uint32_t *flags) |
|
||||
{ |
|
||||
*pc = env->pc; |
|
||||
*cs_base = 0; |
|
||||
*flags = env->dslot | |
|
||||
(env->pregs[PR_CCS] & (S_FLAG | P_FLAG | U_FLAG |
|
||||
| X_FLAG | PFIX_FLAG)); |
|
||||
} |
|
||||
|
|
||||
#endif |
|
||||
@ -1,112 +0,0 @@ |
|||||
/*
|
|
||||
* CRISv10 insn decoding macros. |
|
||||
* |
|
||||
* Copyright (c) 2010 AXIS Communications AB |
|
||||
* Written by Edgar E. Iglesias. |
|
||||
* |
|
||||
* This library is free software; you can redistribute it and/or |
|
||||
* modify it under the terms of the GNU Lesser General Public |
|
||||
* License as published by the Free Software Foundation; either |
|
||||
* version 2.1 of the License, or (at your option) any later version. |
|
||||
* |
|
||||
* This library is distributed in the hope that it will be useful, |
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
||||
* Lesser General Public License for more details. |
|
||||
* |
|
||||
* You should have received a copy of the GNU Lesser General Public |
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||
*/ |
|
||||
|
|
||||
#ifndef TARGET_CRIS_CRISV10_DECODE_H |
|
||||
#define TARGET_CRIS_CRISV10_DECODE_H |
|
||||
|
|
||||
#define CRISV10_MODE_QIMMEDIATE 0 |
|
||||
#define CRISV10_MODE_REG 1 |
|
||||
#define CRISV10_MODE_INDIRECT 2 |
|
||||
#define CRISV10_MODE_AUTOINC 3 |
|
||||
|
|
||||
/* Quick Immediate. */ |
|
||||
#define CRISV10_QIMM_BCC_R0 0 |
|
||||
#define CRISV10_QIMM_BCC_R1 1 |
|
||||
#define CRISV10_QIMM_BCC_R2 2 |
|
||||
#define CRISV10_QIMM_BCC_R3 3 |
|
||||
|
|
||||
#define CRISV10_QIMM_BDAP_R0 4 |
|
||||
#define CRISV10_QIMM_BDAP_R1 5 |
|
||||
#define CRISV10_QIMM_BDAP_R2 6 |
|
||||
#define CRISV10_QIMM_BDAP_R3 7 |
|
||||
|
|
||||
#define CRISV10_QIMM_ADDQ 8 |
|
||||
#define CRISV10_QIMM_MOVEQ 9 |
|
||||
#define CRISV10_QIMM_SUBQ 10 |
|
||||
#define CRISV10_QIMM_CMPQ 11 |
|
||||
#define CRISV10_QIMM_ANDQ 12 |
|
||||
#define CRISV10_QIMM_ORQ 13 |
|
||||
#define CRISV10_QIMM_ASHQ 14 |
|
||||
#define CRISV10_QIMM_LSHQ 15 |
|
||||
|
|
||||
|
|
||||
#define CRISV10_REG_ADDX 0 |
|
||||
#define CRISV10_REG_MOVX 1 |
|
||||
#define CRISV10_REG_SUBX 2 |
|
||||
#define CRISV10_REG_LSL 3 |
|
||||
#define CRISV10_REG_ADDI 4 |
|
||||
#define CRISV10_REG_BIAP 5 |
|
||||
#define CRISV10_REG_NEG 6 |
|
||||
#define CRISV10_REG_BOUND 7 |
|
||||
#define CRISV10_REG_ADD 8 |
|
||||
#define CRISV10_REG_MOVE_R 9 |
|
||||
#define CRISV10_REG_MOVE_SPR_R 9 |
|
||||
#define CRISV10_REG_MOVE_R_SPR 8 |
|
||||
#define CRISV10_REG_SUB 10 |
|
||||
#define CRISV10_REG_CMP 11 |
|
||||
#define CRISV10_REG_AND 12 |
|
||||
#define CRISV10_REG_OR 13 |
|
||||
#define CRISV10_REG_ASR 14 |
|
||||
#define CRISV10_REG_LSR 15 |
|
||||
|
|
||||
#define CRISV10_REG_BTST 3 |
|
||||
#define CRISV10_REG_SCC 4 |
|
||||
#define CRISV10_REG_SETF 6 |
|
||||
#define CRISV10_REG_CLEARF 7 |
|
||||
#define CRISV10_REG_BIAP 5 |
|
||||
#define CRISV10_REG_ABS 10 |
|
||||
#define CRISV10_REG_DSTEP 11 |
|
||||
#define CRISV10_REG_LZ 12 |
|
||||
#define CRISV10_REG_NOT 13 |
|
||||
#define CRISV10_REG_SWAP 13 |
|
||||
#define CRISV10_REG_XOR 14 |
|
||||
#define CRISV10_REG_MSTEP 15 |
|
||||
|
|
||||
/* Indirect, var size. */ |
|
||||
#define CRISV10_IND_TEST 14 |
|
||||
#define CRISV10_IND_MUL 4 |
|
||||
#define CRISV10_IND_BDAP_M 5 |
|
||||
#define CRISV10_IND_ADD 8 |
|
||||
#define CRISV10_IND_MOVE_M_R 9 |
|
||||
|
|
||||
|
|
||||
/* indirect fixed size. */ |
|
||||
#define CRISV10_IND_ADDX 0 |
|
||||
#define CRISV10_IND_MOVX 1 |
|
||||
#define CRISV10_IND_SUBX 2 |
|
||||
#define CRISV10_IND_CMPX 3 |
|
||||
#define CRISV10_IND_JUMP_M 4 |
|
||||
#define CRISV10_IND_DIP 5 |
|
||||
#define CRISV10_IND_JUMP_R 6 |
|
||||
#define CRISV17_IND_ADDC 6 |
|
||||
#define CRISV10_IND_BOUND 7 |
|
||||
#define CRISV10_IND_BCC_M 7 |
|
||||
#define CRISV10_IND_MOVE_M_SPR 8 |
|
||||
#define CRISV10_IND_MOVE_SPR_M 9 |
|
||||
#define CRISV10_IND_SUB 10 |
|
||||
#define CRISV10_IND_CMP 11 |
|
||||
#define CRISV10_IND_AND 12 |
|
||||
#define CRISV10_IND_OR 13 |
|
||||
#define CRISV10_IND_MOVE_R_M 15 |
|
||||
|
|
||||
#define CRISV10_IND_MOVEM_M_R 14 |
|
||||
#define CRISV10_IND_MOVEM_R_M 15 |
|
||||
|
|
||||
#endif |
|
||||
@ -1,133 +0,0 @@ |
|||||
/*
|
|
||||
* CRIS insn decoding macros. |
|
||||
* |
|
||||
* Copyright (c) 2007 AXIS Communications AB |
|
||||
* Written by Edgar E. Iglesias. |
|
||||
* |
|
||||
* This library is free software; you can redistribute it and/or |
|
||||
* modify it under the terms of the GNU Lesser General Public |
|
||||
* License as published by the Free Software Foundation; either |
|
||||
* version 2.1 of the License, or (at your option) any later version. |
|
||||
* |
|
||||
* This library is distributed in the hope that it will be useful, |
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
||||
* Lesser General Public License for more details. |
|
||||
* |
|
||||
* You should have received a copy of the GNU Lesser General Public |
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||
*/ |
|
||||
|
|
||||
#ifndef CRISV32_DECODE_H |
|
||||
#define CRISV32_DECODE_H |
|
||||
|
|
||||
/* Convenient binary macros. */ |
|
||||
#define HEX__(n) 0x##n##LU |
|
||||
#define B8__(x) ((x&0x0000000FLU)?1:0) \ |
|
||||
+ ((x&0x000000F0LU)?2:0) \ |
|
||||
+ ((x&0x00000F00LU)?4:0) \ |
|
||||
+ ((x&0x0000F000LU)?8:0) \ |
|
||||
+ ((x&0x000F0000LU)?16:0) \ |
|
||||
+ ((x&0x00F00000LU)?32:0) \ |
|
||||
+ ((x&0x0F000000LU)?64:0) \ |
|
||||
+ ((x&0xF0000000LU)?128:0) |
|
||||
#define B8(d) ((unsigned char)B8__(HEX__(d))) |
|
||||
|
|
||||
/* Quick imm. */ |
|
||||
#define DEC_BCCQ {B8(00000000), B8(11110000)} |
|
||||
#define DEC_ADDOQ {B8(00010000), B8(11110000)} |
|
||||
#define DEC_ADDQ {B8(00100000), B8(11111100)} |
|
||||
#define DEC_MOVEQ {B8(00100100), B8(11111100)} |
|
||||
#define DEC_SUBQ {B8(00101000), B8(11111100)} |
|
||||
#define DEC_CMPQ {B8(00101100), B8(11111100)} |
|
||||
#define DEC_ANDQ {B8(00110000), B8(11111100)} |
|
||||
#define DEC_ORQ {B8(00110100), B8(11111100)} |
|
||||
#define DEC_BTSTQ {B8(00111000), B8(11111110)} |
|
||||
#define DEC_ASRQ {B8(00111010), B8(11111110)} |
|
||||
#define DEC_LSLQ {B8(00111100), B8(11111110)} |
|
||||
#define DEC_LSRQ {B8(00111110), B8(11111110)} |
|
||||
|
|
||||
/* Register. */ |
|
||||
#define DEC_MOVU_R {B8(01000100), B8(11111110)} |
|
||||
#define DEC_MOVU_R {B8(01000100), B8(11111110)} |
|
||||
#define DEC_MOVS_R {B8(01000110), B8(11111110)} |
|
||||
#define DEC_MOVE_R {B8(01100100), B8(11111100)} |
|
||||
#define DEC_MOVE_RP {B8(01100011), B8(11111111)} |
|
||||
#define DEC_MOVE_PR {B8(01100111), B8(11111111)} |
|
||||
#define DEC_DSTEP_R {B8(01101111), B8(11111111)} |
|
||||
#define DEC_MOVE_RS {B8(10110111), B8(11111111)} |
|
||||
#define DEC_MOVE_SR {B8(11110111), B8(11111111)} |
|
||||
#define DEC_ADDU_R {B8(01000000), B8(11111110)} |
|
||||
#define DEC_ADDS_R {B8(01000010), B8(11111110)} |
|
||||
#define DEC_ADD_R {B8(01100000), B8(11111100)} |
|
||||
#define DEC_ADDI_R {B8(01010000), B8(11111100)} |
|
||||
#define DEC_MULS_R {B8(11010000), B8(11111100)} |
|
||||
#define DEC_MULU_R {B8(10010000), B8(11111100)} |
|
||||
#define DEC_ADDI_ACR {B8(01010100), B8(11111100)} |
|
||||
#define DEC_NEG_R {B8(01011000), B8(11111100)} |
|
||||
#define DEC_BOUND_R {B8(01011100), B8(11111100)} |
|
||||
#define DEC_SUBU_R {B8(01001000), B8(11111110)} |
|
||||
#define DEC_SUBS_R {B8(01001010), B8(11111110)} |
|
||||
#define DEC_SUB_R {B8(01101000), B8(11111100)} |
|
||||
#define DEC_CMP_R {B8(01101100), B8(11111100)} |
|
||||
#define DEC_AND_R {B8(01110000), B8(11111100)} |
|
||||
#define DEC_ABS_R {B8(01101011), B8(11111111)} |
|
||||
#define DEC_LZ_R {B8(01110011), B8(11111111)} |
|
||||
#define DEC_MCP_R {B8(01111111), B8(11111111)} |
|
||||
#define DEC_SWAP_R {B8(01110111), B8(11111111)} |
|
||||
#define DEC_XOR_R {B8(01111011), B8(11111111)} |
|
||||
#define DEC_LSL_R {B8(01001100), B8(11111100)} |
|
||||
#define DEC_LSR_R {B8(01111100), B8(11111100)} |
|
||||
#define DEC_ASR_R {B8(01111000), B8(11111100)} |
|
||||
#define DEC_OR_R {B8(01110100), B8(11111100)} |
|
||||
#define DEC_BTST_R {B8(01001111), B8(11111111)} |
|
||||
|
|
||||
/* Fixed. */ |
|
||||
#define DEC_SETF {B8(01011011), B8(11111111)} |
|
||||
#define DEC_CLEARF {B8(01011111), B8(11111111)} |
|
||||
|
|
||||
/* Memory. */ |
|
||||
#define DEC_ADDU_M {B8(10000000), B8(10111110)} |
|
||||
#define DEC_ADDS_M {B8(10000010), B8(10111110)} |
|
||||
#define DEC_MOVU_M {B8(10000100), B8(10111110)} |
|
||||
#define DEC_MOVS_M {B8(10000110), B8(10111110)} |
|
||||
#define DEC_SUBU_M {B8(10001000), B8(10111110)} |
|
||||
#define DEC_SUBS_M {B8(10001010), B8(10111110)} |
|
||||
#define DEC_CMPU_M {B8(10001100), B8(10111110)} |
|
||||
#define DEC_CMPS_M {B8(10001110), B8(10111110)} |
|
||||
#define DEC_ADDO_M {B8(10010100), B8(10111100)} |
|
||||
#define DEC_BOUND_M {B8(10011100), B8(10111100)} |
|
||||
#define DEC_ADD_M {B8(10100000), B8(10111100)} |
|
||||
#define DEC_MOVE_MR {B8(10100100), B8(10111100)} |
|
||||
#define DEC_SUB_M {B8(10101000), B8(10111100)} |
|
||||
#define DEC_CMP_M {B8(10101100), B8(10111100)} |
|
||||
#define DEC_AND_M {B8(10110000), B8(10111100)} |
|
||||
#define DEC_OR_M {B8(10110100), B8(10111100)} |
|
||||
#define DEC_TEST_M {B8(10111000), B8(10111100)} |
|
||||
#define DEC_MOVE_RM {B8(10111100), B8(10111100)} |
|
||||
|
|
||||
#define DEC_ADDC_R {B8(01010111), B8(11111111)} |
|
||||
#define DEC_ADDC_MR {B8(10011010), B8(10111111)} |
|
||||
#define DEC_LAPCQ {B8(10010111), B8(11111111)} |
|
||||
#define DEC_LAPC_IM {B8(11010111), B8(11111111)} |
|
||||
|
|
||||
#define DEC_MOVE_MP {B8(10100011), B8(10111111)} |
|
||||
#define DEC_MOVE_PM {B8(10100111), B8(10111111)} |
|
||||
|
|
||||
#define DEC_SCC_R {B8(01010011), B8(11111111)} |
|
||||
#define DEC_RFE_ETC {B8(10010011), B8(11111111)} |
|
||||
#define DEC_JUMP_P {B8(10011111), B8(11111111)} |
|
||||
#define DEC_BCC_IM {B8(11011111), B8(11111111)} |
|
||||
#define DEC_JAS_R {B8(10011011), B8(11111111)} |
|
||||
#define DEC_JASC_R {B8(10110011), B8(11111111)} |
|
||||
#define DEC_JAS_IM {B8(11011011), B8(11111111)} |
|
||||
#define DEC_JASC_IM {B8(11110011), B8(11111111)} |
|
||||
#define DEC_BAS_IM {B8(11101011), B8(11111111)} |
|
||||
#define DEC_BASC_IM {B8(11101111), B8(11111111)} |
|
||||
#define DEC_MOVEM_MR {B8(10111011), B8(10111111)} |
|
||||
#define DEC_MOVEM_RM {B8(10111111), B8(10111111)} |
|
||||
|
|
||||
#define DEC_FTAG_FIDX_D_M {B8(10101011), B8(11111111)} |
|
||||
#define DEC_FTAG_FIDX_I_M {B8(11010011), B8(11111111)} |
|
||||
|
|
||||
#endif |
|
||||
@ -1,127 +0,0 @@ |
|||||
/*
|
|
||||
* CRIS gdb server stub |
|
||||
* |
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard |
|
||||
* Copyright (c) 2013 SUSE LINUX Products GmbH |
|
||||
* |
|
||||
* This library is free software; you can redistribute it and/or |
|
||||
* modify it under the terms of the GNU Lesser General Public |
|
||||
* License as published by the Free Software Foundation; either |
|
||||
* version 2.1 of the License, or (at your option) any later version. |
|
||||
* |
|
||||
* This library is distributed in the hope that it will be useful, |
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
||||
* Lesser General Public License for more details. |
|
||||
* |
|
||||
* You should have received a copy of the GNU Lesser General Public |
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||
*/ |
|
||||
#include "qemu/osdep.h" |
|
||||
#include "cpu.h" |
|
||||
#include "gdbstub/helpers.h" |
|
||||
|
|
||||
int crisv10_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) |
|
||||
{ |
|
||||
CPUCRISState *env = cpu_env(cs); |
|
||||
|
|
||||
if (n < 15) { |
|
||||
return gdb_get_reg32(mem_buf, env->regs[n]); |
|
||||
} |
|
||||
|
|
||||
if (n == 15) { |
|
||||
return gdb_get_reg32(mem_buf, env->pc); |
|
||||
} |
|
||||
|
|
||||
if (n < 32) { |
|
||||
switch (n) { |
|
||||
case 16: |
|
||||
return gdb_get_reg8(mem_buf, env->pregs[n - 16]); |
|
||||
case 17: |
|
||||
return gdb_get_reg8(mem_buf, env->pregs[n - 16]); |
|
||||
case 20: |
|
||||
case 21: |
|
||||
return gdb_get_reg16(mem_buf, env->pregs[n - 16]); |
|
||||
default: |
|
||||
if (n >= 23) { |
|
||||
return gdb_get_reg32(mem_buf, env->pregs[n - 16]); |
|
||||
} |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
int cris_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) |
|
||||
{ |
|
||||
CPUCRISState *env = cpu_env(cs); |
|
||||
uint8_t srs; |
|
||||
|
|
||||
srs = env->pregs[PR_SRS]; |
|
||||
if (n < 16) { |
|
||||
return gdb_get_reg32(mem_buf, env->regs[n]); |
|
||||
} |
|
||||
|
|
||||
if (n >= 21 && n < 32) { |
|
||||
return gdb_get_reg32(mem_buf, env->pregs[n - 16]); |
|
||||
} |
|
||||
if (n >= 33 && n < 49) { |
|
||||
return gdb_get_reg32(mem_buf, env->sregs[srs][n - 33]); |
|
||||
} |
|
||||
switch (n) { |
|
||||
case 16: |
|
||||
return gdb_get_reg8(mem_buf, env->pregs[0]); |
|
||||
case 17: |
|
||||
return gdb_get_reg8(mem_buf, env->pregs[1]); |
|
||||
case 18: |
|
||||
return gdb_get_reg32(mem_buf, env->pregs[2]); |
|
||||
case 19: |
|
||||
return gdb_get_reg8(mem_buf, srs); |
|
||||
case 20: |
|
||||
return gdb_get_reg16(mem_buf, env->pregs[4]); |
|
||||
case 32: |
|
||||
return gdb_get_reg32(mem_buf, env->pc); |
|
||||
} |
|
||||
|
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
int cris_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) |
|
||||
{ |
|
||||
CPUCRISState *env = cpu_env(cs); |
|
||||
uint32_t tmp; |
|
||||
|
|
||||
if (n > 49) { |
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
tmp = ldl_p(mem_buf); |
|
||||
|
|
||||
if (n < 16) { |
|
||||
env->regs[n] = tmp; |
|
||||
} |
|
||||
|
|
||||
if (n >= 21 && n < 32) { |
|
||||
env->pregs[n - 16] = tmp; |
|
||||
} |
|
||||
|
|
||||
/* FIXME: Should support function regs be writable? */ |
|
||||
switch (n) { |
|
||||
case 16: |
|
||||
return 1; |
|
||||
case 17: |
|
||||
return 1; |
|
||||
case 18: |
|
||||
env->pregs[PR_PID] = tmp; |
|
||||
break; |
|
||||
case 19: |
|
||||
return 1; |
|
||||
case 20: |
|
||||
return 2; |
|
||||
case 32: |
|
||||
env->pc = tmp; |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
return 4; |
|
||||
} |
|
||||
@ -1,287 +0,0 @@ |
|||||
/*
|
|
||||
* CRIS helper routines. |
|
||||
* |
|
||||
* Copyright (c) 2007 AXIS Communications AB |
|
||||
* Written by Edgar E. Iglesias. |
|
||||
* |
|
||||
* This library is free software; you can redistribute it and/or |
|
||||
* modify it under the terms of the GNU Lesser General Public |
|
||||
* License as published by the Free Software Foundation; either |
|
||||
* version 2.1 of the License, or (at your option) any later version. |
|
||||
* |
|
||||
* This library is distributed in the hope that it will be useful, |
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
||||
* Lesser General Public License for more details. |
|
||||
* |
|
||||
* You should have received a copy of the GNU Lesser General Public |
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||
*/ |
|
||||
|
|
||||
#include "qemu/osdep.h" |
|
||||
#include "qemu/log.h" |
|
||||
#include "cpu.h" |
|
||||
#include "hw/core/tcg-cpu-ops.h" |
|
||||
#include "mmu.h" |
|
||||
#include "qemu/host-utils.h" |
|
||||
#include "exec/exec-all.h" |
|
||||
#include "exec/cpu_ldst.h" |
|
||||
#include "exec/helper-proto.h" |
|
||||
|
|
||||
|
|
||||
//#define CRIS_HELPER_DEBUG
|
|
||||
|
|
||||
|
|
||||
#ifdef CRIS_HELPER_DEBUG |
|
||||
#define D(x) x |
|
||||
#define D_LOG(...) qemu_log(__VA_ARGS__) |
|
||||
#else |
|
||||
#define D(x) |
|
||||
#define D_LOG(...) do { } while (0) |
|
||||
#endif |
|
||||
|
|
||||
static void cris_shift_ccs(CPUCRISState *env) |
|
||||
{ |
|
||||
uint32_t ccs; |
|
||||
/* Apply the ccs shift. */ |
|
||||
ccs = env->pregs[PR_CCS]; |
|
||||
ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff; |
|
||||
env->pregs[PR_CCS] = ccs; |
|
||||
} |
|
||||
|
|
||||
bool cris_cpu_tlb_fill(CPUState *cs, vaddr address, int size, |
|
||||
MMUAccessType access_type, int mmu_idx, |
|
||||
bool probe, uintptr_t retaddr) |
|
||||
{ |
|
||||
CPUCRISState *env = cpu_env(cs); |
|
||||
struct cris_mmu_result res; |
|
||||
int prot, miss; |
|
||||
target_ulong phy; |
|
||||
|
|
||||
miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK, |
|
||||
access_type, mmu_idx, 0); |
|
||||
if (likely(!miss)) { |
|
||||
/*
|
|
||||
* Mask off the cache selection bit. The ETRAX busses do not |
|
||||
* see the top bit. |
|
||||
*/ |
|
||||
phy = res.phy & ~0x80000000; |
|
||||
prot = res.prot; |
|
||||
tlb_set_page(cs, address & TARGET_PAGE_MASK, phy, |
|
||||
prot, mmu_idx, TARGET_PAGE_SIZE); |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
if (probe) { |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
if (cs->exception_index == EXCP_BUSFAULT) { |
|
||||
cpu_abort(cs, "CRIS: Illegal recursive bus fault." |
|
||||
"addr=%" VADDR_PRIx " access_type=%d\n", |
|
||||
address, access_type); |
|
||||
} |
|
||||
|
|
||||
env->pregs[PR_EDA] = address; |
|
||||
cs->exception_index = EXCP_BUSFAULT; |
|
||||
env->fault_vector = res.bf_vec; |
|
||||
if (retaddr) { |
|
||||
if (cpu_restore_state(cs, retaddr)) { |
|
||||
/* Evaluate flags after retranslation. */ |
|
||||
helper_top_evaluate_flags(env); |
|
||||
} |
|
||||
} |
|
||||
cpu_loop_exit(cs); |
|
||||
} |
|
||||
|
|
||||
void crisv10_cpu_do_interrupt(CPUState *cs) |
|
||||
{ |
|
||||
CPUCRISState *env = cpu_env(cs); |
|
||||
int ex_vec = -1; |
|
||||
|
|
||||
D_LOG("exception index=%d interrupt_req=%d\n", |
|
||||
cs->exception_index, |
|
||||
cs->interrupt_request); |
|
||||
|
|
||||
if (env->dslot) { |
|
||||
/* CRISv10 never takes interrupts while in a delay-slot. */ |
|
||||
cpu_abort(cs, "CRIS: Interrupt on delay-slot\n"); |
|
||||
} |
|
||||
|
|
||||
assert(!(env->pregs[PR_CCS] & PFIX_FLAG)); |
|
||||
switch (cs->exception_index) { |
|
||||
case EXCP_BREAK: |
|
||||
/* These exceptions are generated by the core itself.
|
|
||||
ERP should point to the insn following the brk. */ |
|
||||
ex_vec = env->trap_vector; |
|
||||
env->pregs[PRV10_BRP] = env->pc; |
|
||||
break; |
|
||||
|
|
||||
case EXCP_NMI: |
|
||||
/* NMI is hardwired to vector zero. */ |
|
||||
ex_vec = 0; |
|
||||
env->pregs[PR_CCS] &= ~M_FLAG_V10; |
|
||||
env->pregs[PRV10_BRP] = env->pc; |
|
||||
break; |
|
||||
|
|
||||
case EXCP_BUSFAULT: |
|
||||
cpu_abort(cs, "Unhandled busfault"); |
|
||||
break; |
|
||||
|
|
||||
default: |
|
||||
/* The interrupt controller gives us the vector. */ |
|
||||
ex_vec = env->interrupt_vector; |
|
||||
/* Normal interrupts are taken between
|
|
||||
TB's. env->pc is valid here. */ |
|
||||
env->pregs[PR_ERP] = env->pc; |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
if (env->pregs[PR_CCS] & U_FLAG) { |
|
||||
/* Swap stack pointers. */ |
|
||||
env->pregs[PR_USP] = env->regs[R_SP]; |
|
||||
env->regs[R_SP] = env->ksp; |
|
||||
} |
|
||||
|
|
||||
/* Now that we are in kernel mode, load the handlers address. */ |
|
||||
env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); |
|
||||
env->locked_irq = 1; |
|
||||
env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */ |
|
||||
|
|
||||
qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", |
|
||||
__func__, env->pc, ex_vec, |
|
||||
env->pregs[PR_CCS], |
|
||||
env->pregs[PR_PID], |
|
||||
env->pregs[PR_ERP]); |
|
||||
} |
|
||||
|
|
||||
void cris_cpu_do_interrupt(CPUState *cs) |
|
||||
{ |
|
||||
CPUCRISState *env = cpu_env(cs); |
|
||||
int ex_vec = -1; |
|
||||
|
|
||||
D_LOG("exception index=%d interrupt_req=%d\n", |
|
||||
cs->exception_index, |
|
||||
cs->interrupt_request); |
|
||||
|
|
||||
switch (cs->exception_index) { |
|
||||
case EXCP_BREAK: |
|
||||
/* These exceptions are generated by the core itself.
|
|
||||
ERP should point to the insn following the brk. */ |
|
||||
ex_vec = env->trap_vector; |
|
||||
env->pregs[PR_ERP] = env->pc; |
|
||||
break; |
|
||||
|
|
||||
case EXCP_NMI: |
|
||||
/* NMI is hardwired to vector zero. */ |
|
||||
ex_vec = 0; |
|
||||
env->pregs[PR_CCS] &= ~M_FLAG_V32; |
|
||||
env->pregs[PR_NRP] = env->pc; |
|
||||
break; |
|
||||
|
|
||||
case EXCP_BUSFAULT: |
|
||||
ex_vec = env->fault_vector; |
|
||||
env->pregs[PR_ERP] = env->pc; |
|
||||
break; |
|
||||
|
|
||||
default: |
|
||||
/* The interrupt controller gives us the vector. */ |
|
||||
ex_vec = env->interrupt_vector; |
|
||||
/* Normal interrupts are taken between
|
|
||||
TB's. env->pc is valid here. */ |
|
||||
env->pregs[PR_ERP] = env->pc; |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
/* Fill in the IDX field. */ |
|
||||
env->pregs[PR_EXS] = (ex_vec & 0xff) << 8; |
|
||||
|
|
||||
if (env->dslot) { |
|
||||
D_LOG("excp isr=%x PC=%x ds=%d SP=%x" |
|
||||
" ERP=%x pid=%x ccs=%x cc=%d %x\n", |
|
||||
ex_vec, env->pc, env->dslot, |
|
||||
env->regs[R_SP], |
|
||||
env->pregs[PR_ERP], env->pregs[PR_PID], |
|
||||
env->pregs[PR_CCS], |
|
||||
env->cc_op, env->cc_mask); |
|
||||
/* We loose the btarget, btaken state here so rexec the
|
|
||||
branch. */ |
|
||||
env->pregs[PR_ERP] -= env->dslot; |
|
||||
/* Exception starts with dslot cleared. */ |
|
||||
env->dslot = 0; |
|
||||
} |
|
||||
|
|
||||
if (env->pregs[PR_CCS] & U_FLAG) { |
|
||||
/* Swap stack pointers. */ |
|
||||
env->pregs[PR_USP] = env->regs[R_SP]; |
|
||||
env->regs[R_SP] = env->ksp; |
|
||||
} |
|
||||
|
|
||||
/* Apply the CRIS CCS shift. Clears U if set. */ |
|
||||
cris_shift_ccs(env); |
|
||||
|
|
||||
/* Now that we are in kernel mode, load the handlers address.
|
|
||||
This load may not fault, real hw leaves that behaviour as |
|
||||
undefined. */ |
|
||||
env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); |
|
||||
|
|
||||
/* Clear the excption_index to avoid spurious hw_aborts for recursive
|
|
||||
bus faults. */ |
|
||||
cs->exception_index = -1; |
|
||||
|
|
||||
D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", |
|
||||
__func__, env->pc, ex_vec, |
|
||||
env->pregs[PR_CCS], |
|
||||
env->pregs[PR_PID], |
|
||||
env->pregs[PR_ERP]); |
|
||||
} |
|
||||
|
|
||||
hwaddr cris_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) |
|
||||
{ |
|
||||
CRISCPU *cpu = CRIS_CPU(cs); |
|
||||
uint32_t phy = addr; |
|
||||
struct cris_mmu_result res; |
|
||||
int miss; |
|
||||
|
|
||||
miss = cris_mmu_translate(&res, &cpu->env, addr, MMU_DATA_LOAD, 0, 1); |
|
||||
/* If D TLB misses, try I TLB. */ |
|
||||
if (miss) { |
|
||||
miss = cris_mmu_translate(&res, &cpu->env, addr, MMU_INST_FETCH, 0, 1); |
|
||||
} |
|
||||
|
|
||||
if (!miss) { |
|
||||
phy = res.phy; |
|
||||
} |
|
||||
D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy)); |
|
||||
return phy; |
|
||||
} |
|
||||
|
|
||||
bool cris_cpu_exec_interrupt(CPUState *cs, int interrupt_request) |
|
||||
{ |
|
||||
CPUClass *cc = CPU_GET_CLASS(cs); |
|
||||
CPUCRISState *env = cpu_env(cs); |
|
||||
bool ret = false; |
|
||||
|
|
||||
if (interrupt_request & CPU_INTERRUPT_HARD |
|
||||
&& (env->pregs[PR_CCS] & I_FLAG) |
|
||||
&& !env->locked_irq) { |
|
||||
cs->exception_index = EXCP_IRQ; |
|
||||
cc->tcg_ops->do_interrupt(cs); |
|
||||
ret = true; |
|
||||
} |
|
||||
if (interrupt_request & CPU_INTERRUPT_NMI) { |
|
||||
unsigned int m_flag_archval; |
|
||||
if (env->pregs[PR_VR] < 32) { |
|
||||
m_flag_archval = M_FLAG_V10; |
|
||||
} else { |
|
||||
m_flag_archval = M_FLAG_V32; |
|
||||
} |
|
||||
if ((env->pregs[PR_CCS] & m_flag_archval)) { |
|
||||
cs->exception_index = EXCP_NMI; |
|
||||
cc->tcg_ops->do_interrupt(cs); |
|
||||
ret = true; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return ret; |
|
||||
} |
|
||||
@ -1,23 +0,0 @@ |
|||||
DEF_HELPER_2(raise_exception, noreturn, env, i32) |
|
||||
DEF_HELPER_2(tlb_flush_pid, void, env, i32) |
|
||||
DEF_HELPER_2(spc_write, void, env, i32) |
|
||||
DEF_HELPER_1(rfe, void, env) |
|
||||
DEF_HELPER_1(rfn, void, env) |
|
||||
|
|
||||
DEF_HELPER_3(movl_sreg_reg, void, env, i32, i32) |
|
||||
DEF_HELPER_3(movl_reg_sreg, void, env, i32, i32) |
|
||||
|
|
||||
DEF_HELPER_FLAGS_4(btst, TCG_CALL_NO_SE, i32, env, i32, i32, i32) |
|
||||
|
|
||||
DEF_HELPER_FLAGS_4(evaluate_flags_muls, TCG_CALL_NO_SE, i32, env, i32, i32, i32) |
|
||||
DEF_HELPER_FLAGS_4(evaluate_flags_mulu, TCG_CALL_NO_SE, i32, env, i32, i32, i32) |
|
||||
DEF_HELPER_FLAGS_5(evaluate_flags_mcp, TCG_CALL_NO_SE, i32, env, |
|
||||
i32, i32, i32, i32) |
|
||||
DEF_HELPER_FLAGS_5(evaluate_flags_alu_4, TCG_CALL_NO_SE, i32, env, |
|
||||
i32, i32, i32, i32) |
|
||||
DEF_HELPER_FLAGS_5(evaluate_flags_sub_4, TCG_CALL_NO_SE, i32, env, |
|
||||
i32, i32, i32, i32) |
|
||||
DEF_HELPER_FLAGS_3(evaluate_flags_move_4, TCG_CALL_NO_SE, i32, env, i32, i32) |
|
||||
DEF_HELPER_FLAGS_3(evaluate_flags_move_2, TCG_CALL_NO_SE, i32, env, i32, i32) |
|
||||
DEF_HELPER_1(evaluate_flags, void, env) |
|
||||
DEF_HELPER_1(top_evaluate_flags, void, env) |
|
||||
@ -1,93 +0,0 @@ |
|||||
/*
|
|
||||
* CRIS virtual CPU state save/load support |
|
||||
* |
|
||||
* Copyright (c) 2012 Red Hat, Inc. |
|
||||
* Written by Juan Quintela <quintela@redhat.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.1 of the License, or (at your option) any later version. |
|
||||
* |
|
||||
* This library is distributed in the hope that it will be useful, |
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
||||
* 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 "migration/cpu.h" |
|
||||
|
|
||||
static const VMStateDescription vmstate_tlbset = { |
|
||||
.name = "cpu/tlbset", |
|
||||
.version_id = 1, |
|
||||
.minimum_version_id = 1, |
|
||||
.fields = (const VMStateField[]) { |
|
||||
VMSTATE_UINT32(lo, TLBSet), |
|
||||
VMSTATE_UINT32(hi, TLBSet), |
|
||||
VMSTATE_END_OF_LIST() |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
static const VMStateDescription vmstate_cris_env = { |
|
||||
.name = "env", |
|
||||
.version_id = 2, |
|
||||
.minimum_version_id = 2, |
|
||||
.fields = (const VMStateField[]) { |
|
||||
VMSTATE_UINT32_ARRAY(regs, CPUCRISState, 16), |
|
||||
VMSTATE_UINT32_ARRAY(pregs, CPUCRISState, 16), |
|
||||
VMSTATE_UINT32(pc, CPUCRISState), |
|
||||
VMSTATE_UINT32(ksp, CPUCRISState), |
|
||||
VMSTATE_INT32(dslot, CPUCRISState), |
|
||||
VMSTATE_INT32(btaken, CPUCRISState), |
|
||||
VMSTATE_UINT32(btarget, CPUCRISState), |
|
||||
VMSTATE_UINT32(cc_op, CPUCRISState), |
|
||||
VMSTATE_UINT32(cc_mask, CPUCRISState), |
|
||||
VMSTATE_UINT32(cc_dest, CPUCRISState), |
|
||||
VMSTATE_UINT32(cc_src, CPUCRISState), |
|
||||
VMSTATE_UINT32(cc_result, CPUCRISState), |
|
||||
VMSTATE_INT32(cc_size, CPUCRISState), |
|
||||
VMSTATE_INT32(cc_x, CPUCRISState), |
|
||||
VMSTATE_INT32(locked_irq, CPUCRISState), |
|
||||
VMSTATE_INT32(interrupt_vector, CPUCRISState), |
|
||||
VMSTATE_INT32(fault_vector, CPUCRISState), |
|
||||
VMSTATE_INT32(trap_vector, CPUCRISState), |
|
||||
VMSTATE_UINT32_ARRAY(sregs[0], CPUCRISState, 16), |
|
||||
VMSTATE_UINT32_ARRAY(sregs[1], CPUCRISState, 16), |
|
||||
VMSTATE_UINT32_ARRAY(sregs[2], CPUCRISState, 16), |
|
||||
VMSTATE_UINT32_ARRAY(sregs[3], CPUCRISState, 16), |
|
||||
VMSTATE_UINT32(mmu_rand_lfsr, CPUCRISState), |
|
||||
VMSTATE_STRUCT_ARRAY(tlbsets[0][0], CPUCRISState, 16, 0, |
|
||||
vmstate_tlbset, TLBSet), |
|
||||
VMSTATE_STRUCT_ARRAY(tlbsets[0][1], CPUCRISState, 16, 0, |
|
||||
vmstate_tlbset, TLBSet), |
|
||||
VMSTATE_STRUCT_ARRAY(tlbsets[0][2], CPUCRISState, 16, 0, |
|
||||
vmstate_tlbset, TLBSet), |
|
||||
VMSTATE_STRUCT_ARRAY(tlbsets[0][3], CPUCRISState, 16, 0, |
|
||||
vmstate_tlbset, TLBSet), |
|
||||
VMSTATE_STRUCT_ARRAY(tlbsets[1][0], CPUCRISState, 16, 0, |
|
||||
vmstate_tlbset, TLBSet), |
|
||||
VMSTATE_STRUCT_ARRAY(tlbsets[1][1], CPUCRISState, 16, 0, |
|
||||
vmstate_tlbset, TLBSet), |
|
||||
VMSTATE_STRUCT_ARRAY(tlbsets[1][2], CPUCRISState, 16, 0, |
|
||||
vmstate_tlbset, TLBSet), |
|
||||
VMSTATE_STRUCT_ARRAY(tlbsets[1][3], CPUCRISState, 16, 0, |
|
||||
vmstate_tlbset, TLBSet), |
|
||||
VMSTATE_END_OF_LIST() |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
const VMStateDescription vmstate_cris_cpu = { |
|
||||
.name = "cpu", |
|
||||
.version_id = 1, |
|
||||
.minimum_version_id = 1, |
|
||||
.fields = (const VMStateField[]) { |
|
||||
VMSTATE_CPU(), |
|
||||
VMSTATE_STRUCT(env, CRISCPU, 1, vmstate_cris_env, CPUCRISState), |
|
||||
VMSTATE_END_OF_LIST() |
|
||||
} |
|
||||
}; |
|
||||
@ -1,17 +0,0 @@ |
|||||
cris_ss = ss.source_set() |
|
||||
cris_ss.add(files( |
|
||||
'cpu.c', |
|
||||
'gdbstub.c', |
|
||||
'op_helper.c', |
|
||||
'translate.c', |
|
||||
)) |
|
||||
|
|
||||
cris_system_ss = ss.source_set() |
|
||||
cris_system_ss.add(files( |
|
||||
'helper.c', |
|
||||
'machine.c', |
|
||||
'mmu.c', |
|
||||
)) |
|
||||
|
|
||||
target_arch += {'cris': cris_ss} |
|
||||
target_system_arch += {'cris': cris_system_ss} |
|
||||
@ -1,356 +0,0 @@ |
|||||
/*
|
|
||||
* CRIS mmu emulation. |
|
||||
* |
|
||||
* Copyright (c) 2007 AXIS Communications AB |
|
||||
* Written by Edgar E. Iglesias. |
|
||||
* |
|
||||
* This library is free software; you can redistribute it and/or |
|
||||
* modify it under the terms of the GNU Lesser General Public |
|
||||
* License as published by the Free Software Foundation; either |
|
||||
* version 2.1 of the License, or (at your option) any later version. |
|
||||
* |
|
||||
* This library is distributed in the hope that it will be useful, |
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
||||
* Lesser General Public License for more details. |
|
||||
* |
|
||||
* You should have received a copy of the GNU Lesser General Public |
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||
*/ |
|
||||
|
|
||||
#include "qemu/osdep.h" |
|
||||
#include "cpu.h" |
|
||||
#include "exec/exec-all.h" |
|
||||
#include "exec/page-protection.h" |
|
||||
#include "mmu.h" |
|
||||
|
|
||||
#ifdef DEBUG |
|
||||
#define D(x) x |
|
||||
#define D_LOG(...) qemu_log(__VA_ARGS__) |
|
||||
#else |
|
||||
#define D(x) do { } while (0) |
|
||||
#define D_LOG(...) do { } while (0) |
|
||||
#endif |
|
||||
|
|
||||
void cris_mmu_init(CPUCRISState *env) |
|
||||
{ |
|
||||
env->mmu_rand_lfsr = 0xcccc; |
|
||||
} |
|
||||
|
|
||||
#define SR_POLYNOM 0x8805 |
|
||||
static inline unsigned int compute_polynom(unsigned int sr) |
|
||||
{ |
|
||||
unsigned int i; |
|
||||
unsigned int f; |
|
||||
|
|
||||
f = 0; |
|
||||
for (i = 0; i < 16; i++) { |
|
||||
f += ((SR_POLYNOM >> i) & 1) & ((sr >> i) & 1); |
|
||||
} |
|
||||
|
|
||||
return f; |
|
||||
} |
|
||||
|
|
||||
static void cris_mmu_update_rand_lfsr(CPUCRISState *env) |
|
||||
{ |
|
||||
unsigned int f; |
|
||||
|
|
||||
/* Update lfsr at every fault. */ |
|
||||
f = compute_polynom(env->mmu_rand_lfsr); |
|
||||
env->mmu_rand_lfsr >>= 1; |
|
||||
env->mmu_rand_lfsr |= (f << 15); |
|
||||
env->mmu_rand_lfsr &= 0xffff; |
|
||||
} |
|
||||
|
|
||||
static inline int cris_mmu_enabled(uint32_t rw_gc_cfg) |
|
||||
{ |
|
||||
return (rw_gc_cfg & 12) != 0; |
|
||||
} |
|
||||
|
|
||||
static inline int cris_mmu_segmented_addr(int seg, uint32_t rw_mm_cfg) |
|
||||
{ |
|
||||
return (1 << seg) & rw_mm_cfg; |
|
||||
} |
|
||||
|
|
||||
static uint32_t cris_mmu_translate_seg(CPUCRISState *env, int seg) |
|
||||
{ |
|
||||
uint32_t base; |
|
||||
int i; |
|
||||
|
|
||||
if (seg < 8) { |
|
||||
base = env->sregs[SFR_RW_MM_KBASE_LO]; |
|
||||
} else { |
|
||||
base = env->sregs[SFR_RW_MM_KBASE_HI]; |
|
||||
} |
|
||||
|
|
||||
i = seg & 7; |
|
||||
base >>= i * 4; |
|
||||
base &= 15; |
|
||||
|
|
||||
base <<= 28; |
|
||||
return base; |
|
||||
} |
|
||||
|
|
||||
/* Used by the tlb decoder. */ |
|
||||
#define EXTRACT_FIELD(src, start, end) \ |
|
||||
(((src) >> start) & ((1 << (end - start + 1)) - 1)) |
|
||||
|
|
||||
static inline void set_field(uint32_t *dst, unsigned int val, |
|
||||
unsigned int offset, unsigned int width) |
|
||||
{ |
|
||||
uint32_t mask; |
|
||||
|
|
||||
mask = (1 << width) - 1; |
|
||||
mask <<= offset; |
|
||||
val <<= offset; |
|
||||
|
|
||||
val &= mask; |
|
||||
*dst &= ~(mask); |
|
||||
*dst |= val; |
|
||||
} |
|
||||
|
|
||||
#ifdef DEBUG |
|
||||
static void dump_tlb(CPUCRISState *env, int mmu) |
|
||||
{ |
|
||||
int set; |
|
||||
int idx; |
|
||||
uint32_t hi, lo, tlb_vpn, tlb_pfn; |
|
||||
|
|
||||
for (set = 0; set < 4; set++) { |
|
||||
for (idx = 0; idx < 16; idx++) { |
|
||||
lo = env->tlbsets[mmu][set][idx].lo; |
|
||||
hi = env->tlbsets[mmu][set][idx].hi; |
|
||||
tlb_vpn = EXTRACT_FIELD(hi, 13, 31); |
|
||||
tlb_pfn = EXTRACT_FIELD(lo, 13, 31); |
|
||||
|
|
||||
printf("TLB: [%d][%d] hi=%x lo=%x v=%x p=%x\n", |
|
||||
set, idx, hi, lo, tlb_vpn, tlb_pfn); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
#endif |
|
||||
|
|
||||
static int cris_mmu_translate_page(struct cris_mmu_result *res, |
|
||||
CPUCRISState *env, uint32_t vaddr, |
|
||||
MMUAccessType access_type, |
|
||||
int usermode, int debug) |
|
||||
{ |
|
||||
unsigned int vpage; |
|
||||
unsigned int idx; |
|
||||
uint32_t pid, lo, hi; |
|
||||
uint32_t tlb_vpn, tlb_pfn = 0; |
|
||||
int tlb_pid, tlb_g, tlb_v, tlb_k, tlb_w, tlb_x; |
|
||||
int cfg_v, cfg_k, cfg_w, cfg_x; |
|
||||
int set, match = 0; |
|
||||
uint32_t r_cause; |
|
||||
uint32_t r_cfg; |
|
||||
int rwcause; |
|
||||
int mmu = 1; /* Data mmu is default. */ |
|
||||
int vect_base; |
|
||||
|
|
||||
r_cause = env->sregs[SFR_R_MM_CAUSE]; |
|
||||
r_cfg = env->sregs[SFR_RW_MM_CFG]; |
|
||||
pid = env->pregs[PR_PID] & 0xff; |
|
||||
|
|
||||
switch (access_type) { |
|
||||
case MMU_INST_FETCH: |
|
||||
rwcause = CRIS_MMU_ERR_EXEC; |
|
||||
mmu = 0; |
|
||||
break; |
|
||||
case MMU_DATA_STORE: |
|
||||
rwcause = CRIS_MMU_ERR_WRITE; |
|
||||
break; |
|
||||
default: |
|
||||
case MMU_DATA_LOAD: |
|
||||
rwcause = CRIS_MMU_ERR_READ; |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
/* I exception vectors 4 - 7, D 8 - 11. */ |
|
||||
vect_base = (mmu + 1) * 4; |
|
||||
|
|
||||
vpage = vaddr >> 13; |
|
||||
|
|
||||
/*
|
|
||||
* We know the index which to check on each set. |
|
||||
* Scan both I and D. |
|
||||
*/ |
|
||||
idx = vpage & 15; |
|
||||
for (set = 0; set < 4; set++) { |
|
||||
lo = env->tlbsets[mmu][set][idx].lo; |
|
||||
hi = env->tlbsets[mmu][set][idx].hi; |
|
||||
|
|
||||
tlb_vpn = hi >> 13; |
|
||||
tlb_pid = EXTRACT_FIELD(hi, 0, 7); |
|
||||
tlb_g = EXTRACT_FIELD(lo, 4, 4); |
|
||||
|
|
||||
D_LOG("TLB[%d][%d][%d] v=%x vpage=%x lo=%x hi=%x\n", |
|
||||
mmu, set, idx, tlb_vpn, vpage, lo, hi); |
|
||||
if ((tlb_g || (tlb_pid == pid)) && tlb_vpn == vpage) { |
|
||||
match = 1; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
res->bf_vec = vect_base; |
|
||||
if (match) { |
|
||||
cfg_w = EXTRACT_FIELD(r_cfg, 19, 19); |
|
||||
cfg_k = EXTRACT_FIELD(r_cfg, 18, 18); |
|
||||
cfg_x = EXTRACT_FIELD(r_cfg, 17, 17); |
|
||||
cfg_v = EXTRACT_FIELD(r_cfg, 16, 16); |
|
||||
|
|
||||
tlb_pfn = EXTRACT_FIELD(lo, 13, 31); |
|
||||
tlb_v = EXTRACT_FIELD(lo, 3, 3); |
|
||||
tlb_k = EXTRACT_FIELD(lo, 2, 2); |
|
||||
tlb_w = EXTRACT_FIELD(lo, 1, 1); |
|
||||
tlb_x = EXTRACT_FIELD(lo, 0, 0); |
|
||||
|
|
||||
/*
|
|
||||
* set_exception_vector(0x04, i_mmu_refill); |
|
||||
* set_exception_vector(0x05, i_mmu_invalid); |
|
||||
* set_exception_vector(0x06, i_mmu_access); |
|
||||
* set_exception_vector(0x07, i_mmu_execute); |
|
||||
* set_exception_vector(0x08, d_mmu_refill); |
|
||||
* set_exception_vector(0x09, d_mmu_invalid); |
|
||||
* set_exception_vector(0x0a, d_mmu_access); |
|
||||
* set_exception_vector(0x0b, d_mmu_write); |
|
||||
*/ |
|
||||
if (cfg_k && tlb_k && usermode) { |
|
||||
D(printf("tlb: kernel protected %x lo=%x pc=%x\n", |
|
||||
vaddr, lo, env->pc)); |
|
||||
match = 0; |
|
||||
res->bf_vec = vect_base + 2; |
|
||||
} else if (access_type == MMU_DATA_STORE && cfg_w && !tlb_w) { |
|
||||
D(printf("tlb: write protected %x lo=%x pc=%x\n", |
|
||||
vaddr, lo, env->pc)); |
|
||||
match = 0; |
|
||||
/* write accesses never go through the I mmu. */ |
|
||||
res->bf_vec = vect_base + 3; |
|
||||
} else if (access_type == MMU_INST_FETCH && cfg_x && !tlb_x) { |
|
||||
D(printf("tlb: exec protected %x lo=%x pc=%x\n", |
|
||||
vaddr, lo, env->pc)); |
|
||||
match = 0; |
|
||||
res->bf_vec = vect_base + 3; |
|
||||
} else if (cfg_v && !tlb_v) { |
|
||||
D(printf("tlb: invalid %x\n", vaddr)); |
|
||||
match = 0; |
|
||||
res->bf_vec = vect_base + 1; |
|
||||
} |
|
||||
|
|
||||
res->prot = 0; |
|
||||
if (match) { |
|
||||
res->prot |= PAGE_READ; |
|
||||
if (tlb_w) { |
|
||||
res->prot |= PAGE_WRITE; |
|
||||
} |
|
||||
if (mmu == 0 && (cfg_x || tlb_x)) { |
|
||||
res->prot |= PAGE_EXEC; |
|
||||
} |
|
||||
} else { |
|
||||
D(dump_tlb(env, mmu)); |
|
||||
} |
|
||||
} else { |
|
||||
/* If refill, provide a randomized set. */ |
|
||||
set = env->mmu_rand_lfsr & 3; |
|
||||
} |
|
||||
|
|
||||
if (!match && !debug) { |
|
||||
cris_mmu_update_rand_lfsr(env); |
|
||||
|
|
||||
/* Compute index. */ |
|
||||
idx = vpage & 15; |
|
||||
|
|
||||
/* Update RW_MM_TLB_SEL. */ |
|
||||
env->sregs[SFR_RW_MM_TLB_SEL] = 0; |
|
||||
set_field(&env->sregs[SFR_RW_MM_TLB_SEL], idx, 0, 4); |
|
||||
set_field(&env->sregs[SFR_RW_MM_TLB_SEL], set, 4, 2); |
|
||||
|
|
||||
/* Update RW_MM_CAUSE. */ |
|
||||
set_field(&r_cause, rwcause, 8, 2); |
|
||||
set_field(&r_cause, vpage, 13, 19); |
|
||||
set_field(&r_cause, pid, 0, 8); |
|
||||
env->sregs[SFR_R_MM_CAUSE] = r_cause; |
|
||||
D(printf("refill vaddr=%x pc=%x\n", vaddr, env->pc)); |
|
||||
} |
|
||||
|
|
||||
D(printf("%s access=%u mtch=%d pc=%x va=%x vpn=%x tlbvpn=%x pfn=%x pid=%x" |
|
||||
" %x cause=%x sel=%x sp=%x %x %x\n", |
|
||||
__func__, access_type, match, env->pc, |
|
||||
vaddr, vpage, |
|
||||
tlb_vpn, tlb_pfn, tlb_pid, |
|
||||
pid, |
|
||||
r_cause, |
|
||||
env->sregs[SFR_RW_MM_TLB_SEL], |
|
||||
env->regs[R_SP], env->pregs[PR_USP], env->ksp)); |
|
||||
|
|
||||
res->phy = tlb_pfn << TARGET_PAGE_BITS; |
|
||||
return !match; |
|
||||
} |
|
||||
|
|
||||
void cris_mmu_flush_pid(CPUCRISState *env, uint32_t pid) |
|
||||
{ |
|
||||
target_ulong vaddr; |
|
||||
unsigned int idx; |
|
||||
uint32_t lo, hi; |
|
||||
uint32_t tlb_vpn; |
|
||||
int tlb_pid, tlb_g, tlb_v; |
|
||||
unsigned int set; |
|
||||
unsigned int mmu; |
|
||||
|
|
||||
pid &= 0xff; |
|
||||
for (mmu = 0; mmu < 2; mmu++) { |
|
||||
for (set = 0; set < 4; set++) { |
|
||||
for (idx = 0; idx < 16; idx++) { |
|
||||
lo = env->tlbsets[mmu][set][idx].lo; |
|
||||
hi = env->tlbsets[mmu][set][idx].hi; |
|
||||
|
|
||||
tlb_vpn = EXTRACT_FIELD(hi, 13, 31); |
|
||||
tlb_pid = EXTRACT_FIELD(hi, 0, 7); |
|
||||
tlb_g = EXTRACT_FIELD(lo, 4, 4); |
|
||||
tlb_v = EXTRACT_FIELD(lo, 3, 3); |
|
||||
|
|
||||
if (tlb_v && !tlb_g && (tlb_pid == pid)) { |
|
||||
vaddr = tlb_vpn << TARGET_PAGE_BITS; |
|
||||
D_LOG("flush pid=%x vaddr=%x\n", pid, vaddr); |
|
||||
tlb_flush_page(env_cpu(env), vaddr); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
int cris_mmu_translate(struct cris_mmu_result *res, |
|
||||
CPUCRISState *env, uint32_t vaddr, |
|
||||
MMUAccessType access_type, int mmu_idx, int debug) |
|
||||
{ |
|
||||
int seg; |
|
||||
int miss = 0; |
|
||||
int is_user = mmu_idx == MMU_USER_IDX; |
|
||||
uint32_t old_srs; |
|
||||
|
|
||||
old_srs = env->pregs[PR_SRS]; |
|
||||
|
|
||||
env->pregs[PR_SRS] = access_type == MMU_INST_FETCH ? 1 : 2; |
|
||||
|
|
||||
if (!cris_mmu_enabled(env->sregs[SFR_RW_GC_CFG])) { |
|
||||
res->phy = vaddr; |
|
||||
res->prot = PAGE_RWX; |
|
||||
goto done; |
|
||||
} |
|
||||
|
|
||||
seg = vaddr >> 28; |
|
||||
if (!is_user && cris_mmu_segmented_addr(seg, env->sregs[SFR_RW_MM_CFG])) { |
|
||||
uint32_t base; |
|
||||
|
|
||||
miss = 0; |
|
||||
base = cris_mmu_translate_seg(env, seg); |
|
||||
res->phy = base | (0x0fffffff & vaddr); |
|
||||
res->prot = PAGE_RWX; |
|
||||
} else { |
|
||||
miss = cris_mmu_translate_page(res, env, vaddr, access_type, |
|
||||
is_user, debug); |
|
||||
} |
|
||||
done: |
|
||||
env->pregs[PR_SRS] = old_srs; |
|
||||
return miss; |
|
||||
} |
|
||||
@ -1,22 +0,0 @@ |
|||||
#ifndef TARGET_CRIS_MMU_H |
|
||||
#define TARGET_CRIS_MMU_H |
|
||||
|
|
||||
#define CRIS_MMU_ERR_EXEC 0 |
|
||||
#define CRIS_MMU_ERR_READ 1 |
|
||||
#define CRIS_MMU_ERR_WRITE 2 |
|
||||
#define CRIS_MMU_ERR_FLUSH 3 |
|
||||
|
|
||||
struct cris_mmu_result |
|
||||
{ |
|
||||
uint32_t phy; |
|
||||
int prot; |
|
||||
int bf_vec; |
|
||||
}; |
|
||||
|
|
||||
void cris_mmu_init(CPUCRISState *env); |
|
||||
void cris_mmu_flush_pid(CPUCRISState *env, uint32_t pid); |
|
||||
int cris_mmu_translate(struct cris_mmu_result *res, |
|
||||
CPUCRISState *env, uint32_t vaddr, |
|
||||
MMUAccessType access_type, int mmu_idx, int debug); |
|
||||
|
|
||||
#endif |
|
||||
@ -1,580 +0,0 @@ |
|||||
/*
|
|
||||
* CRIS helper routines |
|
||||
* |
|
||||
* Copyright (c) 2007 AXIS Communications |
|
||||
* Written by Edgar E. Iglesias |
|
||||
* |
|
||||
* This library is free software; you can redistribute it and/or |
|
||||
* modify it under the terms of the GNU Lesser General Public |
|
||||
* License as published by the Free Software Foundation; either |
|
||||
* version 2.1 of the License, or (at your option) any later version. |
|
||||
* |
|
||||
* This library is distributed in the hope that it will be useful, |
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
||||
* Lesser General Public License for more details. |
|
||||
* |
|
||||
* You should have received a copy of the GNU Lesser General Public |
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||
*/ |
|
||||
|
|
||||
#include "qemu/osdep.h" |
|
||||
#include "cpu.h" |
|
||||
#include "mmu.h" |
|
||||
#include "exec/helper-proto.h" |
|
||||
#include "qemu/host-utils.h" |
|
||||
#include "exec/exec-all.h" |
|
||||
|
|
||||
//#define CRIS_OP_HELPER_DEBUG
|
|
||||
|
|
||||
|
|
||||
#ifdef CRIS_OP_HELPER_DEBUG |
|
||||
#define D(x) x |
|
||||
#define D_LOG(...) qemu_log(__VA_ARGS__) |
|
||||
#else |
|
||||
#define D(x) |
|
||||
#define D_LOG(...) do { } while (0) |
|
||||
#endif |
|
||||
|
|
||||
void helper_raise_exception(CPUCRISState *env, uint32_t index) |
|
||||
{ |
|
||||
CPUState *cs = env_cpu(env); |
|
||||
|
|
||||
cs->exception_index = index; |
|
||||
cpu_loop_exit(cs); |
|
||||
} |
|
||||
|
|
||||
void helper_tlb_flush_pid(CPUCRISState *env, uint32_t pid) |
|
||||
{ |
|
||||
#if !defined(CONFIG_USER_ONLY) |
|
||||
pid &= 0xff; |
|
||||
if (pid != (env->pregs[PR_PID] & 0xff)) { |
|
||||
cris_mmu_flush_pid(env, env->pregs[PR_PID]); |
|
||||
} |
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
void helper_spc_write(CPUCRISState *env, uint32_t new_spc) |
|
||||
{ |
|
||||
#if !defined(CONFIG_USER_ONLY) |
|
||||
CPUState *cs = env_cpu(env); |
|
||||
|
|
||||
tlb_flush_page(cs, env->pregs[PR_SPC]); |
|
||||
tlb_flush_page(cs, new_spc); |
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
/* Used by the tlb decoder. */ |
|
||||
#define EXTRACT_FIELD(src, start, end) \ |
|
||||
(((src) >> start) & ((1 << (end - start + 1)) - 1)) |
|
||||
|
|
||||
void helper_movl_sreg_reg(CPUCRISState *env, uint32_t sreg, uint32_t reg) |
|
||||
{ |
|
||||
uint32_t srs; |
|
||||
srs = env->pregs[PR_SRS]; |
|
||||
srs &= 3; |
|
||||
env->sregs[srs][sreg] = env->regs[reg]; |
|
||||
|
|
||||
#if !defined(CONFIG_USER_ONLY) |
|
||||
if (srs == 1 || srs == 2) { |
|
||||
if (sreg == 6) { |
|
||||
/* Writes to tlb-hi write to mm_cause as a side effect. */ |
|
||||
env->sregs[SFR_RW_MM_TLB_HI] = env->regs[reg]; |
|
||||
env->sregs[SFR_R_MM_CAUSE] = env->regs[reg]; |
|
||||
} else if (sreg == 5) { |
|
||||
uint32_t set; |
|
||||
uint32_t idx; |
|
||||
uint32_t lo, hi; |
|
||||
uint32_t vaddr; |
|
||||
int tlb_v; |
|
||||
|
|
||||
idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; |
|
||||
set >>= 4; |
|
||||
set &= 3; |
|
||||
|
|
||||
idx &= 15; |
|
||||
/* We've just made a write to tlb_lo. */ |
|
||||
lo = env->sregs[SFR_RW_MM_TLB_LO]; |
|
||||
/* Writes are done via r_mm_cause. */ |
|
||||
hi = env->sregs[SFR_R_MM_CAUSE]; |
|
||||
|
|
||||
vaddr = EXTRACT_FIELD(env->tlbsets[srs - 1][set][idx].hi, 13, 31); |
|
||||
vaddr <<= TARGET_PAGE_BITS; |
|
||||
tlb_v = EXTRACT_FIELD(env->tlbsets[srs - 1][set][idx].lo, 3, 3); |
|
||||
env->tlbsets[srs - 1][set][idx].lo = lo; |
|
||||
env->tlbsets[srs - 1][set][idx].hi = hi; |
|
||||
|
|
||||
D_LOG("tlb flush vaddr=%x v=%d pc=%x\n", |
|
||||
vaddr, tlb_v, env->pc); |
|
||||
if (tlb_v) { |
|
||||
tlb_flush_page(env_cpu(env), vaddr); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
void helper_movl_reg_sreg(CPUCRISState *env, uint32_t reg, uint32_t sreg) |
|
||||
{ |
|
||||
uint32_t srs; |
|
||||
env->pregs[PR_SRS] &= 3; |
|
||||
srs = env->pregs[PR_SRS]; |
|
||||
|
|
||||
#if !defined(CONFIG_USER_ONLY) |
|
||||
if (srs == 1 || srs == 2) { |
|
||||
uint32_t set; |
|
||||
uint32_t idx; |
|
||||
uint32_t lo, hi; |
|
||||
|
|
||||
idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; |
|
||||
set >>= 4; |
|
||||
set &= 3; |
|
||||
idx &= 15; |
|
||||
|
|
||||
/* Update the mirror regs. */ |
|
||||
hi = env->tlbsets[srs - 1][set][idx].hi; |
|
||||
lo = env->tlbsets[srs - 1][set][idx].lo; |
|
||||
env->sregs[SFR_RW_MM_TLB_HI] = hi; |
|
||||
env->sregs[SFR_RW_MM_TLB_LO] = lo; |
|
||||
} |
|
||||
#endif |
|
||||
env->regs[reg] = env->sregs[srs][sreg]; |
|
||||
} |
|
||||
|
|
||||
static void cris_ccs_rshift(CPUCRISState *env) |
|
||||
{ |
|
||||
uint32_t ccs; |
|
||||
|
|
||||
/* Apply the ccs shift. */ |
|
||||
ccs = env->pregs[PR_CCS]; |
|
||||
ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10); |
|
||||
if (ccs & U_FLAG) { |
|
||||
/* Enter user mode. */ |
|
||||
env->ksp = env->regs[R_SP]; |
|
||||
env->regs[R_SP] = env->pregs[PR_USP]; |
|
||||
} |
|
||||
|
|
||||
env->pregs[PR_CCS] = ccs; |
|
||||
} |
|
||||
|
|
||||
void helper_rfe(CPUCRISState *env) |
|
||||
{ |
|
||||
int rflag = env->pregs[PR_CCS] & R_FLAG; |
|
||||
|
|
||||
D_LOG("rfe: erp=%x pid=%x ccs=%x btarget=%x\n", |
|
||||
env->pregs[PR_ERP], env->pregs[PR_PID], |
|
||||
env->pregs[PR_CCS], |
|
||||
env->btarget); |
|
||||
|
|
||||
cris_ccs_rshift(env); |
|
||||
|
|
||||
/* RFE sets the P_FLAG only if the R_FLAG is not set. */ |
|
||||
if (!rflag) { |
|
||||
env->pregs[PR_CCS] |= P_FLAG; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void helper_rfn(CPUCRISState *env) |
|
||||
{ |
|
||||
int rflag = env->pregs[PR_CCS] & R_FLAG; |
|
||||
|
|
||||
D_LOG("rfn: erp=%x pid=%x ccs=%x btarget=%x\n", |
|
||||
env->pregs[PR_ERP], env->pregs[PR_PID], |
|
||||
env->pregs[PR_CCS], |
|
||||
env->btarget); |
|
||||
|
|
||||
cris_ccs_rshift(env); |
|
||||
|
|
||||
/* Set the P_FLAG only if the R_FLAG is not set. */ |
|
||||
if (!rflag) { |
|
||||
env->pregs[PR_CCS] |= P_FLAG; |
|
||||
} |
|
||||
|
|
||||
/* Always set the M flag. */ |
|
||||
env->pregs[PR_CCS] |= M_FLAG_V32; |
|
||||
} |
|
||||
|
|
||||
uint32_t helper_btst(CPUCRISState *env, uint32_t t0, uint32_t t1, uint32_t ccs) |
|
||||
{ |
|
||||
/* FIXME: clean this up. */ |
|
||||
|
|
||||
/*
|
|
||||
* des ref: |
|
||||
* The N flag is set according to the selected bit in the dest reg. |
|
||||
* The Z flag is set if the selected bit and all bits to the right are |
|
||||
* zero. |
|
||||
* The X flag is cleared. |
|
||||
* Other flags are left untouched. |
|
||||
* The destination reg is not affected. |
|
||||
*/ |
|
||||
unsigned int fz, sbit, bset, mask, masked_t0; |
|
||||
|
|
||||
sbit = t1 & 31; |
|
||||
bset = !!(t0 & (1 << sbit)); |
|
||||
mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1; |
|
||||
masked_t0 = t0 & mask; |
|
||||
fz = !(masked_t0 | bset); |
|
||||
|
|
||||
/* Clear the X, N and Z flags. */ |
|
||||
ccs = ccs & ~(X_FLAG | N_FLAG | Z_FLAG); |
|
||||
if (env->pregs[PR_VR] < 32) { |
|
||||
ccs &= ~(V_FLAG | C_FLAG); |
|
||||
} |
|
||||
/* Set the N and Z flags accordingly. */ |
|
||||
ccs |= (bset << 3) | (fz << 2); |
|
||||
return ccs; |
|
||||
} |
|
||||
|
|
||||
static inline uint32_t evaluate_flags_writeback(CPUCRISState *env, |
|
||||
uint32_t flags, uint32_t ccs) |
|
||||
{ |
|
||||
unsigned int x, z, mask; |
|
||||
|
|
||||
/* Extended arithmetic, leave the z flag alone. */ |
|
||||
x = env->cc_x; |
|
||||
mask = env->cc_mask | X_FLAG; |
|
||||
if (x) { |
|
||||
z = flags & Z_FLAG; |
|
||||
mask = mask & ~z; |
|
||||
} |
|
||||
flags &= mask; |
|
||||
|
|
||||
/* all insn clear the x-flag except setf or clrf. */ |
|
||||
ccs &= ~mask; |
|
||||
ccs |= flags; |
|
||||
return ccs; |
|
||||
} |
|
||||
|
|
||||
uint32_t helper_evaluate_flags_muls(CPUCRISState *env, |
|
||||
uint32_t ccs, uint32_t res, uint32_t mof) |
|
||||
{ |
|
||||
uint32_t flags = 0; |
|
||||
int64_t tmp; |
|
||||
int dneg; |
|
||||
|
|
||||
dneg = ((int32_t)res) < 0; |
|
||||
|
|
||||
tmp = mof; |
|
||||
tmp <<= 32; |
|
||||
tmp |= res; |
|
||||
if (tmp == 0) { |
|
||||
flags |= Z_FLAG; |
|
||||
} else if (tmp < 0) { |
|
||||
flags |= N_FLAG; |
|
||||
} |
|
||||
if ((dneg && mof != -1) || (!dneg && mof != 0)) { |
|
||||
flags |= V_FLAG; |
|
||||
} |
|
||||
return evaluate_flags_writeback(env, flags, ccs); |
|
||||
} |
|
||||
|
|
||||
uint32_t helper_evaluate_flags_mulu(CPUCRISState *env, |
|
||||
uint32_t ccs, uint32_t res, uint32_t mof) |
|
||||
{ |
|
||||
uint32_t flags = 0; |
|
||||
uint64_t tmp; |
|
||||
|
|
||||
tmp = mof; |
|
||||
tmp <<= 32; |
|
||||
tmp |= res; |
|
||||
if (tmp == 0) { |
|
||||
flags |= Z_FLAG; |
|
||||
} else if (tmp >> 63) { |
|
||||
flags |= N_FLAG; |
|
||||
} |
|
||||
if (mof) { |
|
||||
flags |= V_FLAG; |
|
||||
} |
|
||||
|
|
||||
return evaluate_flags_writeback(env, flags, ccs); |
|
||||
} |
|
||||
|
|
||||
uint32_t helper_evaluate_flags_mcp(CPUCRISState *env, uint32_t ccs, |
|
||||
uint32_t src, uint32_t dst, uint32_t res) |
|
||||
{ |
|
||||
uint32_t flags = 0; |
|
||||
|
|
||||
src = src & 0x80000000; |
|
||||
dst = dst & 0x80000000; |
|
||||
|
|
||||
if ((res & 0x80000000L) != 0L) { |
|
||||
flags |= N_FLAG; |
|
||||
if (!src && !dst) { |
|
||||
flags |= V_FLAG; |
|
||||
} else if (src & dst) { |
|
||||
flags |= R_FLAG; |
|
||||
} |
|
||||
} else { |
|
||||
if (res == 0L) { |
|
||||
flags |= Z_FLAG; |
|
||||
} |
|
||||
if (src & dst) { |
|
||||
flags |= V_FLAG; |
|
||||
} |
|
||||
if (dst | src) { |
|
||||
flags |= R_FLAG; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return evaluate_flags_writeback(env, flags, ccs); |
|
||||
} |
|
||||
|
|
||||
uint32_t helper_evaluate_flags_alu_4(CPUCRISState *env, uint32_t ccs, |
|
||||
uint32_t src, uint32_t dst, uint32_t res) |
|
||||
{ |
|
||||
uint32_t flags = 0; |
|
||||
|
|
||||
src = src & 0x80000000; |
|
||||
dst = dst & 0x80000000; |
|
||||
|
|
||||
if ((res & 0x80000000L) != 0L) { |
|
||||
flags |= N_FLAG; |
|
||||
if (!src && !dst) { |
|
||||
flags |= V_FLAG; |
|
||||
} else if (src & dst) { |
|
||||
flags |= C_FLAG; |
|
||||
} |
|
||||
} else { |
|
||||
if (res == 0L) { |
|
||||
flags |= Z_FLAG; |
|
||||
} |
|
||||
if (src & dst) { |
|
||||
flags |= V_FLAG; |
|
||||
} |
|
||||
if (dst | src) { |
|
||||
flags |= C_FLAG; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return evaluate_flags_writeback(env, flags, ccs); |
|
||||
} |
|
||||
|
|
||||
uint32_t helper_evaluate_flags_sub_4(CPUCRISState *env, uint32_t ccs, |
|
||||
uint32_t src, uint32_t dst, uint32_t res) |
|
||||
{ |
|
||||
uint32_t flags = 0; |
|
||||
|
|
||||
src = (~src) & 0x80000000; |
|
||||
dst = dst & 0x80000000; |
|
||||
|
|
||||
if ((res & 0x80000000L) != 0L) { |
|
||||
flags |= N_FLAG; |
|
||||
if (!src && !dst) { |
|
||||
flags |= V_FLAG; |
|
||||
} else if (src & dst) { |
|
||||
flags |= C_FLAG; |
|
||||
} |
|
||||
} else { |
|
||||
if (res == 0L) { |
|
||||
flags |= Z_FLAG; |
|
||||
} |
|
||||
if (src & dst) { |
|
||||
flags |= V_FLAG; |
|
||||
} |
|
||||
if (dst | src) { |
|
||||
flags |= C_FLAG; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
flags ^= C_FLAG; |
|
||||
return evaluate_flags_writeback(env, flags, ccs); |
|
||||
} |
|
||||
|
|
||||
uint32_t helper_evaluate_flags_move_4(CPUCRISState *env, |
|
||||
uint32_t ccs, uint32_t res) |
|
||||
{ |
|
||||
uint32_t flags = 0; |
|
||||
|
|
||||
if ((int32_t)res < 0) { |
|
||||
flags |= N_FLAG; |
|
||||
} else if (res == 0L) { |
|
||||
flags |= Z_FLAG; |
|
||||
} |
|
||||
|
|
||||
return evaluate_flags_writeback(env, flags, ccs); |
|
||||
} |
|
||||
|
|
||||
uint32_t helper_evaluate_flags_move_2(CPUCRISState *env, |
|
||||
uint32_t ccs, uint32_t res) |
|
||||
{ |
|
||||
uint32_t flags = 0; |
|
||||
|
|
||||
if ((int16_t)res < 0L) { |
|
||||
flags |= N_FLAG; |
|
||||
} else if (res == 0) { |
|
||||
flags |= Z_FLAG; |
|
||||
} |
|
||||
|
|
||||
return evaluate_flags_writeback(env, flags, ccs); |
|
||||
} |
|
||||
|
|
||||
/*
|
|
||||
* TODO: This is expensive. We could split things up and only evaluate part of |
|
||||
* CCR on a need to know basis. For now, we simply re-evaluate everything. |
|
||||
*/ |
|
||||
void helper_evaluate_flags(CPUCRISState *env) |
|
||||
{ |
|
||||
uint32_t src, dst, res; |
|
||||
uint32_t flags = 0; |
|
||||
|
|
||||
src = env->cc_src; |
|
||||
dst = env->cc_dest; |
|
||||
res = env->cc_result; |
|
||||
|
|
||||
if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) { |
|
||||
src = ~src; |
|
||||
} |
|
||||
|
|
||||
/*
|
|
||||
* Now, evaluate the flags. This stuff is based on |
|
||||
* Per Zander's CRISv10 simulator. |
|
||||
*/ |
|
||||
switch (env->cc_size) { |
|
||||
case 1: |
|
||||
if ((res & 0x80L) != 0L) { |
|
||||
flags |= N_FLAG; |
|
||||
if (((src & 0x80L) == 0L) && ((dst & 0x80L) == 0L)) { |
|
||||
flags |= V_FLAG; |
|
||||
} else if (((src & 0x80L) != 0L) && ((dst & 0x80L) != 0L)) { |
|
||||
flags |= C_FLAG; |
|
||||
} |
|
||||
} else { |
|
||||
if ((res & 0xFFL) == 0L) { |
|
||||
flags |= Z_FLAG; |
|
||||
} |
|
||||
if (((src & 0x80L) != 0L) && ((dst & 0x80L) != 0L)) { |
|
||||
flags |= V_FLAG; |
|
||||
} |
|
||||
if ((dst & 0x80L) != 0L || (src & 0x80L) != 0L) { |
|
||||
flags |= C_FLAG; |
|
||||
} |
|
||||
} |
|
||||
break; |
|
||||
case 2: |
|
||||
if ((res & 0x8000L) != 0L) { |
|
||||
flags |= N_FLAG; |
|
||||
if (((src & 0x8000L) == 0L) && ((dst & 0x8000L) == 0L)) { |
|
||||
flags |= V_FLAG; |
|
||||
} else if (((src & 0x8000L) != 0L) && ((dst & 0x8000L) != 0L)) { |
|
||||
flags |= C_FLAG; |
|
||||
} |
|
||||
} else { |
|
||||
if ((res & 0xFFFFL) == 0L) { |
|
||||
flags |= Z_FLAG; |
|
||||
} |
|
||||
if (((src & 0x8000L) != 0L) && ((dst & 0x8000L) != 0L)) { |
|
||||
flags |= V_FLAG; |
|
||||
} |
|
||||
if ((dst & 0x8000L) != 0L || (src & 0x8000L) != 0L) { |
|
||||
flags |= C_FLAG; |
|
||||
} |
|
||||
} |
|
||||
break; |
|
||||
case 4: |
|
||||
if ((res & 0x80000000L) != 0L) { |
|
||||
flags |= N_FLAG; |
|
||||
if (((src & 0x80000000L) == 0L) && ((dst & 0x80000000L) == 0L)) { |
|
||||
flags |= V_FLAG; |
|
||||
} else if (((src & 0x80000000L) != 0L) && |
|
||||
((dst & 0x80000000L) != 0L)) { |
|
||||
flags |= C_FLAG; |
|
||||
} |
|
||||
} else { |
|
||||
if (res == 0L) { |
|
||||
flags |= Z_FLAG; |
|
||||
} |
|
||||
if (((src & 0x80000000L) != 0L) && ((dst & 0x80000000L) != 0L)) { |
|
||||
flags |= V_FLAG; |
|
||||
} |
|
||||
if ((dst & 0x80000000L) != 0L || (src & 0x80000000L) != 0L) { |
|
||||
flags |= C_FLAG; |
|
||||
} |
|
||||
} |
|
||||
break; |
|
||||
default: |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) { |
|
||||
flags ^= C_FLAG; |
|
||||
} |
|
||||
|
|
||||
env->pregs[PR_CCS] = evaluate_flags_writeback(env, flags, |
|
||||
env->pregs[PR_CCS]); |
|
||||
} |
|
||||
|
|
||||
void helper_top_evaluate_flags(CPUCRISState *env) |
|
||||
{ |
|
||||
switch (env->cc_op) { |
|
||||
case CC_OP_MCP: |
|
||||
env->pregs[PR_CCS] |
|
||||
= helper_evaluate_flags_mcp(env, env->pregs[PR_CCS], |
|
||||
env->cc_src, env->cc_dest, |
|
||||
env->cc_result); |
|
||||
break; |
|
||||
case CC_OP_MULS: |
|
||||
env->pregs[PR_CCS] |
|
||||
= helper_evaluate_flags_muls(env, env->pregs[PR_CCS], |
|
||||
env->cc_result, env->pregs[PR_MOF]); |
|
||||
break; |
|
||||
case CC_OP_MULU: |
|
||||
env->pregs[PR_CCS] |
|
||||
= helper_evaluate_flags_mulu(env, env->pregs[PR_CCS], |
|
||||
env->cc_result, env->pregs[PR_MOF]); |
|
||||
break; |
|
||||
case CC_OP_MOVE: |
|
||||
case CC_OP_AND: |
|
||||
case CC_OP_OR: |
|
||||
case CC_OP_XOR: |
|
||||
case CC_OP_ASR: |
|
||||
case CC_OP_LSR: |
|
||||
case CC_OP_LSL: |
|
||||
switch (env->cc_size) { |
|
||||
case 4: |
|
||||
env->pregs[PR_CCS] = |
|
||||
helper_evaluate_flags_move_4(env, |
|
||||
env->pregs[PR_CCS], |
|
||||
env->cc_result); |
|
||||
break; |
|
||||
case 2: |
|
||||
env->pregs[PR_CCS] = |
|
||||
helper_evaluate_flags_move_2(env, |
|
||||
env->pregs[PR_CCS], |
|
||||
env->cc_result); |
|
||||
break; |
|
||||
default: |
|
||||
helper_evaluate_flags(env); |
|
||||
break; |
|
||||
} |
|
||||
break; |
|
||||
case CC_OP_FLAGS: |
|
||||
/* live. */ |
|
||||
break; |
|
||||
case CC_OP_SUB: |
|
||||
case CC_OP_CMP: |
|
||||
if (env->cc_size == 4) { |
|
||||
env->pregs[PR_CCS] = |
|
||||
helper_evaluate_flags_sub_4(env, |
|
||||
env->pregs[PR_CCS], |
|
||||
env->cc_src, env->cc_dest, |
|
||||
env->cc_result); |
|
||||
} else { |
|
||||
helper_evaluate_flags(env); |
|
||||
} |
|
||||
break; |
|
||||
default: |
|
||||
switch (env->cc_size) { |
|
||||
case 4: |
|
||||
env->pregs[PR_CCS] = |
|
||||
helper_evaluate_flags_alu_4(env, |
|
||||
env->pregs[PR_CCS], |
|
||||
env->cc_src, env->cc_dest, |
|
||||
env->cc_result); |
|
||||
break; |
|
||||
default: |
|
||||
helper_evaluate_flags(env); |
|
||||
break; |
|
||||
} |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
@ -1,355 +0,0 @@ |
|||||
/* cris.h -- Header file for CRIS opcode and register tables.
|
|
||||
Copyright (C) 2000, 2001, 2004 Free Software Foundation, Inc. |
|
||||
Contributed by Axis Communications AB, Lund, Sweden. |
|
||||
Originally written for GAS 1.38.1 by Mikael Asker. |
|
||||
Updated, BFDized and GNUified by Hans-Peter Nilsson. |
|
||||
|
|
||||
This file is part of GAS, GDB and the GNU binutils. |
|
||||
|
|
||||
GAS, GDB, and GNU binutils is free software; you can redistribute it |
|
||||
and/or modify it under the terms of the GNU General Public License as |
|
||||
published by the Free Software Foundation; either version 2, or (at your |
|
||||
option) any later version. |
|
||||
|
|
||||
GAS, GDB, and GNU binutils are distributed in the hope that they will be |
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
GNU General Public License for more details. |
|
||||
|
|
||||
You should have received a copy of the GNU General Public License |
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>. */
|
|
||||
|
|
||||
#ifndef TARGET_CRIS_OPCODE_CRIS_H |
|
||||
#define TARGET_CRIS_OPCODE_CRIS_H |
|
||||
|
|
||||
#if !defined(__STDC__) && !defined(const) |
|
||||
#define const |
|
||||
#endif |
|
||||
|
|
||||
|
|
||||
/* Registers. */ |
|
||||
#define MAX_REG (15) |
|
||||
#define CRIS_REG_SP (14) |
|
||||
#define CRIS_REG_PC (15) |
|
||||
|
|
||||
/* CPU version control of disassembly and assembly of instructions.
|
|
||||
May affect how the instruction is assembled, at least the size of |
|
||||
immediate operands. */ |
|
||||
enum cris_insn_version_usage |
|
||||
{ |
|
||||
/* Any version. */ |
|
||||
cris_ver_version_all=0, |
|
||||
|
|
||||
/* Indeterminate (intended for disassembly only, or obsolete). */ |
|
||||
cris_ver_warning, |
|
||||
|
|
||||
/* Only for v0..3 (Etrax 1..4). */ |
|
||||
cris_ver_v0_3, |
|
||||
|
|
||||
/* Only for v3 or higher (ETRAX 4 and beyond). */ |
|
||||
cris_ver_v3p, |
|
||||
|
|
||||
/* Only for v8 (Etrax 100). */ |
|
||||
cris_ver_v8, |
|
||||
|
|
||||
/* Only for v8 or higher (ETRAX 100, ETRAX 100 LX). */ |
|
||||
cris_ver_v8p, |
|
||||
|
|
||||
/* Only for v0..10. FIXME: Not sure what to do with this. */ |
|
||||
cris_ver_sim_v0_10, |
|
||||
|
|
||||
/* Only for v0..10. */ |
|
||||
cris_ver_v0_10, |
|
||||
|
|
||||
/* Only for v3..10. (ETRAX 4, ETRAX 100 and ETRAX 100 LX). */ |
|
||||
cris_ver_v3_10, |
|
||||
|
|
||||
/* Only for v8..10 (ETRAX 100 and ETRAX 100 LX). */ |
|
||||
cris_ver_v8_10, |
|
||||
|
|
||||
/* Only for v10 (ETRAX 100 LX) and same series. */ |
|
||||
cris_ver_v10, |
|
||||
|
|
||||
/* Only for v10 (ETRAX 100 LX) and same series. */ |
|
||||
cris_ver_v10p, |
|
||||
|
|
||||
/* Only for v32 or higher (codename GUINNESS).
|
|
||||
Of course some or all these of may change to cris_ver_v32p if/when |
|
||||
there's a new revision. */ |
|
||||
cris_ver_v32p |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
/* Special registers. */ |
|
||||
struct cris_spec_reg |
|
||||
{ |
|
||||
const char *const name; |
|
||||
unsigned int number; |
|
||||
|
|
||||
/* The size of the register. */ |
|
||||
unsigned int reg_size; |
|
||||
|
|
||||
/* What CPU version the special register of that name is implemented
|
|
||||
in. If cris_ver_warning, emit an unimplemented-warning. */ |
|
||||
enum cris_insn_version_usage applicable_version; |
|
||||
|
|
||||
/* There might be a specific warning for using a special register
|
|
||||
here. */ |
|
||||
const char *const warning; |
|
||||
}; |
|
||||
extern const struct cris_spec_reg cris_spec_regs[]; |
|
||||
|
|
||||
|
|
||||
/* Support registers (kind of special too, but not named as such). */ |
|
||||
struct cris_support_reg |
|
||||
{ |
|
||||
const char *const name; |
|
||||
unsigned int number; |
|
||||
}; |
|
||||
extern const struct cris_support_reg cris_support_regs[]; |
|
||||
|
|
||||
/* Opcode-dependent constants. */ |
|
||||
#define AUTOINCR_BIT (0x04) |
|
||||
|
|
||||
/* Prefixes. */ |
|
||||
#define BDAP_QUICK_OPCODE (0x0100) |
|
||||
#define BDAP_QUICK_Z_BITS (0x0e00) |
|
||||
|
|
||||
#define BIAP_OPCODE (0x0540) |
|
||||
#define BIAP_Z_BITS (0x0a80) |
|
||||
|
|
||||
#define DIP_OPCODE (0x0970) |
|
||||
#define DIP_Z_BITS (0xf280) |
|
||||
|
|
||||
#define BDAP_INDIR_LOW (0x40) |
|
||||
#define BDAP_INDIR_LOW_Z (0x80) |
|
||||
#define BDAP_INDIR_HIGH (0x09) |
|
||||
#define BDAP_INDIR_HIGH_Z (0x02) |
|
||||
|
|
||||
#define BDAP_INDIR_OPCODE (BDAP_INDIR_HIGH * 0x0100 + BDAP_INDIR_LOW) |
|
||||
#define BDAP_INDIR_Z_BITS (BDAP_INDIR_HIGH_Z * 0x100 + BDAP_INDIR_LOW_Z) |
|
||||
#define BDAP_PC_LOW (BDAP_INDIR_LOW + CRIS_REG_PC) |
|
||||
#define BDAP_INCR_HIGH (BDAP_INDIR_HIGH + AUTOINCR_BIT) |
|
||||
|
|
||||
/* No prefix must have this code for its "match" bits in the
|
|
||||
opcode-table. "BCC .+2" will do nicely. */ |
|
||||
#define NO_CRIS_PREFIX 0 |
|
||||
|
|
||||
/* Definitions for condition codes. */ |
|
||||
#define CC_CC 0x0 |
|
||||
#define CC_HS 0x0 |
|
||||
#define CC_CS 0x1 |
|
||||
#define CC_LO 0x1 |
|
||||
#define CC_NE 0x2 |
|
||||
#define CC_EQ 0x3 |
|
||||
#define CC_VC 0x4 |
|
||||
#define CC_VS 0x5 |
|
||||
#define CC_PL 0x6 |
|
||||
#define CC_MI 0x7 |
|
||||
#define CC_LS 0x8 |
|
||||
#define CC_HI 0x9 |
|
||||
#define CC_GE 0xA |
|
||||
#define CC_LT 0xB |
|
||||
#define CC_GT 0xC |
|
||||
#define CC_LE 0xD |
|
||||
#define CC_A 0xE |
|
||||
#define CC_EXT 0xF |
|
||||
|
|
||||
/* A table of strings "cc", "cs"... indexed with condition code
|
|
||||
values as above. */ |
|
||||
extern const char *const cris_cc_strings[]; |
|
||||
|
|
||||
/* Bcc quick. */ |
|
||||
#define BRANCH_QUICK_LOW (0) |
|
||||
#define BRANCH_QUICK_HIGH (0) |
|
||||
#define BRANCH_QUICK_OPCODE (BRANCH_QUICK_HIGH * 0x0100 + BRANCH_QUICK_LOW) |
|
||||
#define BRANCH_QUICK_Z_BITS (0x0F00) |
|
||||
|
|
||||
/* BA quick. */ |
|
||||
#define BA_QUICK_HIGH (BRANCH_QUICK_HIGH + CC_A * 0x10) |
|
||||
#define BA_QUICK_OPCODE (BA_QUICK_HIGH * 0x100 + BRANCH_QUICK_LOW) |
|
||||
|
|
||||
/* Bcc [PC+]. */ |
|
||||
#define BRANCH_PC_LOW (0xFF) |
|
||||
#define BRANCH_INCR_HIGH (0x0D) |
|
||||
#define BA_PC_INCR_OPCODE \ |
|
||||
((BRANCH_INCR_HIGH + CC_A * 0x10) * 0x0100 + BRANCH_PC_LOW) |
|
||||
|
|
||||
/* Jump. */ |
|
||||
/* Note that old versions generated special register 8 (in high bits)
|
|
||||
and not-that-old versions recognized it as a jump-instruction. |
|
||||
That opcode now belongs to JUMPU. */ |
|
||||
#define JUMP_INDIR_OPCODE (0x0930) |
|
||||
#define JUMP_INDIR_Z_BITS (0xf2c0) |
|
||||
#define JUMP_PC_INCR_OPCODE \ |
|
||||
(JUMP_INDIR_OPCODE + AUTOINCR_BIT * 0x0100 + CRIS_REG_PC) |
|
||||
|
|
||||
#define MOVE_M_TO_PREG_OPCODE 0x0a30 |
|
||||
#define MOVE_M_TO_PREG_ZBITS 0x01c0 |
|
||||
|
|
||||
/* BDAP.D N,PC. */ |
|
||||
#define MOVE_PC_INCR_OPCODE_PREFIX \ |
|
||||
(((BDAP_INCR_HIGH | (CRIS_REG_PC << 4)) << 8) | BDAP_PC_LOW | (2 << 4)) |
|
||||
#define MOVE_PC_INCR_OPCODE_SUFFIX \ |
|
||||
(MOVE_M_TO_PREG_OPCODE | CRIS_REG_PC | (AUTOINCR_BIT << 8)) |
|
||||
|
|
||||
#define JUMP_PC_INCR_OPCODE_V32 (0x0DBF) |
|
||||
|
|
||||
/* BA DWORD (V32). */ |
|
||||
#define BA_DWORD_OPCODE (0x0EBF) |
|
||||
|
|
||||
/* Nop. */ |
|
||||
#define NOP_OPCODE (0x050F) |
|
||||
#define NOP_Z_BITS (0xFFFF ^ NOP_OPCODE) |
|
||||
|
|
||||
#define NOP_OPCODE_V32 (0x05B0) |
|
||||
#define NOP_Z_BITS_V32 (0xFFFF ^ NOP_OPCODE_V32) |
|
||||
|
|
||||
/* For the compatibility mode, let's use "MOVE R0,P0". Doesn't affect
|
|
||||
registers or flags. Unfortunately shuts off interrupts for one cycle |
|
||||
for < v32, but there doesn't seem to be any alternative without that |
|
||||
effect. */ |
|
||||
#define NOP_OPCODE_COMMON (0x630) |
|
||||
#define NOP_OPCODE_ZBITS_COMMON (0xffff & ~NOP_OPCODE_COMMON) |
|
||||
|
|
||||
/* LAPC.D */ |
|
||||
#define LAPC_DWORD_OPCODE (0x0D7F) |
|
||||
#define LAPC_DWORD_Z_BITS (0x0fff & ~LAPC_DWORD_OPCODE) |
|
||||
|
|
||||
/* Structure of an opcode table entry. */ |
|
||||
enum cris_imm_oprnd_size_type |
|
||||
{ |
|
||||
/* No size is applicable. */ |
|
||||
SIZE_NONE, |
|
||||
|
|
||||
/* Always 32 bits. */ |
|
||||
SIZE_FIX_32, |
|
||||
|
|
||||
/* Indicated by size of special register. */ |
|
||||
SIZE_SPEC_REG, |
|
||||
|
|
||||
/* Indicated by size field, signed. */ |
|
||||
SIZE_FIELD_SIGNED, |
|
||||
|
|
||||
/* Indicated by size field, unsigned. */ |
|
||||
SIZE_FIELD_UNSIGNED, |
|
||||
|
|
||||
/* Indicated by size field, no sign implied. */ |
|
||||
SIZE_FIELD |
|
||||
}; |
|
||||
|
|
||||
/* For GDB. FIXME: Is this the best way to handle opcode
|
|
||||
interpretation? */ |
|
||||
enum cris_op_type |
|
||||
{ |
|
||||
cris_not_implemented_op = 0, |
|
||||
cris_abs_op, |
|
||||
cris_addi_op, |
|
||||
cris_asr_op, |
|
||||
cris_asrq_op, |
|
||||
cris_ax_ei_setf_op, |
|
||||
cris_bdap_prefix, |
|
||||
cris_biap_prefix, |
|
||||
cris_break_op, |
|
||||
cris_btst_nop_op, |
|
||||
cris_clearf_di_op, |
|
||||
cris_dip_prefix, |
|
||||
cris_dstep_logshift_mstep_neg_not_op, |
|
||||
cris_eight_bit_offset_branch_op, |
|
||||
cris_move_mem_to_reg_movem_op, |
|
||||
cris_move_reg_to_mem_movem_op, |
|
||||
cris_move_to_preg_op, |
|
||||
cris_muls_op, |
|
||||
cris_mulu_op, |
|
||||
cris_none_reg_mode_add_sub_cmp_and_or_move_op, |
|
||||
cris_none_reg_mode_clear_test_op, |
|
||||
cris_none_reg_mode_jump_op, |
|
||||
cris_none_reg_mode_move_from_preg_op, |
|
||||
cris_quick_mode_add_sub_op, |
|
||||
cris_quick_mode_and_cmp_move_or_op, |
|
||||
cris_quick_mode_bdap_prefix, |
|
||||
cris_reg_mode_add_sub_cmp_and_or_move_op, |
|
||||
cris_reg_mode_clear_op, |
|
||||
cris_reg_mode_jump_op, |
|
||||
cris_reg_mode_move_from_preg_op, |
|
||||
cris_reg_mode_test_op, |
|
||||
cris_scc_op, |
|
||||
cris_sixteen_bit_offset_branch_op, |
|
||||
cris_three_operand_add_sub_cmp_and_or_op, |
|
||||
cris_three_operand_bound_op, |
|
||||
cris_two_operand_bound_op, |
|
||||
cris_xor_op |
|
||||
}; |
|
||||
|
|
||||
struct cris_opcode |
|
||||
{ |
|
||||
/* The name of the insn. */ |
|
||||
const char *name; |
|
||||
|
|
||||
/* Bits that must be 1 for a match. */ |
|
||||
unsigned int match; |
|
||||
|
|
||||
/* Bits that must be 0 for a match. */ |
|
||||
unsigned int lose; |
|
||||
|
|
||||
/* See the table in "opcodes/cris-opc.c". */ |
|
||||
const char *args; |
|
||||
|
|
||||
/* Nonzero if this is a delayed branch instruction. */ |
|
||||
char delayed; |
|
||||
|
|
||||
/* Size of immediate operands. */ |
|
||||
enum cris_imm_oprnd_size_type imm_oprnd_size; |
|
||||
|
|
||||
/* Indicates which version this insn was first implemented in. */ |
|
||||
enum cris_insn_version_usage applicable_version; |
|
||||
|
|
||||
/* What kind of operation this is. */ |
|
||||
enum cris_op_type op; |
|
||||
}; |
|
||||
extern const struct cris_opcode cris_opcodes[]; |
|
||||
|
|
||||
|
|
||||
/* These macros are for the target-specific flags in disassemble_info
|
|
||||
used at disassembly. */ |
|
||||
|
|
||||
/* This insn accesses memory. This flag is more trustworthy than
|
|
||||
checking insn_type for "dis_dref" which does not work for |
|
||||
e.g. "JSR [foo]". */ |
|
||||
#define CRIS_DIS_FLAG_MEMREF (1 << 0) |
|
||||
|
|
||||
/* The "target" field holds a register number. */ |
|
||||
#define CRIS_DIS_FLAG_MEM_TARGET_IS_REG (1 << 1) |
|
||||
|
|
||||
/* The "target2" field holds a register number; add it to "target". */ |
|
||||
#define CRIS_DIS_FLAG_MEM_TARGET2_IS_REG (1 << 2) |
|
||||
|
|
||||
/* Yet another add-on: the register in "target2" must be multiplied
|
|
||||
by 2 before adding to "target". */ |
|
||||
#define CRIS_DIS_FLAG_MEM_TARGET2_MULT2 (1 << 3) |
|
||||
|
|
||||
/* Yet another add-on: the register in "target2" must be multiplied
|
|
||||
by 4 (mutually exclusive with .._MULT2). */ |
|
||||
#define CRIS_DIS_FLAG_MEM_TARGET2_MULT4 (1 << 4) |
|
||||
|
|
||||
/* The register in "target2" is an indirect memory reference (of the
|
|
||||
register there), add to "target". Assumed size is dword (mutually |
|
||||
exclusive with .._MULT[24]). */ |
|
||||
#define CRIS_DIS_FLAG_MEM_TARGET2_MEM (1 << 5) |
|
||||
|
|
||||
/* Add-on to CRIS_DIS_FLAG_MEM_TARGET2_MEM; the memory access is "byte";
|
|
||||
sign-extended before adding to "target". */ |
|
||||
#define CRIS_DIS_FLAG_MEM_TARGET2_MEM_BYTE (1 << 6) |
|
||||
|
|
||||
/* Add-on to CRIS_DIS_FLAG_MEM_TARGET2_MEM; the memory access is "word";
|
|
||||
sign-extended before adding to "target". */ |
|
||||
#define CRIS_DIS_FLAG_MEM_TARGET2_MEM_WORD (1 << 7) |
|
||||
|
|
||||
#endif /* TARGET_CRIS_OPCODE_CRIS_H */ |
|
||||
|
|
||||
/*
|
|
||||
* Local variables: |
|
||||
* eval: (c-set-style "gnu") |
|
||||
* indent-tabs-mode: t |
|
||||
* End: |
|
||||
*/ |
|
||||
File diff suppressed because it is too large
File diff suppressed because it is too large
Loading…
Reference in new issue