aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/riscv/cpu.c204
-rw-r--r--target/riscv/cpu.h48
-rw-r--r--target/riscv/cpu_bits.h63
-rw-r--r--target/riscv/cpu_helper.c293
-rw-r--r--target/riscv/csr.c1038
-rw-r--r--target/riscv/insn16.decode7
-rw-r--r--target/riscv/insn32.decode7
-rw-r--r--target/riscv/insn_trans/trans_rvi.c.inc16
-rw-r--r--target/riscv/insn_trans/trans_rvv.c.inc28
-rw-r--r--target/riscv/instmap.h45
-rw-r--r--target/riscv/internals.h5
-rw-r--r--target/riscv/machine.c8
-rw-r--r--target/riscv/meson.build3
-rw-r--r--target/riscv/pmu.c425
-rw-r--r--target/riscv/pmu.h8
-rw-r--r--target/riscv/time_helper.c114
-rw-r--r--target/riscv/time_helper.h30
-rw-r--r--target/riscv/translate.c24
-rw-r--r--target/riscv/vector_helper.c152
19 files changed, 2033 insertions, 485 deletions
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index ac6f82e..aee14a2 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -22,7 +22,9 @@
#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"
@@ -43,9 +45,88 @@ static const char riscv_single_letter_exts[] = "IEMAFDQCPVH";
struct isa_ext_data {
const char *name;
- bool enabled;
+ 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",
"x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3",
@@ -530,7 +611,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
CPURISCVState *env = &cpu->env;
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
CPUClass *cc = CPU_CLASS(mcc);
- int priv_version = -1;
+ int i, priv_version = -1;
Error *local_err = NULL;
cpu_exec_realizefn(cs, &local_err);
@@ -558,6 +639,23 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
set_priv_version(env, priv_version);
}
+ /* 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) {
riscv_set_feature(env, RISCV_FEATURE_MMU);
}
@@ -574,16 +672,18 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
}
}
- 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) {
#ifdef TARGET_RISCV64
@@ -631,6 +731,23 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
return;
}
+ 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;
@@ -774,6 +891,15 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
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);
@@ -878,14 +1004,17 @@ static Property riscv_cpu_extensions[] = {
DEFINE_PROP_BOOL("v", RISCVCPU, cfg.ext_v, false),
DEFINE_PROP_BOOL("h", RISCVCPU, cfg.ext_h, 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),
@@ -919,15 +1048,17 @@ static Property riscv_cpu_extensions[] = {
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),
/* These are experimental so mark with 'x-' */
DEFINE_PROP_BOOL("x-j", RISCVCPU, cfg.ext_j, false),
- DEFINE_PROP_BOOL("x-zmmul", RISCVCPU, cfg.ext_zmmul, 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(),
};
@@ -953,6 +1084,7 @@ static Property riscv_cpu_properties[] = {
DEFINE_PROP_BOOL("short-isa-string", RISCVCPU, cfg.short_isa_string, false),
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(),
};
@@ -1044,67 +1176,15 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
device_class_set_props(dc, riscv_cpu_properties);
}
-#define ISA_EDATA_ENTRY(name, prop) {#name, cpu->cfg.prop}
-
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;
- /**
- * 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.
- */
- struct isa_ext_data isa_edata_arr[] = {
- ISA_EDATA_ENTRY(zicsr, ext_icsr),
- ISA_EDATA_ENTRY(zifencei, ext_ifencei),
- ISA_EDATA_ENTRY(zmmul, ext_zmmul),
- ISA_EDATA_ENTRY(zfh, ext_zfh),
- ISA_EDATA_ENTRY(zfhmin, ext_zfhmin),
- ISA_EDATA_ENTRY(zfinx, ext_zfinx),
- ISA_EDATA_ENTRY(zdinx, ext_zdinx),
- ISA_EDATA_ENTRY(zba, ext_zba),
- ISA_EDATA_ENTRY(zbb, ext_zbb),
- ISA_EDATA_ENTRY(zbc, ext_zbc),
- ISA_EDATA_ENTRY(zbkb, ext_zbkb),
- ISA_EDATA_ENTRY(zbkc, ext_zbkc),
- ISA_EDATA_ENTRY(zbkx, ext_zbkx),
- ISA_EDATA_ENTRY(zbs, ext_zbs),
- ISA_EDATA_ENTRY(zk, ext_zk),
- ISA_EDATA_ENTRY(zkn, ext_zkn),
- ISA_EDATA_ENTRY(zknd, ext_zknd),
- ISA_EDATA_ENTRY(zkne, ext_zkne),
- ISA_EDATA_ENTRY(zknh, ext_zknh),
- ISA_EDATA_ENTRY(zkr, ext_zkr),
- ISA_EDATA_ENTRY(zks, ext_zks),
- ISA_EDATA_ENTRY(zksed, ext_zksed),
- ISA_EDATA_ENTRY(zksh, ext_zksh),
- ISA_EDATA_ENTRY(zkt, ext_zkt),
- ISA_EDATA_ENTRY(zve32f, ext_zve32f),
- ISA_EDATA_ENTRY(zve64f, ext_zve64f),
- ISA_EDATA_ENTRY(zhinx, ext_zhinx),
- ISA_EDATA_ENTRY(zhinxmin, ext_zhinxmin),
- ISA_EDATA_ENTRY(svinval, ext_svinval),
- ISA_EDATA_ENTRY(svnapot, ext_svnapot),
- ISA_EDATA_ENTRY(svpbmt, ext_svpbmt),
- };
-
for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) {
- if (isa_edata_arr[i].enabled) {
+ 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;
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 5c7acc0..06751e1 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -85,7 +85,6 @@ enum {
RISCV_FEATURE_PMP,
RISCV_FEATURE_EPMP,
RISCV_FEATURE_MISA,
- RISCV_FEATURE_AIA,
RISCV_FEATURE_DEBUG
};
@@ -137,6 +136,8 @@ typedef struct PMUCTRState {
/* Snapshort value of a counter in RV32 */
target_ulong mhpmcounterh_prev;
bool started;
+ /* Value beyond UINT32_MAX/UINT64_MAX before overflow interrupt trigger */
+ target_ulong irq_overflow_left;
} PMUCTRState;
struct CPUArchState {
@@ -285,6 +286,11 @@ struct CPUArchState {
/* Signals whether the current exception occurred with two-stage address
translation active. */
bool two_stage_lookup;
+ /*
+ * Signals whether the current exception occurred while doing two-stage
+ * address translation for the VS-stage page table walk.
+ */
+ bool two_stage_indirect_lookup;
target_ulong scounteren;
target_ulong mcounteren;
@@ -297,13 +303,20 @@ struct CPUArchState {
/* PMU event selector configured values. First three are unused*/
target_ulong mhpmevent_val[RV_MAX_MHPMEVENTS];
+ /* PMU event selector configured values for RV32*/
+ target_ulong mhpmeventh_val[RV_MAX_MHPMEVENTS];
+
target_ulong sscratch;
target_ulong mscratch;
/* temporary htif regs */
uint64_t mfromhost;
uint64_t mtohost;
- uint64_t timecmp;
+
+ /* Sstc CSRs */
+ uint64_t stimecmp;
+
+ uint64_t vstimecmp;
/* physical memory protection */
pmp_table_t pmp_state;
@@ -358,7 +371,9 @@ struct CPUArchState {
float_status fp_status;
/* Fields from here on are preserved across CPU reset. */
- QEMUTimer *timer; /* Internal timer */
+ QEMUTimer *stimer; /* Internal timer for S-mode interrupt */
+ QEMUTimer *vstimer; /* Internal timer for VS-mode interrupt */
+ bool vstime_irq;
hwaddr kernel_addr;
hwaddr fdt_addr;
@@ -421,6 +436,8 @@ struct RISCVCPUConfig {
bool ext_zkt;
bool ext_ifencei;
bool ext_icsr;
+ bool ext_zihintpause;
+ bool ext_sstc;
bool ext_svinval;
bool ext_svnapot;
bool ext_svpbmt;
@@ -433,7 +450,11 @@ struct RISCVCPUConfig {
bool ext_zve32f;
bool ext_zve64f;
bool ext_zmmul;
+ bool ext_smaia;
+ bool ext_ssaia;
+ bool ext_sscofpmf;
bool rvv_ta_all_1s;
+ bool rvv_ma_all_1s;
uint32_t mvendorid;
uint64_t marchid;
@@ -452,7 +473,6 @@ struct RISCVCPUConfig {
bool mmu;
bool pmp;
bool epmp;
- bool aia;
bool debug;
uint64_t resetvec;
@@ -479,6 +499,12 @@ struct ArchCPU {
/* Configuration Settings */
RISCVCPUConfig cfg;
+
+ QEMUTimer *pmu_timer;
+ /* A bitmask of Available programmable counters */
+ uint32_t pmu_avail_ctrs;
+ /* Mapping of events to counters */
+ GHashTable *pmu_event_ctr_map;
};
static inline int riscv_has_ext(CPURISCVState *env, target_ulong ext)
@@ -591,6 +617,7 @@ FIELD(TB_FLAGS, XL, 20, 2)
FIELD(TB_FLAGS, PM_MASK_ENABLED, 22, 1)
FIELD(TB_FLAGS, PM_BASE_ENABLED, 23, 1)
FIELD(TB_FLAGS, VTA, 24, 1)
+FIELD(TB_FLAGS, VMA, 25, 1)
#ifdef TARGET_RISCV32
#define riscv_cpu_mxl(env) ((void)(env), MXL_RV32)
@@ -738,6 +765,19 @@ enum {
CSR_TABLE_SIZE = 0x1000
};
+/**
+ * The event id are encoded based on the encoding specified in the
+ * SBI specification v0.3
+ */
+
+enum riscv_pmu_event_idx {
+ RISCV_PMU_EVENT_HW_CPU_CYCLES = 0x01,
+ RISCV_PMU_EVENT_HW_INSTRUCTIONS = 0x02,
+ RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS = 0x10019,
+ RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS = 0x1001B,
+ RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS = 0x10021,
+};
+
/* CSR function table */
extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE];
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 6be5a9e..7be12ca 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -206,6 +206,10 @@
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
+/* Sstc supervisor CSRs */
+#define CSR_STIMECMP 0x14D
+#define CSR_STIMECMPH 0x15D
+
/* Supervisor Protection and Translation */
#define CSR_SPTBR 0x180
#define CSR_SATP 0x180
@@ -253,6 +257,10 @@
#define CSR_VSIP 0x244
#define CSR_VSATP 0x280
+/* Sstc virtual CSRs */
+#define CSR_VSTIMECMP 0x24D
+#define CSR_VSTIMECMPH 0x25D
+
#define CSR_MTINST 0x34a
#define CSR_MTVAL2 0x34b
@@ -382,6 +390,37 @@
#define CSR_MHPMEVENT29 0x33d
#define CSR_MHPMEVENT30 0x33e
#define CSR_MHPMEVENT31 0x33f
+
+#define CSR_MHPMEVENT3H 0x723
+#define CSR_MHPMEVENT4H 0x724
+#define CSR_MHPMEVENT5H 0x725
+#define CSR_MHPMEVENT6H 0x726
+#define CSR_MHPMEVENT7H 0x727
+#define CSR_MHPMEVENT8H 0x728
+#define CSR_MHPMEVENT9H 0x729
+#define CSR_MHPMEVENT10H 0x72a
+#define CSR_MHPMEVENT11H 0x72b
+#define CSR_MHPMEVENT12H 0x72c
+#define CSR_MHPMEVENT13H 0x72d
+#define CSR_MHPMEVENT14H 0x72e
+#define CSR_MHPMEVENT15H 0x72f
+#define CSR_MHPMEVENT16H 0x730
+#define CSR_MHPMEVENT17H 0x731
+#define CSR_MHPMEVENT18H 0x732
+#define CSR_MHPMEVENT19H 0x733
+#define CSR_MHPMEVENT20H 0x734
+#define CSR_MHPMEVENT21H 0x735
+#define CSR_MHPMEVENT22H 0x736
+#define CSR_MHPMEVENT23H 0x737
+#define CSR_MHPMEVENT24H 0x738
+#define CSR_MHPMEVENT25H 0x739
+#define CSR_MHPMEVENT26H 0x73a
+#define CSR_MHPMEVENT27H 0x73b
+#define CSR_MHPMEVENT28H 0x73c
+#define CSR_MHPMEVENT29H 0x73d
+#define CSR_MHPMEVENT30H 0x73e
+#define CSR_MHPMEVENT31H 0x73f
+
#define CSR_MHPMCOUNTER3H 0xb83
#define CSR_MHPMCOUNTER4H 0xb84
#define CSR_MHPMCOUNTER5H 0xb85
@@ -443,6 +482,7 @@
#define CSR_VSMTE 0x2c0
#define CSR_VSPMMASK 0x2c1
#define CSR_VSPMBASE 0x2c2
+#define CSR_SCOUNTOVF 0xda0
/* Crypto Extension */
#define CSR_SEED 0x015
@@ -620,6 +660,7 @@ typedef enum RISCVException {
#define IRQ_VS_EXT 10
#define IRQ_M_EXT 11
#define IRQ_S_GEXT 12
+#define IRQ_PMU_OVF 13
#define IRQ_LOCAL_MAX 16
#define IRQ_LOCAL_GUEST_MAX (TARGET_LONG_BITS - 1)
@@ -637,11 +678,13 @@ typedef enum RISCVException {
#define MIP_VSEIP (1 << IRQ_VS_EXT)
#define MIP_MEIP (1 << IRQ_M_EXT)
#define MIP_SGEIP (1 << IRQ_S_GEXT)
+#define MIP_LCOFIP (1 << IRQ_PMU_OVF)
/* sip masks */
#define SIP_SSIP MIP_SSIP
#define SIP_STIP MIP_STIP
#define SIP_SEIP MIP_SEIP
+#define SIP_LCOFIP MIP_LCOFIP
/* MIE masks */
#define MIE_SEIE (1 << IRQ_S_EXT)
@@ -795,4 +838,24 @@ typedef enum RISCVException {
#define SEED_OPST_WAIT (0b01 << 30)
#define SEED_OPST_ES16 (0b10 << 30)
#define SEED_OPST_DEAD (0b11 << 30)
+/* PMU related bits */
+#define MIE_LCOFIE (1 << IRQ_PMU_OVF)
+
+#define MHPMEVENT_BIT_OF BIT_ULL(63)
+#define MHPMEVENTH_BIT_OF BIT(31)
+#define MHPMEVENT_BIT_MINH BIT_ULL(62)
+#define MHPMEVENTH_BIT_MINH BIT(30)
+#define MHPMEVENT_BIT_SINH BIT_ULL(61)
+#define MHPMEVENTH_BIT_SINH BIT(29)
+#define MHPMEVENT_BIT_UINH BIT_ULL(60)
+#define MHPMEVENTH_BIT_UINH BIT(28)
+#define MHPMEVENT_BIT_VSINH BIT_ULL(59)
+#define MHPMEVENTH_BIT_VSINH BIT(27)
+#define MHPMEVENT_BIT_VUINH BIT_ULL(58)
+#define MHPMEVENTH_BIT_VUINH BIT(26)
+
+#define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000)
+#define MHPMEVENT_IDX_MASK 0xFFFFF
+#define MHPMEVENT_SSCOF_RESVD 16
+
#endif
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 59b3680..67e4c0e 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -21,10 +21,13 @@
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "cpu.h"
+#include "pmu.h"
#include "exec/exec-all.h"
+#include "instmap.h"
#include "tcg/tcg-op.h"
#include "trace.h"
#include "semihosting/common-semi.h"
+#include "cpu_bits.h"
int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
{
@@ -67,6 +70,8 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
flags = FIELD_DP32(flags, TB_FLAGS, VL_EQ_VLMAX, vl_eq_vlmax);
flags = FIELD_DP32(flags, TB_FLAGS, VTA,
FIELD_EX64(env->vtype, VTYPE, VTA));
+ flags = FIELD_DP32(flags, TB_FLAGS, VMA,
+ FIELD_EX64(env->vtype, VTYPE, VMA));
} else {
flags = FIELD_DP32(flags, TB_FLAGS, VILL, 1);
}
@@ -304,6 +309,7 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
int extirq, unsigned int extirq_def_prio,
uint64_t pending, uint8_t *iprio)
{
+ RISCVCPU *cpu = env_archcpu(env);
int irq, best_irq = RISCV_EXCP_NONE;
unsigned int prio, best_prio = UINT_MAX;
@@ -312,7 +318,7 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
}
irq = ctz64(pending);
- if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
+ if (!((extirq == IRQ_M_EXT) ? cpu->cfg.ext_smaia : cpu->cfg.ext_ssaia)) {
return irq;
}
@@ -342,8 +348,9 @@ uint64_t riscv_cpu_all_pending(CPURISCVState *env)
{
uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN);
uint64_t vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
+ uint64_t vstip = (env->vstime_irq) ? MIP_VSTIP : 0;
- return (env->mip | vsgein) & env->mie;
+ return (env->mip | vsgein | vstip) & env->mie;
}
int riscv_cpu_mirq_pending(CPURISCVState *env)
@@ -602,7 +609,7 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
{
CPURISCVState *env = &cpu->env;
CPUState *cs = CPU(cpu);
- uint64_t gein, vsgein = 0, old = env->mip;
+ uint64_t gein, vsgein = 0, vstip = 0, old = env->mip;
bool locked = false;
if (riscv_cpu_virt_enabled(env)) {
@@ -610,6 +617,10 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
}
+ /* No need to update mip for VSTIP */
+ mask = ((mask == MIP_VSTIP) && env->vstime_irq) ? 0 : mask;
+ vstip = env->vstime_irq ? MIP_VSTIP : 0;
+
if (!qemu_mutex_iothread_locked()) {
locked = true;
qemu_mutex_lock_iothread();
@@ -617,7 +628,7 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
env->mip = (env->mip & ~mask) | (value & mask);
- if (env->mip | vsgein) {
+ if (env->mip | vsgein | vstip) {
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
} else {
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
@@ -1053,7 +1064,8 @@ restart:
static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
MMUAccessType access_type, bool pmp_violation,
- bool first_stage, bool two_stage)
+ bool first_stage, bool two_stage,
+ bool two_stage_indirect)
{
CPUState *cs = env_cpu(env);
int page_fault_exceptions, vm;
@@ -1103,6 +1115,7 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
}
env->badaddr = address;
env->two_stage_lookup = two_stage;
+ env->two_stage_indirect_lookup = two_stage_indirect;
}
hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
@@ -1148,6 +1161,7 @@ void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
env->badaddr = addr;
env->two_stage_lookup = riscv_cpu_virt_enabled(env) ||
riscv_cpu_two_stage_lookup(mmu_idx);
+ env->two_stage_indirect_lookup = false;
cpu_loop_exit_restore(cs, retaddr);
}
@@ -1173,9 +1187,32 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
env->badaddr = addr;
env->two_stage_lookup = riscv_cpu_virt_enabled(env) ||
riscv_cpu_two_stage_lookup(mmu_idx);
+ env->two_stage_indirect_lookup = false;
cpu_loop_exit_restore(cs, retaddr);
}
+
+static void pmu_tlb_fill_incr_ctr(RISCVCPU *cpu, MMUAccessType access_type)
+{
+ enum riscv_pmu_event_idx pmu_event_type;
+
+ switch (access_type) {
+ case MMU_INST_FETCH:
+ pmu_event_type = RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS;
+ break;
+ case MMU_DATA_LOAD:
+ pmu_event_type = RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS;
+ break;
+ case MMU_DATA_STORE:
+ pmu_event_type = RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS;
+ break;
+ default:
+ return;
+ }
+
+ riscv_pmu_incr_ctr(cpu, pmu_event_type);
+}
+
bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr)
@@ -1188,6 +1225,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
bool pmp_violation = false;
bool first_stage_error = true;
bool two_stage_lookup = false;
+ bool two_stage_indirect_error = false;
int ret = TRANSLATE_FAIL;
int mode = mmu_idx;
/* default TLB page size */
@@ -1225,6 +1263,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
*/
if (ret == TRANSLATE_G_STAGE_FAIL) {
first_stage_error = false;
+ two_stage_indirect_error = true;
access_type = MMU_DATA_LOAD;
}
@@ -1272,6 +1311,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
}
}
} else {
+ pmu_tlb_fill_incr_ctr(cpu, access_type);
/* Single stage lookup */
ret = get_physical_address(env, &pa, &prot, address, NULL,
access_type, mmu_idx, true, false, false);
@@ -1308,12 +1348,218 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
raise_mmu_exception(env, address, access_type, pmp_violation,
first_stage_error,
riscv_cpu_virt_enabled(env) ||
- riscv_cpu_two_stage_lookup(mmu_idx));
+ riscv_cpu_two_stage_lookup(mmu_idx),
+ two_stage_indirect_error);
cpu_loop_exit_restore(cs, retaddr);
}
return true;
}
+
+static target_ulong riscv_transformed_insn(CPURISCVState *env,
+ target_ulong insn,
+ target_ulong taddr)
+{
+ target_ulong xinsn = 0;
+ target_ulong access_rs1 = 0, access_imm = 0, access_size = 0;
+
+ /*
+ * Only Quadrant 0 and Quadrant 2 of RVC instruction space need to
+ * be uncompressed. The Quadrant 1 of RVC instruction space need
+ * not be transformed because these instructions won't generate
+ * any load/store trap.
+ */
+
+ if ((insn & 0x3) != 0x3) {
+ /* Transform 16bit instruction into 32bit instruction */
+ switch (GET_C_OP(insn)) {
+ case OPC_RISC_C_OP_QUAD0: /* Quadrant 0 */
+ switch (GET_C_FUNC(insn)) {
+ case OPC_RISC_C_FUNC_FLD_LQ:
+ if (riscv_cpu_xlen(env) != 128) { /* C.FLD (RV32/64) */
+ xinsn = OPC_RISC_FLD;
+ xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
+ access_rs1 = GET_C_RS1S(insn);
+ access_imm = GET_C_LD_IMM(insn);
+ access_size = 8;
+ }
+ break;
+ case OPC_RISC_C_FUNC_LW: /* C.LW */
+ xinsn = OPC_RISC_LW;
+ xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
+ access_rs1 = GET_C_RS1S(insn);
+ access_imm = GET_C_LW_IMM(insn);
+ access_size = 4;
+ break;
+ case OPC_RISC_C_FUNC_FLW_LD:
+ if (riscv_cpu_xlen(env) == 32) { /* C.FLW (RV32) */
+ xinsn = OPC_RISC_FLW;
+ xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
+ access_rs1 = GET_C_RS1S(insn);
+ access_imm = GET_C_LW_IMM(insn);
+ access_size = 4;
+ } else { /* C.LD (RV64/RV128) */
+ xinsn = OPC_RISC_LD;
+ xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
+ access_rs1 = GET_C_RS1S(insn);
+ access_imm = GET_C_LD_IMM(insn);
+ access_size = 8;
+ }
+ break;
+ case OPC_RISC_C_FUNC_FSD_SQ:
+ if (riscv_cpu_xlen(env) != 128) { /* C.FSD (RV32/64) */
+ xinsn = OPC_RISC_FSD;
+ xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
+ access_rs1 = GET_C_RS1S(insn);
+ access_imm = GET_C_SD_IMM(insn);
+ access_size = 8;
+ }
+ break;
+ case OPC_RISC_C_FUNC_SW: /* C.SW */
+ xinsn = OPC_RISC_SW;
+ xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
+ access_rs1 = GET_C_RS1S(insn);
+ access_imm = GET_C_SW_IMM(insn);
+ access_size = 4;
+ break;
+ case OPC_RISC_C_FUNC_FSW_SD:
+ if (riscv_cpu_xlen(env) == 32) { /* C.FSW (RV32) */
+ xinsn = OPC_RISC_FSW;
+ xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
+ access_rs1 = GET_C_RS1S(insn);
+ access_imm = GET_C_SW_IMM(insn);
+ access_size = 4;
+ } else { /* C.SD (RV64/RV128) */
+ xinsn = OPC_RISC_SD;
+ xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
+ access_rs1 = GET_C_RS1S(insn);
+ access_imm = GET_C_SD_IMM(insn);
+ access_size = 8;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case OPC_RISC_C_OP_QUAD2: /* Quadrant 2 */
+ switch (GET_C_FUNC(insn)) {
+ case OPC_RISC_C_FUNC_FLDSP_LQSP:
+ if (riscv_cpu_xlen(env) != 128) { /* C.FLDSP (RV32/64) */
+ xinsn = OPC_RISC_FLD;
+ xinsn = SET_RD(xinsn, GET_C_RD(insn));
+ access_rs1 = 2;
+ access_imm = GET_C_LDSP_IMM(insn);
+ access_size = 8;
+ }
+ break;
+ case OPC_RISC_C_FUNC_LWSP: /* C.LWSP */
+ xinsn = OPC_RISC_LW;
+ xinsn = SET_RD(xinsn, GET_C_RD(insn));
+ access_rs1 = 2;
+ access_imm = GET_C_LWSP_IMM(insn);
+ access_size = 4;
+ break;
+ case OPC_RISC_C_FUNC_FLWSP_LDSP:
+ if (riscv_cpu_xlen(env) == 32) { /* C.FLWSP (RV32) */
+ xinsn = OPC_RISC_FLW;
+ xinsn = SET_RD(xinsn, GET_C_RD(insn));
+ access_rs1 = 2;
+ access_imm = GET_C_LWSP_IMM(insn);
+ access_size = 4;
+ } else { /* C.LDSP (RV64/RV128) */
+ xinsn = OPC_RISC_LD;
+ xinsn = SET_RD(xinsn, GET_C_RD(insn));
+ access_rs1 = 2;
+ access_imm = GET_C_LDSP_IMM(insn);
+ access_size = 8;
+ }
+ break;
+ case OPC_RISC_C_FUNC_FSDSP_SQSP:
+ if (riscv_cpu_xlen(env) != 128) { /* C.FSDSP (RV32/64) */
+ xinsn = OPC_RISC_FSD;
+ xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
+ access_rs1 = 2;
+ access_imm = GET_C_SDSP_IMM(insn);
+ access_size = 8;
+ }
+ break;
+ case OPC_RISC_C_FUNC_SWSP: /* C.SWSP */
+ xinsn = OPC_RISC_SW;
+ xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
+ access_rs1 = 2;
+ access_imm = GET_C_SWSP_IMM(insn);
+ access_size = 4;
+ break;
+ case 7:
+ if (riscv_cpu_xlen(env) == 32) { /* C.FSWSP (RV32) */
+ xinsn = OPC_RISC_FSW;
+ xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
+ access_rs1 = 2;
+ access_imm = GET_C_SWSP_IMM(insn);
+ access_size = 4;
+ } else { /* C.SDSP (RV64/RV128) */
+ xinsn = OPC_RISC_SD;
+ xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
+ access_rs1 = 2;
+ access_imm = GET_C_SDSP_IMM(insn);
+ access_size = 8;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Clear Bit1 of transformed instruction to indicate that
+ * original insruction was a 16bit instruction
+ */
+ xinsn &= ~((target_ulong)0x2);
+ } else {
+ /* Transform 32bit (or wider) instructions */
+ switch (MASK_OP_MAJOR(insn)) {
+ case OPC_RISC_ATOMIC:
+ xinsn = insn;
+ access_rs1 = GET_RS1(insn);
+ access_size = 1 << GET_FUNCT3(insn);
+ break;
+ case OPC_RISC_LOAD:
+ case OPC_RISC_FP_LOAD:
+ xinsn = SET_I_IMM(insn, 0);
+ access_rs1 = GET_RS1(insn);
+ access_imm = GET_IMM(insn);
+ access_size = 1 << GET_FUNCT3(insn);
+ break;
+ case OPC_RISC_STORE:
+ case OPC_RISC_FP_STORE:
+ xinsn = SET_S_IMM(insn, 0);
+ access_rs1 = GET_RS1(insn);
+ access_imm = GET_STORE_IMM(insn);
+ access_size = 1 << GET_FUNCT3(insn);
+ break;
+ case OPC_RISC_SYSTEM:
+ if (MASK_OP_SYSTEM(insn) == OPC_RISC_HLVHSV) {
+ xinsn = insn;
+ access_rs1 = GET_RS1(insn);
+ access_size = 1 << ((GET_FUNCT7(insn) >> 1) & 0x3);
+ access_size = 1 << access_size;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (access_size) {
+ xinsn = SET_RS1(xinsn, (taddr - (env->gpr[access_rs1] + access_imm)) &
+ (access_size - 1));
+ }
+
+ return xinsn;
+}
#endif /* !CONFIG_USER_ONLY */
/*
@@ -1338,6 +1584,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
uint64_t deleg = async ? env->mideleg : env->medeleg;
target_ulong tval = 0;
+ target_ulong tinst = 0;
target_ulong htval = 0;
target_ulong mtval2 = 0;
@@ -1353,20 +1600,43 @@ void riscv_cpu_do_interrupt(CPUState *cs)
if (!async) {
/* set tval to badaddr for traps with address information */
switch (cause) {
- case RISCV_EXCP_INST_GUEST_PAGE_FAULT:
case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT:
- case RISCV_EXCP_INST_ADDR_MIS:
- case RISCV_EXCP_INST_ACCESS_FAULT:
case RISCV_EXCP_LOAD_ADDR_MIS:
case RISCV_EXCP_STORE_AMO_ADDR_MIS:
case RISCV_EXCP_LOAD_ACCESS_FAULT:
case RISCV_EXCP_STORE_AMO_ACCESS_FAULT:
- case RISCV_EXCP_INST_PAGE_FAULT:
case RISCV_EXCP_LOAD_PAGE_FAULT:
case RISCV_EXCP_STORE_PAGE_FAULT:
write_gva = env->two_stage_lookup;
tval = env->badaddr;
+ if (env->two_stage_indirect_lookup) {
+ /*
+ * special pseudoinstruction for G-stage fault taken while
+ * doing VS-stage page table walk.
+ */
+ tinst = (riscv_cpu_xlen(env) == 32) ? 0x00002000 : 0x00003000;
+ } else {
+ /*
+ * The "Addr. Offset" field in transformed instruction is
+ * non-zero only for misaligned access.
+ */
+ tinst = riscv_transformed_insn(env, env->bins, tval);
+ }
+ break;
+ case RISCV_EXCP_INST_GUEST_PAGE_FAULT:
+ case RISCV_EXCP_INST_ADDR_MIS:
+ case RISCV_EXCP_INST_ACCESS_FAULT:
+ case RISCV_EXCP_INST_PAGE_FAULT:
+ write_gva = env->two_stage_lookup;
+ tval = env->badaddr;
+ if (env->two_stage_indirect_lookup) {
+ /*
+ * special pseudoinstruction for G-stage fault taken while
+ * doing VS-stage page table walk.
+ */
+ tinst = (riscv_cpu_xlen(env) == 32) ? 0x00002000 : 0x00003000;
+ }
break;
case RISCV_EXCP_ILLEGAL_INST:
case RISCV_EXCP_VIRT_INSTRUCTION_FAULT:
@@ -1446,6 +1716,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
env->sepc = env->pc;
env->stval = tval;
env->htval = htval;
+ env->htinst = tinst;
env->pc = (env->stvec >> 2 << 2) +
((async && (env->stvec & 3) == 1) ? cause * 4 : 0);
riscv_cpu_set_mode(env, PRV_S);
@@ -1476,6 +1747,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
env->mepc = env->pc;
env->mtval = tval;
env->mtval2 = mtval2;
+ env->mtinst = tinst;
env->pc = (env->mtvec >> 2 << 2) +
((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
riscv_cpu_set_mode(env, PRV_M);
@@ -1488,6 +1760,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
*/
env->two_stage_lookup = false;
+ env->two_stage_indirect_lookup = false;
#endif
cs->exception_index = RISCV_EXCP_NONE; /* mark handled to qemu */
}
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 235f2a0..b96db1b 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -22,6 +22,7 @@
#include "qemu/timer.h"
#include "cpu.h"
#include "pmu.h"
+#include "time_helper.h"
#include "qemu/main-loop.h"
#include "exec/exec-all.h"
#include "sysemu/cpu-timers.h"
@@ -74,7 +75,8 @@ static RISCVException ctr(CPURISCVState *env, int csrno)
CPUState *cs = env_cpu(env);
RISCVCPU *cpu = RISCV_CPU(cs);
int ctr_index;
- int base_csrno = CSR_HPMCOUNTER3;
+ target_ulong ctr_mask;
+ int base_csrno = CSR_CYCLE;
bool rv32 = riscv_cpu_mxl(env) == MXL_RV32 ? true : false;
if (rv32 && csrno >= CSR_CYCLEH) {
@@ -82,119 +84,29 @@ static RISCVException ctr(CPURISCVState *env, int csrno)
base_csrno += 0x80;
}
ctr_index = csrno - base_csrno;
+ ctr_mask = BIT(ctr_index);
- if (!cpu->cfg.pmu_num || ctr_index >= (cpu->cfg.pmu_num)) {
+ if ((csrno >= CSR_CYCLE && csrno <= CSR_INSTRET) ||
+ (csrno >= CSR_CYCLEH && csrno <= CSR_INSTRETH)) {
+ goto skip_ext_pmu_check;
+ }
+
+ if (!(cpu->pmu_avail_ctrs & ctr_mask)) {
/* No counter is enabled in PMU or the counter is out of range */
return RISCV_EXCP_ILLEGAL_INST;
}
- if (env->priv == PRV_S) {
- switch (csrno) {
- case CSR_CYCLE:
- if (!get_field(env->mcounteren, COUNTEREN_CY)) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
- break;
- case CSR_TIME:
- if (!get_field(env->mcounteren, COUNTEREN_TM)) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
- break;
- case CSR_INSTRET:
- if (!get_field(env->mcounteren, COUNTEREN_IR)) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
- break;
- case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31:
- ctr_index = csrno - CSR_CYCLE;
- if (!get_field(env->mcounteren, 1 << ctr_index)) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
- break;
- }
- if (rv32) {
- switch (csrno) {
- case CSR_CYCLEH:
- if (!get_field(env->mcounteren, COUNTEREN_CY)) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
- break;
- case CSR_TIMEH:
- if (!get_field(env->mcounteren, COUNTEREN_TM)) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
- break;
- case CSR_INSTRETH:
- if (!get_field(env->mcounteren, COUNTEREN_IR)) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
- break;
- case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H:
- ctr_index = csrno - CSR_CYCLEH;
- if (!get_field(env->mcounteren, 1 << ctr_index)) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
- break;
- }
- }
+skip_ext_pmu_check:
+
+ if (((env->priv == PRV_S) && (!get_field(env->mcounteren, ctr_mask))) ||
+ ((env->priv == PRV_U) && (!get_field(env->scounteren, ctr_mask)))) {
+ return RISCV_EXCP_ILLEGAL_INST;
}
if (riscv_cpu_virt_enabled(env)) {
- switch (csrno) {
- case CSR_CYCLE:
- if (!get_field(env->hcounteren, COUNTEREN_CY) &&
- get_field(env->mcounteren, COUNTEREN_CY)) {
- return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
- }
- break;
- case CSR_TIME:
- if (!get_field(env->hcounteren, COUNTEREN_TM) &&
- get_field(env->mcounteren, COUNTEREN_TM)) {
- return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
- }
- break;
- case CSR_INSTRET:
- if (!get_field(env->hcounteren, COUNTEREN_IR) &&
- get_field(env->mcounteren, COUNTEREN_IR)) {
- return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
- }
- break;
- case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31:
- ctr_index = csrno - CSR_CYCLE;
- if (!get_field(env->hcounteren, 1 << ctr_index) &&
- get_field(env->mcounteren, 1 << ctr_index)) {
- return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
- }
- break;
- }
- if (rv32) {
- switch (csrno) {
- case CSR_CYCLEH:
- if (!get_field(env->hcounteren, COUNTEREN_CY) &&
- get_field(env->mcounteren, COUNTEREN_CY)) {
- return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
- }
- break;
- case CSR_TIMEH:
- if (!get_field(env->hcounteren, COUNTEREN_TM) &&
- get_field(env->mcounteren, COUNTEREN_TM)) {
- return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
- }
- break;
- case CSR_INSTRETH:
- if (!get_field(env->hcounteren, COUNTEREN_IR) &&
- get_field(env->mcounteren, COUNTEREN_IR)) {
- return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
- }
- break;
- case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H:
- ctr_index = csrno - CSR_CYCLEH;
- if (!get_field(env->hcounteren, 1 << ctr_index) &&
- get_field(env->mcounteren, 1 << ctr_index)) {
- return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
- }
- break;
- }
+ if (!get_field(env->hcounteren, ctr_mask) &&
+ get_field(env->mcounteren, ctr_mask)) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
}
#endif
@@ -240,6 +152,18 @@ static RISCVException mctr32(CPURISCVState *env, int csrno)
return mctr(env, csrno);
}
+static RISCVException sscofpmf(CPURISCVState *env, int csrno)
+{
+ CPUState *cs = env_cpu(env);
+ RISCVCPU *cpu = RISCV_CPU(cs);
+
+ if (!cpu->cfg.ext_sscofpmf) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
static RISCVException any(CPURISCVState *env, int csrno)
{
return RISCV_EXCP_NONE;
@@ -257,7 +181,9 @@ static RISCVException any32(CPURISCVState *env, int csrno)
static int aia_any(CPURISCVState *env, int csrno)
{
- if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
+ RISCVCPU *cpu = env_archcpu(env);
+
+ if (!cpu->cfg.ext_smaia) {
return RISCV_EXCP_ILLEGAL_INST;
}
@@ -266,7 +192,9 @@ static int aia_any(CPURISCVState *env, int csrno)
static int aia_any32(CPURISCVState *env, int csrno)
{
- if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
+ RISCVCPU *cpu = env_archcpu(env);
+
+ if (!cpu->cfg.ext_smaia) {
return RISCV_EXCP_ILLEGAL_INST;
}
@@ -293,7 +221,9 @@ static int smode32(CPURISCVState *env, int csrno)
static int aia_smode(CPURISCVState *env, int csrno)
{
- if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
+ RISCVCPU *cpu = env_archcpu(env);
+
+ if (!cpu->cfg.ext_ssaia) {
return RISCV_EXCP_ILLEGAL_INST;
}
@@ -302,7 +232,9 @@ static int aia_smode(CPURISCVState *env, int csrno)
static int aia_smode32(CPURISCVState *env, int csrno)
{
- if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
+ RISCVCPU *cpu = env_archcpu(env);
+
+ if (!cpu->cfg.ext_ssaia) {
return RISCV_EXCP_ILLEGAL_INST;
}
@@ -311,15 +243,8 @@ static int aia_smode32(CPURISCVState *env, int csrno)
static RISCVException hmode(CPURISCVState *env, int csrno)
{
- if (riscv_has_ext(env, RVS) &&
- riscv_has_ext(env, RVH)) {
- /* Hypervisor extension is supported */
- if ((env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
- env->priv == PRV_M) {
- return RISCV_EXCP_NONE;
- } else {
- return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
- }
+ if (riscv_has_ext(env, RVH)) {
+ return RISCV_EXCP_NONE;
}
return RISCV_EXCP_ILLEGAL_INST;
@@ -328,17 +253,31 @@ static RISCVException hmode(CPURISCVState *env, int csrno)
static RISCVException hmode32(CPURISCVState *env, int csrno)
{
if (riscv_cpu_mxl(env) != MXL_RV32) {
- if (!riscv_cpu_virt_enabled(env)) {
- return RISCV_EXCP_ILLEGAL_INST;
- } else {
- return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
- }
+ return RISCV_EXCP_ILLEGAL_INST;
}
return hmode(env, csrno);
}
+static RISCVException umode(CPURISCVState *env, int csrno)
+{
+ if (riscv_has_ext(env, RVU)) {
+ return RISCV_EXCP_NONE;
+ }
+
+ return RISCV_EXCP_ILLEGAL_INST;
+}
+
+static RISCVException umode32(CPURISCVState *env, int csrno)
+{
+ if (riscv_cpu_mxl(env) != MXL_RV32) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return umode(env, csrno);
+}
+
/* Checks if PointerMasking registers could be accessed */
static RISCVException pointer_masking(CPURISCVState *env, int csrno)
{
@@ -351,7 +290,9 @@ static RISCVException pointer_masking(CPURISCVState *env, int csrno)
static int aia_hmode(CPURISCVState *env, int csrno)
{
- if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
+ RISCVCPU *cpu = env_archcpu(env);
+
+ if (!cpu->cfg.ext_ssaia) {
return RISCV_EXCP_ILLEGAL_INST;
}
@@ -360,7 +301,9 @@ static int aia_hmode(CPURISCVState *env, int csrno)
static int aia_hmode32(CPURISCVState *env, int csrno)
{
- if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
+ RISCVCPU *cpu = env_archcpu(env);
+
+ if (!cpu->cfg.ext_ssaia) {
return RISCV_EXCP_ILLEGAL_INST;
}
@@ -663,9 +606,39 @@ static int read_mhpmevent(CPURISCVState *env, int csrno, target_ulong *val)
static int write_mhpmevent(CPURISCVState *env, int csrno, target_ulong val)
{
int evt_index = csrno - CSR_MCOUNTINHIBIT;
+ uint64_t mhpmevt_val = val;
env->mhpmevent_val[evt_index] = val;
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ mhpmevt_val = mhpmevt_val |
+ ((uint64_t)env->mhpmeventh_val[evt_index] << 32);
+ }
+ riscv_pmu_update_event_map(env, mhpmevt_val, evt_index);
+
+ return RISCV_EXCP_NONE;
+}
+
+static int read_mhpmeventh(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ int evt_index = csrno - CSR_MHPMEVENT3H + 3;
+
+ *val = env->mhpmeventh_val[evt_index];
+
+ return RISCV_EXCP_NONE;
+}
+
+static int write_mhpmeventh(CPURISCVState *env, int csrno, target_ulong val)
+{
+ int evt_index = csrno - CSR_MHPMEVENT3H + 3;
+ uint64_t mhpmevth_val = val;
+ uint64_t mhpmevt_val = env->mhpmevent_val[evt_index];
+
+ mhpmevt_val = mhpmevt_val | (mhpmevth_val << 32);
+ env->mhpmeventh_val[evt_index] = val;
+
+ riscv_pmu_update_event_map(env, mhpmevt_val, evt_index);
+
return RISCV_EXCP_NONE;
}
@@ -673,12 +646,20 @@ static int write_mhpmcounter(CPURISCVState *env, int csrno, target_ulong val)
{
int ctr_idx = csrno - CSR_MCYCLE;
PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
+ uint64_t mhpmctr_val = val;
counter->mhpmcounter_val = val;
if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) {
counter->mhpmcounter_prev = get_ticks(false);
- } else {
+ if (ctr_idx > 2) {
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ mhpmctr_val = mhpmctr_val |
+ ((uint64_t)counter->mhpmcounterh_val << 32);
+ }
+ riscv_pmu_setup_timer(env, mhpmctr_val, ctr_idx);
+ }
+ } else {
/* Other counters can keep incrementing from the given value */
counter->mhpmcounter_prev = val;
}
@@ -690,11 +671,17 @@ static int write_mhpmcounterh(CPURISCVState *env, int csrno, target_ulong val)
{
int ctr_idx = csrno - CSR_MCYCLEH;
PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
+ uint64_t mhpmctr_val = counter->mhpmcounter_val;
+ uint64_t mhpmctrh_val = val;
counter->mhpmcounterh_val = val;
+ mhpmctr_val = mhpmctr_val | (mhpmctrh_val << 32);
if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) {
counter->mhpmcounterh_prev = get_ticks(true);
+ if (ctr_idx > 2) {
+ riscv_pmu_setup_timer(env, mhpmctr_val, ctr_idx);
+ }
} else {
counter->mhpmcounterh_prev = val;
}
@@ -770,6 +757,32 @@ static int read_hpmcounterh(CPURISCVState *env, int csrno, target_ulong *val)
return riscv_pmu_read_ctr(env, val, true, ctr_index);
}
+static int read_scountovf(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ int mhpmevt_start = CSR_MHPMEVENT3 - CSR_MCOUNTINHIBIT;
+ int i;
+ *val = 0;
+ target_ulong *mhpm_evt_val;
+ uint64_t of_bit_mask;
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ mhpm_evt_val = env->mhpmeventh_val;
+ of_bit_mask = MHPMEVENTH_BIT_OF;
+ } else {
+ mhpm_evt_val = env->mhpmevent_val;
+ of_bit_mask = MHPMEVENT_BIT_OF;
+ }
+
+ for (i = mhpmevt_start; i < RV_MAX_MHPMEVENTS; i++) {
+ if ((get_field(env->mcounteren, BIT(i))) &&
+ (mhpm_evt_val[i] & of_bit_mask)) {
+ *val |= BIT(i);
+ }
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
static RISCVException read_time(CPURISCVState *env, int csrno,
target_ulong *val)
{
@@ -796,10 +809,161 @@ static RISCVException read_timeh(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
+static RISCVException sstc(CPURISCVState *env, int csrno)
+{
+ CPUState *cs = env_cpu(env);
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ bool hmode_check = false;
+
+ if (!cpu->cfg.ext_sstc || !env->rdtime_fn) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ if (env->priv == PRV_M) {
+ return RISCV_EXCP_NONE;
+ }
+
+ /*
+ * No need of separate function for rv32 as menvcfg stores both menvcfg
+ * menvcfgh for RV32.
+ */
+ if (!(get_field(env->mcounteren, COUNTEREN_TM) &&
+ get_field(env->menvcfg, MENVCFG_STCE))) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ if (riscv_cpu_virt_enabled(env)) {
+ if (!(get_field(env->hcounteren, COUNTEREN_TM) &
+ get_field(env->henvcfg, HENVCFG_STCE))) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ }
+
+ if ((csrno == CSR_VSTIMECMP) || (csrno == CSR_VSTIMECMPH)) {
+ hmode_check = true;
+ }
+
+ return hmode_check ? hmode(env, csrno) : smode(env, csrno);
+}
+
+static RISCVException sstc_32(CPURISCVState *env, int csrno)
+{
+ if (riscv_cpu_mxl(env) != MXL_RV32) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return sstc(env, csrno);
+}
+
+static RISCVException read_vstimecmp(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vstimecmp;
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_vstimecmph(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vstimecmp >> 32;
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vstimecmp(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ RISCVCPU *cpu = env_archcpu(env);
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ env->vstimecmp = deposit64(env->vstimecmp, 0, 32, (uint64_t)val);
+ } else {
+ env->vstimecmp = val;
+ }
+
+ riscv_timer_write_timecmp(cpu, env->vstimer, env->vstimecmp,
+ env->htimedelta, MIP_VSTIP);
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vstimecmph(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ RISCVCPU *cpu = env_archcpu(env);
+
+ env->vstimecmp = deposit64(env->vstimecmp, 32, 32, (uint64_t)val);
+ riscv_timer_write_timecmp(cpu, env->vstimer, env->vstimecmp,
+ env->htimedelta, MIP_VSTIP);
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_stimecmp(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ if (riscv_cpu_virt_enabled(env)) {
+ *val = env->vstimecmp;
+ } else {
+ *val = env->stimecmp;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_stimecmph(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ if (riscv_cpu_virt_enabled(env)) {
+ *val = env->vstimecmp >> 32;
+ } else {
+ *val = env->stimecmp >> 32;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_stimecmp(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ RISCVCPU *cpu = env_archcpu(env);
+
+ if (riscv_cpu_virt_enabled(env)) {
+ return write_vstimecmp(env, csrno, val);
+ }
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ env->stimecmp = deposit64(env->stimecmp, 0, 32, (uint64_t)val);
+ } else {
+ env->stimecmp = val;
+ }
+
+ riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP);
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_stimecmph(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ RISCVCPU *cpu = env_archcpu(env);
+
+ if (riscv_cpu_virt_enabled(env)) {
+ return write_vstimecmph(env, csrno, val);
+ }
+
+ env->stimecmp = deposit64(env->stimecmp, 32, 32, (uint64_t)val);
+ riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP);
+
+ return RISCV_EXCP_NONE;
+}
+
/* Machine constants */
#define M_MODE_INTERRUPTS ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
-#define S_MODE_INTERRUPTS ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
+#define S_MODE_INTERRUPTS ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP | \
+ MIP_LCOFIP))
#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
#define HS_MODE_INTERRUPTS ((uint64_t)(MIP_SGEIP | VS_MODE_INTERRUPTS))
@@ -840,7 +1004,8 @@ static const target_ulong vs_delegable_excps = DELEGABLE_EXCPS &
static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
SSTATUS_SUM | SSTATUS_MXR | SSTATUS_VS;
-static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
+static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP |
+ SIP_LCOFIP;
static const target_ulong hip_writable_mask = MIP_VSSIP;
static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
static const target_ulong vsip_writable_mask = MIP_VSSIP;
@@ -1487,10 +1652,6 @@ static RISCVException write_mtvec(CPURISCVState *env, int csrno,
static RISCVException read_mcountinhibit(CPURISCVState *env, int csrno,
target_ulong *val)
{
- if (env->priv_ver < PRIV_VERSION_1_11_0) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
-
*val = env->mcountinhibit;
return RISCV_EXCP_NONE;
}
@@ -1501,10 +1662,6 @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno,
int cidx;
PMUCTRState *counter;
- if (env->priv_ver < PRIV_VERSION_1_11_0) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
-
env->mcountinhibit = val;
/* Check if any other counter is also monitoring cycles/instructions */
@@ -1712,6 +1869,12 @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno,
new_val |= env->external_seip * MIP_SEIP;
}
+ if (cpu->cfg.ext_sstc && (env->priv == PRV_M) &&
+ get_field(env->menvcfg, MENVCFG_STCE)) {
+ /* sstc extension forbids STIP & VSTIP to be writeable in mip */
+ mask = mask & ~(MIP_STIP | MIP_VSTIP);
+ }
+
if (mask) {
old_mip = riscv_cpu_update_mip(cpu, mask, (new_val & mask));
} else {
@@ -1721,6 +1884,7 @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno,
if (csrno != CSR_HVIP) {
gin = get_field(env->hstatus, HSTATUS_VGEIN);
old_mip |= (env->hgeip & ((target_ulong)1 << gin)) ? MIP_VSEIP : 0;
+ old_mip |= env->vstime_irq ? MIP_VSTIP : 0;
}
if (ret_val) {
@@ -3263,16 +3427,38 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
/* check privileges and return RISCV_EXCP_ILLEGAL_INST if check fails */
int read_only = get_field(csrno, 0xC00) == 3;
int csr_min_priv = csr_ops[csrno].min_priv_ver;
+
+ /* ensure the CSR extension is enabled. */
+ if (!cpu->cfg.ext_icsr) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ if (env->priv_ver < csr_min_priv) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ /* check predicate */
+ if (!csr_ops[csrno].predicate) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ if (write_mask && read_only) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ RISCVException ret = csr_ops[csrno].predicate(env, csrno);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
#if !defined(CONFIG_USER_ONLY)
int csr_priv, effective_priv = env->priv;
- if (riscv_has_ext(env, RVH) && env->priv == PRV_S) {
+ if (riscv_has_ext(env, RVH) && env->priv == PRV_S &&
+ !riscv_cpu_virt_enabled(env)) {
/*
- * We are in either HS or VS mode.
- * Add 1 to the effective privledge level to allow us to access the
- * Hypervisor CSRs. The `hmode` predicate will determine if access
- * should be allowed(HS) or if a virtual instruction exception should be
- * raised(VS).
+ * We are in HS mode. Add 1 to the effective privledge level to
+ * allow us to access the Hypervisor CSRs.
*/
effective_priv++;
}
@@ -3285,25 +3471,7 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
return RISCV_EXCP_ILLEGAL_INST;
}
#endif
- if (write_mask && read_only) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
-
- /* ensure the CSR extension is enabled. */
- if (!cpu->cfg.ext_icsr) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
-
- /* check predicate */
- if (!csr_ops[csrno].predicate) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
-
- if (env->priv_ver < csr_min_priv) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
-
- return csr_ops[csrno].predicate(env, csrno);
+ return RISCV_EXCP_NONE;
}
static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno,
@@ -3461,20 +3629,20 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_FRM] = { "frm", fs, read_frm, write_frm },
[CSR_FCSR] = { "fcsr", fs, read_fcsr, write_fcsr },
/* Vector CSRs */
- [CSR_VSTART] = { "vstart", vs, read_vstart, write_vstart,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VCSR] = { "vcsr", vs, read_vcsr, write_vcsr,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VL] = { "vl", vs, read_vl,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VTYPE] = { "vtype", vs, read_vtype,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VLENB] = { "vlenb", vs, read_vlenb,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VSTART] = { "vstart", vs, read_vstart, write_vstart,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VCSR] = { "vcsr", vs, read_vcsr, write_vcsr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VL] = { "vl", vs, read_vl,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VTYPE] = { "vtype", vs, read_vtype,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VLENB] = { "vlenb", vs, read_vlenb,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
/* User Timers and Counters */
[CSR_CYCLE] = { "cycle", ctr, read_hpmcounter },
[CSR_INSTRET] = { "instret", ctr, read_hpmcounter },
@@ -3493,10 +3661,14 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
#if !defined(CONFIG_USER_ONLY)
/* Machine Timers and Counters */
- [CSR_MCYCLE] = { "mcycle", any, read_hpmcounter, write_mhpmcounter},
- [CSR_MINSTRET] = { "minstret", any, read_hpmcounter, write_mhpmcounter},
- [CSR_MCYCLEH] = { "mcycleh", any32, read_hpmcounterh, write_mhpmcounterh},
- [CSR_MINSTRETH] = { "minstreth", any32, read_hpmcounterh, write_mhpmcounterh},
+ [CSR_MCYCLE] = { "mcycle", any, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MINSTRET] = { "minstret", any, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MCYCLEH] = { "mcycleh", any32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MINSTRETH] = { "minstreth", any32, read_hpmcounterh,
+ write_mhpmcounterh },
/* Machine Information Registers */
[CSR_MVENDORID] = { "mvendorid", any, read_mvendorid },
@@ -3505,23 +3677,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_MHARTID] = { "mhartid", any, read_mhartid },
[CSR_MCONFIGPTR] = { "mconfigptr", any, read_zero,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
/* Machine Trap Setup */
- [CSR_MSTATUS] = { "mstatus", any, read_mstatus, write_mstatus, NULL,
- read_mstatus_i128 },
- [CSR_MISA] = { "misa", any, read_misa, write_misa, NULL,
- read_misa_i128 },
- [CSR_MIDELEG] = { "mideleg", any, NULL, NULL, rmw_mideleg },
- [CSR_MEDELEG] = { "medeleg", any, read_medeleg, write_medeleg },
- [CSR_MIE] = { "mie", any, NULL, NULL, rmw_mie },
- [CSR_MTVEC] = { "mtvec", any, read_mtvec, write_mtvec },
- [CSR_MCOUNTEREN] = { "mcounteren", any, read_mcounteren, write_mcounteren },
-
- [CSR_MSTATUSH] = { "mstatush", any32, read_mstatush, write_mstatush },
+ [CSR_MSTATUS] = { "mstatus", any, read_mstatus, write_mstatus,
+ NULL, read_mstatus_i128 },
+ [CSR_MISA] = { "misa", any, read_misa, write_misa,
+ NULL, read_misa_i128 },
+ [CSR_MIDELEG] = { "mideleg", any, NULL, NULL, rmw_mideleg },
+ [CSR_MEDELEG] = { "medeleg", any, read_medeleg, write_medeleg },
+ [CSR_MIE] = { "mie", any, NULL, NULL, rmw_mie },
+ [CSR_MTVEC] = { "mtvec", any, read_mtvec, write_mtvec },
+ [CSR_MCOUNTEREN] = { "mcounteren", umode, read_mcounteren,
+ write_mcounteren },
+
+ [CSR_MSTATUSH] = { "mstatush", any32, read_mstatush,
+ write_mstatush },
/* Machine Trap Handling */
- [CSR_MSCRATCH] = { "mscratch", any, read_mscratch, write_mscratch, NULL,
- read_mscratch_i128, write_mscratch_i128 },
+ [CSR_MSCRATCH] = { "mscratch", any, read_mscratch, write_mscratch,
+ NULL, read_mscratch_i128, write_mscratch_i128 },
[CSR_MEPC] = { "mepc", any, read_mepc, write_mepc },
[CSR_MCAUSE] = { "mcause", any, read_mcause, write_mcause },
[CSR_MTVAL] = { "mtval", any, read_mtval, write_mtval },
@@ -3532,12 +3706,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_MIREG] = { "mireg", aia_any, NULL, NULL, rmw_xireg },
/* Machine-Level Interrupts (AIA) */
- [CSR_MTOPEI] = { "mtopei", aia_any, NULL, NULL, rmw_xtopei },
- [CSR_MTOPI] = { "mtopi", aia_any, read_mtopi },
+ [CSR_MTOPEI] = { "mtopei", aia_any, NULL, NULL, rmw_xtopei },
+ [CSR_MTOPI] = { "mtopi", aia_any, read_mtopi },
/* Virtual Interrupts for Supervisor Level (AIA) */
- [CSR_MVIEN] = { "mvien", aia_any, read_zero, write_ignore },
- [CSR_MVIP] = { "mvip", aia_any, read_zero, write_ignore },
+ [CSR_MVIEN] = { "mvien", aia_any, read_zero, write_ignore },
+ [CSR_MVIP] = { "mvip", aia_any, read_zero, write_ignore },
/* Machine-Level High-Half CSRs (AIA) */
[CSR_MIDELEGH] = { "midelegh", aia_any32, NULL, NULL, rmw_midelegh },
@@ -3547,34 +3721,45 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_MIPH] = { "miph", aia_any32, NULL, NULL, rmw_miph },
/* Execution environment configuration */
- [CSR_MENVCFG] = { "menvcfg", any, read_menvcfg, write_menvcfg,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MENVCFGH] = { "menvcfgh", any32, read_menvcfgh, write_menvcfgh,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MENVCFG] = { "menvcfg", umode, read_menvcfg, write_menvcfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MENVCFGH] = { "menvcfgh", umode32, read_menvcfgh, write_menvcfgh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
[CSR_SENVCFG] = { "senvcfg", smode, read_senvcfg, write_senvcfg,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
[CSR_HENVCFG] = { "henvcfg", hmode, read_henvcfg, write_henvcfg,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
[CSR_HENVCFGH] = { "henvcfgh", hmode32, read_henvcfgh, write_henvcfgh,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
/* Supervisor Trap Setup */
- [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus, NULL,
- read_sstatus_i128 },
- [CSR_SIE] = { "sie", smode, NULL, NULL, rmw_sie },
- [CSR_STVEC] = { "stvec", smode, read_stvec, write_stvec },
- [CSR_SCOUNTEREN] = { "scounteren", smode, read_scounteren, write_scounteren },
+ [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus,
+ NULL, read_sstatus_i128 },
+ [CSR_SIE] = { "sie", smode, NULL, NULL, rmw_sie },
+ [CSR_STVEC] = { "stvec", smode, read_stvec, write_stvec },
+ [CSR_SCOUNTEREN] = { "scounteren", smode, read_scounteren,
+ write_scounteren },
/* Supervisor Trap Handling */
- [CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch, NULL,
- read_sscratch_i128, write_sscratch_i128 },
+ [CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch,
+ NULL, read_sscratch_i128, write_sscratch_i128 },
[CSR_SEPC] = { "sepc", smode, read_sepc, write_sepc },
[CSR_SCAUSE] = { "scause", smode, read_scause, write_scause },
- [CSR_STVAL] = { "stval", smode, read_stval, write_stval },
+ [CSR_STVAL] = { "stval", smode, read_stval, write_stval },
[CSR_SIP] = { "sip", smode, NULL, NULL, rmw_sip },
+ [CSR_STIMECMP] = { "stimecmp", sstc, read_stimecmp, write_stimecmp,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_STIMECMPH] = { "stimecmph", sstc_32, read_stimecmph, write_stimecmph,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VSTIMECMP] = { "vstimecmp", sstc, read_vstimecmp,
+ write_vstimecmp,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VSTIMECMPH] = { "vstimecmph", sstc_32, read_vstimecmph,
+ write_vstimecmph,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
/* Supervisor Protection and Translation */
- [CSR_SATP] = { "satp", smode, read_satp, write_satp },
+ [CSR_SATP] = { "satp", smode, read_satp, write_satp },
/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
[CSR_SISELECT] = { "siselect", aia_smode, NULL, NULL, rmw_xiselect },
@@ -3588,87 +3773,100 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_SIEH] = { "sieh", aia_smode32, NULL, NULL, rmw_sieh },
[CSR_SIPH] = { "siph", aia_smode32, NULL, NULL, rmw_siph },
- [CSR_HSTATUS] = { "hstatus", hmode, read_hstatus, write_hstatus,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_HEDELEG] = { "hedeleg", hmode, read_hedeleg, write_hedeleg,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HSTATUS] = { "hstatus", hmode, read_hstatus, write_hstatus,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HEDELEG] = { "hedeleg", hmode, read_hedeleg, write_hedeleg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
[CSR_HIDELEG] = { "hideleg", hmode, NULL, NULL, rmw_hideleg,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_HVIP] = { "hvip", hmode, NULL, NULL, rmw_hvip,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_HIP] = { "hip", hmode, NULL, NULL, rmw_hip,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_HIE] = { "hie", hmode, NULL, NULL, rmw_hie,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_HCOUNTEREN] = { "hcounteren", hmode, read_hcounteren, write_hcounteren,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_HGEIE] = { "hgeie", hmode, read_hgeie, write_hgeie,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_HTVAL] = { "htval", hmode, read_htval, write_htval,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_HTINST] = { "htinst", hmode, read_htinst, write_htinst,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HVIP] = { "hvip", hmode, NULL, NULL, rmw_hvip,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HIP] = { "hip", hmode, NULL, NULL, rmw_hip,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HIE] = { "hie", hmode, NULL, NULL, rmw_hie,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HCOUNTEREN] = { "hcounteren", hmode, read_hcounteren,
+ write_hcounteren,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HGEIE] = { "hgeie", hmode, read_hgeie, write_hgeie,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HTVAL] = { "htval", hmode, read_htval, write_htval,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HTINST] = { "htinst", hmode, read_htinst, write_htinst,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
[CSR_HGEIP] = { "hgeip", hmode, read_hgeip,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_HGATP] = { "hgatp", hmode, read_hgatp, write_hgatp,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_HTIMEDELTA] = { "htimedelta", hmode, read_htimedelta, write_htimedelta,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_HTIMEDELTAH] = { "htimedeltah", hmode32, read_htimedeltah, write_htimedeltah,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
-
- [CSR_VSSTATUS] = { "vsstatus", hmode, read_vsstatus, write_vsstatus,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VSIP] = { "vsip", hmode, NULL, NULL, rmw_vsip,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VSIE] = { "vsie", hmode, NULL, NULL, rmw_vsie ,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VSTVEC] = { "vstvec", hmode, read_vstvec, write_vstvec,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VSSCRATCH] = { "vsscratch", hmode, read_vsscratch, write_vsscratch,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VSEPC] = { "vsepc", hmode, read_vsepc, write_vsepc,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VSCAUSE] = { "vscause", hmode, read_vscause, write_vscause,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VSTVAL] = { "vstval", hmode, read_vstval, write_vstval,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VSATP] = { "vsatp", hmode, read_vsatp, write_vsatp,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
-
- [CSR_MTVAL2] = { "mtval2", hmode, read_mtval2, write_mtval2,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MTINST] = { "mtinst", hmode, read_mtinst, write_mtinst,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HGATP] = { "hgatp", hmode, read_hgatp, write_hgatp,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HTIMEDELTA] = { "htimedelta", hmode, read_htimedelta,
+ write_htimedelta,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HTIMEDELTAH] = { "htimedeltah", hmode32, read_htimedeltah,
+ write_htimedeltah,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+
+ [CSR_VSSTATUS] = { "vsstatus", hmode, read_vsstatus,
+ write_vsstatus,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VSIP] = { "vsip", hmode, NULL, NULL, rmw_vsip,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VSIE] = { "vsie", hmode, NULL, NULL, rmw_vsie ,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VSTVEC] = { "vstvec", hmode, read_vstvec, write_vstvec,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VSSCRATCH] = { "vsscratch", hmode, read_vsscratch,
+ write_vsscratch,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VSEPC] = { "vsepc", hmode, read_vsepc, write_vsepc,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VSCAUSE] = { "vscause", hmode, read_vscause, write_vscause,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VSTVAL] = { "vstval", hmode, read_vstval, write_vstval,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VSATP] = { "vsatp", hmode, read_vsatp, write_vsatp,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+
+ [CSR_MTVAL2] = { "mtval2", hmode, read_mtval2, write_mtval2,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MTINST] = { "mtinst", hmode, read_mtinst, write_mtinst,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
[CSR_HVIEN] = { "hvien", aia_hmode, read_zero, write_ignore },
- [CSR_HVICTL] = { "hvictl", aia_hmode, read_hvictl, write_hvictl },
- [CSR_HVIPRIO1] = { "hviprio1", aia_hmode, read_hviprio1, write_hviprio1 },
- [CSR_HVIPRIO2] = { "hviprio2", aia_hmode, read_hviprio2, write_hviprio2 },
+ [CSR_HVICTL] = { "hvictl", aia_hmode, read_hvictl,
+ write_hvictl },
+ [CSR_HVIPRIO1] = { "hviprio1", aia_hmode, read_hviprio1,
+ write_hviprio1 },
+ [CSR_HVIPRIO2] = { "hviprio2", aia_hmode, read_hviprio2,
+ write_hviprio2 },
/*
* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA)
*/
- [CSR_VSISELECT] = { "vsiselect", aia_hmode, NULL, NULL, rmw_xiselect },
- [CSR_VSIREG] = { "vsireg", aia_hmode, NULL, NULL, rmw_xireg },
+ [CSR_VSISELECT] = { "vsiselect", aia_hmode, NULL, NULL,
+ rmw_xiselect },
+ [CSR_VSIREG] = { "vsireg", aia_hmode, NULL, NULL, rmw_xireg },
/* VS-Level Interrupts (H-extension with AIA) */
[CSR_VSTOPEI] = { "vstopei", aia_hmode, NULL, NULL, rmw_xtopei },
[CSR_VSTOPI] = { "vstopi", aia_hmode, read_vstopi },
/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
- [CSR_HIDELEGH] = { "hidelegh", aia_hmode32, NULL, NULL, rmw_hidelegh },
- [CSR_HVIENH] = { "hvienh", aia_hmode32, read_zero, write_ignore },
+ [CSR_HIDELEGH] = { "hidelegh", aia_hmode32, NULL, NULL,
+ rmw_hidelegh },
+ [CSR_HVIENH] = { "hvienh", aia_hmode32, read_zero,
+ write_ignore },
[CSR_HVIPH] = { "hviph", aia_hmode32, NULL, NULL, rmw_hviph },
- [CSR_HVIPRIO1H] = { "hviprio1h", aia_hmode32, read_hviprio1h, write_hviprio1h },
- [CSR_HVIPRIO2H] = { "hviprio2h", aia_hmode32, read_hviprio2h, write_hviprio2h },
+ [CSR_HVIPRIO1H] = { "hviprio1h", aia_hmode32, read_hviprio1h,
+ write_hviprio1h },
+ [CSR_HVIPRIO2H] = { "hviprio2h", aia_hmode32, read_hviprio2h,
+ write_hviprio2h },
[CSR_VSIEH] = { "vsieh", aia_hmode32, NULL, NULL, rmw_vsieh },
[CSR_VSIPH] = { "vsiph", aia_hmode32, NULL, NULL, rmw_vsiph },
/* Physical Memory Protection */
[CSR_MSECCFG] = { "mseccfg", epmp, read_mseccfg, write_mseccfg,
- .min_priv_ver = PRIV_VERSION_1_11_0 },
+ .min_priv_ver = PRIV_VERSION_1_11_0 },
[CSR_PMPCFG0] = { "pmpcfg0", pmp, read_pmpcfg, write_pmpcfg },
[CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg },
[CSR_PMPCFG2] = { "pmpcfg2", pmp, read_pmpcfg, write_pmpcfg },
@@ -3697,17 +3895,23 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_TDATA3] = { "tdata3", debug, read_tdata, write_tdata },
/* User Pointer Masking */
- [CSR_UMTE] = { "umte", pointer_masking, read_umte, write_umte },
- [CSR_UPMMASK] = { "upmmask", pointer_masking, read_upmmask, write_upmmask },
- [CSR_UPMBASE] = { "upmbase", pointer_masking, read_upmbase, write_upmbase },
+ [CSR_UMTE] = { "umte", pointer_masking, read_umte, write_umte },
+ [CSR_UPMMASK] = { "upmmask", pointer_masking, read_upmmask,
+ write_upmmask },
+ [CSR_UPMBASE] = { "upmbase", pointer_masking, read_upmbase,
+ write_upmbase },
/* Machine Pointer Masking */
- [CSR_MMTE] = { "mmte", pointer_masking, read_mmte, write_mmte },
- [CSR_MPMMASK] = { "mpmmask", pointer_masking, read_mpmmask, write_mpmmask },
- [CSR_MPMBASE] = { "mpmbase", pointer_masking, read_mpmbase, write_mpmbase },
+ [CSR_MMTE] = { "mmte", pointer_masking, read_mmte, write_mmte },
+ [CSR_MPMMASK] = { "mpmmask", pointer_masking, read_mpmmask,
+ write_mpmmask },
+ [CSR_MPMBASE] = { "mpmbase", pointer_masking, read_mpmbase,
+ write_mpmbase },
/* Supervisor Pointer Masking */
- [CSR_SMTE] = { "smte", pointer_masking, read_smte, write_smte },
- [CSR_SPMMASK] = { "spmmask", pointer_masking, read_spmmask, write_spmmask },
- [CSR_SPMBASE] = { "spmbase", pointer_masking, read_spmbase, write_spmbase },
+ [CSR_SMTE] = { "smte", pointer_masking, read_smte, write_smte },
+ [CSR_SPMMASK] = { "spmmask", pointer_masking, read_spmmask,
+ write_spmmask },
+ [CSR_SPMBASE] = { "spmbase", pointer_masking, read_spmbase,
+ write_spmbase },
/* Performance Counters */
[CSR_HPMCOUNTER3] = { "hpmcounter3", ctr, read_hpmcounter },
@@ -3741,125 +3945,214 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_HPMCOUNTER31] = { "hpmcounter31", ctr, read_hpmcounter },
[CSR_MHPMCOUNTER3] = { "mhpmcounter3", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER4] = { "mhpmcounter4", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER5] = { "mhpmcounter5", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER6] = { "mhpmcounter6", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER7] = { "mhpmcounter7", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER8] = { "mhpmcounter8", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER9] = { "mhpmcounter9", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER10] = { "mhpmcounter10", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER11] = { "mhpmcounter11", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER12] = { "mhpmcounter12", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER13] = { "mhpmcounter13", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER14] = { "mhpmcounter14", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER15] = { "mhpmcounter15", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER16] = { "mhpmcounter16", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER17] = { "mhpmcounter17", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER18] = { "mhpmcounter18", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER19] = { "mhpmcounter19", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER20] = { "mhpmcounter20", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER21] = { "mhpmcounter21", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER22] = { "mhpmcounter22", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER23] = { "mhpmcounter23", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER24] = { "mhpmcounter24", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER25] = { "mhpmcounter25", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER26] = { "mhpmcounter26", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER27] = { "mhpmcounter27", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER28] = { "mhpmcounter28", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER29] = { "mhpmcounter29", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER30] = { "mhpmcounter30", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MHPMCOUNTER31] = { "mhpmcounter31", mctr, read_hpmcounter,
- write_mhpmcounter },
+ write_mhpmcounter },
[CSR_MCOUNTINHIBIT] = { "mcountinhibit", any, read_mcountinhibit,
- write_mcountinhibit, .min_priv_ver = PRIV_VERSION_1_11_0 },
+ write_mcountinhibit,
+ .min_priv_ver = PRIV_VERSION_1_11_0 },
[CSR_MHPMEVENT3] = { "mhpmevent3", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT4] = { "mhpmevent4", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT5] = { "mhpmevent5", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT6] = { "mhpmevent6", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT7] = { "mhpmevent7", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT8] = { "mhpmevent8", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT9] = { "mhpmevent9", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT10] = { "mhpmevent10", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT11] = { "mhpmevent11", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT12] = { "mhpmevent12", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT13] = { "mhpmevent13", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT14] = { "mhpmevent14", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT15] = { "mhpmevent15", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT16] = { "mhpmevent16", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT17] = { "mhpmevent17", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT18] = { "mhpmevent18", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT19] = { "mhpmevent19", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT20] = { "mhpmevent20", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT21] = { "mhpmevent21", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT22] = { "mhpmevent22", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT23] = { "mhpmevent23", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT24] = { "mhpmevent24", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT25] = { "mhpmevent25", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT26] = { "mhpmevent26", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT27] = { "mhpmevent27", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT28] = { "mhpmevent28", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT29] = { "mhpmevent29", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT30] = { "mhpmevent30", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
[CSR_MHPMEVENT31] = { "mhpmevent31", any, read_mhpmevent,
- write_mhpmevent },
+ write_mhpmevent },
+
+ [CSR_MHPMEVENT3H] = { "mhpmevent3h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT4H] = { "mhpmevent4h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT5H] = { "mhpmevent5h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT6H] = { "mhpmevent6h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT7H] = { "mhpmevent7h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT8H] = { "mhpmevent8h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT9H] = { "mhpmevent9h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT10H] = { "mhpmevent10h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT11H] = { "mhpmevent11h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT12H] = { "mhpmevent12h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT13H] = { "mhpmevent13h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT14H] = { "mhpmevent14h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT15H] = { "mhpmevent15h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT16H] = { "mhpmevent16h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT17H] = { "mhpmevent17h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT18H] = { "mhpmevent18h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT19H] = { "mhpmevent19h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT20H] = { "mhpmevent20h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT21H] = { "mhpmevent21h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT22H] = { "mhpmevent22h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT23H] = { "mhpmevent23h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT24H] = { "mhpmevent24h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT25H] = { "mhpmevent25h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT26H] = { "mhpmevent26h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT27H] = { "mhpmevent27h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT28H] = { "mhpmevent28h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT29H] = { "mhpmevent29h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT30H] = { "mhpmevent30h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MHPMEVENT31H] = { "mhpmevent31h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
[CSR_HPMCOUNTER3H] = { "hpmcounter3h", ctr32, read_hpmcounterh },
[CSR_HPMCOUNTER4H] = { "hpmcounter4h", ctr32, read_hpmcounterh },
@@ -3892,62 +4185,65 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_HPMCOUNTER31H] = { "hpmcounter31h", ctr32, read_hpmcounterh },
[CSR_MHPMCOUNTER3H] = { "mhpmcounter3h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER4H] = { "mhpmcounter4h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER5H] = { "mhpmcounter5h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER6H] = { "mhpmcounter6h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER7H] = { "mhpmcounter7h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER8H] = { "mhpmcounter8h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER9H] = { "mhpmcounter9h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER10H] = { "mhpmcounter10h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER11H] = { "mhpmcounter11h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER12H] = { "mhpmcounter12h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER13H] = { "mhpmcounter13h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER14H] = { "mhpmcounter14h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER15H] = { "mhpmcounter15h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER16H] = { "mhpmcounter16h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER17H] = { "mhpmcounter17h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER18H] = { "mhpmcounter18h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER19H] = { "mhpmcounter19h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER20H] = { "mhpmcounter20h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER21H] = { "mhpmcounter21h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER22H] = { "mhpmcounter22h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER23H] = { "mhpmcounter23h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER24H] = { "mhpmcounter24h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER25H] = { "mhpmcounter25h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER26H] = { "mhpmcounter26h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER27H] = { "mhpmcounter27h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER28H] = { "mhpmcounter28h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER29H] = { "mhpmcounter29h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER30H] = { "mhpmcounter30h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
[CSR_MHPMCOUNTER31H] = { "mhpmcounter31h", mctr32, read_hpmcounterh,
- write_mhpmcounterh },
+ write_mhpmcounterh },
+ [CSR_SCOUNTOVF] = { "scountovf", sscofpmf, read_scountovf,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+
#endif /* !CONFIG_USER_ONLY */
};
diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode
index 02c8f61..ccfe59f 100644
--- a/target/riscv/insn16.decode
+++ b/target/riscv/insn16.decode
@@ -31,7 +31,8 @@
%imm_cb 12:s1 5:2 2:1 10:2 3:2 !function=ex_shift_1
%imm_cj 12:s1 8:1 9:2 6:1 7:1 2:1 11:1 3:3 !function=ex_shift_1
-%shimm_6bit 12:1 2:5 !function=ex_rvc_shifti
+%shlimm_6bit 12:1 2:5 !function=ex_rvc_shiftli
+%shrimm_6bit 12:1 2:5 !function=ex_rvc_shiftri
%uimm_6bit_lq 2:4 12:1 6:1 !function=ex_shift_4
%uimm_6bit_ld 2:3 12:1 5:2 !function=ex_shift_3
%uimm_6bit_lw 2:2 12:1 4:3 !function=ex_shift_2
@@ -82,9 +83,9 @@
@c_addi16sp ... . ..... ..... .. &i imm=%imm_addi16sp rs1=2 rd=2
@c_shift ... . .. ... ..... .. \
- &shift rd=%rs1_3 rs1=%rs1_3 shamt=%shimm_6bit
+ &shift rd=%rs1_3 rs1=%rs1_3 shamt=%shrimm_6bit
@c_shift2 ... . .. ... ..... .. \
- &shift rd=%rd rs1=%rd shamt=%shimm_6bit
+ &shift rd=%rd rs1=%rd shamt=%shlimm_6bit
@c_andi ... . .. ... ..... .. &i imm=%imm_ci rs1=%rs1_3 rd=%rs1_3
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 4033565..595fdcd 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -149,7 +149,12 @@ srl 0000000 ..... ..... 101 ..... 0110011 @r
sra 0100000 ..... ..... 101 ..... 0110011 @r
or 0000000 ..... ..... 110 ..... 0110011 @r
and 0000000 ..... ..... 111 ..... 0110011 @r
-fence ---- pred:4 succ:4 ----- 000 ----- 0001111
+
+{
+ pause 0000 0001 0000 00000 000 00000 0001111
+ fence ---- pred:4 succ:4 ----- 000 ----- 0001111
+}
+
fence_i ---- ---- ---- ----- 001 ----- 0001111
csrrw ............ ..... 001 ..... 1110011 @csr
csrrs ............ ..... 010 ..... 1110011 @csr
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
index ca8e3d1..c49dbec 100644
--- a/target/riscv/insn_trans/trans_rvi.c.inc
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -792,6 +792,22 @@ static bool trans_srad(DisasContext *ctx, arg_srad *a)
return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl, NULL);
}
+static bool trans_pause(DisasContext *ctx, arg_pause *a)
+{
+ if (!ctx->cfg_ptr->ext_zihintpause) {
+ return false;
+ }
+
+ /*
+ * PAUSE is a no-op in QEMU,
+ * end the TB and return to main loop
+ */
+ gen_set_pc_imm(ctx, ctx->pc_succ_insn);
+ tcg_gen_exit_tb(NULL, 0);
+ ctx->base.is_jmp = DISAS_NORETURN;
+
+ return true;
+}
static bool trans_fence(DisasContext *ctx, arg_fence *a)
{
diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc
index 6c09182..e58208f 100644
--- a/target/riscv/insn_trans/trans_rvv.c.inc
+++ b/target/riscv/insn_trans/trans_rvv.c.inc
@@ -712,6 +712,7 @@ static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew)
data = FIELD_DP32(data, VDATA, LMUL, emul);
data = FIELD_DP32(data, VDATA, NF, a->nf);
data = FIELD_DP32(data, VDATA, VTA, s->vta);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
return ldst_us_trans(a->rd, a->rs1, data, fn, s, false);
}
@@ -777,6 +778,7 @@ static bool ld_us_mask_op(DisasContext *s, arg_vlm_v *a, uint8_t eew)
data = FIELD_DP32(data, VDATA, NF, 1);
/* Mask destination register are always tail-agnostic */
data = FIELD_DP32(data, VDATA, VTA, s->cfg_vta_all_1s);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
return ldst_us_trans(a->rd, a->rs1, data, fn, s, false);
}
@@ -866,6 +868,7 @@ static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew)
data = FIELD_DP32(data, VDATA, LMUL, emul);
data = FIELD_DP32(data, VDATA, NF, a->nf);
data = FIELD_DP32(data, VDATA, VTA, s->vta);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, false);
}
@@ -996,6 +999,7 @@ static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew)
data = FIELD_DP32(data, VDATA, LMUL, emul);
data = FIELD_DP32(data, VDATA, NF, a->nf);
data = FIELD_DP32(data, VDATA, VTA, s->vta);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, false);
}
@@ -1114,6 +1118,7 @@ static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew)
data = FIELD_DP32(data, VDATA, LMUL, emul);
data = FIELD_DP32(data, VDATA, NF, a->nf);
data = FIELD_DP32(data, VDATA, VTA, s->vta);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
return ldff_trans(a->rd, a->rs1, data, fn, s);
}
@@ -1247,6 +1252,7 @@ do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn,
data = FIELD_DP32(data, VDATA, VM, a->vm);
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
data = FIELD_DP32(data, VDATA, VTA, s->vta);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
cpu_env, s->cfg_ptr->vlen / 8,
@@ -1295,6 +1301,7 @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
data = FIELD_DP32(data, VDATA, VTA, s->vta);
data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
s->cfg_ptr->vlen / 8, data));
@@ -1462,6 +1469,7 @@ static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
data = FIELD_DP32(data, VDATA, VTA, s->vta);
data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
s->cfg_ptr->vlen / 8, data));
@@ -1545,6 +1553,7 @@ static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
data = FIELD_DP32(data, VDATA, VM, a->vm);
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
data = FIELD_DP32(data, VDATA, VTA, s->vta);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
vreg_ofs(s, a->rs1),
vreg_ofs(s, a->rs2),
@@ -1627,6 +1636,7 @@ static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a,
data = FIELD_DP32(data, VDATA, VM, a->vm);
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
data = FIELD_DP32(data, VDATA, VTA, s->vta);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
vreg_ofs(s, a->rs1),
vreg_ofs(s, a->rs2),
@@ -1708,6 +1718,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
data = \
FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\
+ data = FIELD_DP32(data, VDATA, VMA, s->vma); \
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
vreg_ofs(s, a->rs1), \
vreg_ofs(s, a->rs2), cpu_env, \
@@ -1891,6 +1902,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
data = FIELD_DP32(data, VDATA, VM, a->vm); \
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
+ data = FIELD_DP32(data, VDATA, VMA, s->vma); \
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
vreg_ofs(s, a->rs1), \
vreg_ofs(s, a->rs2), cpu_env, \
@@ -2349,6 +2361,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
data = \
FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\
+ data = FIELD_DP32(data, VDATA, VMA, s->vma); \
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
vreg_ofs(s, a->rs1), \
vreg_ofs(s, a->rs2), cpu_env, \
@@ -2434,6 +2447,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
data = FIELD_DP32(data, VDATA, VTA_ALL_1S, \
s->cfg_vta_all_1s); \
+ data = FIELD_DP32(data, VDATA, VMA, s->vma); \
return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
fns[s->sew - 1], s); \
} \
@@ -2473,6 +2487,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
data = FIELD_DP32(data, VDATA, VM, a->vm); \
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
+ data = FIELD_DP32(data, VDATA, VMA, s->vma); \
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
vreg_ofs(s, a->rs1), \
vreg_ofs(s, a->rs2), cpu_env, \
@@ -2513,6 +2528,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
data = FIELD_DP32(data, VDATA, VM, a->vm); \
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
+ data = FIELD_DP32(data, VDATA, VMA, s->vma); \
return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
fns[s->sew - 1], s); \
} \
@@ -2550,6 +2566,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
data = FIELD_DP32(data, VDATA, VM, a->vm); \
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
+ data = FIELD_DP32(data, VDATA, VMA, s->vma); \
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
vreg_ofs(s, a->rs1), \
vreg_ofs(s, a->rs2), cpu_env, \
@@ -2590,6 +2607,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
data = FIELD_DP32(data, VDATA, VM, a->vm); \
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
+ data = FIELD_DP32(data, VDATA, VMA, s->vma); \
return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
fns[s->sew - 1], s); \
} \
@@ -2674,6 +2692,7 @@ static bool do_opfv(DisasContext *s, arg_rmr *a,
data = FIELD_DP32(data, VDATA, VM, a->vm);
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
data = FIELD_DP32(data, VDATA, VTA, s->vta);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
vreg_ofs(s, a->rs2), cpu_env,
s->cfg_ptr->vlen / 8,
@@ -2778,6 +2797,7 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
TCGv_i32 desc;
uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
data = FIELD_DP32(data, VDATA, VTA, s->vta);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
static gen_helper_vmv_vx * const fns[3] = {
gen_helper_vmv_v_x_h,
gen_helper_vmv_v_x_w,
@@ -2879,6 +2899,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
data = FIELD_DP32(data, VDATA, VM, a->vm); \
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
+ data = FIELD_DP32(data, VDATA, VMA, s->vma); \
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
vreg_ofs(s, a->rs2), cpu_env, \
s->cfg_ptr->vlen / 8, \
@@ -2932,6 +2953,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
data = FIELD_DP32(data, VDATA, VM, a->vm); \
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
+ data = FIELD_DP32(data, VDATA, VMA, s->vma); \
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
vreg_ofs(s, a->rs2), cpu_env, \
s->cfg_ptr->vlen / 8, \
@@ -3000,6 +3022,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
data = FIELD_DP32(data, VDATA, VM, a->vm); \
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
+ data = FIELD_DP32(data, VDATA, VMA, s->vma); \
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
vreg_ofs(s, a->rs2), cpu_env, \
s->cfg_ptr->vlen / 8, \
@@ -3055,6 +3078,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
data = FIELD_DP32(data, VDATA, VM, a->vm); \
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
data = FIELD_DP32(data, VDATA, VTA, s->vta); \
+ data = FIELD_DP32(data, VDATA, VMA, s->vma); \
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
vreg_ofs(s, a->rs2), cpu_env, \
s->cfg_ptr->vlen / 8, \
@@ -3251,6 +3275,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
data = \
FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\
+ data = FIELD_DP32(data, VDATA, VMA, s->vma); \
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \
vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \
cpu_env, s->cfg_ptr->vlen / 8, \
@@ -3289,6 +3314,7 @@ static bool trans_viota_m(DisasContext *s, arg_viota_m *a)
data = FIELD_DP32(data, VDATA, VM, a->vm);
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
data = FIELD_DP32(data, VDATA, VTA, s->vta);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
static gen_helper_gvec_3_ptr * const fns[4] = {
gen_helper_viota_m_b, gen_helper_viota_m_h,
gen_helper_viota_m_w, gen_helper_viota_m_d,
@@ -3319,6 +3345,7 @@ static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
data = FIELD_DP32(data, VDATA, VM, a->vm);
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
data = FIELD_DP32(data, VDATA, VTA, s->vta);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
static gen_helper_gvec_2_ptr * const fns[4] = {
gen_helper_vid_v_b, gen_helper_vid_v_h,
gen_helper_vid_v_w, gen_helper_vid_v_d,
@@ -3864,6 +3891,7 @@ static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq)
data = FIELD_DP32(data, VDATA, VM, a->vm);
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
data = FIELD_DP32(data, VDATA, VTA, s->vta);
+ data = FIELD_DP32(data, VDATA, VMA, s->vma);
tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
vreg_ofs(s, a->rs2), cpu_env,
diff --git a/target/riscv/instmap.h b/target/riscv/instmap.h
index 40b6d2b..f877530 100644
--- a/target/riscv/instmap.h
+++ b/target/riscv/instmap.h
@@ -184,6 +184,8 @@ enum {
OPC_RISC_CSRRWI = OPC_RISC_SYSTEM | (0x5 << 12),
OPC_RISC_CSRRSI = OPC_RISC_SYSTEM | (0x6 << 12),
OPC_RISC_CSRRCI = OPC_RISC_SYSTEM | (0x7 << 12),
+
+ OPC_RISC_HLVHSV = OPC_RISC_SYSTEM | (0x4 << 12),
};
#define MASK_OP_FP_LOAD(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
@@ -310,12 +312,20 @@ enum {
| (extract32(inst, 12, 8) << 12) \
| (sextract64(inst, 31, 1) << 20))
+#define GET_FUNCT3(inst) extract32(inst, 12, 3)
+#define GET_FUNCT7(inst) extract32(inst, 25, 7)
#define GET_RM(inst) extract32(inst, 12, 3)
#define GET_RS3(inst) extract32(inst, 27, 5)
#define GET_RS1(inst) extract32(inst, 15, 5)
#define GET_RS2(inst) extract32(inst, 20, 5)
#define GET_RD(inst) extract32(inst, 7, 5)
#define GET_IMM(inst) sextract64(inst, 20, 12)
+#define SET_RS1(inst, val) deposit32(inst, 15, 5, val)
+#define SET_RS2(inst, val) deposit32(inst, 20, 5, val)
+#define SET_RD(inst, val) deposit32(inst, 7, 5, val)
+#define SET_I_IMM(inst, val) deposit32(inst, 20, 12, val)
+#define SET_S_IMM(inst, val) \
+ deposit32(deposit32(inst, 7, 5, val), 25, 7, (val) >> 5)
/* RVC decoding macros */
#define GET_C_IMM(inst) (extract32(inst, 2, 5) \
@@ -346,6 +356,8 @@ enum {
| (extract32(inst, 5, 1) << 6))
#define GET_C_LD_IMM(inst) ((extract16(inst, 10, 3) << 3) \
| (extract16(inst, 5, 2) << 6))
+#define GET_C_SW_IMM(inst) GET_C_LW_IMM(inst)
+#define GET_C_SD_IMM(inst) GET_C_LD_IMM(inst)
#define GET_C_J_IMM(inst) ((extract32(inst, 3, 3) << 1) \
| (extract32(inst, 11, 1) << 4) \
| (extract32(inst, 2, 1) << 5) \
@@ -366,4 +378,37 @@ enum {
#define GET_C_RS1S(inst) (8 + extract16(inst, 7, 3))
#define GET_C_RS2S(inst) (8 + extract16(inst, 2, 3))
+#define GET_C_FUNC(inst) extract32(inst, 13, 3)
+#define GET_C_OP(inst) extract32(inst, 0, 2)
+
+enum {
+ /* RVC Quadrants */
+ OPC_RISC_C_OP_QUAD0 = 0x0,
+ OPC_RISC_C_OP_QUAD1 = 0x1,
+ OPC_RISC_C_OP_QUAD2 = 0x2
+};
+
+enum {
+ /* RVC Quadrant 0 */
+ OPC_RISC_C_FUNC_ADDI4SPN = 0x0,
+ OPC_RISC_C_FUNC_FLD_LQ = 0x1,
+ OPC_RISC_C_FUNC_LW = 0x2,
+ OPC_RISC_C_FUNC_FLW_LD = 0x3,
+ OPC_RISC_C_FUNC_FSD_SQ = 0x5,
+ OPC_RISC_C_FUNC_SW = 0x6,
+ OPC_RISC_C_FUNC_FSW_SD = 0x7
+};
+
+enum {
+ /* RVC Quadrant 2 */
+ OPC_RISC_C_FUNC_SLLI_SLLI64 = 0x0,
+ OPC_RISC_C_FUNC_FLDSP_LQSP = 0x1,
+ OPC_RISC_C_FUNC_LWSP = 0x2,
+ OPC_RISC_C_FUNC_FLWSP_LDSP = 0x3,
+ OPC_RISC_C_FUNC_JR_MV_EBREAK_JALR_ADD = 0x4,
+ OPC_RISC_C_FUNC_FSDSP_SQSP = 0x5,
+ OPC_RISC_C_FUNC_SWSP = 0x6,
+ OPC_RISC_C_FUNC_FSWSP_SDSP = 0x7
+};
+
#endif
diff --git a/target/riscv/internals.h b/target/riscv/internals.h
index 193ce57..5620fbf 100644
--- a/target/riscv/internals.h
+++ b/target/riscv/internals.h
@@ -26,8 +26,9 @@ FIELD(VDATA, VM, 0, 1)
FIELD(VDATA, LMUL, 1, 3)
FIELD(VDATA, VTA, 4, 1)
FIELD(VDATA, VTA_ALL_1S, 5, 1)
-FIELD(VDATA, NF, 6, 4)
-FIELD(VDATA, WD, 6, 1)
+FIELD(VDATA, VMA, 6, 1)
+FIELD(VDATA, NF, 7, 4)
+FIELD(VDATA, WD, 7, 1)
/* float point classify helpers */
target_ulong fclass_h(uint64_t frs1);
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index dc182ca..41098f6 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -92,6 +92,7 @@ static const VMStateDescription vmstate_hyper = {
VMSTATE_UINTTL(env.hgeie, RISCVCPU),
VMSTATE_UINTTL(env.hgeip, RISCVCPU),
VMSTATE_UINT64(env.htimedelta, RISCVCPU),
+ VMSTATE_UINT64(env.vstimecmp, RISCVCPU),
VMSTATE_UINTTL(env.hvictl, RISCVCPU),
VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64),
@@ -307,8 +308,8 @@ static const VMStateDescription vmstate_pmu_ctr_state = {
const VMStateDescription vmstate_riscv_cpu = {
.name = "cpu",
- .version_id = 3,
- .minimum_version_id = 3,
+ .version_id = 4,
+ .minimum_version_id = 4,
.post_load = riscv_cpu_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
@@ -355,11 +356,12 @@ const VMStateDescription vmstate_riscv_cpu = {
VMSTATE_STRUCT_ARRAY(env.pmu_ctrs, RISCVCPU, RV_MAX_MHPMCOUNTERS, 0,
vmstate_pmu_ctr_state, PMUCTRState),
VMSTATE_UINTTL_ARRAY(env.mhpmevent_val, RISCVCPU, RV_MAX_MHPMEVENTS),
+ VMSTATE_UINTTL_ARRAY(env.mhpmeventh_val, RISCVCPU, RV_MAX_MHPMEVENTS),
VMSTATE_UINTTL(env.sscratch, RISCVCPU),
VMSTATE_UINTTL(env.mscratch, RISCVCPU),
VMSTATE_UINT64(env.mfromhost, RISCVCPU),
VMSTATE_UINT64(env.mtohost, RISCVCPU),
- VMSTATE_UINT64(env.timecmp, RISCVCPU),
+ VMSTATE_UINT64(env.stimecmp, RISCVCPU),
VMSTATE_END_OF_LIST()
},
diff --git a/target/riscv/meson.build b/target/riscv/meson.build
index 6b9435d..ba25164 100644
--- a/target/riscv/meson.build
+++ b/target/riscv/meson.build
@@ -29,7 +29,8 @@ riscv_softmmu_ss.add(files(
'debug.c',
'monitor.c',
'machine.c',
- 'pmu.c'
+ 'pmu.c',
+ 'time_helper.c'
))
target_arch += {'riscv': riscv_ss}
diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c
index 000fe8d..b8e56d2 100644
--- a/target/riscv/pmu.c
+++ b/target/riscv/pmu.c
@@ -19,14 +19,435 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "pmu.h"
+#include "sysemu/cpu-timers.h"
+#include "sysemu/device_tree.h"
+
+#define RISCV_TIMEBASE_FREQ 1000000000 /* 1Ghz */
+#define MAKE_32BIT_MASK(shift, length) \
+ (((uint32_t)(~0UL) >> (32 - (length))) << (shift))
+
+/*
+ * To keep it simple, any event can be mapped to any programmable counters in
+ * QEMU. The generic cycle & instruction count events can also be monitored
+ * using programmable counters. In that case, mcycle & minstret must continue
+ * to provide the correct value as well. Heterogeneous PMU per hart is not
+ * supported yet. Thus, number of counters are same across all harts.
+ */
+void riscv_pmu_generate_fdt_node(void *fdt, int num_ctrs, char *pmu_name)
+{
+ uint32_t fdt_event_ctr_map[20] = {};
+ uint32_t cmask;
+
+ /* All the programmable counters can map to any event */
+ cmask = MAKE_32BIT_MASK(3, num_ctrs);
+
+ /*
+ * The event encoding is specified in the SBI specification
+ * Event idx is a 20bits wide number encoded as follows:
+ * event_idx[19:16] = type
+ * event_idx[15:0] = code
+ * The code field in cache events are encoded as follows:
+ * event_idx.code[15:3] = cache_id
+ * event_idx.code[2:1] = op_id
+ * event_idx.code[0:0] = result_id
+ */
+
+ /* SBI_PMU_HW_CPU_CYCLES: 0x01 : type(0x00) */
+ fdt_event_ctr_map[0] = cpu_to_be32(0x00000001);
+ fdt_event_ctr_map[1] = cpu_to_be32(0x00000001);
+ fdt_event_ctr_map[2] = cpu_to_be32(cmask | 1 << 0);
+
+ /* SBI_PMU_HW_INSTRUCTIONS: 0x02 : type(0x00) */
+ fdt_event_ctr_map[3] = cpu_to_be32(0x00000002);
+ fdt_event_ctr_map[4] = cpu_to_be32(0x00000002);
+ fdt_event_ctr_map[5] = cpu_to_be32(cmask | 1 << 2);
+
+ /* SBI_PMU_HW_CACHE_DTLB : 0x03 READ : 0x00 MISS : 0x00 type(0x01) */
+ fdt_event_ctr_map[6] = cpu_to_be32(0x00010019);
+ fdt_event_ctr_map[7] = cpu_to_be32(0x00010019);
+ fdt_event_ctr_map[8] = cpu_to_be32(cmask);
+
+ /* SBI_PMU_HW_CACHE_DTLB : 0x03 WRITE : 0x01 MISS : 0x00 type(0x01) */
+ fdt_event_ctr_map[9] = cpu_to_be32(0x0001001B);
+ fdt_event_ctr_map[10] = cpu_to_be32(0x0001001B);
+ fdt_event_ctr_map[11] = cpu_to_be32(cmask);
+
+ /* SBI_PMU_HW_CACHE_ITLB : 0x04 READ : 0x00 MISS : 0x00 type(0x01) */
+ fdt_event_ctr_map[12] = cpu_to_be32(0x00010021);
+ fdt_event_ctr_map[13] = cpu_to_be32(0x00010021);
+ fdt_event_ctr_map[14] = cpu_to_be32(cmask);
+
+ /* This a OpenSBI specific DT property documented in OpenSBI docs */
+ qemu_fdt_setprop(fdt, pmu_name, "riscv,event-to-mhpmcounters",
+ fdt_event_ctr_map, sizeof(fdt_event_ctr_map));
+}
+
+static bool riscv_pmu_counter_valid(RISCVCPU *cpu, uint32_t ctr_idx)
+{
+ if (ctr_idx < 3 || ctr_idx >= RV_MAX_MHPMCOUNTERS ||
+ !(cpu->pmu_avail_ctrs & BIT(ctr_idx))) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+static bool riscv_pmu_counter_enabled(RISCVCPU *cpu, uint32_t ctr_idx)
+{
+ CPURISCVState *env = &cpu->env;
+
+ if (riscv_pmu_counter_valid(cpu, ctr_idx) &&
+ !get_field(env->mcountinhibit, BIT(ctr_idx))) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static int riscv_pmu_incr_ctr_rv32(RISCVCPU *cpu, uint32_t ctr_idx)
+{
+ CPURISCVState *env = &cpu->env;
+ target_ulong max_val = UINT32_MAX;
+ PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
+ bool virt_on = riscv_cpu_virt_enabled(env);
+
+ /* Privilege mode filtering */
+ if ((env->priv == PRV_M &&
+ (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_MINH)) ||
+ (env->priv == PRV_S && virt_on &&
+ (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_VSINH)) ||
+ (env->priv == PRV_U && virt_on &&
+ (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_VUINH)) ||
+ (env->priv == PRV_S && !virt_on &&
+ (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_SINH)) ||
+ (env->priv == PRV_U && !virt_on &&
+ (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_UINH))) {
+ return 0;
+ }
+
+ /* Handle the overflow scenario */
+ if (counter->mhpmcounter_val == max_val) {
+ if (counter->mhpmcounterh_val == max_val) {
+ counter->mhpmcounter_val = 0;
+ counter->mhpmcounterh_val = 0;
+ /* Generate interrupt only if OF bit is clear */
+ if (!(env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_OF)) {
+ env->mhpmeventh_val[ctr_idx] |= MHPMEVENTH_BIT_OF;
+ riscv_cpu_update_mip(cpu, MIP_LCOFIP, BOOL_TO_MASK(1));
+ }
+ } else {
+ counter->mhpmcounterh_val++;
+ }
+ } else {
+ counter->mhpmcounter_val++;
+ }
+
+ return 0;
+}
+
+static int riscv_pmu_incr_ctr_rv64(RISCVCPU *cpu, uint32_t ctr_idx)
+{
+ CPURISCVState *env = &cpu->env;
+ PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
+ uint64_t max_val = UINT64_MAX;
+ bool virt_on = riscv_cpu_virt_enabled(env);
+
+ /* Privilege mode filtering */
+ if ((env->priv == PRV_M &&
+ (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_MINH)) ||
+ (env->priv == PRV_S && virt_on &&
+ (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VSINH)) ||
+ (env->priv == PRV_U && virt_on &&
+ (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VUINH)) ||
+ (env->priv == PRV_S && !virt_on &&
+ (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_SINH)) ||
+ (env->priv == PRV_U && !virt_on &&
+ (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_UINH))) {
+ return 0;
+ }
+
+ /* Handle the overflow scenario */
+ if (counter->mhpmcounter_val == max_val) {
+ counter->mhpmcounter_val = 0;
+ /* Generate interrupt only if OF bit is clear */
+ if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) {
+ env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF;
+ riscv_cpu_update_mip(cpu, MIP_LCOFIP, BOOL_TO_MASK(1));
+ }
+ } else {
+ counter->mhpmcounter_val++;
+ }
+ return 0;
+}
+
+int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx)
+{
+ uint32_t ctr_idx;
+ int ret;
+ CPURISCVState *env = &cpu->env;
+ gpointer value;
+
+ if (!cpu->cfg.pmu_num) {
+ return 0;
+ }
+ value = g_hash_table_lookup(cpu->pmu_event_ctr_map,
+ GUINT_TO_POINTER(event_idx));
+ if (!value) {
+ return -1;
+ }
+
+ ctr_idx = GPOINTER_TO_UINT(value);
+ if (!riscv_pmu_counter_enabled(cpu, ctr_idx) ||
+ get_field(env->mcountinhibit, BIT(ctr_idx))) {
+ return -1;
+ }
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ ret = riscv_pmu_incr_ctr_rv32(cpu, ctr_idx);
+ } else {
+ ret = riscv_pmu_incr_ctr_rv64(cpu, ctr_idx);
+ }
+
+ return ret;
+}
bool riscv_pmu_ctr_monitor_instructions(CPURISCVState *env,
uint32_t target_ctr)
{
- return (target_ctr == 0) ? true : false;
+ RISCVCPU *cpu;
+ uint32_t event_idx;
+ uint32_t ctr_idx;
+
+ /* Fixed instret counter */
+ if (target_ctr == 2) {
+ return true;
+ }
+
+ cpu = RISCV_CPU(env_cpu(env));
+ if (!cpu->pmu_event_ctr_map) {
+ return false;
+ }
+
+ event_idx = RISCV_PMU_EVENT_HW_INSTRUCTIONS;
+ ctr_idx = GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_map,
+ GUINT_TO_POINTER(event_idx)));
+ if (!ctr_idx) {
+ return false;
+ }
+
+ return target_ctr == ctr_idx ? true : false;
}
bool riscv_pmu_ctr_monitor_cycles(CPURISCVState *env, uint32_t target_ctr)
{
- return (target_ctr == 2) ? true : false;
+ RISCVCPU *cpu;
+ uint32_t event_idx;
+ uint32_t ctr_idx;
+
+ /* Fixed mcycle counter */
+ if (target_ctr == 0) {
+ return true;
+ }
+
+ cpu = RISCV_CPU(env_cpu(env));
+ if (!cpu->pmu_event_ctr_map) {
+ return false;
+ }
+
+ event_idx = RISCV_PMU_EVENT_HW_CPU_CYCLES;
+ ctr_idx = GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_map,
+ GUINT_TO_POINTER(event_idx)));
+
+ /* Counter zero is not used for event_ctr_map */
+ if (!ctr_idx) {
+ return false;
+ }
+
+ return (target_ctr == ctr_idx) ? true : false;
+}
+
+static gboolean pmu_remove_event_map(gpointer key, gpointer value,
+ gpointer udata)
+{
+ return (GPOINTER_TO_UINT(value) == GPOINTER_TO_UINT(udata)) ? true : false;
+}
+
+static int64_t pmu_icount_ticks_to_ns(int64_t value)
+{
+ int64_t ret = 0;
+
+ if (icount_enabled()) {
+ ret = icount_to_ns(value);
+ } else {
+ ret = (NANOSECONDS_PER_SECOND / RISCV_TIMEBASE_FREQ) * value;
+ }
+
+ return ret;
+}
+
+int riscv_pmu_update_event_map(CPURISCVState *env, uint64_t value,
+ uint32_t ctr_idx)
+{
+ uint32_t event_idx;
+ RISCVCPU *cpu = RISCV_CPU(env_cpu(env));
+
+ if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->pmu_event_ctr_map) {
+ return -1;
+ }
+
+ /*
+ * Expected mhpmevent value is zero for reset case. Remove the current
+ * mapping.
+ */
+ if (!value) {
+ g_hash_table_foreach_remove(cpu->pmu_event_ctr_map,
+ pmu_remove_event_map,
+ GUINT_TO_POINTER(ctr_idx));
+ return 0;
+ }
+
+ event_idx = value & MHPMEVENT_IDX_MASK;
+ if (g_hash_table_lookup(cpu->pmu_event_ctr_map,
+ GUINT_TO_POINTER(event_idx))) {
+ return 0;
+ }
+
+ switch (event_idx) {
+ case RISCV_PMU_EVENT_HW_CPU_CYCLES:
+ case RISCV_PMU_EVENT_HW_INSTRUCTIONS:
+ case RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS:
+ case RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS:
+ case RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS:
+ break;
+ default:
+ /* We don't support any raw events right now */
+ return -1;
+ }
+ g_hash_table_insert(cpu->pmu_event_ctr_map, GUINT_TO_POINTER(event_idx),
+ GUINT_TO_POINTER(ctr_idx));
+
+ return 0;
+}
+
+static void pmu_timer_trigger_irq(RISCVCPU *cpu,
+ enum riscv_pmu_event_idx evt_idx)
+{
+ uint32_t ctr_idx;
+ CPURISCVState *env = &cpu->env;
+ PMUCTRState *counter;
+ target_ulong *mhpmevent_val;
+ uint64_t of_bit_mask;
+ int64_t irq_trigger_at;
+
+ if (evt_idx != RISCV_PMU_EVENT_HW_CPU_CYCLES &&
+ evt_idx != RISCV_PMU_EVENT_HW_INSTRUCTIONS) {
+ return;
+ }
+
+ ctr_idx = GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_map,
+ GUINT_TO_POINTER(evt_idx)));
+ if (!riscv_pmu_counter_enabled(cpu, ctr_idx)) {
+ return;
+ }
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ mhpmevent_val = &env->mhpmeventh_val[ctr_idx];
+ of_bit_mask = MHPMEVENTH_BIT_OF;
+ } else {
+ mhpmevent_val = &env->mhpmevent_val[ctr_idx];
+ of_bit_mask = MHPMEVENT_BIT_OF;
+ }
+
+ counter = &env->pmu_ctrs[ctr_idx];
+ if (counter->irq_overflow_left > 0) {
+ irq_trigger_at = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ counter->irq_overflow_left;
+ timer_mod_anticipate_ns(cpu->pmu_timer, irq_trigger_at);
+ counter->irq_overflow_left = 0;
+ return;
+ }
+
+ if (cpu->pmu_avail_ctrs & BIT(ctr_idx)) {
+ /* Generate interrupt only if OF bit is clear */
+ if (!(*mhpmevent_val & of_bit_mask)) {
+ *mhpmevent_val |= of_bit_mask;
+ riscv_cpu_update_mip(cpu, MIP_LCOFIP, BOOL_TO_MASK(1));
+ }
+ }
+}
+
+/* Timer callback for instret and cycle counter overflow */
+void riscv_pmu_timer_cb(void *priv)
+{
+ RISCVCPU *cpu = priv;
+
+ /* Timer event was triggered only for these events */
+ pmu_timer_trigger_irq(cpu, RISCV_PMU_EVENT_HW_CPU_CYCLES);
+ pmu_timer_trigger_irq(cpu, RISCV_PMU_EVENT_HW_INSTRUCTIONS);
+}
+
+int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr_idx)
+{
+ uint64_t overflow_delta, overflow_at;
+ int64_t overflow_ns, overflow_left = 0;
+ RISCVCPU *cpu = RISCV_CPU(env_cpu(env));
+ PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
+
+ if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->cfg.ext_sscofpmf) {
+ return -1;
+ }
+
+ if (value) {
+ overflow_delta = UINT64_MAX - value + 1;
+ } else {
+ overflow_delta = UINT64_MAX;
+ }
+
+ /*
+ * QEMU supports only int64_t timers while RISC-V counters are uint64_t.
+ * Compute the leftover and save it so that it can be reprogrammed again
+ * when timer expires.
+ */
+ if (overflow_delta > INT64_MAX) {
+ overflow_left = overflow_delta - INT64_MAX;
+ }
+
+ if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
+ riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) {
+ overflow_ns = pmu_icount_ticks_to_ns((int64_t)overflow_delta);
+ overflow_left = pmu_icount_ticks_to_ns(overflow_left) ;
+ } else {
+ return -1;
+ }
+ overflow_at = (uint64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + overflow_ns;
+
+ if (overflow_at > INT64_MAX) {
+ overflow_left += overflow_at - INT64_MAX;
+ counter->irq_overflow_left = overflow_left;
+ overflow_at = INT64_MAX;
+ }
+ timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at);
+
+ return 0;
+}
+
+
+int riscv_pmu_init(RISCVCPU *cpu, int num_counters)
+{
+ if (num_counters > (RV_MAX_MHPMCOUNTERS - 3)) {
+ return -1;
+ }
+
+ cpu->pmu_event_ctr_map = g_hash_table_new(g_direct_hash, g_direct_equal);
+ if (!cpu->pmu_event_ctr_map) {
+ /* PMU support can not be enabled */
+ qemu_log_mask(LOG_UNIMP, "PMU events can't be supported\n");
+ cpu->cfg.pmu_num = 0;
+ return -1;
+ }
+
+ /* Create a bitmask of available programmable counters */
+ cpu->pmu_avail_ctrs = MAKE_32BIT_MASK(3, num_counters);
+
+ return 0;
}
diff --git a/target/riscv/pmu.h b/target/riscv/pmu.h
index 58a5bc3..3004ce3 100644
--- a/target/riscv/pmu.h
+++ b/target/riscv/pmu.h
@@ -26,3 +26,11 @@ bool riscv_pmu_ctr_monitor_instructions(CPURISCVState *env,
uint32_t target_ctr);
bool riscv_pmu_ctr_monitor_cycles(CPURISCVState *env,
uint32_t target_ctr);
+void riscv_pmu_timer_cb(void *priv);
+int riscv_pmu_init(RISCVCPU *cpu, int num_counters);
+int riscv_pmu_update_event_map(CPURISCVState *env, uint64_t value,
+ uint32_t ctr_idx);
+int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx);
+void riscv_pmu_generate_fdt_node(void *fdt, int num_counters, char *pmu_name);
+int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value,
+ uint32_t ctr_idx);
diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
new file mode 100644
index 0000000..8cce667
--- /dev/null
+++ b/target/riscv/time_helper.c
@@ -0,0 +1,114 @@
+/*
+ * RISC-V timer helper implementation.
+ *
+ * Copyright (c) 2022 Rivos Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "cpu_bits.h"
+#include "time_helper.h"
+#include "hw/intc/riscv_aclint.h"
+
+static void riscv_vstimer_cb(void *opaque)
+{
+ RISCVCPU *cpu = opaque;
+ CPURISCVState *env = &cpu->env;
+ env->vstime_irq = 1;
+ riscv_cpu_update_mip(cpu, MIP_VSTIP, BOOL_TO_MASK(1));
+}
+
+static void riscv_stimer_cb(void *opaque)
+{
+ RISCVCPU *cpu = opaque;
+ riscv_cpu_update_mip(cpu, MIP_STIP, BOOL_TO_MASK(1));
+}
+
+/*
+ * Called when timecmp is written to update the QEMU timer or immediately
+ * trigger timer interrupt if mtimecmp <= current timer value.
+ */
+void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer,
+ uint64_t timecmp, uint64_t delta,
+ uint32_t timer_irq)
+{
+ uint64_t diff, ns_diff, next;
+ CPURISCVState *env = &cpu->env;
+ RISCVAclintMTimerState *mtimer = env->rdtime_fn_arg;
+ uint32_t timebase_freq = mtimer->timebase_freq;
+ uint64_t rtc_r = env->rdtime_fn(env->rdtime_fn_arg) + delta;
+
+ if (timecmp <= rtc_r) {
+ /*
+ * If we're setting an stimecmp value in the "past",
+ * immediately raise the timer interrupt
+ */
+ if (timer_irq == MIP_VSTIP) {
+ env->vstime_irq = 1;
+ }
+ riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(1));
+ return;
+ }
+
+ if (timer_irq == MIP_VSTIP) {
+ env->vstime_irq = 0;
+ }
+ /* Clear the [V]STIP bit in mip */
+ riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(0));
+
+ /* otherwise, set up the future timer interrupt */
+ diff = timecmp - rtc_r;
+ /* back to ns (note args switched in muldiv64) */
+ ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
+
+ /*
+ * check if ns_diff overflowed and check if the addition would potentially
+ * overflow
+ */
+ if ((NANOSECONDS_PER_SECOND > timebase_freq && ns_diff < diff) ||
+ ns_diff > INT64_MAX) {
+ next = INT64_MAX;
+ } else {
+ /*
+ * as it is very unlikely qemu_clock_get_ns will return a value
+ * greater than INT64_MAX, no additional check is needed for an
+ * unsigned integer overflow.
+ */
+ next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns_diff;
+ /*
+ * if ns_diff is INT64_MAX next may still be outside the range
+ * of a signed integer.
+ */
+ next = MIN(next, INT64_MAX);
+ }
+
+ timer_mod(timer, next);
+}
+
+void riscv_timer_init(RISCVCPU *cpu)
+{
+ CPURISCVState *env;
+
+ if (!cpu) {
+ return;
+ }
+
+ env = &cpu->env;
+ env->stimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_stimer_cb, cpu);
+ env->stimecmp = 0;
+
+ env->vstimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_vstimer_cb, cpu);
+ env->vstimecmp = 0;
+}
diff --git a/target/riscv/time_helper.h b/target/riscv/time_helper.h
new file mode 100644
index 0000000..7b3cdcc
--- /dev/null
+++ b/target/riscv/time_helper.h
@@ -0,0 +1,30 @@
+/*
+ * RISC-V timer header file.
+ *
+ * Copyright (c) 2022 Rivos Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef RISCV_TIME_HELPER_H
+#define RISCV_TIME_HELPER_H
+
+#include "cpu.h"
+#include "qemu/timer.h"
+
+void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer,
+ uint64_t timecmp, uint64_t delta,
+ uint32_t timer_irq);
+void riscv_timer_init(RISCVCPU *cpu);
+
+#endif
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index f8af6da..8925a44 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -95,6 +95,7 @@ typedef struct DisasContext {
int8_t lmul;
uint8_t sew;
uint8_t vta;
+ uint8_t vma;
bool cfg_vta_all_1s;
target_ulong vstart;
bool vl_eq_vlmax;
@@ -544,7 +545,7 @@ static TCGv get_address(DisasContext *ctx, int rs1, int imm)
tcg_gen_addi_tl(addr, src1, imm);
if (ctx->pm_mask_enabled) {
- tcg_gen_and_tl(addr, addr, pm_mask);
+ tcg_gen_andc_tl(addr, addr, pm_mask);
} else if (get_xl(ctx) == MXL_RV32) {
tcg_gen_ext32u_tl(addr, addr);
}
@@ -705,10 +706,26 @@ static int ex_rvc_register(DisasContext *ctx, int reg)
return 8 + reg;
}
-static int ex_rvc_shifti(DisasContext *ctx, int imm)
+static int ex_rvc_shiftli(DisasContext *ctx, int imm)
{
/* For RV128 a shamt of 0 means a shift by 64. */
- return imm ? imm : 64;
+ if (get_ol(ctx) == MXL_RV128) {
+ imm = imm ? imm : 64;
+ }
+ return imm;
+}
+
+static int ex_rvc_shiftri(DisasContext *ctx, int imm)
+{
+ /*
+ * For RV128 a shamt of 0 means a shift by 64, furthermore, for right
+ * shifts, the shamt is sign-extended.
+ */
+ if (get_ol(ctx) == MXL_RV128) {
+ imm = imm | (imm & 32) << 1;
+ imm = imm ? imm : 64;
+ }
+ return imm;
}
/* Include the auto-generated decoder for 32 bit insn */
@@ -1105,6 +1122,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->sew = FIELD_EX32(tb_flags, TB_FLAGS, SEW);
ctx->lmul = sextract32(FIELD_EX32(tb_flags, TB_FLAGS, LMUL), 0, 3);
ctx->vta = FIELD_EX32(tb_flags, TB_FLAGS, VTA) && cpu->cfg.rvv_ta_all_1s;
+ ctx->vma = FIELD_EX32(tb_flags, TB_FLAGS, VMA) && cpu->cfg.rvv_ma_all_1s;
ctx->cfg_vta_all_1s = cpu->cfg.rvv_ta_all_1s;
ctx->vstart = env->vstart;
ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c
index a96fc49..d224861 100644
--- a/target/riscv/vector_helper.c
+++ b/target/riscv/vector_helper.c
@@ -127,6 +127,11 @@ static inline uint32_t vext_vta(uint32_t desc)
return FIELD_EX32(simd_data(desc), VDATA, VTA);
}
+static inline uint32_t vext_vma(uint32_t desc)
+{
+ return FIELD_EX32(simd_data(desc), VDATA, VMA);
+}
+
static inline uint32_t vext_vta_all_1s(uint32_t desc)
{
return FIELD_EX32(simd_data(desc), VDATA, VTA_ALL_1S);
@@ -278,14 +283,18 @@ vext_ldst_stride(void *vd, void *v0, target_ulong base,
uint32_t esz = 1 << log2_esz;
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
uint32_t vta = vext_vta(desc);
+ uint32_t vma = vext_vma(desc);
for (i = env->vstart; i < env->vl; i++, env->vstart++) {
- if (!vm && !vext_elem_mask(v0, i)) {
- continue;
- }
-
k = 0;
while (k < nf) {
+ if (!vm && !vext_elem_mask(v0, i)) {
+ /* set masked-off elements to 1s */
+ vext_set_elems_1s(vd, vma, (i + k * max_elems) * esz,
+ (i + k * max_elems + 1) * esz);
+ k++;
+ continue;
+ }
target_ulong addr = base + stride * i + (k << log2_esz);
ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra);
k++;
@@ -477,15 +486,19 @@ vext_ldst_index(void *vd, void *v0, target_ulong base,
uint32_t esz = 1 << log2_esz;
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
uint32_t vta = vext_vta(desc);
+ uint32_t vma = vext_vma(desc);
/* load bytes from guest memory */
for (i = env->vstart; i < env->vl; i++, env->vstart++) {
- if (!vm && !vext_elem_mask(v0, i)) {
- continue;
- }
-
k = 0;
while (k < nf) {
+ if (!vm && !vext_elem_mask(v0, i)) {
+ /* set masked-off elements to 1s */
+ vext_set_elems_1s(vd, vma, (i + k * max_elems) * esz,
+ (i + k * max_elems + 1) * esz);
+ k++;
+ continue;
+ }
abi_ptr addr = get_index_addr(base, i, vs2) + (k << log2_esz);
ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra);
k++;
@@ -574,6 +587,7 @@ vext_ldff(void *vd, void *v0, target_ulong base,
uint32_t esz = 1 << log2_esz;
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
uint32_t vta = vext_vta(desc);
+ uint32_t vma = vext_vma(desc);
target_ulong addr, offset, remain;
/* probe every access*/
@@ -619,10 +633,14 @@ ProbeSuccess:
}
for (i = env->vstart; i < env->vl; i++) {
k = 0;
- if (!vm && !vext_elem_mask(v0, i)) {
- continue;
- }
while (k < nf) {
+ if (!vm && !vext_elem_mask(v0, i)) {
+ /* set masked-off elements to 1s */
+ vext_set_elems_1s(vd, vma, (i + k * max_elems) * esz,
+ (i + k * max_elems + 1) * esz);
+ k++;
+ continue;
+ }
target_ulong addr = base + ((i * nf + k) << log2_esz);
ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra);
k++;
@@ -812,10 +830,13 @@ static void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2,
uint32_t vl = env->vl;
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
uint32_t vta = vext_vta(desc);
+ uint32_t vma = vext_vma(desc);
uint32_t i;
for (i = env->vstart; i < vl; i++) {
if (!vm && !vext_elem_mask(v0, i)) {
+ /* set masked-off elements to 1s */
+ vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz);
continue;
}
fn(vd, vs1, vs2, i);
@@ -878,10 +899,13 @@ static void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2,
uint32_t vl = env->vl;
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
uint32_t vta = vext_vta(desc);
+ uint32_t vma = vext_vma(desc);
uint32_t i;
for (i = env->vstart; i < vl; i++) {
if (!vm && !vext_elem_mask(v0, i)) {
+ /* set masked-off elements to 1s */
+ vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz);
continue;
}
fn(vd, s1, vs2, i);
@@ -1274,10 +1298,13 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \
uint32_t esz = sizeof(TS1); \
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
uint32_t i; \
\
for (i = env->vstart; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
continue; \
} \
TS1 s1 = *((TS1 *)vs1 + HS1(i)); \
@@ -1315,10 +1342,14 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
uint32_t total_elems = \
vext_get_total_elems(env, desc, esz); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
uint32_t i; \
\
for (i = env->vstart; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * esz, \
+ (i + 1) * esz); \
continue; \
} \
TS2 s2 = *((TS2 *)vs2 + HS2(i)); \
@@ -1373,12 +1404,17 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
uint32_t vl = env->vl; \
uint32_t total_elems = env_archcpu(env)->cfg.vlen; \
uint32_t vta_all_1s = vext_vta_all_1s(desc); \
+ uint32_t vma = vext_vma(desc); \
uint32_t i; \
\
for (i = env->vstart; i < vl; i++) { \
ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ if (vma) { \
+ vext_set_elem_mask(vd, i, 1); \
+ } \
continue; \
} \
vext_set_elem_mask(vd, i, DO_OP(s2, s1)); \
@@ -1431,11 +1467,16 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
uint32_t vl = env->vl; \
uint32_t total_elems = env_archcpu(env)->cfg.vlen; \
uint32_t vta_all_1s = vext_vta_all_1s(desc); \
+ uint32_t vma = vext_vma(desc); \
uint32_t i; \
\
for (i = env->vstart; i < vl; i++) { \
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ if (vma) { \
+ vext_set_elem_mask(vd, i, 1); \
+ } \
continue; \
} \
vext_set_elem_mask(vd, i, \
@@ -2088,10 +2129,12 @@ static inline void
vext_vv_rm_1(void *vd, void *v0, void *vs1, void *vs2,
CPURISCVState *env,
uint32_t vl, uint32_t vm, int vxrm,
- opivv2_rm_fn *fn)
+ opivv2_rm_fn *fn, uint32_t vma, uint32_t esz)
{
for (uint32_t i = env->vstart; i < vl; i++) {
if (!vm && !vext_elem_mask(v0, i)) {
+ /* set masked-off elements to 1s */
+ vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz);
continue;
}
fn(vd, vs1, vs2, i, env, vxrm);
@@ -2109,23 +2152,24 @@ vext_vv_rm_2(void *vd, void *v0, void *vs1, void *vs2,
uint32_t vl = env->vl;
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
uint32_t vta = vext_vta(desc);
+ uint32_t vma = vext_vma(desc);
switch (env->vxrm) {
case 0: /* rnu */
vext_vv_rm_1(vd, v0, vs1, vs2,
- env, vl, vm, 0, fn);
+ env, vl, vm, 0, fn, vma, esz);
break;
case 1: /* rne */
vext_vv_rm_1(vd, v0, vs1, vs2,
- env, vl, vm, 1, fn);
+ env, vl, vm, 1, fn, vma, esz);
break;
case 2: /* rdn */
vext_vv_rm_1(vd, v0, vs1, vs2,
- env, vl, vm, 2, fn);
+ env, vl, vm, 2, fn, vma, esz);
break;
default: /* rod */
vext_vv_rm_1(vd, v0, vs1, vs2,
- env, vl, vm, 3, fn);
+ env, vl, vm, 3, fn, vma, esz);
break;
}
/* set tail elements to 1s */
@@ -2209,10 +2253,12 @@ static inline void
vext_vx_rm_1(void *vd, void *v0, target_long s1, void *vs2,
CPURISCVState *env,
uint32_t vl, uint32_t vm, int vxrm,
- opivx2_rm_fn *fn)
+ opivx2_rm_fn *fn, uint32_t vma, uint32_t esz)
{
for (uint32_t i = env->vstart; i < vl; i++) {
if (!vm && !vext_elem_mask(v0, i)) {
+ /* set masked-off elements to 1s */
+ vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz);
continue;
}
fn(vd, s1, vs2, i, env, vxrm);
@@ -2230,23 +2276,24 @@ vext_vx_rm_2(void *vd, void *v0, target_long s1, void *vs2,
uint32_t vl = env->vl;
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
uint32_t vta = vext_vta(desc);
+ uint32_t vma = vext_vma(desc);
switch (env->vxrm) {
case 0: /* rnu */
vext_vx_rm_1(vd, v0, s1, vs2,
- env, vl, vm, 0, fn);
+ env, vl, vm, 0, fn, vma, esz);
break;
case 1: /* rne */
vext_vx_rm_1(vd, v0, s1, vs2,
- env, vl, vm, 1, fn);
+ env, vl, vm, 1, fn, vma, esz);
break;
case 2: /* rdn */
vext_vx_rm_1(vd, v0, s1, vs2,
- env, vl, vm, 2, fn);
+ env, vl, vm, 2, fn, vma, esz);
break;
default: /* rod */
vext_vx_rm_1(vd, v0, s1, vs2,
- env, vl, vm, 3, fn);
+ env, vl, vm, 3, fn, vma, esz);
break;
}
/* set tail elements to 1s */
@@ -3004,10 +3051,14 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \
uint32_t total_elems = \
vext_get_total_elems(env, desc, ESZ); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
uint32_t i; \
\
for (i = env->vstart; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * ESZ, \
+ (i + 1) * ESZ); \
continue; \
} \
do_##NAME(vd, vs1, vs2, i, env); \
@@ -3043,10 +3094,14 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, \
uint32_t total_elems = \
vext_get_total_elems(env, desc, ESZ); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
uint32_t i; \
\
for (i = env->vstart; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * ESZ, \
+ (i + 1) * ESZ); \
continue; \
} \
do_##NAME(vd, s1, vs2, i, env); \
@@ -3618,6 +3673,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \
uint32_t total_elems = \
vext_get_total_elems(env, desc, ESZ); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
uint32_t i; \
\
if (vl == 0) { \
@@ -3625,6 +3681,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \
} \
for (i = env->vstart; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * ESZ, \
+ (i + 1) * ESZ); \
continue; \
} \
do_##NAME(vd, vs2, i, env); \
@@ -4135,12 +4194,17 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
uint32_t vl = env->vl; \
uint32_t total_elems = env_archcpu(env)->cfg.vlen; \
uint32_t vta_all_1s = vext_vta_all_1s(desc); \
+ uint32_t vma = vext_vma(desc); \
uint32_t i; \
\
for (i = env->vstart; i < vl; i++) { \
ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ if (vma) { \
+ vext_set_elem_mask(vd, i, 1); \
+ } \
continue; \
} \
vext_set_elem_mask(vd, i, \
@@ -4168,11 +4232,16 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \
uint32_t vl = env->vl; \
uint32_t total_elems = env_archcpu(env)->cfg.vlen; \
uint32_t vta_all_1s = vext_vta_all_1s(desc); \
+ uint32_t vma = vext_vma(desc); \
uint32_t i; \
\
for (i = env->vstart; i < vl; i++) { \
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ if (vma) { \
+ vext_set_elem_mask(vd, i, 1); \
+ } \
continue; \
} \
vext_set_elem_mask(vd, i, \
@@ -4295,10 +4364,14 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \
uint32_t total_elems = \
vext_get_total_elems(env, desc, ESZ); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
uint32_t i; \
\
for (i = env->vstart; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * ESZ, \
+ (i + 1) * ESZ); \
continue; \
} \
do_##NAME(vd, vs2, i); \
@@ -4806,11 +4879,16 @@ static void vmsetm(void *vd, void *v0, void *vs2, CPURISCVState *env,
uint32_t vl = env->vl;
uint32_t total_elems = env_archcpu(env)->cfg.vlen;
uint32_t vta_all_1s = vext_vta_all_1s(desc);
+ uint32_t vma = vext_vma(desc);
int i;
bool first_mask_bit = false;
for (i = env->vstart; i < vl; i++) {
if (!vm && !vext_elem_mask(v0, i)) {
+ /* set masked-off elements to 1s */
+ if (vma) {
+ vext_set_elem_mask(vd, i, 1);
+ }
continue;
}
/* write a zero to all following active elements */
@@ -4871,11 +4949,14 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, CPURISCVState *env, \
uint32_t esz = sizeof(ETYPE); \
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
uint32_t sum = 0; \
int i; \
\
for (i = env->vstart; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
continue; \
} \
*((ETYPE *)vd + H(i)) = sum; \
@@ -4902,10 +4983,13 @@ void HELPER(NAME)(void *vd, void *v0, CPURISCVState *env, uint32_t desc) \
uint32_t esz = sizeof(ETYPE); \
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
int i; \
\
for (i = env->vstart; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
continue; \
} \
*((ETYPE *)vd + H(i)) = i; \
@@ -4934,11 +5018,14 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
uint32_t esz = sizeof(ETYPE); \
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
target_ulong offset = s1, i_min, i; \
\
i_min = MAX(env->vstart, offset); \
for (i = i_min; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
continue; \
} \
*((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i - offset)); \
@@ -4963,13 +5050,17 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
uint32_t esz = sizeof(ETYPE); \
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
target_ulong i_max, i; \
\
i_max = MAX(MIN(s1 < vlmax ? vlmax - s1 : 0, vl), env->vstart); \
for (i = env->vstart; i < i_max; ++i) { \
- if (vm || vext_elem_mask(v0, i)) { \
- *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i + s1)); \
+ if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
+ continue; \
} \
+ *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i + s1)); \
} \
\
for (i = i_max; i < vl; ++i) { \
@@ -4999,10 +5090,13 @@ static void vslide1up_##BITWIDTH(void *vd, void *v0, target_ulong s1, \
uint32_t esz = sizeof(ETYPE); \
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
uint32_t i; \
\
for (i = env->vstart; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
continue; \
} \
if (i == 0) { \
@@ -5044,10 +5138,13 @@ static void vslide1down_##BITWIDTH(void *vd, void *v0, target_ulong s1, \
uint32_t esz = sizeof(ETYPE); \
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
uint32_t i; \
\
for (i = env->vstart; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
continue; \
} \
if (i == vl - 1) { \
@@ -5115,11 +5212,14 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
uint32_t esz = sizeof(TS2); \
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
uint64_t index; \
uint32_t i; \
\
for (i = env->vstart; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
continue; \
} \
index = *((TS1 *)vs1 + HS1(i)); \
@@ -5155,11 +5255,14 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
uint32_t esz = sizeof(ETYPE); \
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
uint64_t index = s1; \
uint32_t i; \
\
for (i = env->vstart; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
continue; \
} \
if (index >= vlmax) { \
@@ -5234,10 +5337,13 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \
uint32_t esz = sizeof(ETYPE); \
uint32_t total_elems = vext_get_total_elems(env, desc, esz); \
uint32_t vta = vext_vta(desc); \
+ uint32_t vma = vext_vma(desc); \
uint32_t i; \
\
for (i = env->vstart; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, i)) { \
+ /* set masked-off elements to 1s */ \
+ vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
continue; \
} \
*((ETYPE *)vd + HD(i)) = *((DTYPE *)vs2 + HS1(i)); \