target/riscv: move riscv_cpu_validate_set_extensions() to tcg-cpu.c
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> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20230925175709.35696-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
parent
9dcecbd724
commit
36c1118d50
@ -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)
|
||||
{
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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 "exec/exec-all.h"
|
||||
|
@ -19,14 +19,43 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "exec/exec-all.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 "qemu/log.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) {
|
||||
@ -85,6 +114,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:
|
||||
*
|
||||
|
27
target/riscv/tcg/tcg-cpu.h
Normal file
27
target/riscv/tcg/tcg-cpu.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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
|
Loading…
Reference in New Issue
Block a user