#include "qemu/ctype.h"
#include "qemu/log.h"
#include "cpu.h"
+#include "pmu.h"
#include "internals.h"
+#include "time_helper.h"
#include "exec/exec-all.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
/* RISC-V CPU definitions */
-static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG";
+#define RISCV_CPU_MARCHID ((QEMU_VERSION_MAJOR << 16) | \
+ (QEMU_VERSION_MINOR << 8) | \
+ (QEMU_VERSION_MICRO))
+#define RISCV_CPU_MIMPID RISCV_CPU_MARCHID
+
+static const char riscv_single_letter_exts[] = "IEMAFDQCPVH";
+
+struct isa_ext_data {
+ const char *name;
+ bool multi_letter;
+ int min_version;
+ int ext_enable_offset;
+};
+
+#define ISA_EXT_DATA_ENTRY(_name, _m_letter, _min_ver, _prop) \
+{#_name, _m_letter, _min_ver, offsetof(struct RISCVCPUConfig, _prop)}
+
+/**
+ * Here are the ordering rules of extension naming defined by RISC-V
+ * specification :
+ * 1. All extensions should be separated from other multi-letter extensions
+ * by an underscore.
+ * 2. The first letter following the 'Z' conventionally indicates the most
+ * closely related alphabetical extension category, IMAFDQLCBKJTPVH.
+ * If multiple 'Z' extensions are named, they should be ordered first
+ * by category, then alphabetically within a category.
+ * 3. Standard supervisor-level extensions (starts with 'S') should be
+ * listed after standard unprivileged extensions. If multiple
+ * supervisor-level extensions are listed, they should be ordered
+ * alphabetically.
+ * 4. Non-standard extensions (starts with 'X') must be listed after all
+ * standard extensions. They must be separated from other multi-letter
+ * extensions by an underscore.
+ */
+static const struct isa_ext_data isa_edata_arr[] = {
+ ISA_EXT_DATA_ENTRY(h, false, PRIV_VERSION_1_12_0, ext_h),
+ ISA_EXT_DATA_ENTRY(v, false, PRIV_VERSION_1_12_0, ext_v),
+ ISA_EXT_DATA_ENTRY(zicsr, true, PRIV_VERSION_1_10_0, ext_icsr),
+ ISA_EXT_DATA_ENTRY(zifencei, true, PRIV_VERSION_1_10_0, ext_ifencei),
+ ISA_EXT_DATA_ENTRY(zihintpause, true, PRIV_VERSION_1_10_0, ext_zihintpause),
+ ISA_EXT_DATA_ENTRY(zfh, true, PRIV_VERSION_1_12_0, ext_zfh),
+ ISA_EXT_DATA_ENTRY(zfhmin, true, PRIV_VERSION_1_12_0, ext_zfhmin),
+ ISA_EXT_DATA_ENTRY(zfinx, true, PRIV_VERSION_1_12_0, ext_zfinx),
+ ISA_EXT_DATA_ENTRY(zdinx, true, PRIV_VERSION_1_12_0, ext_zdinx),
+ ISA_EXT_DATA_ENTRY(zba, true, PRIV_VERSION_1_12_0, ext_zba),
+ ISA_EXT_DATA_ENTRY(zbb, true, PRIV_VERSION_1_12_0, ext_zbb),
+ ISA_EXT_DATA_ENTRY(zbc, true, PRIV_VERSION_1_12_0, ext_zbc),
+ ISA_EXT_DATA_ENTRY(zbkb, true, PRIV_VERSION_1_12_0, ext_zbkb),
+ ISA_EXT_DATA_ENTRY(zbkc, true, PRIV_VERSION_1_12_0, ext_zbkc),
+ ISA_EXT_DATA_ENTRY(zbkx, true, PRIV_VERSION_1_12_0, ext_zbkx),
+ ISA_EXT_DATA_ENTRY(zbs, true, PRIV_VERSION_1_12_0, ext_zbs),
+ ISA_EXT_DATA_ENTRY(zk, true, PRIV_VERSION_1_12_0, ext_zk),
+ ISA_EXT_DATA_ENTRY(zkn, true, PRIV_VERSION_1_12_0, ext_zkn),
+ ISA_EXT_DATA_ENTRY(zknd, true, PRIV_VERSION_1_12_0, ext_zknd),
+ ISA_EXT_DATA_ENTRY(zkne, true, PRIV_VERSION_1_12_0, ext_zkne),
+ ISA_EXT_DATA_ENTRY(zknh, true, PRIV_VERSION_1_12_0, ext_zknh),
+ ISA_EXT_DATA_ENTRY(zkr, true, PRIV_VERSION_1_12_0, ext_zkr),
+ ISA_EXT_DATA_ENTRY(zks, true, PRIV_VERSION_1_12_0, ext_zks),
+ ISA_EXT_DATA_ENTRY(zksed, true, PRIV_VERSION_1_12_0, ext_zksed),
+ ISA_EXT_DATA_ENTRY(zksh, true, PRIV_VERSION_1_12_0, ext_zksh),
+ ISA_EXT_DATA_ENTRY(zkt, true, PRIV_VERSION_1_12_0, ext_zkt),
+ ISA_EXT_DATA_ENTRY(zve32f, true, PRIV_VERSION_1_12_0, ext_zve32f),
+ ISA_EXT_DATA_ENTRY(zve64f, true, PRIV_VERSION_1_12_0, ext_zve64f),
+ ISA_EXT_DATA_ENTRY(zhinx, true, PRIV_VERSION_1_12_0, ext_zhinx),
+ ISA_EXT_DATA_ENTRY(zhinxmin, true, PRIV_VERSION_1_12_0, ext_zhinxmin),
+ ISA_EXT_DATA_ENTRY(smaia, true, PRIV_VERSION_1_12_0, ext_smaia),
+ ISA_EXT_DATA_ENTRY(ssaia, true, PRIV_VERSION_1_12_0, ext_ssaia),
+ ISA_EXT_DATA_ENTRY(sscofpmf, true, PRIV_VERSION_1_12_0, ext_sscofpmf),
+ ISA_EXT_DATA_ENTRY(sstc, true, PRIV_VERSION_1_12_0, ext_sstc),
+ ISA_EXT_DATA_ENTRY(svinval, true, PRIV_VERSION_1_12_0, ext_svinval),
+ ISA_EXT_DATA_ENTRY(svnapot, true, PRIV_VERSION_1_12_0, ext_svnapot),
+ ISA_EXT_DATA_ENTRY(svpbmt, true, PRIV_VERSION_1_12_0, ext_svpbmt),
+ ISA_EXT_DATA_ENTRY(xventanacondops, true, PRIV_VERSION_1_12_0, ext_XVentanaCondOps),
+};
+
+static bool isa_ext_is_enabled(RISCVCPU *cpu,
+ const struct isa_ext_data *edata)
+{
+ bool *ext_enabled = (void *)&cpu->cfg + edata->ext_enable_offset;
+
+ return *ext_enabled;
+}
+
+static void isa_ext_update_enabled(RISCVCPU *cpu,
+ const struct isa_ext_data *edata, bool en)
+{
+ bool *ext_enabled = (void *)&cpu->cfg + edata->ext_enable_offset;
+
+ *ext_enabled = en;
+}
const char * const riscv_int_regnames[] = {
"x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1",
"reserved"
};
+static void register_cpu_props(DeviceState *dev);
+
const char *riscv_cpu_get_trap_name(target_ulong cause, bool async)
{
if (async) {
env->vext_ver = vext_ver;
}
-static void set_resetvec(CPURISCVState *env, target_ulong resetvec)
-{
-#ifndef CONFIG_USER_ONLY
- env->resetvec = resetvec;
-#endif
-}
-
static void riscv_any_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
#elif defined(TARGET_RISCV64)
set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
#endif
- set_priv_version(env, PRIV_VERSION_1_11_0);
+ set_priv_version(env, PRIV_VERSION_1_12_0);
+ register_cpu_props(DEVICE(obj));
}
#if defined(TARGET_RISCV64)
CPURISCVState *env = &RISCV_CPU(obj)->env;
/* We set this in the realise function */
set_misa(env, MXL_RV64, 0);
+ register_cpu_props(DEVICE(obj));
+ /* Set latest version of privileged specification */
+ set_priv_version(env, PRIV_VERSION_1_12_0);
}
static void rv64_sifive_u_cpu_init(Object *obj)
static void rv64_sifive_e_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
+ RISCVCPU *cpu = RISCV_CPU(obj);
+
set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0);
- qdev_prop_set_bit(DEVICE(obj), "mmu", false);
+ cpu->cfg.mmu = false;
}
static void rv128_base_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env;
/* We set this in the realise function */
set_misa(env, MXL_RV128, 0);
+ register_cpu_props(DEVICE(obj));
+ /* Set latest version of privileged specification */
+ set_priv_version(env, PRIV_VERSION_1_12_0);
}
#else
static void rv32_base_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env;
/* We set this in the realise function */
set_misa(env, MXL_RV32, 0);
+ register_cpu_props(DEVICE(obj));
+ /* Set latest version of privileged specification */
+ set_priv_version(env, PRIV_VERSION_1_12_0);
}
static void rv32_sifive_u_cpu_init(Object *obj)
static void rv32_sifive_e_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
+ RISCVCPU *cpu = RISCV_CPU(obj);
+
set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0);
- qdev_prop_set_bit(DEVICE(obj), "mmu", false);
+ cpu->cfg.mmu = false;
}
static void rv32_ibex_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
+ RISCVCPU *cpu = RISCV_CPU(obj);
+
set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU);
- set_priv_version(env, PRIV_VERSION_1_10_0);
- qdev_prop_set_bit(DEVICE(obj), "mmu", false);
- qdev_prop_set_bit(DEVICE(obj), "x-epmp", true);
+ set_priv_version(env, PRIV_VERSION_1_11_0);
+ cpu->cfg.mmu = false;
+ cpu->cfg.epmp = true;
}
static void rv32_imafcu_nommu_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
+ RISCVCPU *cpu = RISCV_CPU(obj);
+
set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0);
- set_resetvec(env, DEFAULT_RSTVEC);
- qdev_prop_set_bit(DEVICE(obj), "mmu", false);
+ cpu->cfg.mmu = false;
}
#endif
#elif defined(TARGET_RISCV64)
set_misa(env, MXL_RV64, 0);
#endif
+ register_cpu_props(DEVICE(obj));
}
#endif
}
}
+static vaddr riscv_cpu_get_pc(CPUState *cs)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+
+ /* Match cpu_get_tb_cpu_state. */
+ if (env->xl == MXL_RV32) {
+ return env->pc & UINT32_MAX;
+ }
+ return env->pc;
+}
+
static void riscv_cpu_synchronize_from_tb(CPUState *cs,
const TranslationBlock *tb)
{
* Definition of the WFI instruction requires it to ignore the privilege
* mode and delegation registers, but respect individual enables
*/
- return (env->mip & env->mie) != 0;
+ return riscv_cpu_all_pending(env) != 0;
#else
return true;
#endif
} else {
env->pc = data[0];
}
+ env->bins = data[1];
}
static void riscv_cpu_reset(DeviceState *dev)
env->mcause = 0;
env->miclaim = MIP_SGEIP;
env->pc = env->resetvec;
+ env->bins = 0;
env->two_stage_lookup = false;
/* Initialized default priorities of local interrupts. */
set_default_nan_mode(1, &env->fp_status);
#ifndef CONFIG_USER_ONLY
+ if (riscv_feature(env, RISCV_FEATURE_DEBUG)) {
+ riscv_trigger_init(env);
+ }
+
if (kvm_enabled()) {
kvm_riscv_reset_vcpu(cpu);
}
CPURISCVState *env = &cpu->env;
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
CPUClass *cc = CPU_CLASS(mcc);
- int priv_version = 0;
+ int i, priv_version = -1;
Error *local_err = NULL;
cpu_exec_realizefn(cs, &local_err);
}
if (cpu->cfg.priv_spec) {
- if (!g_strcmp0(cpu->cfg.priv_spec, "v1.11.0")) {
+ if (!g_strcmp0(cpu->cfg.priv_spec, "v1.12.0")) {
+ priv_version = PRIV_VERSION_1_12_0;
+ } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.11.0")) {
priv_version = PRIV_VERSION_1_11_0;
} else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) {
priv_version = PRIV_VERSION_1_10_0;
}
}
- if (priv_version) {
+ if (priv_version >= PRIV_VERSION_1_10_0) {
set_priv_version(env, priv_version);
- } else if (!env->priv_ver) {
- set_priv_version(env, PRIV_VERSION_1_11_0);
+ }
+
+ /* Force disable extensions if priv spec version does not match */
+ for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) {
+ if (isa_ext_is_enabled(cpu, &isa_edata_arr[i]) &&
+ (env->priv_ver < isa_edata_arr[i].min_version)) {
+ isa_ext_update_enabled(cpu, &isa_edata_arr[i], false);
+#ifndef CONFIG_USER_ONLY
+ warn_report("disabling %s extension for hart 0x%lx because "
+ "privilege spec version does not match",
+ isa_edata_arr[i].name, (unsigned long)env->mhartid);
+#else
+ warn_report("disabling %s extension because "
+ "privilege spec version does not match",
+ isa_edata_arr[i].name);
+#endif
+ }
}
if (cpu->cfg.mmu) {
}
}
- if (cpu->cfg.aia) {
- riscv_set_feature(env, RISCV_FEATURE_AIA);
+ if (cpu->cfg.debug) {
+ riscv_set_feature(env, RISCV_FEATURE_DEBUG);
}
- set_resetvec(env, cpu->cfg.resetvec);
+
+#ifndef CONFIG_USER_ONLY
+ if (cpu->cfg.ext_sstc) {
+ riscv_timer_init(cpu);
+ }
+#endif /* CONFIG_USER_ONLY */
/* Validate that MISA_MXL is set properly. */
switch (env->misa_mxl_max) {
uint32_t ext = 0;
/* Do some ISA extension error checking */
+ if (cpu->cfg.ext_g && !(cpu->cfg.ext_i && cpu->cfg.ext_m &&
+ cpu->cfg.ext_a && cpu->cfg.ext_f &&
+ cpu->cfg.ext_d &&
+ cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) {
+ warn_report("Setting G will also set IMAFD_Zicsr_Zifencei");
+ cpu->cfg.ext_i = true;
+ cpu->cfg.ext_m = true;
+ cpu->cfg.ext_a = true;
+ cpu->cfg.ext_f = true;
+ cpu->cfg.ext_d = true;
+ cpu->cfg.ext_icsr = true;
+ cpu->cfg.ext_ifencei = true;
+ }
+
if (cpu->cfg.ext_i && cpu->cfg.ext_e) {
error_setg(errp,
"I and E extensions are incompatible");
- return;
- }
+ return;
+ }
if (!cpu->cfg.ext_i && !cpu->cfg.ext_e) {
error_setg(errp,
"Either I or E extension must be set");
- return;
- }
+ return;
+ }
- if (cpu->cfg.ext_g && !(cpu->cfg.ext_i & cpu->cfg.ext_m &
- cpu->cfg.ext_a & cpu->cfg.ext_f &
- cpu->cfg.ext_d)) {
- warn_report("Setting G will also set IMAFD");
- cpu->cfg.ext_i = true;
- cpu->cfg.ext_m = true;
- cpu->cfg.ext_a = true;
- cpu->cfg.ext_f = true;
- cpu->cfg.ext_d = true;
+ if (cpu->cfg.ext_s && !cpu->cfg.ext_u) {
+ error_setg(errp,
+ "Setting S extension without U extension is illegal");
+ return;
+ }
+
+ if (cpu->cfg.ext_h && !cpu->cfg.ext_i) {
+ error_setg(errp,
+ "H depends on an I base integer ISA with 32 x registers");
+ return;
+ }
+
+ if (cpu->cfg.ext_h && !cpu->cfg.ext_s) {
+ error_setg(errp, "H extension implicitly requires S-mode");
+ return;
+ }
+
+ if (cpu->cfg.ext_f && !cpu->cfg.ext_icsr) {
+ error_setg(errp, "F extension requires Zicsr");
+ return;
+ }
+
+ if ((cpu->cfg.ext_zfh || cpu->cfg.ext_zfhmin) && !cpu->cfg.ext_f) {
+ error_setg(errp, "Zfh/Zfhmin extensions require F extension");
+ return;
+ }
+
+ if (cpu->cfg.ext_d && !cpu->cfg.ext_f) {
+ error_setg(errp, "D extension requires F extension");
+ return;
+ }
+
+ if (cpu->cfg.ext_v && !cpu->cfg.ext_d) {
+ error_setg(errp, "V extension requires D extension");
+ return;
+ }
+
+ if ((cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) && !cpu->cfg.ext_f) {
+ error_setg(errp, "Zve32f/Zve64f extensions require F extension");
+ return;
}
/* Set the ISA extensions, checks should have happened above */
+ if (cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinx ||
+ cpu->cfg.ext_zhinxmin) {
+ cpu->cfg.ext_zfinx = true;
+ }
+
+ if (cpu->cfg.ext_zfinx) {
+ if (!cpu->cfg.ext_icsr) {
+ error_setg(errp, "Zfinx extension requires Zicsr");
+ return;
+ }
+ if (cpu->cfg.ext_f) {
+ error_setg(errp,
+ "Zfinx cannot be supported together with F extension");
+ return;
+ }
+ }
+
+ if (cpu->cfg.ext_zk) {
+ cpu->cfg.ext_zkn = true;
+ cpu->cfg.ext_zkr = true;
+ cpu->cfg.ext_zkt = true;
+ }
+
+ if (cpu->cfg.ext_zkn) {
+ cpu->cfg.ext_zbkb = true;
+ cpu->cfg.ext_zbkc = true;
+ cpu->cfg.ext_zbkx = true;
+ cpu->cfg.ext_zkne = true;
+ cpu->cfg.ext_zknd = true;
+ cpu->cfg.ext_zknh = true;
+ }
+
+ if (cpu->cfg.ext_zks) {
+ cpu->cfg.ext_zbkb = true;
+ cpu->cfg.ext_zbkc = true;
+ cpu->cfg.ext_zbkx = true;
+ cpu->cfg.ext_zksed = true;
+ cpu->cfg.ext_zksh = true;
+ }
+
if (cpu->cfg.ext_i) {
ext |= RVI;
}
}
set_vext_version(env, vext_version);
}
- if ((cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) && !cpu->cfg.ext_f) {
- error_setg(errp, "Zve32f/Zve64f extension depends upon RVF.");
- return;
- }
if (cpu->cfg.ext_j) {
ext |= RVJ;
}
set_misa(env, env->misa_mxl, ext);
}
+#ifndef CONFIG_USER_ONLY
+ if (cpu->cfg.pmu_num) {
+ if (!riscv_pmu_init(cpu, cpu->cfg.pmu_num) && cpu->cfg.ext_sscofpmf) {
+ cpu->pmu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ riscv_pmu_timer_cb, cpu);
+ }
+ }
+#endif
+
riscv_cpu_register_gdb_regs_for_features(cs);
qemu_init_vcpu(cs);
case IRQ_VS_TIMER:
case IRQ_M_TIMER:
case IRQ_U_EXT:
- case IRQ_S_EXT:
case IRQ_VS_EXT:
case IRQ_M_EXT:
- if (kvm_enabled()) {
+ if (kvm_enabled()) {
kvm_riscv_set_irq(cpu, irq, level);
- } else {
+ } else {
riscv_cpu_update_mip(cpu, 1 << irq, BOOL_TO_MASK(level));
- }
+ }
break;
+ case IRQ_S_EXT:
+ if (kvm_enabled()) {
+ kvm_riscv_set_irq(cpu, irq, level);
+ } else {
+ env->external_seip = level;
+ riscv_cpu_update_mip(cpu, 1 << irq,
+ BOOL_TO_MASK(level | env->software_seip));
+ }
+ break;
default:
g_assert_not_reached();
}
{
RISCVCPU *cpu = RISCV_CPU(obj);
+ cpu->cfg.ext_ifencei = true;
+ cpu->cfg.ext_icsr = true;
+ cpu->cfg.mmu = true;
+ cpu->cfg.pmp = true;
+
cpu_set_cpustate_pointers(cpu);
#ifndef CONFIG_USER_ONLY
#endif /* CONFIG_USER_ONLY */
}
-static Property riscv_cpu_properties[] = {
+static Property riscv_cpu_extensions[] = {
/* Defaults for standard extensions */
DEFINE_PROP_BOOL("i", RISCVCPU, cfg.ext_i, true),
DEFINE_PROP_BOOL("e", RISCVCPU, cfg.ext_e, false),
- DEFINE_PROP_BOOL("g", RISCVCPU, cfg.ext_g, true),
+ DEFINE_PROP_BOOL("g", RISCVCPU, cfg.ext_g, false),
DEFINE_PROP_BOOL("m", RISCVCPU, cfg.ext_m, true),
DEFINE_PROP_BOOL("a", RISCVCPU, cfg.ext_a, true),
DEFINE_PROP_BOOL("f", RISCVCPU, cfg.ext_f, true),
DEFINE_PROP_BOOL("u", RISCVCPU, cfg.ext_u, true),
DEFINE_PROP_BOOL("v", RISCVCPU, cfg.ext_v, false),
DEFINE_PROP_BOOL("h", RISCVCPU, cfg.ext_h, true),
- DEFINE_PROP_BOOL("Counters", RISCVCPU, cfg.ext_counters, true),
+ DEFINE_PROP_UINT8("pmu-num", RISCVCPU, cfg.pmu_num, 16),
+ DEFINE_PROP_BOOL("sscofpmf", RISCVCPU, cfg.ext_sscofpmf, false),
DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true),
DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true),
+ DEFINE_PROP_BOOL("Zihintpause", RISCVCPU, cfg.ext_zihintpause, true),
DEFINE_PROP_BOOL("Zfh", RISCVCPU, cfg.ext_zfh, false),
DEFINE_PROP_BOOL("Zfhmin", RISCVCPU, cfg.ext_zfhmin, false),
DEFINE_PROP_BOOL("Zve32f", RISCVCPU, cfg.ext_zve32f, false),
DEFINE_PROP_BOOL("Zve64f", RISCVCPU, cfg.ext_zve64f, false),
DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
+ DEFINE_PROP_BOOL("sstc", RISCVCPU, cfg.ext_sstc, true),
DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec),
DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec),
DEFINE_PROP_BOOL("svinval", RISCVCPU, cfg.ext_svinval, false),
DEFINE_PROP_BOOL("svnapot", RISCVCPU, cfg.ext_svnapot, false),
+ DEFINE_PROP_BOOL("svpbmt", RISCVCPU, cfg.ext_svpbmt, false),
DEFINE_PROP_BOOL("zba", RISCVCPU, cfg.ext_zba, true),
DEFINE_PROP_BOOL("zbb", RISCVCPU, cfg.ext_zbb, true),
DEFINE_PROP_BOOL("zbc", RISCVCPU, cfg.ext_zbc, true),
+ DEFINE_PROP_BOOL("zbkb", RISCVCPU, cfg.ext_zbkb, false),
+ DEFINE_PROP_BOOL("zbkc", RISCVCPU, cfg.ext_zbkc, false),
+ DEFINE_PROP_BOOL("zbkx", RISCVCPU, cfg.ext_zbkx, false),
DEFINE_PROP_BOOL("zbs", RISCVCPU, cfg.ext_zbs, true),
+ DEFINE_PROP_BOOL("zk", RISCVCPU, cfg.ext_zk, false),
+ DEFINE_PROP_BOOL("zkn", RISCVCPU, cfg.ext_zkn, false),
+ DEFINE_PROP_BOOL("zknd", RISCVCPU, cfg.ext_zknd, false),
+ DEFINE_PROP_BOOL("zkne", RISCVCPU, cfg.ext_zkne, false),
+ DEFINE_PROP_BOOL("zknh", RISCVCPU, cfg.ext_zknh, false),
+ DEFINE_PROP_BOOL("zkr", RISCVCPU, cfg.ext_zkr, false),
+ DEFINE_PROP_BOOL("zks", RISCVCPU, cfg.ext_zks, false),
+ DEFINE_PROP_BOOL("zksed", RISCVCPU, cfg.ext_zksed, false),
+ DEFINE_PROP_BOOL("zksh", RISCVCPU, cfg.ext_zksh, false),
+ DEFINE_PROP_BOOL("zkt", RISCVCPU, cfg.ext_zkt, false),
+
+ DEFINE_PROP_BOOL("zdinx", RISCVCPU, cfg.ext_zdinx, false),
+ DEFINE_PROP_BOOL("zfinx", RISCVCPU, cfg.ext_zfinx, false),
+ DEFINE_PROP_BOOL("zhinx", RISCVCPU, cfg.ext_zhinx, false),
+ DEFINE_PROP_BOOL("zhinxmin", RISCVCPU, cfg.ext_zhinxmin, false),
+
+ DEFINE_PROP_BOOL("zmmul", RISCVCPU, cfg.ext_zmmul, false),
/* Vendor-specific custom extensions */
DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false),
DEFINE_PROP_BOOL("x-j", RISCVCPU, cfg.ext_j, false),
/* ePMP 0.9.3 */
DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false),
- DEFINE_PROP_BOOL("x-aia", RISCVCPU, cfg.aia, false),
+ DEFINE_PROP_BOOL("x-smaia", RISCVCPU, cfg.ext_smaia, false),
+ DEFINE_PROP_BOOL("x-ssaia", RISCVCPU, cfg.ext_ssaia, false),
+
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void register_cpu_props(DeviceState *dev)
+{
+ Property *prop;
+
+ for (prop = riscv_cpu_extensions; prop && prop->name; prop++) {
+ qdev_property_add_static(dev, prop);
+ }
+}
+
+static Property riscv_cpu_properties[] = {
+ DEFINE_PROP_BOOL("debug", RISCVCPU, cfg.debug, true),
+
+ DEFINE_PROP_UINT32("mvendorid", RISCVCPU, cfg.mvendorid, 0),
+ DEFINE_PROP_UINT64("marchid", RISCVCPU, cfg.marchid, RISCV_CPU_MARCHID),
+ DEFINE_PROP_UINT64("mimpid", RISCVCPU, cfg.mimpid, RISCV_CPU_MIMPID),
+
+#ifndef CONFIG_USER_ONLY
+ DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC),
+#endif
+
+ DEFINE_PROP_BOOL("short-isa-string", RISCVCPU, cfg.short_isa_string, false),
- DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC),
+ DEFINE_PROP_BOOL("rvv_ta_all_1s", RISCVCPU, cfg.rvv_ta_all_1s, false),
+ DEFINE_PROP_BOOL("rvv_ma_all_1s", RISCVCPU, cfg.rvv_ma_all_1s, false),
DEFINE_PROP_END_OF_LIST(),
};
.do_interrupt = riscv_cpu_do_interrupt,
.do_transaction_failed = riscv_cpu_do_transaction_failed,
.do_unaligned_access = riscv_cpu_do_unaligned_access,
+ .debug_excp_handler = riscv_cpu_debug_excp_handler,
+ .debug_check_breakpoint = riscv_cpu_debug_check_breakpoint,
+ .debug_check_watchpoint = riscv_cpu_debug_check_watchpoint,
#endif /* !CONFIG_USER_ONLY */
};
cc->has_work = riscv_cpu_has_work;
cc->dump_state = riscv_cpu_dump_state;
cc->set_pc = riscv_cpu_set_pc;
+ cc->get_pc = riscv_cpu_get_pc;
cc->gdb_read_register = riscv_cpu_gdb_read_register;
cc->gdb_write_register = riscv_cpu_gdb_write_register;
cc->gdb_num_core_regs = 33;
device_class_set_props(dc, riscv_cpu_properties);
}
+static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, int max_str_len)
+{
+ char *old = *isa_str;
+ char *new = *isa_str;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) {
+ if (isa_edata_arr[i].multi_letter &&
+ isa_ext_is_enabled(cpu, &isa_edata_arr[i])) {
+ new = g_strconcat(old, "_", isa_edata_arr[i].name, NULL);
+ g_free(old);
+ old = new;
+ }
+ }
+
+ *isa_str = new;
+}
+
char *riscv_isa_string(RISCVCPU *cpu)
{
int i;
- const size_t maxlen = sizeof("rv128") + sizeof(riscv_exts) + 1;
+ const size_t maxlen = sizeof("rv128") + sizeof(riscv_single_letter_exts);
char *isa_str = g_new(char, maxlen);
char *p = isa_str + snprintf(isa_str, maxlen, "rv%d", TARGET_LONG_BITS);
- for (i = 0; i < sizeof(riscv_exts); i++) {
- if (cpu->env.misa_ext & RV(riscv_exts[i])) {
- *p++ = qemu_tolower(riscv_exts[i]);
+ for (i = 0; i < sizeof(riscv_single_letter_exts) - 1; i++) {
+ if (cpu->env.misa_ext & RV(riscv_single_letter_exts[i])) {
+ *p++ = qemu_tolower(riscv_single_letter_exts[i]);
}
}
*p = '\0';
+ if (!cpu->cfg.short_isa_string) {
+ riscv_isa_string_ext(cpu, &isa_str, maxlen);
+ }
return isa_str;
}