aboutsummaryrefslogtreecommitdiff
path: root/target/riscv/tcg/tcg-cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/riscv/tcg/tcg-cpu.c')
-rw-r--r--target/riscv/tcg/tcg-cpu.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index c92dfc20cb..30740ba030 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -24,6 +24,7 @@
#include "pmu.h"
#include "time_helper.h"
#include "qapi/error.h"
+#include "qapi/visitor.h"
#include "qemu/accel.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
@@ -31,6 +32,15 @@
#include "hw/core/tcg-cpu-ops.h"
#include "tcg/tcg.h"
+/* Hash that stores user set extensions */
+static GHashTable *multi_ext_user_opts;
+
+static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset)
+{
+ return g_hash_table_contains(multi_ext_user_opts,
+ GUINT_TO_POINTER(ext_offset));
+}
+
static void riscv_cpu_synchronize_from_tb(CPUState *cs,
const TranslationBlock *tb)
{
@@ -570,6 +580,144 @@ static bool tcg_cpu_realize(CPUState *cs, Error **errp)
return true;
}
+static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ const RISCVCPUMultiExtConfig *multi_ext_cfg = opaque;
+ bool value;
+
+ if (!visit_type_bool(v, name, &value, errp)) {
+ return;
+ }
+
+ isa_ext_update_enabled(RISCV_CPU(obj), multi_ext_cfg->offset, value);
+
+ g_hash_table_insert(multi_ext_user_opts,
+ GUINT_TO_POINTER(multi_ext_cfg->offset),
+ (gpointer)value);
+}
+
+static void cpu_get_multi_ext_cfg(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ const RISCVCPUMultiExtConfig *multi_ext_cfg = opaque;
+ bool value = isa_ext_is_enabled(RISCV_CPU(obj), multi_ext_cfg->offset);
+
+ visit_type_bool(v, name, &value, errp);
+}
+
+static void cpu_add_multi_ext_prop(Object *cpu_obj,
+ const RISCVCPUMultiExtConfig *multi_cfg)
+{
+ object_property_add(cpu_obj, multi_cfg->name, "bool",
+ cpu_get_multi_ext_cfg,
+ cpu_set_multi_ext_cfg,
+ NULL, (void *)multi_cfg);
+
+ /*
+ * Set def val directly instead of using
+ * object_property_set_bool() to save the set()
+ * callback hash for user inputs.
+ */
+ isa_ext_update_enabled(RISCV_CPU(cpu_obj), multi_cfg->offset,
+ multi_cfg->enabled);
+}
+
+static void riscv_cpu_add_multiext_prop_array(Object *obj,
+ const RISCVCPUMultiExtConfig *array)
+{
+ const RISCVCPUMultiExtConfig *prop;
+
+ g_assert(array);
+
+ for (prop = array; prop && prop->name; prop++) {
+ cpu_add_multi_ext_prop(obj, prop);
+ }
+}
+
+/*
+ * Add CPU properties with user-facing flags.
+ *
+ * This will overwrite existing env->misa_ext values with the
+ * defaults set via riscv_cpu_add_misa_properties().
+ */
+static void riscv_cpu_add_user_properties(Object *obj)
+{
+#ifndef CONFIG_USER_ONLY
+ riscv_add_satp_mode_properties(obj);
+#endif
+
+ riscv_cpu_add_misa_properties(obj);
+
+ riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_extensions);
+ riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_vendor_exts);
+ riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_experimental_exts);
+
+ for (Property *prop = riscv_cpu_options; prop && prop->name; prop++) {
+ qdev_property_add_static(DEVICE(obj), prop);
+ }
+}
+
+/*
+ * The 'max' type CPU will have all possible ratified
+ * non-vendor extensions enabled.
+ */
+static void riscv_init_max_cpu_extensions(Object *obj)
+{
+ RISCVCPU *cpu = RISCV_CPU(obj);
+ CPURISCVState *env = &cpu->env;
+ const RISCVCPUMultiExtConfig *prop;
+
+ /* Enable RVG, RVJ and RVV that are disabled by default */
+ riscv_cpu_set_misa(env, env->misa_mxl, env->misa_ext | RVG | RVJ | RVV);
+
+ for (prop = riscv_cpu_extensions; prop && prop->name; prop++) {
+ isa_ext_update_enabled(cpu, prop->offset, true);
+ }
+
+ /* set vector version */
+ env->vext_ver = VEXT_VERSION_1_00_0;
+
+ /* Zfinx is not compatible with F. Disable it */
+ isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zfinx), false);
+ isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zdinx), false);
+ isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zhinx), false);
+ isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zhinxmin), false);
+
+ isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zce), false);
+ isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcmp), false);
+ isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcmt), false);
+
+ if (env->misa_mxl != MXL_RV32) {
+ isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcf), false);
+ }
+}
+
+static bool riscv_cpu_has_max_extensions(Object *cpu_obj)
+{
+ return object_dynamic_cast(cpu_obj, TYPE_RISCV_CPU_MAX) != NULL;
+}
+
+static bool riscv_cpu_has_user_properties(Object *cpu_obj)
+{
+ return object_dynamic_cast(cpu_obj, TYPE_RISCV_DYNAMIC_CPU) != NULL;
+}
+
+static void tcg_cpu_instance_init(CPUState *cs)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ Object *obj = OBJECT(cpu);
+
+ if (riscv_cpu_has_user_properties(obj)) {
+ multi_ext_user_opts = g_hash_table_new(NULL, g_direct_equal);
+ riscv_cpu_add_user_properties(obj);
+ }
+
+ if (riscv_cpu_has_max_extensions(obj)) {
+ riscv_init_max_cpu_extensions(obj);
+ }
+}
+
static void tcg_cpu_init_ops(AccelCPUClass *accel_cpu, CPUClass *cc)
{
/*
@@ -588,6 +736,7 @@ static void tcg_cpu_accel_class_init(ObjectClass *oc, void *data)
AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);
acc->cpu_class_init = tcg_cpu_class_init;
+ acc->cpu_instance_init = tcg_cpu_instance_init;
acc->cpu_target_realize = tcg_cpu_realize;
}