This function is the core of the RISC-V validations for TCG CPUs, and it
has a lot going on.
Functions in cpu.c were made public to allow them to be used by the KVM
accelerator class later on. 'cpu_cfg_ext_get_min_version()' is notably
hard to move it to another file due to its dependency with isa_edata_arr[]
array, thus make it public and use it as is for now.
riscv_cpu_validate_set_extensions() is kept public because it's used by
csr.c in write_misa().
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
---
target/riscv/cpu.c | 361 +------------------------------------
target/riscv/cpu.h | 8 +-
target/riscv/csr.c | 1 +
target/riscv/tcg/tcg-cpu.c | 356 ++++++++++++++++++++++++++++++++++++
target/riscv/tcg/tcg-cpu.h | 28 +++
5 files changed, 397 insertions(+), 357 deletions(-)
create mode 100644 target/riscv/tcg/tcg-cpu.h
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 59785f5d9a..e186c026c9 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -163,22 +163,21 @@ static const struct isa_ext_data isa_edata_arr[] = {
/* Hash that stores user set extensions */
static GHashTable *multi_ext_user_opts;
-static bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset)
+bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset)
{
bool *ext_enabled = (void *)&cpu->cfg + ext_offset;
return *ext_enabled;
}
-static void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset,
- bool en)
+void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en)
{
bool *ext_enabled = (void *)&cpu->cfg + ext_offset;
*ext_enabled = en;
}
-static int cpu_cfg_ext_get_min_version(uint32_t ext_offset)
+int cpu_cfg_ext_get_min_version(uint32_t ext_offset)
{
int i;
@@ -193,38 +192,12 @@ static int cpu_cfg_ext_get_min_version(uint32_t ext_offset)
g_assert_not_reached();
}
-static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset)
+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 cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset,
- bool value)
-{
- CPURISCVState *env = &cpu->env;
- bool prev_val = isa_ext_is_enabled(cpu, ext_offset);
- int min_version;
-
- if (prev_val == value) {
- return;
- }
-
- if (cpu_cfg_ext_is_user_set(ext_offset)) {
- return;
- }
-
- if (value && env->priv_ver != PRIV_VERSION_LATEST) {
- /* Do not enable it if priv_ver is older than min_version */
- min_version = cpu_cfg_ext_get_min_version(ext_offset);
- if (env->priv_ver < min_version) {
- return;
- }
- }
-
- isa_ext_update_enabled(cpu, ext_offset, value);
-}
-
const char * const riscv_int_regnames[] = {
"x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1",
"x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3",
@@ -1023,46 +996,7 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
}
}
-static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg,
- Error **errp)
-{
- if (!is_power_of_2(cfg->vlen)) {
- error_setg(errp, "Vector extension VLEN must be power of 2");
- return;
- }
- if (cfg->vlen > RV_VLEN_MAX || cfg->vlen < 128) {
- error_setg(errp,
- "Vector extension implementation only supports VLEN "
- "in the range [128, %d]", RV_VLEN_MAX);
- return;
- }
- if (!is_power_of_2(cfg->elen)) {
- error_setg(errp, "Vector extension ELEN must be power of 2");
- return;
- }
- if (cfg->elen > 64 || cfg->elen < 8) {
- error_setg(errp,
- "Vector extension implementation only supports ELEN "
- "in the range [8, 64]");
- return;
- }
- if (cfg->vext_spec) {
- if (!g_strcmp0(cfg->vext_spec, "v1.0")) {
- env->vext_ver = VEXT_VERSION_1_00_0;
- } else {
- error_setg(errp, "Unsupported vector spec version '%s'",
- cfg->vext_spec);
- return;
- }
- } else if (env->vext_ver == 0) {
- qemu_log("vector version is not specified, "
- "use the default value v1.0\n");
-
- env->vext_ver = VEXT_VERSION_1_00_0;
- }
-}
-
-static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu)
+void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu)
{
CPURISCVState *env = &cpu->env;
int i;
@@ -1086,291 +1020,6 @@ static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu)
}
}
-/*
- * Check consistency between chosen extensions while setting
- * cpu->cfg accordingly.
- */
-void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
-{
- CPURISCVState *env = &cpu->env;
- Error *local_err = NULL;
-
- /* Do some ISA extension error checking */
- if (riscv_has_ext(env, RVG) &&
- !(riscv_has_ext(env, RVI) && riscv_has_ext(env, RVM) &&
- riscv_has_ext(env, RVA) && riscv_has_ext(env, RVF) &&
- riscv_has_ext(env, RVD) &&
- cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) {
-
- if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_icsr)) &&
- !cpu->cfg.ext_icsr) {
- error_setg(errp, "RVG requires Zicsr but user set Zicsr to false");
- return;
- }
-
- if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_ifencei)) &&
- !cpu->cfg.ext_ifencei) {
- error_setg(errp, "RVG requires Zifencei but user set "
- "Zifencei to false");
- return;
- }
-
- warn_report("Setting G will also set IMAFD_Zicsr_Zifencei");
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_icsr), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_ifencei), true);
-
- env->misa_ext |= RVI | RVM | RVA | RVF | RVD;
- env->misa_ext_mask |= RVI | RVM | RVA | RVF | RVD;
- }
-
- if (riscv_has_ext(env, RVI) && riscv_has_ext(env, RVE)) {
- error_setg(errp,
- "I and E extensions are incompatible");
- return;
- }
-
- if (!riscv_has_ext(env, RVI) && !riscv_has_ext(env, RVE)) {
- error_setg(errp,
- "Either I or E extension must be set");
- return;
- }
-
- if (riscv_has_ext(env, RVS) && !riscv_has_ext(env, RVU)) {
- error_setg(errp,
- "Setting S extension without U extension is illegal");
- return;
- }
-
- if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVI)) {
- error_setg(errp,
- "H depends on an I base integer ISA with 32 x registers");
- return;
- }
-
- if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVS)) {
- error_setg(errp, "H extension implicitly requires S-mode");
- return;
- }
-
- if (riscv_has_ext(env, RVF) && !cpu->cfg.ext_icsr) {
- error_setg(errp, "F extension requires Zicsr");
- return;
- }
-
- if ((cpu->cfg.ext_zawrs) && !riscv_has_ext(env, RVA)) {
- error_setg(errp, "Zawrs extension requires A extension");
- return;
- }
-
- if (cpu->cfg.ext_zfa && !riscv_has_ext(env, RVF)) {
- error_setg(errp, "Zfa extension requires F extension");
- return;
- }
-
- if (cpu->cfg.ext_zfh) {
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zfhmin), true);
- }
-
- if (cpu->cfg.ext_zfhmin && !riscv_has_ext(env, RVF)) {
- error_setg(errp, "Zfh/Zfhmin extensions require F extension");
- return;
- }
-
- if (cpu->cfg.ext_zfbfmin && !riscv_has_ext(env, RVF)) {
- error_setg(errp, "Zfbfmin extension depends on F extension");
- return;
- }
-
- if (riscv_has_ext(env, RVD) && !riscv_has_ext(env, RVF)) {
- error_setg(errp, "D extension requires F extension");
- return;
- }
-
- if (riscv_has_ext(env, RVV)) {
- riscv_cpu_validate_v(env, &cpu->cfg, &local_err);
- if (local_err != NULL) {
- error_propagate(errp, local_err);
- return;
- }
-
- /* The V vector extension depends on the Zve64d extension */
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64d), true);
- }
-
- /* The Zve64d extension depends on the Zve64f extension */
- if (cpu->cfg.ext_zve64d) {
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64f), true);
- }
-
- /* The Zve64f extension depends on the Zve32f extension */
- if (cpu->cfg.ext_zve64f) {
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve32f), true);
- }
-
- if (cpu->cfg.ext_zve64d && !riscv_has_ext(env, RVD)) {
- error_setg(errp, "Zve64d/V extensions require D extension");
- return;
- }
-
- if (cpu->cfg.ext_zve32f && !riscv_has_ext(env, RVF)) {
- error_setg(errp, "Zve32f/Zve64f extensions require F extension");
- return;
- }
-
- if (cpu->cfg.ext_zvfh) {
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zvfhmin), true);
- }
-
- if (cpu->cfg.ext_zvfhmin && !cpu->cfg.ext_zve32f) {
- error_setg(errp, "Zvfh/Zvfhmin extensions require Zve32f extension");
- return;
- }
-
- if (cpu->cfg.ext_zvfh && !cpu->cfg.ext_zfhmin) {
- error_setg(errp, "Zvfh extensions requires Zfhmin extension");
- return;
- }
-
- if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zfbfmin) {
- error_setg(errp, "Zvfbfmin extension depends on Zfbfmin extension");
- return;
- }
-
- if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zve32f) {
- error_setg(errp, "Zvfbfmin extension depends on Zve32f extension");
- return;
- }
-
- if (cpu->cfg.ext_zvfbfwma && !cpu->cfg.ext_zvfbfmin) {
- error_setg(errp, "Zvfbfwma extension depends on Zvfbfmin extension");
- return;
- }
-
- /* Set the ISA extensions, checks should have happened above */
- if (cpu->cfg.ext_zhinx) {
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
- }
-
- if ((cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinxmin) && !cpu->cfg.ext_zfinx) {
- error_setg(errp, "Zdinx/Zhinx/Zhinxmin extensions require Zfinx");
- return;
- }
-
- if (cpu->cfg.ext_zfinx) {
- if (!cpu->cfg.ext_icsr) {
- error_setg(errp, "Zfinx extension requires Zicsr");
- return;
- }
- if (riscv_has_ext(env, RVF)) {
- error_setg(errp,
- "Zfinx cannot be supported together with F extension");
- return;
- }
- }
-
- if (cpu->cfg.ext_zce) {
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcb), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmp), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmt), true);
- if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) {
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true);
- }
- }
-
- /* zca, zcd and zcf has a PRIV 1.12.0 restriction */
- if (riscv_has_ext(env, RVC) && env->priv_ver >= PRIV_VERSION_1_12_0) {
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
- if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) {
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true);
- }
- if (riscv_has_ext(env, RVD)) {
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcd), true);
- }
- }
-
- if (env->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) {
- error_setg(errp, "Zcf extension is only relevant to RV32");
- return;
- }
-
- if (!riscv_has_ext(env, RVF) && cpu->cfg.ext_zcf) {
- error_setg(errp, "Zcf extension requires F extension");
- return;
- }
-
- if (!riscv_has_ext(env, RVD) && cpu->cfg.ext_zcd) {
- error_setg(errp, "Zcd extension requires D extension");
- return;
- }
-
- if ((cpu->cfg.ext_zcf || cpu->cfg.ext_zcd || cpu->cfg.ext_zcb ||
- cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt) && !cpu->cfg.ext_zca) {
- error_setg(errp, "Zcf/Zcd/Zcb/Zcmp/Zcmt extensions require Zca "
- "extension");
- return;
- }
-
- if (cpu->cfg.ext_zcd && (cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt)) {
- error_setg(errp, "Zcmp/Zcmt extensions are incompatible with "
- "Zcd extension");
- return;
- }
-
- if (cpu->cfg.ext_zcmt && !cpu->cfg.ext_icsr) {
- error_setg(errp, "Zcmt extension requires Zicsr extension");
- return;
- }
-
- /*
- * In principle Zve*x would also suffice here, were they supported
- * in qemu
- */
- if ((cpu->cfg.ext_zvbb || cpu->cfg.ext_zvkg || cpu->cfg.ext_zvkned ||
- cpu->cfg.ext_zvknha || cpu->cfg.ext_zvksed || cpu->cfg.ext_zvksh) &&
- !cpu->cfg.ext_zve32f) {
- error_setg(errp,
- "Vector crypto extensions require V or Zve* extensions");
- return;
- }
-
- if ((cpu->cfg.ext_zvbc || cpu->cfg.ext_zvknhb) && !cpu->cfg.ext_zve64f) {
- error_setg(
- errp,
- "Zvbc and Zvknhb extensions require V or Zve64{f,d} extensions");
- return;
- }
-
- if (cpu->cfg.ext_zk) {
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkn), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkr), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkt), true);
- }
-
- if (cpu->cfg.ext_zkn) {
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkne), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknd), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknh), true);
- }
-
- if (cpu->cfg.ext_zks) {
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksed), true);
- cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksh), true);
- }
-
- /*
- * Disable isa extensions based on priv spec after we
- * validated and set everything we need.
- */
- riscv_cpu_disable_priv_spec_isa_exts(cpu);
-}
-
#ifndef CONFIG_USER_ONLY
static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
{
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index b84b62f84e..721bd0b119 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -445,7 +445,6 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
bool probe, uintptr_t retaddr);
char *riscv_isa_string(RISCVCPU *cpu);
void riscv_cpu_list(void);
-void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp);
#define cpu_list riscv_cpu_list
#define cpu_mmu_index riscv_cpu_mmu_index
@@ -711,6 +710,13 @@ enum riscv_pmu_event_idx {
#include "hw/core/tcg-cpu-ops.h"
extern const struct TCGCPUOps riscv_tcg_ops;
+/* used by tcg/tcg-cpu.c*/
+void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en);
+bool cpu_cfg_ext_is_user_set(uint32_t ext_offset);
+bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset);
+int cpu_cfg_ext_get_min_version(uint32_t ext_offset);
+void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu);
+
/* CSR function table */
extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE];
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 6145039832..65473b257f 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -21,6 +21,7 @@
#include "qemu/log.h"
#include "qemu/timer.h"
#include "cpu.h"
+#include "tcg/tcg-cpu.h"
#include "pmu.h"
#include "time_helper.h"
#include "qemu/main-loop.h"
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 84ad6f1daf..da18851ed4 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -18,14 +18,42 @@
*/
#include "qemu/osdep.h"
+#include "tcg-cpu.h"
#include "cpu.h"
#include "pmu.h"
#include "time_helper.h"
#include "qapi/error.h"
#include "qemu/accel.h"
+#include "qemu/error-report.h"
#include "hw/core/accel-cpu.h"
+static void cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset,
+ bool value)
+{
+ CPURISCVState *env = &cpu->env;
+ bool prev_val = isa_ext_is_enabled(cpu, ext_offset);
+ int min_version;
+
+ if (prev_val == value) {
+ return;
+ }
+
+ if (cpu_cfg_ext_is_user_set(ext_offset)) {
+ return;
+ }
+
+ if (value && env->priv_ver != PRIV_VERSION_LATEST) {
+ /* Do not enable it if priv_ver is older than min_version */
+ min_version = cpu_cfg_ext_get_min_version(ext_offset);
+ if (env->priv_ver < min_version) {
+ return;
+ }
+ }
+
+ isa_ext_update_enabled(cpu, ext_offset, value);
+}
+
static void riscv_cpu_validate_misa_priv(CPURISCVState *env, Error **errp)
{
if (riscv_has_ext(env, RVH) && env->priv_ver < PRIV_VERSION_1_12_0) {
@@ -84,6 +112,334 @@ static void riscv_cpu_validate_priv_spec(RISCVCPU *cpu, Error **errp)
}
}
+static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg,
+ Error **errp)
+{
+ if (!is_power_of_2(cfg->vlen)) {
+ error_setg(errp, "Vector extension VLEN must be power of 2");
+ return;
+ }
+
+ if (cfg->vlen > RV_VLEN_MAX || cfg->vlen < 128) {
+ error_setg(errp,
+ "Vector extension implementation only supports VLEN "
+ "in the range [128, %d]", RV_VLEN_MAX);
+ return;
+ }
+
+ if (!is_power_of_2(cfg->elen)) {
+ error_setg(errp, "Vector extension ELEN must be power of 2");
+ return;
+ }
+
+ if (cfg->elen > 64 || cfg->elen < 8) {
+ error_setg(errp,
+ "Vector extension implementation only supports ELEN "
+ "in the range [8, 64]");
+ return;
+ }
+
+ if (cfg->vext_spec) {
+ if (!g_strcmp0(cfg->vext_spec, "v1.0")) {
+ env->vext_ver = VEXT_VERSION_1_00_0;
+ } else {
+ error_setg(errp, "Unsupported vector spec version '%s'",
+ cfg->vext_spec);
+ return;
+ }
+ } else if (env->vext_ver == 0) {
+ qemu_log("vector version is not specified, "
+ "use the default value v1.0\n");
+
+ env->vext_ver = VEXT_VERSION_1_00_0;
+ }
+}
+
+/*
+ * Check consistency between chosen extensions while setting
+ * cpu->cfg accordingly.
+ */
+void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
+{
+ CPURISCVState *env = &cpu->env;
+ Error *local_err = NULL;
+
+ /* Do some ISA extension error checking */
+ if (riscv_has_ext(env, RVG) &&
+ !(riscv_has_ext(env, RVI) && riscv_has_ext(env, RVM) &&
+ riscv_has_ext(env, RVA) && riscv_has_ext(env, RVF) &&
+ riscv_has_ext(env, RVD) &&
+ cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) {
+
+ if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_icsr)) &&
+ !cpu->cfg.ext_icsr) {
+ error_setg(errp, "RVG requires Zicsr but user set Zicsr to false");
+ return;
+ }
+
+ if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_ifencei)) &&
+ !cpu->cfg.ext_ifencei) {
+ error_setg(errp, "RVG requires Zifencei but user set "
+ "Zifencei to false");
+ return;
+ }
+
+ warn_report("Setting G will also set IMAFD_Zicsr_Zifencei");
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_icsr), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_ifencei), true);
+
+ env->misa_ext |= RVI | RVM | RVA | RVF | RVD;
+ env->misa_ext_mask |= RVI | RVM | RVA | RVF | RVD;
+ }
+
+ if (riscv_has_ext(env, RVI) && riscv_has_ext(env, RVE)) {
+ error_setg(errp,
+ "I and E extensions are incompatible");
+ return;
+ }
+
+ if (!riscv_has_ext(env, RVI) && !riscv_has_ext(env, RVE)) {
+ error_setg(errp,
+ "Either I or E extension must be set");
+ return;
+ }
+
+ if (riscv_has_ext(env, RVS) && !riscv_has_ext(env, RVU)) {
+ error_setg(errp,
+ "Setting S extension without U extension is illegal");
+ return;
+ }
+
+ if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVI)) {
+ error_setg(errp,
+ "H depends on an I base integer ISA with 32 x registers");
+ return;
+ }
+
+ if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVS)) {
+ error_setg(errp, "H extension implicitly requires S-mode");
+ return;
+ }
+
+ if (riscv_has_ext(env, RVF) && !cpu->cfg.ext_icsr) {
+ error_setg(errp, "F extension requires Zicsr");
+ return;
+ }
+
+ if ((cpu->cfg.ext_zawrs) && !riscv_has_ext(env, RVA)) {
+ error_setg(errp, "Zawrs extension requires A extension");
+ return;
+ }
+
+ if (cpu->cfg.ext_zfa && !riscv_has_ext(env, RVF)) {
+ error_setg(errp, "Zfa extension requires F extension");
+ return;
+ }
+
+ if (cpu->cfg.ext_zfh) {
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zfhmin), true);
+ }
+
+ if (cpu->cfg.ext_zfhmin && !riscv_has_ext(env, RVF)) {
+ error_setg(errp, "Zfh/Zfhmin extensions require F extension");
+ return;
+ }
+
+ if (cpu->cfg.ext_zfbfmin && !riscv_has_ext(env, RVF)) {
+ error_setg(errp, "Zfbfmin extension depends on F extension");
+ return;
+ }
+
+ if (riscv_has_ext(env, RVD) && !riscv_has_ext(env, RVF)) {
+ error_setg(errp, "D extension requires F extension");
+ return;
+ }
+
+ if (riscv_has_ext(env, RVV)) {
+ riscv_cpu_validate_v(env, &cpu->cfg, &local_err);
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* The V vector extension depends on the Zve64d extension */
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64d), true);
+ }
+
+ /* The Zve64d extension depends on the Zve64f extension */
+ if (cpu->cfg.ext_zve64d) {
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64f), true);
+ }
+
+ /* The Zve64f extension depends on the Zve32f extension */
+ if (cpu->cfg.ext_zve64f) {
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve32f), true);
+ }
+
+ if (cpu->cfg.ext_zve64d && !riscv_has_ext(env, RVD)) {
+ error_setg(errp, "Zve64d/V extensions require D extension");
+ return;
+ }
+
+ if (cpu->cfg.ext_zve32f && !riscv_has_ext(env, RVF)) {
+ error_setg(errp, "Zve32f/Zve64f extensions require F extension");
+ return;
+ }
+
+ if (cpu->cfg.ext_zvfh) {
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zvfhmin), true);
+ }
+
+ if (cpu->cfg.ext_zvfhmin && !cpu->cfg.ext_zve32f) {
+ error_setg(errp, "Zvfh/Zvfhmin extensions require Zve32f extension");
+ return;
+ }
+
+ if (cpu->cfg.ext_zvfh && !cpu->cfg.ext_zfhmin) {
+ error_setg(errp, "Zvfh extensions requires Zfhmin extension");
+ return;
+ }
+
+ if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zfbfmin) {
+ error_setg(errp, "Zvfbfmin extension depends on Zfbfmin extension");
+ return;
+ }
+
+ if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zve32f) {
+ error_setg(errp, "Zvfbfmin extension depends on Zve32f extension");
+ return;
+ }
+
+ if (cpu->cfg.ext_zvfbfwma && !cpu->cfg.ext_zvfbfmin) {
+ error_setg(errp, "Zvfbfwma extension depends on Zvfbfmin extension");
+ return;
+ }
+
+ /* Set the ISA extensions, checks should have happened above */
+ if (cpu->cfg.ext_zhinx) {
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
+ }
+
+ if ((cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinxmin) && !cpu->cfg.ext_zfinx) {
+ error_setg(errp, "Zdinx/Zhinx/Zhinxmin extensions require Zfinx");
+ return;
+ }
+
+ if (cpu->cfg.ext_zfinx) {
+ if (!cpu->cfg.ext_icsr) {
+ error_setg(errp, "Zfinx extension requires Zicsr");
+ return;
+ }
+ if (riscv_has_ext(env, RVF)) {
+ error_setg(errp,
+ "Zfinx cannot be supported together with F extension");
+ return;
+ }
+ }
+
+ if (cpu->cfg.ext_zce) {
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcb), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmp), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmt), true);
+ if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) {
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true);
+ }
+ }
+
+ /* zca, zcd and zcf has a PRIV 1.12.0 restriction */
+ if (riscv_has_ext(env, RVC) && env->priv_ver >= PRIV_VERSION_1_12_0) {
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
+ if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) {
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true);
+ }
+ if (riscv_has_ext(env, RVD)) {
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcd), true);
+ }
+ }
+
+ if (env->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) {
+ error_setg(errp, "Zcf extension is only relevant to RV32");
+ return;
+ }
+
+ if (!riscv_has_ext(env, RVF) && cpu->cfg.ext_zcf) {
+ error_setg(errp, "Zcf extension requires F extension");
+ return;
+ }
+
+ if (!riscv_has_ext(env, RVD) && cpu->cfg.ext_zcd) {
+ error_setg(errp, "Zcd extension requires D extension");
+ return;
+ }
+
+ if ((cpu->cfg.ext_zcf || cpu->cfg.ext_zcd || cpu->cfg.ext_zcb ||
+ cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt) && !cpu->cfg.ext_zca) {
+ error_setg(errp, "Zcf/Zcd/Zcb/Zcmp/Zcmt extensions require Zca "
+ "extension");
+ return;
+ }
+
+ if (cpu->cfg.ext_zcd && (cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt)) {
+ error_setg(errp, "Zcmp/Zcmt extensions are incompatible with "
+ "Zcd extension");
+ return;
+ }
+
+ if (cpu->cfg.ext_zcmt && !cpu->cfg.ext_icsr) {
+ error_setg(errp, "Zcmt extension requires Zicsr extension");
+ return;
+ }
+
+ /*
+ * In principle Zve*x would also suffice here, were they supported
+ * in qemu
+ */
+ if ((cpu->cfg.ext_zvbb || cpu->cfg.ext_zvkg || cpu->cfg.ext_zvkned ||
+ cpu->cfg.ext_zvknha || cpu->cfg.ext_zvksed || cpu->cfg.ext_zvksh) &&
+ !cpu->cfg.ext_zve32f) {
+ error_setg(errp,
+ "Vector crypto extensions require V or Zve* extensions");
+ return;
+ }
+
+ if ((cpu->cfg.ext_zvbc || cpu->cfg.ext_zvknhb) && !cpu->cfg.ext_zve64f) {
+ error_setg(
+ errp,
+ "Zvbc and Zvknhb extensions require V or Zve64{f,d} extensions");
+ return;
+ }
+
+ if (cpu->cfg.ext_zk) {
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkn), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkr), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkt), true);
+ }
+
+ if (cpu->cfg.ext_zkn) {
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkne), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknd), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknh), true);
+ }
+
+ if (cpu->cfg.ext_zks) {
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksed), true);
+ cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksh), true);
+ }
+
+ /*
+ * Disable isa extensions based on priv spec after we
+ * validated and set everything we need.
+ */
+ riscv_cpu_disable_priv_spec_isa_exts(cpu);
+}
+
/*
* We'll get here via the following path:
*
diff --git a/target/riscv/tcg/tcg-cpu.h b/target/riscv/tcg/tcg-cpu.h
new file mode 100644
index 0000000000..4cf35a8015
--- /dev/null
+++ b/target/riscv/tcg/tcg-cpu.h
@@ -0,0 +1,28 @@
+/*
+ * riscv TCG cpu class initialization
+ *
+ * Copyright (c) 2023 Ventana Micro Systems Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef RISCV_TCG_CPU_H
+#define RISCV_TCG_CPU_H
+
+#include "cpu.h"
+
+void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp);
+
+#endif
+
--
2.41.0
On 2023/9/6 17:16, Daniel Henrique Barboza wrote: > This function is the core of the RISC-V validations for TCG CPUs, and it > has a lot going on. > > Functions in cpu.c were made public to allow them to be used by the KVM > accelerator class later on. 'cpu_cfg_ext_get_min_version()' is notably > hard to move it to another file due to its dependency with isa_edata_arr[] > array, thus make it public and use it as is for now. > > riscv_cpu_validate_set_extensions() is kept public because it's used by > csr.c in write_misa(). > > Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> > Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> Zhiwei > --- > target/riscv/cpu.c | 361 +------------------------------------ > target/riscv/cpu.h | 8 +- > target/riscv/csr.c | 1 + > target/riscv/tcg/tcg-cpu.c | 356 ++++++++++++++++++++++++++++++++++++ > target/riscv/tcg/tcg-cpu.h | 28 +++ > 5 files changed, 397 insertions(+), 357 deletions(-) > create mode 100644 target/riscv/tcg/tcg-cpu.h > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > index 59785f5d9a..e186c026c9 100644 > --- a/target/riscv/cpu.c > +++ b/target/riscv/cpu.c > @@ -163,22 +163,21 @@ static const struct isa_ext_data isa_edata_arr[] = { > /* Hash that stores user set extensions */ > static GHashTable *multi_ext_user_opts; > > -static bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset) > +bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset) > { > bool *ext_enabled = (void *)&cpu->cfg + ext_offset; > > return *ext_enabled; > } > > -static void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, > - bool en) > +void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en) > { > bool *ext_enabled = (void *)&cpu->cfg + ext_offset; > > *ext_enabled = en; > } > > -static int cpu_cfg_ext_get_min_version(uint32_t ext_offset) > +int cpu_cfg_ext_get_min_version(uint32_t ext_offset) > { > int i; > > @@ -193,38 +192,12 @@ static int cpu_cfg_ext_get_min_version(uint32_t ext_offset) > g_assert_not_reached(); > } > > -static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset) > +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 cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset, > - bool value) > -{ > - CPURISCVState *env = &cpu->env; > - bool prev_val = isa_ext_is_enabled(cpu, ext_offset); > - int min_version; > - > - if (prev_val == value) { > - return; > - } > - > - if (cpu_cfg_ext_is_user_set(ext_offset)) { > - return; > - } > - > - if (value && env->priv_ver != PRIV_VERSION_LATEST) { > - /* Do not enable it if priv_ver is older than min_version */ > - min_version = cpu_cfg_ext_get_min_version(ext_offset); > - if (env->priv_ver < min_version) { > - return; > - } > - } > - > - isa_ext_update_enabled(cpu, ext_offset, value); > -} > - > const char * const riscv_int_regnames[] = { > "x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1", > "x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3", > @@ -1023,46 +996,7 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) > } > } > > -static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, > - Error **errp) > -{ > - if (!is_power_of_2(cfg->vlen)) { > - error_setg(errp, "Vector extension VLEN must be power of 2"); > - return; > - } > - if (cfg->vlen > RV_VLEN_MAX || cfg->vlen < 128) { > - error_setg(errp, > - "Vector extension implementation only supports VLEN " > - "in the range [128, %d]", RV_VLEN_MAX); > - return; > - } > - if (!is_power_of_2(cfg->elen)) { > - error_setg(errp, "Vector extension ELEN must be power of 2"); > - return; > - } > - if (cfg->elen > 64 || cfg->elen < 8) { > - error_setg(errp, > - "Vector extension implementation only supports ELEN " > - "in the range [8, 64]"); > - return; > - } > - if (cfg->vext_spec) { > - if (!g_strcmp0(cfg->vext_spec, "v1.0")) { > - env->vext_ver = VEXT_VERSION_1_00_0; > - } else { > - error_setg(errp, "Unsupported vector spec version '%s'", > - cfg->vext_spec); > - return; > - } > - } else if (env->vext_ver == 0) { > - qemu_log("vector version is not specified, " > - "use the default value v1.0\n"); > - > - env->vext_ver = VEXT_VERSION_1_00_0; > - } > -} > - > -static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) > +void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) > { > CPURISCVState *env = &cpu->env; > int i; > @@ -1086,291 +1020,6 @@ static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) > } > } > > -/* > - * Check consistency between chosen extensions while setting > - * cpu->cfg accordingly. > - */ > -void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) > -{ > - CPURISCVState *env = &cpu->env; > - Error *local_err = NULL; > - > - /* Do some ISA extension error checking */ > - if (riscv_has_ext(env, RVG) && > - !(riscv_has_ext(env, RVI) && riscv_has_ext(env, RVM) && > - riscv_has_ext(env, RVA) && riscv_has_ext(env, RVF) && > - riscv_has_ext(env, RVD) && > - cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) { > - > - if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_icsr)) && > - !cpu->cfg.ext_icsr) { > - error_setg(errp, "RVG requires Zicsr but user set Zicsr to false"); > - return; > - } > - > - if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_ifencei)) && > - !cpu->cfg.ext_ifencei) { > - error_setg(errp, "RVG requires Zifencei but user set " > - "Zifencei to false"); > - return; > - } > - > - warn_report("Setting G will also set IMAFD_Zicsr_Zifencei"); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_icsr), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_ifencei), true); > - > - env->misa_ext |= RVI | RVM | RVA | RVF | RVD; > - env->misa_ext_mask |= RVI | RVM | RVA | RVF | RVD; > - } > - > - if (riscv_has_ext(env, RVI) && riscv_has_ext(env, RVE)) { > - error_setg(errp, > - "I and E extensions are incompatible"); > - return; > - } > - > - if (!riscv_has_ext(env, RVI) && !riscv_has_ext(env, RVE)) { > - error_setg(errp, > - "Either I or E extension must be set"); > - return; > - } > - > - if (riscv_has_ext(env, RVS) && !riscv_has_ext(env, RVU)) { > - error_setg(errp, > - "Setting S extension without U extension is illegal"); > - return; > - } > - > - if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVI)) { > - error_setg(errp, > - "H depends on an I base integer ISA with 32 x registers"); > - return; > - } > - > - if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVS)) { > - error_setg(errp, "H extension implicitly requires S-mode"); > - return; > - } > - > - if (riscv_has_ext(env, RVF) && !cpu->cfg.ext_icsr) { > - error_setg(errp, "F extension requires Zicsr"); > - return; > - } > - > - if ((cpu->cfg.ext_zawrs) && !riscv_has_ext(env, RVA)) { > - error_setg(errp, "Zawrs extension requires A extension"); > - return; > - } > - > - if (cpu->cfg.ext_zfa && !riscv_has_ext(env, RVF)) { > - error_setg(errp, "Zfa extension requires F extension"); > - return; > - } > - > - if (cpu->cfg.ext_zfh) { > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zfhmin), true); > - } > - > - if (cpu->cfg.ext_zfhmin && !riscv_has_ext(env, RVF)) { > - error_setg(errp, "Zfh/Zfhmin extensions require F extension"); > - return; > - } > - > - if (cpu->cfg.ext_zfbfmin && !riscv_has_ext(env, RVF)) { > - error_setg(errp, "Zfbfmin extension depends on F extension"); > - return; > - } > - > - if (riscv_has_ext(env, RVD) && !riscv_has_ext(env, RVF)) { > - error_setg(errp, "D extension requires F extension"); > - return; > - } > - > - if (riscv_has_ext(env, RVV)) { > - riscv_cpu_validate_v(env, &cpu->cfg, &local_err); > - if (local_err != NULL) { > - error_propagate(errp, local_err); > - return; > - } > - > - /* The V vector extension depends on the Zve64d extension */ > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64d), true); > - } > - > - /* The Zve64d extension depends on the Zve64f extension */ > - if (cpu->cfg.ext_zve64d) { > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64f), true); > - } > - > - /* The Zve64f extension depends on the Zve32f extension */ > - if (cpu->cfg.ext_zve64f) { > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve32f), true); > - } > - > - if (cpu->cfg.ext_zve64d && !riscv_has_ext(env, RVD)) { > - error_setg(errp, "Zve64d/V extensions require D extension"); > - return; > - } > - > - if (cpu->cfg.ext_zve32f && !riscv_has_ext(env, RVF)) { > - error_setg(errp, "Zve32f/Zve64f extensions require F extension"); > - return; > - } > - > - if (cpu->cfg.ext_zvfh) { > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zvfhmin), true); > - } > - > - if (cpu->cfg.ext_zvfhmin && !cpu->cfg.ext_zve32f) { > - error_setg(errp, "Zvfh/Zvfhmin extensions require Zve32f extension"); > - return; > - } > - > - if (cpu->cfg.ext_zvfh && !cpu->cfg.ext_zfhmin) { > - error_setg(errp, "Zvfh extensions requires Zfhmin extension"); > - return; > - } > - > - if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zfbfmin) { > - error_setg(errp, "Zvfbfmin extension depends on Zfbfmin extension"); > - return; > - } > - > - if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zve32f) { > - error_setg(errp, "Zvfbfmin extension depends on Zve32f extension"); > - return; > - } > - > - if (cpu->cfg.ext_zvfbfwma && !cpu->cfg.ext_zvfbfmin) { > - error_setg(errp, "Zvfbfwma extension depends on Zvfbfmin extension"); > - return; > - } > - > - /* Set the ISA extensions, checks should have happened above */ > - if (cpu->cfg.ext_zhinx) { > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); > - } > - > - if ((cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinxmin) && !cpu->cfg.ext_zfinx) { > - error_setg(errp, "Zdinx/Zhinx/Zhinxmin extensions require Zfinx"); > - return; > - } > - > - if (cpu->cfg.ext_zfinx) { > - if (!cpu->cfg.ext_icsr) { > - error_setg(errp, "Zfinx extension requires Zicsr"); > - return; > - } > - if (riscv_has_ext(env, RVF)) { > - error_setg(errp, > - "Zfinx cannot be supported together with F extension"); > - return; > - } > - } > - > - if (cpu->cfg.ext_zce) { > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcb), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmp), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmt), true); > - if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) { > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true); > - } > - } > - > - /* zca, zcd and zcf has a PRIV 1.12.0 restriction */ > - if (riscv_has_ext(env, RVC) && env->priv_ver >= PRIV_VERSION_1_12_0) { > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); > - if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) { > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true); > - } > - if (riscv_has_ext(env, RVD)) { > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcd), true); > - } > - } > - > - if (env->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) { > - error_setg(errp, "Zcf extension is only relevant to RV32"); > - return; > - } > - > - if (!riscv_has_ext(env, RVF) && cpu->cfg.ext_zcf) { > - error_setg(errp, "Zcf extension requires F extension"); > - return; > - } > - > - if (!riscv_has_ext(env, RVD) && cpu->cfg.ext_zcd) { > - error_setg(errp, "Zcd extension requires D extension"); > - return; > - } > - > - if ((cpu->cfg.ext_zcf || cpu->cfg.ext_zcd || cpu->cfg.ext_zcb || > - cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt) && !cpu->cfg.ext_zca) { > - error_setg(errp, "Zcf/Zcd/Zcb/Zcmp/Zcmt extensions require Zca " > - "extension"); > - return; > - } > - > - if (cpu->cfg.ext_zcd && (cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt)) { > - error_setg(errp, "Zcmp/Zcmt extensions are incompatible with " > - "Zcd extension"); > - return; > - } > - > - if (cpu->cfg.ext_zcmt && !cpu->cfg.ext_icsr) { > - error_setg(errp, "Zcmt extension requires Zicsr extension"); > - return; > - } > - > - /* > - * In principle Zve*x would also suffice here, were they supported > - * in qemu > - */ > - if ((cpu->cfg.ext_zvbb || cpu->cfg.ext_zvkg || cpu->cfg.ext_zvkned || > - cpu->cfg.ext_zvknha || cpu->cfg.ext_zvksed || cpu->cfg.ext_zvksh) && > - !cpu->cfg.ext_zve32f) { > - error_setg(errp, > - "Vector crypto extensions require V or Zve* extensions"); > - return; > - } > - > - if ((cpu->cfg.ext_zvbc || cpu->cfg.ext_zvknhb) && !cpu->cfg.ext_zve64f) { > - error_setg( > - errp, > - "Zvbc and Zvknhb extensions require V or Zve64{f,d} extensions"); > - return; > - } > - > - if (cpu->cfg.ext_zk) { > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkn), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkr), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkt), true); > - } > - > - if (cpu->cfg.ext_zkn) { > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkne), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknd), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknh), true); > - } > - > - if (cpu->cfg.ext_zks) { > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksed), true); > - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksh), true); > - } > - > - /* > - * Disable isa extensions based on priv spec after we > - * validated and set everything we need. > - */ > - riscv_cpu_disable_priv_spec_isa_exts(cpu); > -} > - > #ifndef CONFIG_USER_ONLY > static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) > { > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > index b84b62f84e..721bd0b119 100644 > --- a/target/riscv/cpu.h > +++ b/target/riscv/cpu.h > @@ -445,7 +445,6 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, > bool probe, uintptr_t retaddr); > char *riscv_isa_string(RISCVCPU *cpu); > void riscv_cpu_list(void); > -void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp); > > #define cpu_list riscv_cpu_list > #define cpu_mmu_index riscv_cpu_mmu_index > @@ -711,6 +710,13 @@ enum riscv_pmu_event_idx { > #include "hw/core/tcg-cpu-ops.h" > extern const struct TCGCPUOps riscv_tcg_ops; > > +/* used by tcg/tcg-cpu.c*/ > +void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en); > +bool cpu_cfg_ext_is_user_set(uint32_t ext_offset); > +bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset); > +int cpu_cfg_ext_get_min_version(uint32_t ext_offset); > +void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu); > + > /* CSR function table */ > extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE]; > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c > index 6145039832..65473b257f 100644 > --- a/target/riscv/csr.c > +++ b/target/riscv/csr.c > @@ -21,6 +21,7 @@ > #include "qemu/log.h" > #include "qemu/timer.h" > #include "cpu.h" > +#include "tcg/tcg-cpu.h" > #include "pmu.h" > #include "time_helper.h" > #include "qemu/main-loop.h" > diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c > index 84ad6f1daf..da18851ed4 100644 > --- a/target/riscv/tcg/tcg-cpu.c > +++ b/target/riscv/tcg/tcg-cpu.c > @@ -18,14 +18,42 @@ > */ > > #include "qemu/osdep.h" > +#include "tcg-cpu.h" > #include "cpu.h" > #include "pmu.h" > #include "time_helper.h" > #include "qapi/error.h" > #include "qemu/accel.h" > +#include "qemu/error-report.h" > #include "hw/core/accel-cpu.h" > > > +static void cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset, > + bool value) > +{ > + CPURISCVState *env = &cpu->env; > + bool prev_val = isa_ext_is_enabled(cpu, ext_offset); > + int min_version; > + > + if (prev_val == value) { > + return; > + } > + > + if (cpu_cfg_ext_is_user_set(ext_offset)) { > + return; > + } > + > + if (value && env->priv_ver != PRIV_VERSION_LATEST) { > + /* Do not enable it if priv_ver is older than min_version */ > + min_version = cpu_cfg_ext_get_min_version(ext_offset); > + if (env->priv_ver < min_version) { > + return; > + } > + } > + > + isa_ext_update_enabled(cpu, ext_offset, value); > +} > + > static void riscv_cpu_validate_misa_priv(CPURISCVState *env, Error **errp) > { > if (riscv_has_ext(env, RVH) && env->priv_ver < PRIV_VERSION_1_12_0) { > @@ -84,6 +112,334 @@ static void riscv_cpu_validate_priv_spec(RISCVCPU *cpu, Error **errp) > } > } > > +static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, > + Error **errp) > +{ > + if (!is_power_of_2(cfg->vlen)) { > + error_setg(errp, "Vector extension VLEN must be power of 2"); > + return; > + } > + > + if (cfg->vlen > RV_VLEN_MAX || cfg->vlen < 128) { > + error_setg(errp, > + "Vector extension implementation only supports VLEN " > + "in the range [128, %d]", RV_VLEN_MAX); > + return; > + } > + > + if (!is_power_of_2(cfg->elen)) { > + error_setg(errp, "Vector extension ELEN must be power of 2"); > + return; > + } > + > + if (cfg->elen > 64 || cfg->elen < 8) { > + error_setg(errp, > + "Vector extension implementation only supports ELEN " > + "in the range [8, 64]"); > + return; > + } > + > + if (cfg->vext_spec) { > + if (!g_strcmp0(cfg->vext_spec, "v1.0")) { > + env->vext_ver = VEXT_VERSION_1_00_0; > + } else { > + error_setg(errp, "Unsupported vector spec version '%s'", > + cfg->vext_spec); > + return; > + } > + } else if (env->vext_ver == 0) { > + qemu_log("vector version is not specified, " > + "use the default value v1.0\n"); > + > + env->vext_ver = VEXT_VERSION_1_00_0; > + } > +} > + > +/* > + * Check consistency between chosen extensions while setting > + * cpu->cfg accordingly. > + */ > +void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) > +{ > + CPURISCVState *env = &cpu->env; > + Error *local_err = NULL; > + > + /* Do some ISA extension error checking */ > + if (riscv_has_ext(env, RVG) && > + !(riscv_has_ext(env, RVI) && riscv_has_ext(env, RVM) && > + riscv_has_ext(env, RVA) && riscv_has_ext(env, RVF) && > + riscv_has_ext(env, RVD) && > + cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) { > + > + if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_icsr)) && > + !cpu->cfg.ext_icsr) { > + error_setg(errp, "RVG requires Zicsr but user set Zicsr to false"); > + return; > + } > + > + if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_ifencei)) && > + !cpu->cfg.ext_ifencei) { > + error_setg(errp, "RVG requires Zifencei but user set " > + "Zifencei to false"); > + return; > + } > + > + warn_report("Setting G will also set IMAFD_Zicsr_Zifencei"); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_icsr), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_ifencei), true); > + > + env->misa_ext |= RVI | RVM | RVA | RVF | RVD; > + env->misa_ext_mask |= RVI | RVM | RVA | RVF | RVD; > + } > + > + if (riscv_has_ext(env, RVI) && riscv_has_ext(env, RVE)) { > + error_setg(errp, > + "I and E extensions are incompatible"); > + return; > + } > + > + if (!riscv_has_ext(env, RVI) && !riscv_has_ext(env, RVE)) { > + error_setg(errp, > + "Either I or E extension must be set"); > + return; > + } > + > + if (riscv_has_ext(env, RVS) && !riscv_has_ext(env, RVU)) { > + error_setg(errp, > + "Setting S extension without U extension is illegal"); > + return; > + } > + > + if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVI)) { > + error_setg(errp, > + "H depends on an I base integer ISA with 32 x registers"); > + return; > + } > + > + if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVS)) { > + error_setg(errp, "H extension implicitly requires S-mode"); > + return; > + } > + > + if (riscv_has_ext(env, RVF) && !cpu->cfg.ext_icsr) { > + error_setg(errp, "F extension requires Zicsr"); > + return; > + } > + > + if ((cpu->cfg.ext_zawrs) && !riscv_has_ext(env, RVA)) { > + error_setg(errp, "Zawrs extension requires A extension"); > + return; > + } > + > + if (cpu->cfg.ext_zfa && !riscv_has_ext(env, RVF)) { > + error_setg(errp, "Zfa extension requires F extension"); > + return; > + } > + > + if (cpu->cfg.ext_zfh) { > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zfhmin), true); > + } > + > + if (cpu->cfg.ext_zfhmin && !riscv_has_ext(env, RVF)) { > + error_setg(errp, "Zfh/Zfhmin extensions require F extension"); > + return; > + } > + > + if (cpu->cfg.ext_zfbfmin && !riscv_has_ext(env, RVF)) { > + error_setg(errp, "Zfbfmin extension depends on F extension"); > + return; > + } > + > + if (riscv_has_ext(env, RVD) && !riscv_has_ext(env, RVF)) { > + error_setg(errp, "D extension requires F extension"); > + return; > + } > + > + if (riscv_has_ext(env, RVV)) { > + riscv_cpu_validate_v(env, &cpu->cfg, &local_err); > + if (local_err != NULL) { > + error_propagate(errp, local_err); > + return; > + } > + > + /* The V vector extension depends on the Zve64d extension */ > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64d), true); > + } > + > + /* The Zve64d extension depends on the Zve64f extension */ > + if (cpu->cfg.ext_zve64d) { > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64f), true); > + } > + > + /* The Zve64f extension depends on the Zve32f extension */ > + if (cpu->cfg.ext_zve64f) { > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve32f), true); > + } > + > + if (cpu->cfg.ext_zve64d && !riscv_has_ext(env, RVD)) { > + error_setg(errp, "Zve64d/V extensions require D extension"); > + return; > + } > + > + if (cpu->cfg.ext_zve32f && !riscv_has_ext(env, RVF)) { > + error_setg(errp, "Zve32f/Zve64f extensions require F extension"); > + return; > + } > + > + if (cpu->cfg.ext_zvfh) { > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zvfhmin), true); > + } > + > + if (cpu->cfg.ext_zvfhmin && !cpu->cfg.ext_zve32f) { > + error_setg(errp, "Zvfh/Zvfhmin extensions require Zve32f extension"); > + return; > + } > + > + if (cpu->cfg.ext_zvfh && !cpu->cfg.ext_zfhmin) { > + error_setg(errp, "Zvfh extensions requires Zfhmin extension"); > + return; > + } > + > + if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zfbfmin) { > + error_setg(errp, "Zvfbfmin extension depends on Zfbfmin extension"); > + return; > + } > + > + if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zve32f) { > + error_setg(errp, "Zvfbfmin extension depends on Zve32f extension"); > + return; > + } > + > + if (cpu->cfg.ext_zvfbfwma && !cpu->cfg.ext_zvfbfmin) { > + error_setg(errp, "Zvfbfwma extension depends on Zvfbfmin extension"); > + return; > + } > + > + /* Set the ISA extensions, checks should have happened above */ > + if (cpu->cfg.ext_zhinx) { > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); > + } > + > + if ((cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinxmin) && !cpu->cfg.ext_zfinx) { > + error_setg(errp, "Zdinx/Zhinx/Zhinxmin extensions require Zfinx"); > + return; > + } > + > + if (cpu->cfg.ext_zfinx) { > + if (!cpu->cfg.ext_icsr) { > + error_setg(errp, "Zfinx extension requires Zicsr"); > + return; > + } > + if (riscv_has_ext(env, RVF)) { > + error_setg(errp, > + "Zfinx cannot be supported together with F extension"); > + return; > + } > + } > + > + if (cpu->cfg.ext_zce) { > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcb), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmp), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmt), true); > + if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) { > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true); > + } > + } > + > + /* zca, zcd and zcf has a PRIV 1.12.0 restriction */ > + if (riscv_has_ext(env, RVC) && env->priv_ver >= PRIV_VERSION_1_12_0) { > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); > + if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) { > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true); > + } > + if (riscv_has_ext(env, RVD)) { > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcd), true); > + } > + } > + > + if (env->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) { > + error_setg(errp, "Zcf extension is only relevant to RV32"); > + return; > + } > + > + if (!riscv_has_ext(env, RVF) && cpu->cfg.ext_zcf) { > + error_setg(errp, "Zcf extension requires F extension"); > + return; > + } > + > + if (!riscv_has_ext(env, RVD) && cpu->cfg.ext_zcd) { > + error_setg(errp, "Zcd extension requires D extension"); > + return; > + } > + > + if ((cpu->cfg.ext_zcf || cpu->cfg.ext_zcd || cpu->cfg.ext_zcb || > + cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt) && !cpu->cfg.ext_zca) { > + error_setg(errp, "Zcf/Zcd/Zcb/Zcmp/Zcmt extensions require Zca " > + "extension"); > + return; > + } > + > + if (cpu->cfg.ext_zcd && (cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt)) { > + error_setg(errp, "Zcmp/Zcmt extensions are incompatible with " > + "Zcd extension"); > + return; > + } > + > + if (cpu->cfg.ext_zcmt && !cpu->cfg.ext_icsr) { > + error_setg(errp, "Zcmt extension requires Zicsr extension"); > + return; > + } > + > + /* > + * In principle Zve*x would also suffice here, were they supported > + * in qemu > + */ > + if ((cpu->cfg.ext_zvbb || cpu->cfg.ext_zvkg || cpu->cfg.ext_zvkned || > + cpu->cfg.ext_zvknha || cpu->cfg.ext_zvksed || cpu->cfg.ext_zvksh) && > + !cpu->cfg.ext_zve32f) { > + error_setg(errp, > + "Vector crypto extensions require V or Zve* extensions"); > + return; > + } > + > + if ((cpu->cfg.ext_zvbc || cpu->cfg.ext_zvknhb) && !cpu->cfg.ext_zve64f) { > + error_setg( > + errp, > + "Zvbc and Zvknhb extensions require V or Zve64{f,d} extensions"); > + return; > + } > + > + if (cpu->cfg.ext_zk) { > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkn), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkr), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkt), true); > + } > + > + if (cpu->cfg.ext_zkn) { > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkne), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknd), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknh), true); > + } > + > + if (cpu->cfg.ext_zks) { > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksed), true); > + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksh), true); > + } > + > + /* > + * Disable isa extensions based on priv spec after we > + * validated and set everything we need. > + */ > + riscv_cpu_disable_priv_spec_isa_exts(cpu); > +} > + > /* > * We'll get here via the following path: > * > diff --git a/target/riscv/tcg/tcg-cpu.h b/target/riscv/tcg/tcg-cpu.h > new file mode 100644 > index 0000000000..4cf35a8015 > --- /dev/null > +++ b/target/riscv/tcg/tcg-cpu.h > @@ -0,0 +1,28 @@ > +/* > + * riscv TCG cpu class initialization > + * > + * Copyright (c) 2023 Ventana Micro Systems Inc. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef RISCV_TCG_CPU_H > +#define RISCV_TCG_CPU_H > + > +#include "cpu.h" > + > +void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp); > + > +#endif > +
© 2016 - 2024 Red Hat, Inc.