@@ -166,6 +166,7 @@
#define CSR_MCAUSE 0x342
#define CSR_MTVAL 0x343
#define CSR_MIP 0x344
+#define CSR_MNXTI 0x345 /* clic-spec-draft */
#define CSR_MINTSTATUS 0xfb1 /* clic-spec-draft */
#define CSR_MINTTHRESH 0x347 /* clic-spec-draft */
@@ -210,6 +211,7 @@
#define CSR_SCAUSE 0x142
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
+#define CSR_SNXTI 0x145 /* clic-spec-draft */
#define CSR_SINTSTATUS 0xdb1 /* clic-spec-draft */
#define CSR_SINTTHRESH 0x147 /* clic-spec-draft */
@@ -561,6 +563,8 @@
#define MSTATUS_GVA 0x4000000000ULL
#define MSTATUS_MPV 0x8000000000ULL
+#define MSTATUS_WRITE_MASK 0x0000001f
+
#define MSTATUS64_UXL 0x0000000300000000ULL
#define MSTATUS64_SXL 0x0000000C00000000ULL
@@ -754,6 +758,27 @@ typedef enum RISCVException {
#define SINTSTATUS_SIL 0x0000ff00 /* sil[15:8] */
#define SINTSTATUS_UIL 0x000000ff /* uil[7:0] */
+/* mcause */
+#define MCAUSE_INT (1 << (TARGET_LONG_BITS - 1))
+#define MCAUSE_MINHV 0x40000000 /* minhv */
+#define MCAUSE_MPP 0x30000000 /* mpp[1:0] */
+#define MCAUSE_MPIE 0x08000000 /* mpie */
+#define MCAUSE_MPIL 0x00ff0000 /* mpil[7:0] */
+#define MCAUSE_EXCCODE 0x00000fff /* exccode[11:0] */
+
+/* scause */
+#define SCAUSE_INT (1 << (TARGET_LONG_BITS - 1))
+#define SCAUSE_SINHV 0x40000000 /* sinhv */
+#define SCAUSE_SPP 0x10000000 /* spp */
+#define SCAUSE_SPIE 0x08000000 /* spie */
+#define SCAUSE_SPIL 0x00ff0000 /* spil[7:0] */
+#define SCAUSE_EXCCODE 0x00000fff /* exccode[11:0] */
+
+/* mcause & scause */
+#define XCAUSE_XPP_SHIFT 28
+#define XCAUSE_XPIE_SHIFT 27
+#define XCAUSE_XPIL_SHIFT 16
+
/* mtvec & stvec */
#define XTVEC_MODE 0x03
#define XTVEC_SUBMODE 0x3c
@@ -19,6 +19,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
+#include "qemu/main-loop.h"
#include "qemu/timer.h"
#include "cpu.h"
#include "tcg/tcg-cpu.h"
@@ -2936,6 +2937,77 @@ static RISCVException rmw_mviph(CPURISCVState *env, int csrno,
return ret;
}
+static bool get_xnxti_status(CPURISCVState *env)
+{
+ int clic_irq, clic_priv, clic_il, pil;
+
+ if (!env->exccode) { /* No interrupt */
+ return false;
+ }
+ /* The system is not in a CLIC mode */
+ if (!riscv_clic_is_clic_mode(env)) {
+ return false;
+ } else {
+ riscv_clic_decode_exccode(env->exccode, &clic_priv, &clic_il,
+ &clic_irq);
+
+ if (env->priv == PRV_M) {
+ pil = MAX(get_field(env->mcause, MCAUSE_MPIL), env->mintthresh);
+ } else if (env->priv == PRV_S) {
+ pil = MAX(get_field(env->scause, SCAUSE_SPIL), env->sintthresh);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "CSR: rmw xnxti with unsupported mode\n");
+ exit(1);
+ }
+
+ if ((clic_priv != env->priv) || /* No horizontal interrupt */
+ (clic_il <= pil) || /* No higher level interrupt */
+ (riscv_clic_shv_interrupt(env->clic, clic_irq))) {
+ /* CLIC vector mode */
+ return false;
+ } else {
+ return true;
+ }
+ }
+}
+
+static int rmw_mnxti(CPURISCVState *env, int csrno, target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
+{
+ int clic_priv, clic_il, clic_irq;
+ bool ready;
+ if (write_mask) {
+ env->mstatus |= new_value & (write_mask & MSTATUS_WRITE_MASK);
+ }
+
+ BQL_LOCK_GUARD();
+
+ ready = get_xnxti_status(env);
+ if (ready) {
+ riscv_clic_decode_exccode(env->exccode, &clic_priv, &clic_il,
+ &clic_irq);
+ if (write_mask) {
+ bool edge = riscv_clic_edge_triggered(env->clic, clic_irq);
+ if (edge) {
+ riscv_clic_clean_pending(env->clic, clic_irq);
+ }
+ env->mintstatus = set_field(env->mintstatus,
+ MINTSTATUS_MIL, clic_il);
+ env->mcause = set_field(env->mcause, MCAUSE_EXCCODE, clic_irq);
+ }
+ if (ret_value) {
+ *ret_value = (env->mtvt & ~0x3f) + sizeof(target_ulong) * clic_irq;
+ }
+ } else {
+ if (ret_value) {
+ *ret_value = 0;
+ }
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
static int read_mintstatus(CPURISCVState *env, int csrno, target_ulong *val)
{
*val = env->mintstatus;
@@ -3401,6 +3473,43 @@ static RISCVException rmw_siph(CPURISCVState *env, int csrno,
return ret;
}
+static int rmw_snxti(CPURISCVState *env, int csrno, target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
+{
+ int clic_priv, clic_il, clic_irq;
+ bool ready;
+ if (write_mask) {
+ env->mstatus |= new_value & (write_mask & MSTATUS_WRITE_MASK);
+ }
+
+ BQL_LOCK_GUARD();
+
+ ready = get_xnxti_status(env);
+ if (ready) {
+ riscv_clic_decode_exccode(env->exccode, &clic_priv, &clic_il,
+ &clic_irq);
+ if (write_mask) {
+ bool edge = riscv_clic_edge_triggered(env->clic, clic_irq);
+ if (edge) {
+ riscv_clic_clean_pending(env->clic, clic_irq);
+ }
+ /* update the PRV_S parts of mintstatus */
+ env->mintstatus = set_field(env->mintstatus,
+ MINTSTATUS_SIL, clic_il);
+ env->scause = set_field(env->scause, SCAUSE_EXCCODE, clic_irq);
+ }
+ if (ret_value) {
+ *ret_value = (env->stvt & ~0x3f) + sizeof(target_ulong) * clic_irq;
+ }
+ } else {
+ if (ret_value) {
+ *ret_value = 0;
+ }
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
static int read_sintstatus(CPURISCVState *env, int csrno, target_ulong *val)
{
/* sintstatus is a filtered view of mintstatus with the PRV_M removed */
@@ -5720,12 +5829,14 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
/* Machine Mode Core Level Interrupt Controller */
[CSR_MTVT] = { "mtvt", clic, read_mtvt, write_mtvt },
+ [CSR_MNXTI] = { "mnxti", clic, NULL, NULL, rmw_mnxti },
[CSR_MINTSTATUS] = { "mintstatus", clic, read_mintstatus },
[CSR_MINTTHRESH] = { "mintthresh", clic, read_mintthresh,
write_mintthresh },
/* Supervisor Mode Core Level Interrupt Controller */
[CSR_STVT] = { "stvt", clic, read_stvt, write_stvt },
+ [CSR_SNXTI] = { "snxti", clic, NULL, NULL, rmw_snxti },
[CSR_SINTSTATUS] = { "sintstatus", clic, read_sintstatus },
[CSR_SINTTHRESH] = { "sintthresh", clic, read_sintthresh,
write_sintthresh },