2019-03-08 18:06:28 +00:00
|
|
|
/*
|
|
|
|
* QEMU RISC-V CPU
|
|
|
|
*
|
|
|
|
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
|
|
|
|
* Copyright (c) 2017-2018 SiFive, Inc.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms and conditions of the GNU General Public License,
|
|
|
|
* version 2 or later, as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope 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 General Public License along with
|
|
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "qemu/osdep.h"
|
|
|
|
#include "qemu/log.h"
|
|
|
|
#include "cpu.h"
|
|
|
|
#include "exec/exec-all.h"
|
|
|
|
#include "qapi/error.h"
|
|
|
|
|
|
|
|
#include "uc_priv.h"
|
|
|
|
|
|
|
|
/* RISC-V CPU definitions */
|
|
|
|
|
|
|
|
const char * const riscv_int_regnames[] = {
|
2019-05-28 23:08:45 +00:00
|
|
|
"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
|
|
|
|
"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
|
|
|
|
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
|
|
|
|
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
|
2019-03-08 18:06:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const char * const riscv_fpr_regnames[] = {
|
2019-05-28 23:08:45 +00:00
|
|
|
"ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
|
|
|
|
"fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
|
|
|
|
"fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
|
|
|
|
"fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
|
2019-03-08 18:06:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const char * const riscv_excp_names[] = {
|
|
|
|
"misaligned_fetch",
|
|
|
|
"fault_fetch",
|
|
|
|
"illegal_instruction",
|
|
|
|
"breakpoint",
|
|
|
|
"misaligned_load",
|
|
|
|
"fault_load",
|
|
|
|
"misaligned_store",
|
|
|
|
"fault_store",
|
|
|
|
"user_ecall",
|
|
|
|
"supervisor_ecall",
|
|
|
|
"hypervisor_ecall",
|
|
|
|
"machine_ecall",
|
|
|
|
"exec_page_fault",
|
|
|
|
"load_page_fault",
|
|
|
|
"reserved",
|
|
|
|
"store_page_fault"
|
|
|
|
};
|
|
|
|
|
|
|
|
const char * const riscv_intr_names[] = {
|
|
|
|
"u_software",
|
|
|
|
"s_software",
|
|
|
|
"h_software",
|
|
|
|
"m_software",
|
|
|
|
"u_timer",
|
|
|
|
"s_timer",
|
|
|
|
"h_timer",
|
|
|
|
"m_timer",
|
|
|
|
"u_external",
|
|
|
|
"s_external",
|
|
|
|
"h_external",
|
|
|
|
"m_external",
|
|
|
|
"reserved",
|
|
|
|
"reserved",
|
|
|
|
"reserved",
|
|
|
|
"reserved"
|
|
|
|
};
|
|
|
|
|
|
|
|
static void set_misa(CPURISCVState *env, target_ulong misa)
|
|
|
|
{
|
|
|
|
env->misa_mask = env->misa = misa;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_versions(CPURISCVState *env, int user_ver, int priv_ver)
|
|
|
|
{
|
|
|
|
env->user_ver = user_ver;
|
|
|
|
env->priv_ver = priv_ver;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_feature(CPURISCVState *env, int feature)
|
|
|
|
{
|
|
|
|
env->features |= (1ULL << feature);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_resetvec(CPURISCVState *env, int resetvec)
|
|
|
|
{
|
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
env->resetvec = resetvec;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void riscv_any_cpu_init(struct uc_struct *uc, Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
CPURISCVState *env = &RISCV_CPU(uc, obj)->env;
|
|
|
|
set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVU);
|
2019-08-08 21:05:38 +00:00
|
|
|
set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_11_0);
|
2019-03-08 18:06:28 +00:00
|
|
|
set_resetvec(env, DEFAULT_RSTVEC);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(TARGET_RISCV32)
|
|
|
|
|
2019-05-28 23:11:04 +00:00
|
|
|
static void riscv_base32_cpu_init(struct uc_struct *uc, Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
CPURISCVState *env = &RISCV_CPU(uc, obj)->env;
|
|
|
|
set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
|
|
|
|
}
|
|
|
|
|
2019-03-08 18:06:28 +00:00
|
|
|
static void rv32gcsu_priv1_09_1_cpu_init(struct uc_struct *uc, Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
CPURISCVState *env = &RISCV_CPU(uc, obj)->env;
|
|
|
|
set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
|
|
|
|
set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1);
|
|
|
|
set_resetvec(env, DEFAULT_RSTVEC);
|
|
|
|
set_feature(env, RISCV_FEATURE_MMU);
|
|
|
|
set_feature(env, RISCV_FEATURE_PMP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rv32gcsu_priv1_10_0_cpu_init(struct uc_struct *uc, Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
CPURISCVState *env = &RISCV_CPU(uc, obj)->env;
|
|
|
|
set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
|
|
|
|
set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
|
|
|
|
set_resetvec(env, DEFAULT_RSTVEC);
|
|
|
|
set_feature(env, RISCV_FEATURE_MMU);
|
|
|
|
set_feature(env, RISCV_FEATURE_PMP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rv32imacu_nommu_cpu_init(struct uc_struct *uc, Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
CPURISCVState *env = &RISCV_CPU(uc, obj)->env;
|
|
|
|
set_misa(env, RV32 | RVI | RVM | RVA | RVC | RVU);
|
|
|
|
set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
|
|
|
|
set_resetvec(env, DEFAULT_RSTVEC);
|
|
|
|
set_feature(env, RISCV_FEATURE_PMP);
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(TARGET_RISCV64)
|
|
|
|
|
2019-05-28 23:11:04 +00:00
|
|
|
static void riscv_base64_cpu_init(struct uc_struct *uc, Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
CPURISCVState *env = &RISCV_CPU(uc, obj)->env;
|
|
|
|
set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
|
|
|
|
}
|
|
|
|
|
2019-03-08 18:06:28 +00:00
|
|
|
static void rv64gcsu_priv1_09_1_cpu_init(struct uc_struct *uc, Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
CPURISCVState *env = &RISCV_CPU(uc, obj)->env;
|
|
|
|
set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
|
|
|
|
set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1);
|
|
|
|
set_resetvec(env, DEFAULT_RSTVEC);
|
|
|
|
set_feature(env, RISCV_FEATURE_MMU);
|
|
|
|
set_feature(env, RISCV_FEATURE_PMP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rv64gcsu_priv1_10_0_cpu_init(struct uc_struct *uc, Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
CPURISCVState *env = &RISCV_CPU(uc, obj)->env;
|
|
|
|
set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
|
|
|
|
set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
|
|
|
|
set_resetvec(env, DEFAULT_RSTVEC);
|
|
|
|
set_feature(env, RISCV_FEATURE_MMU);
|
|
|
|
set_feature(env, RISCV_FEATURE_PMP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rv64imacu_nommu_cpu_init(struct uc_struct *uc, Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
CPURISCVState *env = &RISCV_CPU(uc, obj)->env;
|
|
|
|
set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU);
|
|
|
|
set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
|
|
|
|
set_resetvec(env, DEFAULT_RSTVEC);
|
|
|
|
set_feature(env, RISCV_FEATURE_PMP);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static ObjectClass *riscv_cpu_class_by_name(struct uc_struct *uc, const char *cpu_model)
|
|
|
|
{
|
|
|
|
ObjectClass *oc;
|
|
|
|
char *typename;
|
|
|
|
char **cpuname;
|
|
|
|
|
|
|
|
cpuname = g_strsplit(cpu_model, ",", 1);
|
|
|
|
typename = g_strdup_printf(RISCV_CPU_TYPE_NAME("%s"), cpuname[0]);
|
|
|
|
oc = object_class_by_name(uc, typename);
|
|
|
|
g_strfreev(cpuname);
|
|
|
|
g_free(typename);
|
|
|
|
if (!oc || !object_class_dynamic_cast(uc, oc, TYPE_RISCV_CPU) ||
|
|
|
|
object_class_is_abstract(oc)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return oc;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unicorn: if'd out
|
|
|
|
#if 0
|
|
|
|
static void riscv_cpu_dump_state(CPUState *cs, FILE *f,
|
|
|
|
fprintf_function cpu_fprintf, int flags)
|
|
|
|
{
|
|
|
|
RISCVCPU *cpu = RISCV_CPU(cs);
|
|
|
|
CPURISCVState *env = &cpu->env;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc ", env->pc);
|
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid);
|
|
|
|
cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus);
|
|
|
|
cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ",
|
|
|
|
(target_ulong)atomic_read(&env->mip));
|
|
|
|
cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie);
|
|
|
|
cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
|
|
|
|
cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
|
|
|
|
cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtvec ", env->mtvec);
|
|
|
|
cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mepc ", env->mepc);
|
|
|
|
cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mcause ", env->mcause);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
cpu_fprintf(f, " %s " TARGET_FMT_lx,
|
|
|
|
riscv_int_regnames[i], env->gpr[i]);
|
|
|
|
if ((i & 3) == 3) {
|
|
|
|
cpu_fprintf(f, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (flags & CPU_DUMP_FPU) {
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
cpu_fprintf(f, " %s %016" PRIx64,
|
|
|
|
riscv_fpr_regnames[i], env->fpr[i]);
|
|
|
|
if ((i & 3) == 3) {
|
|
|
|
cpu_fprintf(f, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void riscv_cpu_set_pc(CPUState *cs, vaddr value)
|
|
|
|
{
|
|
|
|
RISCVCPU *cpu = RISCV_CPU(cs->uc, cs);
|
|
|
|
CPURISCVState *env = &cpu->env;
|
|
|
|
env->pc = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void riscv_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
|
|
|
|
{
|
|
|
|
RISCVCPU *cpu = RISCV_CPU(cs->uc, cs);
|
|
|
|
CPURISCVState *env = &cpu->env;
|
|
|
|
env->pc = tb->pc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool riscv_cpu_has_work(CPUState *cs)
|
|
|
|
{
|
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
RISCVCPU *cpu = RISCV_CPU(cs->uc, cs);
|
|
|
|
CPURISCVState *env = &cpu->env;
|
|
|
|
/*
|
|
|
|
* Definition of the WFI instruction requires it to ignore the privilege
|
|
|
|
* mode and delegation registers, but respect individual enables
|
|
|
|
*/
|
|
|
|
return (atomic_read(&env->mip) & env->mie) != 0;
|
|
|
|
#else
|
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
|
|
|
|
target_ulong *data)
|
|
|
|
{
|
|
|
|
env->pc = data[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void riscv_cpu_reset(CPUState *cs)
|
|
|
|
{
|
|
|
|
RISCVCPU *cpu = RISCV_CPU(cs->uc, cs);
|
|
|
|
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cs->uc, cpu);
|
|
|
|
CPURISCVState *env = &cpu->env;
|
|
|
|
|
|
|
|
mcc->parent_reset(cs);
|
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
env->priv = PRV_M;
|
|
|
|
env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
|
|
|
|
env->mcause = 0;
|
|
|
|
env->pc = env->resetvec;
|
|
|
|
#endif
|
|
|
|
cs->exception_index = EXCP_NONE;
|
2019-08-08 21:12:21 +00:00
|
|
|
env->load_res = -1;
|
2019-03-08 18:06:28 +00:00
|
|
|
set_default_nan_mode(1, &env->fp_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unicorn: if'd out
|
|
|
|
#if 0
|
|
|
|
static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
|
|
|
|
{
|
|
|
|
#if defined(TARGET_RISCV32)
|
|
|
|
info->print_insn = print_insn_riscv32;
|
|
|
|
#elif defined(TARGET_RISCV64)
|
|
|
|
info->print_insn = print_insn_riscv64;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int riscv_cpu_realize(struct uc_struct *uc, DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(dev);
|
|
|
|
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(uc, dev);
|
|
|
|
|
|
|
|
cpu_reset(cs);
|
|
|
|
qemu_init_vcpu(cs);
|
|
|
|
|
|
|
|
mcc->parent_realize(uc, dev, errp);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void riscv_cpu_init(struct uc_struct *uc, Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(obj);
|
|
|
|
RISCVCPU *cpu = RISCV_CPU(uc, obj);
|
|
|
|
|
2019-06-12 16:27:11 +00:00
|
|
|
cpu_set_cpustate_pointers(cpu);
|
2019-03-08 18:06:28 +00:00
|
|
|
cpu_exec_init(cs, &error_abort, opaque);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void riscv_cpu_class_init(struct uc_struct *uc, ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
RISCVCPUClass *mcc = RISCV_CPU_CLASS(uc, oc);
|
|
|
|
CPUClass *cc = CPU_CLASS(uc, oc);
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(uc, oc);
|
|
|
|
|
|
|
|
mcc->parent_realize = dc->realize;
|
|
|
|
dc->realize = riscv_cpu_realize;
|
|
|
|
|
|
|
|
mcc->parent_reset = cc->reset;
|
|
|
|
cc->reset = riscv_cpu_reset;
|
|
|
|
|
|
|
|
cc->class_by_name = riscv_cpu_class_by_name;
|
|
|
|
cc->has_work = riscv_cpu_has_work;
|
|
|
|
cc->do_interrupt = riscv_cpu_do_interrupt;
|
|
|
|
cc->cpu_exec_interrupt = riscv_cpu_exec_interrupt;
|
|
|
|
//cc->dump_state = riscv_cpu_dump_state;
|
|
|
|
cc->set_pc = riscv_cpu_set_pc;
|
|
|
|
cc->synchronize_from_tb = riscv_cpu_synchronize_from_tb;
|
|
|
|
//cc->gdb_read_register = riscv_cpu_gdb_read_register;
|
|
|
|
//cc->gdb_write_register = riscv_cpu_gdb_write_register;
|
|
|
|
//cc->gdb_num_core_regs = 65;
|
|
|
|
//cc->gdb_stop_before_watchpoint = true;
|
|
|
|
//cc->disas_set_info = riscv_cpu_disas_set_info;
|
2019-05-16 21:23:42 +00:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
2019-08-08 20:45:11 +00:00
|
|
|
cc->do_unassigned_access = riscv_cpu_unassigned_access;
|
2019-03-08 18:06:28 +00:00
|
|
|
cc->do_unaligned_access = riscv_cpu_do_unaligned_access;
|
|
|
|
cc->get_phys_page_debug = riscv_cpu_get_phys_page_debug;
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_TCG
|
|
|
|
cc->tcg_initialize = riscv_translate_init;
|
2019-05-16 21:23:42 +00:00
|
|
|
cc->tlb_fill = riscv_cpu_tlb_fill;
|
2019-03-08 18:06:28 +00:00
|
|
|
#endif
|
|
|
|
/* For now, mark unmigratable: */
|
|
|
|
//cc->vmsd = &vmstate_riscv_cpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define DEFINE_CPU(type_name, initfn) \
|
|
|
|
{ \
|
|
|
|
.name = type_name, \
|
|
|
|
.parent = TYPE_RISCV_CPU, \
|
|
|
|
.instance_init = initfn \
|
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo riscv_cpu_type_infos[] = {
|
|
|
|
DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init),
|
|
|
|
#if defined(TARGET_RISCV32)
|
2019-05-28 23:11:04 +00:00
|
|
|
DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base32_cpu_init),
|
2019-08-08 20:59:58 +00:00
|
|
|
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init),
|
|
|
|
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init),
|
|
|
|
/* Deprecated */
|
2019-03-08 18:06:28 +00:00
|
|
|
DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_09_1, rv32gcsu_priv1_09_1_cpu_init),
|
|
|
|
DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_10_0, rv32gcsu_priv1_10_0_cpu_init),
|
|
|
|
DEFINE_CPU(TYPE_RISCV_CPU_RV32IMACU_NOMMU, rv32imacu_nommu_cpu_init),
|
|
|
|
#elif defined(TARGET_RISCV64)
|
2019-05-28 23:11:04 +00:00
|
|
|
DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base64_cpu_init),
|
2019-03-08 18:06:28 +00:00
|
|
|
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64imacu_nommu_cpu_init),
|
|
|
|
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64gcsu_priv1_10_0_cpu_init),
|
2019-08-08 20:59:58 +00:00
|
|
|
/* Deprecated */
|
|
|
|
DEFINE_CPU(TYPE_RISCV_CPU_RV64IMACU_NOMMU, rv64imacu_nommu_cpu_init),
|
|
|
|
DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_09_1, rv64gcsu_priv1_09_1_cpu_init),
|
|
|
|
DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_10_0, rv64gcsu_priv1_10_0_cpu_init),
|
2019-03-08 18:06:28 +00:00
|
|
|
#endif
|
|
|
|
{ .name = NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
void riscv_cpu_register_types(void *opaque) {
|
|
|
|
const TypeInfo* cpu_infos = riscv_cpu_type_infos;
|
|
|
|
|
|
|
|
TypeInfo parent_type_info = {
|
|
|
|
.name = TYPE_RISCV_CPU,
|
|
|
|
.parent = TYPE_CPU,
|
|
|
|
.instance_userdata = opaque,
|
|
|
|
.instance_size = sizeof(RISCVCPU),
|
|
|
|
.instance_init = riscv_cpu_init,
|
|
|
|
.abstract = true,
|
|
|
|
.class_size = sizeof(RISCVCPUClass),
|
|
|
|
.class_init = riscv_cpu_class_init,
|
|
|
|
};
|
|
|
|
type_register(opaque, &parent_type_info);
|
|
|
|
|
|
|
|
while (cpu_infos->name) {
|
|
|
|
type_register(opaque, cpu_infos);
|
|
|
|
++cpu_infos;
|
|
|
|
}
|
|
|
|
}
|