CPUState *cs = env_cpu(env);
RISCVCPU *cpu = RISCV_CPU(cs);
int ctr_index;
- int base_csrno = CSR_HPMCOUNTER3;
+ int base_csrno = CSR_CYCLE;
bool rv32 = riscv_cpu_mxl(env) == MXL_RV32 ? true : false;
if (rv32 && csrno >= CSR_CYCLEH) {
}
ctr_index = csrno - base_csrno;
- 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->cfg.pmu_num || !(cpu->pmu_avail_ctrs & BIT(ctr_index)))) {
/* No counter is enabled in PMU or the counter is out of range */
return RISCV_EXCP_ILLEGAL_INST;
}
+skip_ext_pmu_check:
+
if (env->priv == PRV_S) {
switch (csrno) {
case CSR_CYCLE:
}
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;
case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H:
- ctr_index = csrno - CSR_CYCLEH;
if (!get_field(env->mcounteren, 1 << ctr_index)) {
return RISCV_EXCP_ILLEGAL_INST;
}
}
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;
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;
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;
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;
}
{
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;
}
{
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;
}
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)
{
/* 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))
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;
[CSR_MHPMEVENT31] = { "mhpmevent31", any, read_mhpmevent,
write_mhpmevent },
+ [CSR_MHPMEVENT3H] = { "mhpmevent3h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT4H] = { "mhpmevent4h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT5H] = { "mhpmevent5h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT6H] = { "mhpmevent6h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT7H] = { "mhpmevent7h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT8H] = { "mhpmevent8h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT9H] = { "mhpmevent9h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT10H] = { "mhpmevent10h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT11H] = { "mhpmevent11h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT12H] = { "mhpmevent12h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT13H] = { "mhpmevent13h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT14H] = { "mhpmevent14h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT15H] = { "mhpmevent15h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT16H] = { "mhpmevent16h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT17H] = { "mhpmevent17h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT18H] = { "mhpmevent18h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT19H] = { "mhpmevent19h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT20H] = { "mhpmevent20h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT21H] = { "mhpmevent21h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT22H] = { "mhpmevent22h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT23H] = { "mhpmevent23h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT24H] = { "mhpmevent24h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT25H] = { "mhpmevent25h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT26H] = { "mhpmevent26h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT27H] = { "mhpmevent27h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT28H] = { "mhpmevent28h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT29H] = { "mhpmevent29h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT30H] = { "mhpmevent30h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+ [CSR_MHPMEVENT31H] = { "mhpmevent31h", sscofpmf, read_mhpmeventh,
+ write_mhpmeventh },
+
[CSR_HPMCOUNTER3H] = { "hpmcounter3h", ctr32, read_hpmcounterh },
[CSR_HPMCOUNTER4H] = { "hpmcounter4h", ctr32, read_hpmcounterh },
[CSR_HPMCOUNTER5H] = { "hpmcounter5h", ctr32, read_hpmcounterh },
write_mhpmcounterh },
[CSR_MHPMCOUNTER31H] = { "mhpmcounter31h", mctr32, read_hpmcounterh,
write_mhpmcounterh },
+ [CSR_SCOUNTOVF] = { "scountovf", sscofpmf, read_scountovf },
+
#endif /* !CONFIG_USER_ONLY */
};