From cf3aa61ad29b65e7976f5f4fb4dbe24da49e0192 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Tue, 27 May 2025 13:25:59 -0700 Subject: [PATCH 01/21] AIA: update encoding.h --- riscv/encoding.h | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/riscv/encoding.h b/riscv/encoding.h index bcc1ace2dc..a8241cbd02 100644 --- a/riscv/encoding.h +++ b/riscv/encoding.h @@ -4,7 +4,7 @@ /* * This file is auto-generated by running 'make' in - * https://github.com/riscv/riscv-opcodes (8899b32) + * https://github.com/riscv/riscv-opcodes (50f5b2c) */ #ifndef RISCV_CSR_ENCODING_H @@ -199,6 +199,7 @@ #define MSTATEEN0_CTR 0x0040000000000000 #define MSTATEEN0_PRIV113 0x0100000000000000 #define MSTATEEN0_PRIV114 0x0080000000000000 +#define MSTATEEN0_IMSIC 0x0400000000000000 #define MSTATEEN0_HCONTEXT 0x0200000000000000 #define MSTATEEN0_AIA 0x0800000000000000 #define MSTATEEN0_CSRIND 0x1000000000000000 @@ -208,6 +209,7 @@ #define MSTATEEN0H_CTR 0x00400000 #define MSTATEEN0H_PRIV113 0x01000000 #define MSTATEEN0H_PRIV114 0x00800000 +#define MSTATEEN0H_IMSIC 0x04000000 #define MSTATEEN0H_HCONTEXT 0x02000000 #define MSTATEEN0H_AIA 0x08000000 #define MSTATEEN0H_CSRIND 0x10000000 @@ -268,11 +270,25 @@ #define SISELECT_SMCDELEG_HPMEVENT_3 0x43 #define SISELECT_SMCDELEG_END 0x5f +#define MISELECT_IPRIO 0x30 +#define MISELECT_IPRIO_TOP 0x3f +#define MISELECT_IMSIC 0x70 +#define MISELECT_IMSIC_TOP 0xff + +#define SISELECT_IPRIO 0x30 +#define SISELECT_IPRIO_TOP 0x3f +#define SISELECT_IMSIC 0x70 +#define SISELECT_IMSIC_TOP 0xff + +#define VSISELECT_IMSIC 0x70 +#define VSISELECT_IMSIC_TOP 0xff + #define HSTATEEN0_CS 0x00000001 #define HSTATEEN0_FCSR 0x00000002 #define HSTATEEN0_JVT 0x00000004 #define HSTATEEN0_CTR 0x0040000000000000 #define HSTATEEN0_SCONTEXT 0x0200000000000000 +#define HSTATEEN0_IMSIC 0x0400000000000000 #define HSTATEEN0_AIA 0x0800000000000000 #define HSTATEEN0_CSRIND 0x1000000000000000 #define HSTATEEN0_SENVCFG 0x4000000000000000 @@ -280,6 +296,7 @@ #define HSTATEEN0H_CTR 0x00400000 #define HSTATEEN0H_SCONTEXT 0x02000000 +#define HSTATEEN0H_IMSIC 0x04000000 #define HSTATEEN0H_AIA 0x08000000 #define HSTATEEN0H_CSRIND 0x10000000 #define HSTATEEN0H_SENVCFG 0x40000000 @@ -1743,8 +1760,14 @@ #define MASK_VFNCVT_X_F_W 0xfc0ff07f #define MATCH_VFNCVT_XU_F_W 0x48081057 #define MASK_VFNCVT_XU_F_W 0xfc0ff07f +#define MATCH_VFNCVTBF16_F_F_Q 0x480c9057 +#define MASK_VFNCVTBF16_F_F_Q 0xfc0ff07f #define MATCH_VFNCVTBF16_F_F_W 0x480e9057 #define MASK_VFNCVTBF16_F_F_W 0xfc0ff07f +#define MATCH_VFNCVTBF16_SAT_F_F_Q 0x480d9057 +#define MASK_VFNCVTBF16_SAT_F_F_Q 0xfc0ff07f +#define MATCH_VFNCVTBF16_SAT_F_F_W 0x480f9057 +#define MASK_VFNCVTBF16_SAT_F_F_W 0xfc0ff07f #define MATCH_VFNMACC_VF 0xb4005057 #define MASK_VFNMACC_VF 0xfc00707f #define MATCH_VFNMACC_VV 0xb4001057 @@ -2967,7 +2990,6 @@ #define INSN_FIELD_IMM4 0xf00000 #define INSN_FIELD_IMM5 0x1f00000 #define INSN_FIELD_IMM6 0x3f00000 -#define INSN_FIELD_ZIMM 0xf8000 #define INSN_FIELD_OPCODE 0x7f #define INSN_FIELD_FUNCT7 0xfe000000 #define INSN_FIELD_VD 0xf80 @@ -3649,7 +3671,10 @@ DECLARE_INSN(vfncvt_rtz_x_f_w, MATCH_VFNCVT_RTZ_X_F_W, MASK_VFNCVT_RTZ_X_F_W) DECLARE_INSN(vfncvt_rtz_xu_f_w, MATCH_VFNCVT_RTZ_XU_F_W, MASK_VFNCVT_RTZ_XU_F_W) DECLARE_INSN(vfncvt_x_f_w, MATCH_VFNCVT_X_F_W, MASK_VFNCVT_X_F_W) DECLARE_INSN(vfncvt_xu_f_w, MATCH_VFNCVT_XU_F_W, MASK_VFNCVT_XU_F_W) +DECLARE_INSN(vfncvtbf16_f_f_q, MATCH_VFNCVTBF16_F_F_Q, MASK_VFNCVTBF16_F_F_Q) DECLARE_INSN(vfncvtbf16_f_f_w, MATCH_VFNCVTBF16_F_F_W, MASK_VFNCVTBF16_F_F_W) +DECLARE_INSN(vfncvtbf16_sat_f_f_q, MATCH_VFNCVTBF16_SAT_F_F_Q, MASK_VFNCVTBF16_SAT_F_F_Q) +DECLARE_INSN(vfncvtbf16_sat_f_f_w, MATCH_VFNCVTBF16_SAT_F_F_W, MASK_VFNCVTBF16_SAT_F_F_W) DECLARE_INSN(vfnmacc_vf, MATCH_VFNMACC_VF, MASK_VFNMACC_VF) DECLARE_INSN(vfnmacc_vv, MATCH_VFNMACC_VV, MASK_VFNMACC_VV) DECLARE_INSN(vfnmadd_vf, MATCH_VFNMADD_VF, MASK_VFNMADD_VF) From 7653592604e09c4f7adbc8d0cac0458930909e99 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Fri, 23 May 2025 06:19:38 -0600 Subject: [PATCH 02/21] AIA: Add IMSIC defines --- riscv/platform.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/riscv/platform.h b/riscv/platform.h index c8a5bf4bfb..076871e9f2 100644 --- a/riscv/platform.h +++ b/riscv/platform.h @@ -8,6 +8,9 @@ #define DEFAULT_PRIV "MSU" #define CLINT_BASE 0x02000000 #define CLINT_SIZE 0x000c0000 +#define GEILEN 31 +#define IMSIC_M_BASE 0x24000000 +#define IMSIC_S_BASE 0x28000000 #define PLIC_BASE 0x0c000000 #define PLIC_SIZE 0x01000000 #define PLIC_NDEV 31 From f12191199f33c75ede35b38cb43ba6bafb5febd2 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Fri, 23 May 2025 06:32:53 -0600 Subject: [PATCH 03/21] AIA: add geilen --- riscv/processor.cc | 2 +- riscv/processor.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/riscv/processor.cc b/riscv/processor.cc index f11cfc0647..be51c47e6a 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -40,7 +40,7 @@ processor_t::processor_t(const char* isa_str, const char* priv_str, log_file(log_file), sout_(sout_.rdbuf()), halt_on_reset(halt_on_reset), in_wfi(false), check_triggers_icount(false), impl_table(256, false), extension_enable_table(isa.get_extension_table()), - last_pc(1), executions(1), TM(cfg->trigger_count) + last_pc(1), executions(1), TM(cfg->trigger_count), geilen(GEILEN) { VU.p = this; TM.proc = this; diff --git a/riscv/processor.h b/riscv/processor.h index cc2897a4b5..d448e79fa7 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -448,6 +448,8 @@ class processor_t : public abstract_device_t vectorUnit_t VU; triggers::module_t TM; + + unsigned geilen; }; #endif From 8fb9ccd1126d33916aafac654bbc284a8de69ee0 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Fri, 23 May 2025 06:42:19 -0600 Subject: [PATCH 04/21] AIA: add IMSIC AIA: add hgeie/hgeip CSRs --- riscv/csr_init.cc | 9 ++- riscv/csrs.cc | 28 ++++++++ riscv/csrs.h | 15 ++++ riscv/imsic.cc | 179 ++++++++++++++++++++++++++++++++++++++++++++++ riscv/imsic.h | 77 ++++++++++++++++++++ riscv/platform.h | 3 + riscv/processor.h | 4 ++ riscv/riscv.mk.in | 2 + 8 files changed, 315 insertions(+), 2 deletions(-) create mode 100644 riscv/imsic.cc create mode 100644 riscv/imsic.h diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc index 0acd1c7fd2..29eff7a086 100644 --- a/riscv/csr_init.cc +++ b/riscv/csr_init.cc @@ -215,8 +215,13 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) add_csr(CSR_MTVAL2, mtval2); add_hypervisor_csr(CSR_MTINST, mtinst = std::make_shared(proc, CSR_MTINST)); add_hypervisor_csr(CSR_HSTATUS, hstatus = std::make_shared(proc, CSR_HSTATUS)); - add_hypervisor_csr(CSR_HGEIE, std::make_shared(proc, CSR_HGEIE, 0)); - add_hypervisor_csr(CSR_HGEIP, std::make_shared(proc, CSR_HGEIP, 0)); + if (proc->extension_enabled_const(EXT_SSAIA)) { + add_hypervisor_csr(CSR_HGEIE, hgeie = std::make_shared(proc, CSR_HGEIE, proc->geilen)); + add_hypervisor_csr(CSR_HGEIP, hgeip = std::make_shared(proc, CSR_HGEIP)); + } else { + add_hypervisor_csr(CSR_HGEIE, std::make_shared(proc, CSR_HGEIE, 0)); + add_hypervisor_csr(CSR_HGEIP, std::make_shared(proc, CSR_HGEIP, 0)); + } hideleg = std::make_shared(proc, CSR_HIDELEG, mideleg); if (xlen == 32 && proc->extension_enabled_const(EXT_SSAIA)) { add_hypervisor_csr(CSR_HIDELEG, std::make_shared(proc, CSR_HIDELEG, hideleg)); diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 3a32712615..76d8353ff9 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -2230,3 +2230,31 @@ void aia_csr_t::verify_permissions(insn_t insn, bool write) const { basic_csr_t::verify_permissions(insn, write); } + +hgeip_csr_t::hgeip_csr_t(processor_t* const proc, const reg_t addr) : csr_t(proc, addr) { +} + +reg_t hgeip_csr_t::read() const noexcept { + // scan through all VGEINs + reg_t v = 0; + for (auto &i: proc->imsic->vs) { + if (i.second->topei()) + v |= reg_t(1) << i.first; + } + return v; +} + +bool hgeip_csr_t::unlogged_write(const reg_t val) noexcept { + // read-only register + return false; +} + +hgeie_csr_t::hgeie_csr_t(processor_t* const proc, const reg_t addr, const reg_t geilen) : masked_csr_t(proc, addr, ((reg_t(1) << geilen) - 1) << 1, 0) { +} + +bool hgeie_csr_t::unlogged_write(const reg_t val) noexcept { + bool sgeip = val & proc->get_state()->hgeip->read(); + // update mip.SGEIP if the hypervisor traps guest SEIP to itself + state->mip->backdoor_write_with_mask(MIP_SGEIP, sgeip ? MIP_SGEIP : 0); + return masked_csr_t::unlogged_write(val); +} diff --git a/riscv/csrs.h b/riscv/csrs.h index f076aaab7c..3a350f6489 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -997,4 +997,19 @@ class aia_csr_t: public masked_csr_t { aia_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init); virtual void verify_permissions(insn_t insn, bool write) const override; }; + +class hgeip_csr_t final: public csr_t { + public: + hgeip_csr_t(processor_t* const proc, const reg_t addr); + virtual reg_t read() const noexcept override; + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; +}; + +class hgeie_csr_t final: public masked_csr_t { + public: + hgeie_csr_t(processor_t* const proc, const reg_t addr, const reg_t geilen); + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; +}; #endif diff --git a/riscv/imsic.cc b/riscv/imsic.cc new file mode 100644 index 0000000000..ed1fccf40a --- /dev/null +++ b/riscv/imsic.cc @@ -0,0 +1,179 @@ +// See LICENSE for license details. +#include "imsic.h" +#include "processor.h" +#include "arith.h" +#include "sim.h" + +class imsic_csr_t : public masked_csr_t { + public: + imsic_csr_t(processor_t* const proc, const reg_t addr, imsic_file_t *imsic_file, const reg_t mask = -1, const reg_t init = 0) : masked_csr_t(proc, addr, mask, init), imsic_file(*imsic_file) { + } + protected: + virtual bool unlogged_write(const reg_t val) noexcept override { + masked_csr_t::unlogged_write(val); + // update MIP after write + imsic_file.update_mip(); + // no logging of indirect registers + return false; + } + private: + imsic_file_t &imsic_file; +}; + +imsic_file_t::imsic_file_t(processor_t* const proc, reg_t mip_mask, size_t num_regs, bool v, reg_t vgein) : proc(proc), state(proc->get_state()), mip_mask(mip_mask), v(v), vgein(vgein) { + auto xlen = proc->get_isa().get_max_xlen(); + csrmap[IMSIC_EIDELIVERY] = eidelivery = std::make_shared(proc, IMSIC_EIDELIVERY, this, 1, 0); + csrmap[IMSIC_EITHRESHOLD] = eithreshold = std::make_shared(proc, IMSIC_EITHRESHOLD, this); + for (size_t i = 0; i < IMSIC_NUM_EI_REGS; i++) { + if (i < num_regs) { + // 1st bits of eip/eie are hard-wired to 0 + const reg_t mask = i == 0 ? ~1ull : -1; + eip.emplace_back(std::make_shared(proc, IMSIC_EIP(i * 2), this, mask)); + eie.emplace_back(std::make_shared(proc, IMSIC_EIE(i * 2), this, mask)); + } else { + // make a const 0 register if index >= number of IMSIC files + eip.emplace_back(std::make_shared(proc, IMSIC_EIP(i * 2), 0)); + eie.emplace_back(std::make_shared(proc, IMSIC_EIP(i * 2), 0)); + } + if (xlen == 32) { + csrmap[IMSIC_EIP(i * 2)] = std::make_shared(proc, IMSIC_EIP(i * 2), eip[i]); + csrmap[IMSIC_EIP(i * 2 + 1)] = std::make_shared(proc, IMSIC_EIP(i * 2 + 1), eip[i]); + csrmap[IMSIC_EIE(i * 2)] = std::make_shared(proc, IMSIC_EIE(i * 2), eie[i]); + csrmap[IMSIC_EIE(i * 2 + 1)] = std::make_shared(proc, IMSIC_EIE(i * 2 + 1), eie[i]); + } else { + csrmap[IMSIC_EIP(i * 2)] = eip[i]; + csrmap[IMSIC_EIE(i * 2)] = eie[i]; + } + } +} + +reg_t imsic_file_t::topei() { + if (eidelivery->read() != 1) + return 0; + reg_t thd = eithreshold->read(); + for (size_t i = 0; i < IMSIC_NUM_EI_REGS; i++) { + reg_t ints = eip[i]->read() & eie[i]->read(); + if (ints == 0) + continue; + reg_t iid = ctz(ints) + i * 64; + // When eithreshold is a nonzero value P, interrupt identities P and higher do not contribute to signaling interrupts + if (thd && iid >= thd) + return 0; + return iid; + } + return 0; +} + +void imsic_file_t::claimei(reg_t intr) { + if (intr > 0 && intr < 64 * IMSIC_NUM_EI_REGS) { + size_t reg = intr / 64; + size_t idx = intr % 64; + eip[reg]->write(eip[reg]->read() & ~(reg_t(1) << idx)); + } +} + +void imsic_file_t::pendei(reg_t intr) { + if (intr > 0 && intr < 64 * IMSIC_NUM_EI_REGS) { + size_t reg = intr / 64; + size_t idx = intr % 64; + eip[reg]->write(eip[reg]->read() | (reg_t(1) << idx)); + } +} + +void imsic_file_t::update_mip() { + reg_t iid = topei(); + if (v) { + // Privileged 9.2.4: Register hgeie selects the subset of guest external interrupts that cause a supervisor-level (HS-level) guest external interrupt. + bool sgeip = proc->get_state()->hgeie->read() & proc->get_state()->hgeip->read(); + state->mip->backdoor_write_with_mask(MIP_SGEIP, sgeip ? MIP_SGEIP : 0); + } + // The enable bits in hgeie do not affect the VS-level external interrupt signal selected from hgeip by hstatus.VGEIN + if (!v || (v && vgein == get_field(state->hstatus->read(), HSTATUS_VGEIN))) { + // if not virtual, or virtual and vgein is selected in hstatus + state->mip->backdoor_write_with_mask(mip_mask, iid ? mip_mask : 0); + } +} + +imsic_mmio_t::imsic_mmio_t(imsic_file_t_p const imsic) : imsic(imsic) { +} + +bool imsic_mmio_t::load(reg_t addr, size_t len, uint8_t* bytes) { + if (len != 4) + return false; + // return 0 in all cases + memset(bytes, 0, 4); + return true; +} + +bool imsic_mmio_t::store(reg_t addr, size_t len, const uint8_t* bytes) { + if (len != 4) + return false; + if (addr == SETEIPNUM_LE || addr == SETEIPNUM_BE) { + uint32_t intr; + memcpy(&intr, bytes, sizeof(intr)); + if (addr == SETEIPNUM_BE) + intr = swap(intr); + imsic->pendei(intr); + } + return true; +} + +imsic_t::imsic_t(processor_t *proc, unsigned geilen) { + if (proc->extension_enabled_const(EXT_SMAIA)) + m = std::make_shared(proc, MIP_MEIP, IMSIC_M_FILE_REGS); + if (proc->extension_enabled_const(EXT_SSAIA)) { + s = std::make_shared(proc, MIP_SEIP, IMSIC_S_FILE_REGS); + assert(geilen <= 63); + for (size_t j = 1; j <= geilen; j++) { + vs[j] = std::make_shared(proc, MIP_VSEIP, IMSIC_VS_FILE_REGS, true, j); + } + } +} + +std::string imsic_mmio_generate_dts(const sim_t* sim, const std::vector& sargs UNUSED) +{ + auto cfg = sim->get_cfg(); + isa_parser_t isa(cfg.isa, cfg.priv); + std::stringstream s; + if (isa.extension_enabled(EXT_SMAIA)) { + s << std::hex + << " IMSIC_M: imsics@" << IMSIC_M_BASE << " {\n" + " riscv,ipi-id = <0x01>;\n" + " riscv,num-ids = <0xff>;\n" + " reg = <0x00 0x" << IMSIC_M_BASE << " 0x00 0x" << sim->nprocs() * IMSIC_MMIO_PAGE_SIZE << ">;\n" + " interrupts-extended = <" << std::dec; + for (size_t i = 0; i < sim->nprocs(); i++) + s << "&CPU" << i << "_intc 0xb "; + s << std::hex << ">;\n" + " msi-controller;\n" + " interrupt-controller;\n" + " #interrupt-cells = <0x00>;\n" + " compatible = \"riscv,imsics\";\n" + " };\n"; + } + if (isa.extension_enabled(EXT_SSAIA)) { + s << std::hex + << " IMSIC_S: imsics@" << IMSIC_S_BASE << " {\n" + " riscv,ipi-id = <0x01>;\n" + " riscv,num-ids = <0xff>;\n" + " riscv,guest-index-bits = <0x6>;\n" + " reg = <0x00 0x" << IMSIC_S_BASE << " 0x00 0x" << sim->nprocs() * IMSIC_MMIO_PAGE_SIZE * 64 << ">;\n" + " interrupts-extended = <" << std::dec; + for (size_t i = 0; i < sim->nprocs(); i++) + s << "&CPU" << i << "_intc 0x9 "; + s << std::hex << ">;\n" + " msi-controller;\n" + " interrupt-controller;\n" + " #interrupt-cells = <0x00>;\n" + " compatible = \"riscv,imsics\";\n" + " };\n"; + } + return s.str(); +} + +imsic_mmio_t* imsic_mmio_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, const std::vector& sargs UNUSED) +{ + return nullptr; +} + +REGISTER_DEVICE(imsic_mmio, imsic_mmio_parse_from_fdt, imsic_mmio_generate_dts) diff --git a/riscv/imsic.h b/riscv/imsic.h new file mode 100644 index 0000000000..30c1104ca1 --- /dev/null +++ b/riscv/imsic.h @@ -0,0 +1,77 @@ +// See LICENSE for license details. +#ifndef _RISCV_IMSIC_H +#define _RISCV_IMSIC_H +#include +#include +#include +#include "csrs.h" +#include "abstract_device.h" + +// EIP/EIE0 to 63 but internally there are only 32 64b registers +#define IMSIC_NUM_EI_REGS 32 +#define IMSIC_MMIO_PAGE_SIZE 0x1000 + +#define IMSIC_EIDELIVERY 0x70 +#define IMSIC_EITHRESHOLD 0x72 +#define IMSIC_EIP(x) (0x80 + x) +#define IMSIC_EIE(x) (0xc0 + x) + +#define IMSIC_TOPI_IID (0x7ffu << 16) +#define IMSIC_TOPI_IPRIO (0x7ffu << 0) + +#define SETEIPNUM_LE 0x0 +#define SETEIPNUM_BE 0x4 + +typedef std::unordered_map csrmap_t; +typedef csrmap_t *csrmap_t_p; + +class imsic_file_t; +typedef std::shared_ptr imsic_file_t_p; + +class imsic_mmio_t : public abstract_device_t { + public: + imsic_mmio_t(imsic_file_t_p const imsic); + bool load(reg_t addr, size_t len, uint8_t* bytes); + bool store(reg_t addr, size_t len, const uint8_t* bytes); + reg_t size() { return IMSIC_MMIO_PAGE_SIZE; } + + private: + imsic_file_t_p const imsic; +}; + +class imsic_file_t { + friend imsic_mmio_t; + public: + imsic_file_t(processor_t* const proc, reg_t mip_mask, size_t num_regs, bool v = false, reg_t vgein = 0); + reg_t topei(); + void claimei(reg_t intr); + void pendei(reg_t intr); + void update_mip(); + csr_t_p get_reg(reg_t reg) { return csrmap.count(reg) ? csrmap[reg] : nullptr; } + csrmap_t csrmap; + + private: + processor_t* const proc; + state_t* const state; + reg_t mip_mask; + bool v; + reg_t vgein; + csr_t_p eidelivery; + csr_t_p eithreshold; + std::vector eip; + std::vector eie; +}; + +struct imsic_t { + imsic_file_t_p m; + imsic_file_t_p s; + std::map vs; + imsic_t(processor_t *proc, unsigned geilen); + bool vgein_valid(unsigned vgein) { return vs.count(vgein); } + csr_t_p get_vs_reg(unsigned vgein, reg_t reg) { return vs.count(vgein) ? vs[vgein]->get_reg(reg) : nullptr; } + csrmap_t_p get_vs_csrmap(reg_t vgein) { + return vs.count(vgein) ? &vs[vgein]->csrmap : nullptr; + } +}; +typedef std::shared_ptr imsic_t_p; +#endif diff --git a/riscv/platform.h b/riscv/platform.h index 076871e9f2..794f8a8b4a 100644 --- a/riscv/platform.h +++ b/riscv/platform.h @@ -11,6 +11,9 @@ #define GEILEN 31 #define IMSIC_M_BASE 0x24000000 #define IMSIC_S_BASE 0x28000000 +#define IMSIC_M_FILE_REGS IMSIC_NUM_EI_REGS +#define IMSIC_S_FILE_REGS IMSIC_NUM_EI_REGS +#define IMSIC_VS_FILE_REGS IMSIC_NUM_EI_REGS #define PLIC_BASE 0x0c000000 #define PLIC_SIZE 0x01000000 #define PLIC_NDEV 31 diff --git a/riscv/processor.h b/riscv/processor.h index d448e79fa7..213f8b8f20 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -17,6 +17,7 @@ #include "triggers.h" #include "../fesvr/memif.h" #include "vector_unit.h" +#include "imsic.h" #define FIRST_HPMCOUNTER 3 #define N_HPMCOUNTERS 29 @@ -130,6 +131,8 @@ struct state_t csr_t_p htval; csr_t_p htinst; csr_t_p hgatp; + csr_t_p hgeie; + csr_t_p hgeip; hvip_csr_t_p hvip; sstatus_csr_t_p sstatus; vsstatus_csr_t_p vsstatus; @@ -450,6 +453,7 @@ class processor_t : public abstract_device_t triggers::module_t TM; unsigned geilen; + imsic_t_p imsic; }; #endif diff --git a/riscv/riscv.mk.in b/riscv/riscv.mk.in index 4239a661dd..c0c78fd542 100644 --- a/riscv/riscv.mk.in +++ b/riscv/riscv.mk.in @@ -32,6 +32,7 @@ riscv_install_hdrs = \ encoding.h \ entropy_source.h \ extension.h \ + imsic.h \ isa_parser.h \ jtag_dtm.h \ log_file.h \ @@ -55,6 +56,7 @@ riscv_srcs = \ execute.cc \ dts.cc \ sim.cc \ + imsic.cc \ interactive.cc \ cachesim.cc \ mmu.cc \ From 915b2c8ef58f0816eca2d4a453d25e8047a45ea9 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Fri, 23 May 2025 06:47:55 -0600 Subject: [PATCH 05/21] AIA: add hstatus.VGEIN support --- riscv/csrs.cc | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 76d8353ff9..a8896f7097 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -2023,15 +2023,32 @@ bool hstatus_csr_t::unlogged_write(const reg_t val) noexcept { const reg_t mask = HSTATUS_VTSR | HSTATUS_VTW | (proc->supports_impl(IMPL_MMU) ? HSTATUS_VTVM : 0) | (proc->extension_enabled(EXT_SSNPM) ? HSTATUS_HUPMM : 0) + | (proc->extension_enabled_const(EXT_SSAIA) ? HSTATUS_VGEIN : 0) | HSTATUS_HU | HSTATUS_SPVP | HSTATUS_SPV | HSTATUS_GVA; const reg_t pmm_reserved = 1; // Reserved value of mseccfg.PMM reg_t pmm = get_field(val, HSTATUS_HUPMM); const reg_t adjusted_val = set_field(val, HSTATUS_HUPMM, pmm != pmm_reserved ? pmm : 0); - const reg_t new_hstatus = (read() & ~mask) | (adjusted_val & mask); + reg_t new_hstatus = (read() & ~mask) | (adjusted_val & mask); if (get_field(new_hstatus, HSTATUS_HUPMM) != get_field(read(), HSTATUS_HUPMM)) proc->get_mmu()->flush_tlb(); + + // VGEIN is WLRL + if (proc->extension_enabled_const(EXT_SSAIA)) { + reg_t old_vgein = get_field(read(), HSTATUS_VGEIN); + reg_t new_vgein = get_field((reg_t)val, HSTATUS_VGEIN); + if (new_vgein && !proc->imsic->vgein_valid(new_vgein)) { + new_vgein = old_vgein; + new_hstatus = set_field(new_hstatus, HSTATUS_VGEIN, old_vgein); + } + // update_mip() needs the new VGEIN, so hstatus must be updated first + bool ret = basic_csr_t::unlogged_write(new_hstatus); + // if vgein = 0, HS controls VSEIP; otherwise IMSIC controls it + if (new_vgein && new_vgein != old_vgein) + proc->imsic->vs[new_vgein]->update_mip(); + return ret; + } return basic_csr_t::unlogged_write(new_hstatus); } From 0bf66efb48f12531a936f5864bf62d0c617df8d5 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Fri, 23 May 2025 07:00:52 -0600 Subject: [PATCH 06/21] AIA: add IMSIC dts parser --- riscv/dts.cc | 29 +++++++++++++++++++++++++++++ riscv/dts.h | 1 + 2 files changed, 30 insertions(+) diff --git a/riscv/dts.cc b/riscv/dts.cc index 5be9d57f6a..78a17b5d29 100644 --- a/riscv/dts.cc +++ b/riscv/dts.cc @@ -441,3 +441,32 @@ int fdt_parse_hartid(const void *fdt, int cpu_offset, uint32_t *hartid) return 0; } + +int fdt_parse_imsics(const void *fdt, reg_t *imsic_m_addr, reg_t *imsic_s_addr, const char *compatible) +{ + int nodeoffset = -1, len, rc; + const fdt32_t *p; + reg_t addr = 0; + int val; + + for (int i = 0; i < 2; i++) { + nodeoffset = fdt_node_offset_by_compatible(fdt, nodeoffset, compatible); + if (nodeoffset < 0) + return nodeoffset; + + rc = fdt_get_node_addr_size(fdt, nodeoffset, &addr, NULL, "reg"); + if (rc < 0) + return -ENODEV; + + p = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "interrupts-extended", &len); + if (!p) + return -ENODEV; + + val = fdt32_to_cpu(p[1]); + if (val == IRQ_M_EXT && imsic_m_addr) + *imsic_m_addr = addr; + if (val == IRQ_S_EXT && imsic_s_addr) + *imsic_s_addr = addr; + } + return 0; +} diff --git a/riscv/dts.h b/riscv/dts.h index 730dea7765..a0a5724207 100644 --- a/riscv/dts.h +++ b/riscv/dts.h @@ -32,4 +32,5 @@ int fdt_parse_pmp_alignment(const void *fdt, int cpu_offset, reg_t *pmp_align); int fdt_parse_mmu_type(const void *fdt, int cpu_offset, const char **mmu_type); int fdt_parse_isa(const void *fdt, int cpu_offset, const char **isa_str); int fdt_parse_hartid(const void *fdt, int cpu_offset, uint32_t *hartid); +int fdt_parse_imsics(const void *fdt, reg_t *imsic_m_addr, reg_t *imsic_s_addr, const char *compatible); #endif From cac2460d9fbeac956013aee08efd980e093ae5b2 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Fri, 23 May 2025 07:12:20 -0600 Subject: [PATCH 07/21] AIA: add IMSIC instantiation --- riscv/processor.cc | 4 ++++ riscv/sim.cc | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/riscv/processor.cc b/riscv/processor.cc index be51c47e6a..fd32815395 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -80,6 +80,10 @@ processor_t::processor_t(const char* isa_str, const char* priv_str, set_impl(IMPL_MMU_ASID, true); set_impl(IMPL_MMU_VMID, true); + // construct IMSIC files + if (extension_enabled_const(EXT_SMAIA) || extension_enabled_const(EXT_SSAIA)) + imsic = std::make_shared(this, isa.extension_enabled('H') ? geilen : 0); + reset(); } diff --git a/riscv/sim.cc b/riscv/sim.cc index 388d729027..030f4f2f1f 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -20,6 +20,7 @@ #include #include #include +#include "imsic.h" volatile bool ctrlc_pressed = false; static void handle_signal(int sig) @@ -35,6 +36,7 @@ const size_t sim_t::INTERLEAVE; extern device_factory_t* clint_factory; extern device_factory_t* plic_factory; extern device_factory_t* ns16550_factory; +extern device_factory_t* imsic_mmio_factory; sim_t::sim_t(const cfg_t *cfg, bool halted, std::vector> mems, @@ -120,6 +122,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, std::vector device_factories = { {clint_factory, {}}, // clint must be element 0 {plic_factory, {}}, // plic must be element 1 + {imsic_mmio_factory, {}}, {ns16550_factory, {}}}; device_factories.insert(device_factories.end(), plugin_device_factories.begin(), @@ -242,6 +245,33 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, cpu_idx++; } + // parse IMSICs & create MMIO portions + reg_t imsic_m_addr = 0, imsic_s_addr = 0; + if (fdt_parse_imsics(fdt, &imsic_m_addr, &imsic_s_addr, "riscv,imsics") == 0) { + for (size_t id = 0; id < cfg->nprocs(); id++) { + auto proc = procs[id]; + if (proc->extension_enabled_const(EXT_SMAIA) && imsic_m_addr) { + reg_t mmio_base = IMSIC_M_BASE + proc->get_id() * IMSIC_MMIO_PAGE_SIZE; + auto imsic = new imsic_mmio_t(proc->imsic->m); + bus.add_device(mmio_base, imsic); + } + if (proc->extension_enabled_const(EXT_SSAIA) && imsic_s_addr) { + // There are 1 S-mode and up to 63 VS-mode pages per core as defined by riscv,guest-index-bits in DTS + assert(proc->geilen <= 63); + reg_t mmio_base = IMSIC_S_BASE + proc->get_id() * IMSIC_MMIO_PAGE_SIZE * 64; + auto imsic = new imsic_mmio_t(proc->imsic->s); + bus.add_device(mmio_base, imsic); + // S+VS files are laid out as S, G1, G2, G3,... + if (proc->extension_enabled('H')) { + for (size_t j = 1; j <= proc->geilen; j++) { + auto imsic = new imsic_mmio_t(proc->imsic->vs[j]); + bus.add_device(mmio_base + IMSIC_MMIO_PAGE_SIZE * j, imsic); + } + } + } + } + } + // must be located after procs/harts are set (devices might use sim_t get_* member functions) for (size_t i = 0; i < device_factories.size(); i++) { const device_factory_t* factory = device_factories[i].first; From 9f3507964bdc271295311b1217e5cfb0cae873a9 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Fri, 23 May 2025 13:47:11 -0700 Subject: [PATCH 08/21] AIA: add aia_ireg_proxy_csr_t --- riscv/csrs.cc | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++ riscv/csrs.h | 17 +++++++++ riscv/imsic.h | 3 -- 3 files changed, 119 insertions(+), 3 deletions(-) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index a8896f7097..3a8397eb3c 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -2275,3 +2275,105 @@ bool hgeie_csr_t::unlogged_write(const reg_t val) noexcept { state->mip->backdoor_write_with_mask(MIP_SGEIP, sgeip ? MIP_SGEIP : 0); return masked_csr_t::unlogged_write(val); } + +aia_ireg_proxy_csr_t::aia_ireg_proxy_csr_t(processor_t* const proc, const reg_t addr, csr_t_p iselect) : csr_t(proc, addr), iselect(iselect), vs(false), csrmap(nullptr) { + auto xlen = proc->get_xlen(); + switch (address) { + case CSR_MIREG: + { + csrmap = &proc->imsic->m->csrmap; + // IMSIC registers are defined to be 32-bit and odd ones drop out when xlen is 64 + const unsigned num_iprio_regs = (MISELECT_IPRIO_TOP - MISELECT_IPRIO + 1) / 2; + for (size_t i = 0; i < num_iprio_regs; i++) { + auto iprio = std::make_shared(proc, MISELECT_IPRIO + i * 2, 0); + if (xlen == 64) { + (*csrmap)[MISELECT_IPRIO + i * 2] = iprio; + } else { + (*csrmap)[MISELECT_IPRIO + i * 2] = std::make_shared(proc, MISELECT_IPRIO + i * 2, iprio); + (*csrmap)[MISELECT_IPRIO + i * 2 + 1] = std::make_shared(proc, MISELECT_IPRIO + i * 2 + 1, iprio); + } + } + break; + } + case CSR_SIREG: + { + csrmap = &proc->imsic->s->csrmap; + // IMSIC registers are defined to be 32-bit and odd ones drop out when xlen is 64 + const unsigned num_iprio_regs = (SISELECT_IPRIO_TOP - SISELECT_IPRIO + 1) / 2; + for (size_t i = 0; i < num_iprio_regs; i++) { + auto iprio = std::make_shared(proc, SISELECT_IPRIO + i * 2, 0); + if (xlen == 64) { + (*csrmap)[SISELECT_IPRIO + i * 2] = iprio; + } else { + (*csrmap)[SISELECT_IPRIO + i * 2] = std::make_shared(proc, SISELECT_IPRIO + i * 2, iprio); + (*csrmap)[SISELECT_IPRIO + i * 2 + 1] = std::make_shared(proc, SISELECT_IPRIO + i * 2 + 1, iprio); + } + } + break; + } + case CSR_VSIREG: + // Virtualized ireg (vsireg) does not have a csrmap ecause it changes based on hstatus.vgein + vs = true; + break; + default: + // Unexpected *ireg address + assert(false); + } +} + +csr_t_p aia_ireg_proxy_csr_t::get_reg() const noexcept { + reg_t reg = iselect->read(); + if (vs) { + // vsireg - look up by vgein + reg_t vgein = get_field(state->hstatus->read(), HSTATUS_VGEIN); + return vgein ? proc->imsic->get_vs_reg(vgein, reg) : nullptr; + } + // !vsireg + return csrmap->count(reg) ? (*csrmap)[reg] : nullptr; +} + +reg_t aia_ireg_proxy_csr_t::read() const noexcept { + csr_t_p reg = get_reg(); + return reg ? reg->read() : 0; +} + +void aia_ireg_proxy_csr_t::verify_permissions(insn_t insn, bool write) const { + // skip verfy_permissions chaining on a VS reg because the address is remapped + if (!vs) + csr_t::verify_permissions(insn, write); + if (get_reg() == nullptr) { + if (state->v) + throw trap_virtual_instruction(insn.bits()); + else + throw trap_illegal_instruction(insn.bits()); + } + if (proc->extension_enabled(EXT_SMSTATEEN)) { + // if iselect >= IMSIC and xSTATEEN_IMSIC not set + reg_t isel = iselect->read(); + if (!state->v && state->prv < PRV_M && isel >= SISELECT_IMSIC && isel <= SISELECT_IMSIC_TOP && !(state->mstateen[0]->read() & MSTATEEN0_IMSIC)) + throw trap_illegal_instruction(insn.bits()); + if (state->v && isel >= VSISELECT_IMSIC && isel <= VSISELECT_IMSIC_TOP && !(state->hstateen[0]->read() & HSTATEEN0_IMSIC)) + throw trap_virtual_instruction(insn.bits()); + } + // if VS & invalid VGEIN + if (vs && !get_reg()) { + if (state->v) + throw trap_virtual_instruction(insn.bits()); + else + throw trap_illegal_instruction(insn.bits()); + } +} + +bool aia_ireg_proxy_csr_t::unlogged_write(const reg_t val) noexcept { + csr_t_p reg = get_reg(); + if (!reg) + return false; + reg->write(val); + return true; +} + +csrmap_t_p aia_ireg_proxy_csr_t::get_csrmap(reg_t vgein) { + if (!vs) + return csrmap; + return proc->imsic->get_vs_csrmap(vgein ? vgein : get_field(state->hstatus->read(), HSTATUS_VGEIN)); +} diff --git a/riscv/csrs.h b/riscv/csrs.h index 3a350f6489..9292573f04 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -1012,4 +1012,21 @@ class hgeie_csr_t final: public masked_csr_t { protected: virtual bool unlogged_write(const reg_t val) noexcept override; }; + +typedef std::unordered_map csrmap_t; +typedef csrmap_t *csrmap_t_p; +class aia_ireg_proxy_csr_t: public csr_t { + public: + aia_ireg_proxy_csr_t(processor_t* const proc, const reg_t addr, csr_t_p iselect); + virtual reg_t read() const noexcept override; + virtual void verify_permissions(insn_t insn, bool write) const override; + csrmap_t_p get_csrmap(reg_t vgein = 0); + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; + private: + csr_t_p get_reg() const noexcept; + csr_t_p iselect; + bool vs; + csrmap_t_p csrmap; +}; #endif diff --git a/riscv/imsic.h b/riscv/imsic.h index 30c1104ca1..dcfdedab67 100644 --- a/riscv/imsic.h +++ b/riscv/imsic.h @@ -22,9 +22,6 @@ #define SETEIPNUM_LE 0x0 #define SETEIPNUM_BE 0x4 -typedef std::unordered_map csrmap_t; -typedef csrmap_t *csrmap_t_p; - class imsic_file_t; typedef std::shared_ptr imsic_file_t_p; From d5783b81e5cc9f5c9ee90068b94efc6b75a73013 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Tue, 27 May 2025 07:47:52 -0700 Subject: [PATCH 09/21] AIA: instantiate M-mode IMSIC indirect CSRs --- riscv/csr_init.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc index 29eff7a086..8a94ef039b 100644 --- a/riscv/csr_init.cc +++ b/riscv/csr_init.cc @@ -420,6 +420,18 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) const reg_t mireg_csrs[] = { CSR_MIREG2, CSR_MIREG3, CSR_MIREG4, CSR_MIREG5, CSR_MIREG6 }; for (auto csr : mireg_csrs) add_csr(csr, std::make_shared(proc, csr, miselect)); + + if (proc->extension_enabled_const(EXT_SMAIA)) { + // *ireg needs to be a proxy of *iselect and a CSR map keyed by the value in *iselect + // If address not in CSR map, throw illegal or virtual instruction trap + auto aia_mireg = std::make_shared(proc, CSR_MIREG, miselect); + for (auto &csr : *aia_mireg->get_csrmap()) + mireg->add_ireg_proxy(csr.first, aia_mireg); + // reserved range RAZ/WI + mireg->add_ireg_proxy(0x71, aia_mireg); + for (int i = 0x73; i <= 0x7f; i++) + mireg->add_ireg_proxy(i, aia_mireg); + } } if (proc->extension_enabled_const(EXT_SSCSRIND)) { From fcaf0d97b8082b0fdb431ccdd78f12dc96519ae8 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Tue, 27 May 2025 08:07:47 -0700 Subject: [PATCH 10/21] AIA: instantiate S/VS IMSIC indirect CSRs --- riscv/csr_init.cc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc index 8a94ef039b..243141d3f8 100644 --- a/riscv/csr_init.cc +++ b/riscv/csr_init.cc @@ -510,6 +510,25 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) } } } + if (proc->extension_enabled_const(EXT_SSAIA)) { + auto aia_vsireg = std::make_shared(proc, CSR_VSIREG, vsiselect); + // csrmaps of vs files are the same as vgein = 1 + for (auto &csr : *aia_vsireg->get_csrmap(1)) + vsireg->add_ireg_proxy(csr.first, aia_vsireg); + // reserved range RAZ/WI + vsireg->add_ireg_proxy(0x71, aia_vsireg); + for (int i = 0x73; i <= 0x7f; i++) + vsireg->add_ireg_proxy(i, aia_vsireg); + + auto aia_sireg = std::make_shared(proc, CSR_SIREG, siselect); + for (auto &csr : *aia_sireg->get_csrmap()) + sireg->add_ireg_proxy(csr.first, aia_sireg); + // reserved range RAZ/WI + sireg->add_ireg_proxy(0x71, aia_sireg); + for (int i = 0x73; i <= 0x7f; i++) + sireg->add_ireg_proxy(i, aia_sireg); + } + } if (proc->extension_enabled_const(EXT_SMCNTRPMF)) { From a7f46b687968b949ecf081bf61bd59aed684fda6 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Tue, 27 May 2025 09:00:40 -0700 Subject: [PATCH 11/21] AIA: add mtopei/stopei/vstopei CSRs --- riscv/csr_init.cc | 6 ++++- riscv/csrs.cc | 68 +++++++++++++++++++++++++++++++++++++++++++++++ riscv/csrs.h | 24 +++++++++++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc index 243141d3f8..b4f5c826e7 100644 --- a/riscv/csr_init.cc +++ b/riscv/csr_init.cc @@ -550,6 +550,7 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) mvip = std::make_shared(proc, CSR_MVIP, 0); if (proc->extension_enabled_const(EXT_SMAIA)) { add_csr(CSR_MTOPI, std::make_shared(proc, CSR_MTOPI)); + add_csr(CSR_MTOPEI, std::make_shared(proc, CSR_MTOPEI, proc->imsic->m)); if (xlen == 32) { add_supervisor_csr(CSR_MVIEN, std::make_shared(proc, CSR_MVIEN, mvien)); add_supervisor_csr(CSR_MVIENH, std::make_shared(proc, CSR_MVIENH, mvien)); @@ -566,7 +567,9 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) if (proc->extension_enabled_const(EXT_SSAIA)) { // Included by EXT_SMAIA csr_t_p nonvirtual_stopi = std::make_shared(proc, CSR_STOPI); add_supervisor_csr(CSR_STOPI, std::make_shared(proc, nonvirtual_stopi, vstopi)); - add_supervisor_csr(CSR_STOPEI, std::make_shared(proc, CSR_STOPEI)); + auto vstopei = std::make_shared(proc, CSR_VSTOPEI); + auto nonvirtual_stopei = std::make_shared(proc, CSR_STOPEI, proc->imsic->s); + add_supervisor_csr(CSR_STOPEI, std::make_shared(proc, nonvirtual_stopei, vstopei)); auto hvien = std::make_shared(proc, CSR_HVIEN, 0, 0); auto hviprio1 = std::make_shared(proc, CSR_HVIPRIO1, 0, 0); auto hviprio2 = std::make_shared(proc, CSR_HVIPRIO2, 0, 0); @@ -584,5 +587,6 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) } add_hypervisor_csr(CSR_HVICTL, hvictl); add_hypervisor_csr(CSR_VSTOPI, vstopi); + add_hypervisor_csr(CSR_VSTOPEI, vstopei); } } diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 3a8397eb3c..f3bd26dfc0 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -2377,3 +2377,71 @@ csrmap_t_p aia_ireg_proxy_csr_t::get_csrmap(reg_t vgein) { return csrmap; return proc->imsic->get_vs_csrmap(vgein ? vgein : get_field(state->hstatus->read(), HSTATUS_VGEIN)); } + +topei_csr_t::topei_csr_t(processor_t* const proc, const reg_t addr, imsic_file_t_p const imsic) : csr_t(proc, addr), imsic(imsic) { +} + +imsic_file_t_p topei_csr_t::get_imsic() const noexcept { + // non-virtualized registers have pointers to IMSIC + if (imsic) + return imsic; + + // Virtualized IMSIC depends on hstatus.vgein + reg_t vgein = get_field(state->hstatus->read(), HSTATUS_VGEIN); + if (!vgein || !proc->imsic->vgein_valid(vgein)) + return nullptr; + return proc->imsic->vs[vgein]; +} + +reg_t topei_csr_t::read() const noexcept { + imsic_file_t_p p = get_imsic(); + if (!p) + return 0; + + reg_t iid = p->topei(); + reg_t v = 0; + v = set_field(v, IMSIC_TOPI_IPRIO, iid); + v = set_field(v, IMSIC_TOPI_IID, iid); + return v; +} + +bool topei_csr_t::unlogged_write(const reg_t val) noexcept { + imsic_file_t_p p = get_imsic(); + if (!p) + return false; + p->claimei(p->topei()); + return true; +} + +void nonvirtual_stopei_csr_t::verify_permissions(insn_t insn, bool write) const { + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if ((state->prv < PRV_M) && !(state->mstateen[0]->read() & MSTATEEN0_IMSIC)) + throw trap_illegal_instruction(insn.bits()); + + if (state->v && !(state->hstateen[0]->read() & HSTATEEN0_IMSIC)) + throw trap_virtual_instruction(insn.bits()); + } + + csr_t::verify_permissions(insn, write); +} + +void vstopei_csr_t::verify_permissions(insn_t insn, bool write) const { + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if ((state->prv < PRV_M) && !(state->mstateen[0]->read() & MSTATEEN0_IMSIC)) + throw trap_illegal_instruction(insn.bits()); + + if (state->v && !(state->hstateen[0]->read() & HSTATEEN0_IMSIC)) + throw trap_virtual_instruction(insn.bits()); + } + + csr_t::verify_permissions(insn, write); + + // VGEIN must be valid + reg_t vgein = get_field(state->hstatus->read(), HSTATUS_VGEIN); + if (!vgein || !proc->imsic->vgein_valid(vgein)) { + if (state->v) + throw trap_virtual_instruction(insn.bits()); + else + throw trap_illegal_instruction(insn.bits()); + } +} diff --git a/riscv/csrs.h b/riscv/csrs.h index 9292573f04..5c62fe898d 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -1029,4 +1029,28 @@ class aia_ireg_proxy_csr_t: public csr_t { bool vs; csrmap_t_p csrmap; }; + +class imsic_file_t; +typedef std::shared_ptr imsic_file_t_p; +class topei_csr_t: public csr_t { + public: + topei_csr_t(processor_t* const proc, const reg_t addr, imsic_file_t_p const imsic); + virtual reg_t read() const noexcept override; + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; + imsic_file_t_p get_imsic() const noexcept; + imsic_file_t_p const imsic; +}; + +class nonvirtual_stopei_csr_t: public topei_csr_t { + public: + nonvirtual_stopei_csr_t(processor_t* const proc, const reg_t addr, imsic_file_t_p const imsic) : topei_csr_t(proc, addr, imsic) {} + virtual void verify_permissions(insn_t insn, bool write) const override; +}; + +class vstopei_csr_t: public topei_csr_t { + public: + vstopei_csr_t(processor_t* const proc, const reg_t addr) : topei_csr_t(proc, addr, nullptr) {} + virtual void verify_permissions(insn_t insn, bool write) const override; +}; #endif From e5db9a72dc60833dc615cb05779dd9d07bc9114c Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Thu, 3 Nov 2022 06:05:37 -0700 Subject: [PATCH 12/21] AIA: Add APLIC support --- riscv/aplic.cc | 295 ++++++++++++++++++++++++++++++++++++++++++++++ riscv/devices.h | 34 ++++++ riscv/dts.cc | 28 ++++- riscv/dts.h | 1 + riscv/ns16550.cc | 11 +- riscv/platform.h | 3 + riscv/riscv.mk.in | 1 + riscv/sim.cc | 21 ++++ riscv/sim.h | 9 +- 9 files changed, 398 insertions(+), 5 deletions(-) create mode 100644 riscv/aplic.cc diff --git a/riscv/aplic.cc b/riscv/aplic.cc new file mode 100644 index 0000000000..ae82e9a739 --- /dev/null +++ b/riscv/aplic.cc @@ -0,0 +1,295 @@ +// See LICENSE for license details. +#include "devices.h" +#include "processor.h" +#include "arith.h" +#include "sim.h" + +#define DOMAINCFG 0x0 +#define SOURCECFG_BASE 0x4 +#define MMSIADDRCFG 0x1bc0 +#define MMSIADDRCFGH 0x1bc4 +#define SMSIADDRCFG 0x1bc8 +#define SMSIADDRCFGH 0x1bcc +#define SETIP_BASE 0x1c00 +#define SETIPNUM 0x1cdc +#define IN_CLRIP_BASE 0x1d00 +#define CLRIPNUM 0x1ddc +#define SETIE_BASE 0x1e00 +#define SETIENUM 0x1edc +#define CLRIE_BASE 0x1f00 +#define CLRIENUM 0x1fdc +#define GENMSI 0x3000 +#define TARGET_BASE 0x3004 +#define IDC 0x4000 + +#define DOMAINCFG_IE_MASK 0x100 +#define DOMAINCFG_DM_MASK 0x4 + +#define SOURCECFG_D_MASK 0x400 +#define SOURCECFG_CHILD_MASK 0x3ff +#define SOURCECFG_SM_MASK 0x7 + +#define MMSIADDRCFGH_L_MASK 0x80000000 + +#define GENMSI_HART_MASK 0xfffc0000 +#define GENMSI_BUSY_MASK 0x1000 +#define GENMSI_EIID_MASK 0x7ff + +#define TARGET_HART_MASK 0xfffc0000 +#define TARGET_GUEST_MASK 0x3f000 +#define TARGET_EIID_MASK 0x7ff + +aplic_t::aplic_t(std::vector& procs, aplic_t *parent) : procs(procs), parent(parent), child(nullptr), domaincfg((0x80 << 24) | DOMAINCFG_DM_MASK), sourcecfg(), mmsiaddrcfgh(MMSIADDRCFGH_L_MASK), ie(), target(), level(), genmsi(0), deleg_mask() +{ +} + +void aplic_t::delegate(uint32_t id, bool dm) +{ + if (!id || id >= APLIC_MAX_DEVICES) + return; + + if (!child) { + // child's sourcecfg = 0 when interrupt is changed to delegated + if (!parent->delegated(id) && dm) + sourcecfg[id] = 0; + } else { + uint32_t mask = (1 << (id % 32)); + deleg_mask[id / 32] &= ~mask; + deleg_mask[id / 32] |= dm ? mask : 0; + child->delegate(id, dm); + } +} + +bool aplic_t::delegated(uint32_t id) +{ + if (!id || id >= APLIC_MAX_DEVICES) + return false; + return (sourcecfg[id] & SOURCECFG_D_MASK); +} + +uint32_t aplic_t::get_deleg_mask(uint32_t idx) { + if (idx >= APLIC_MAX_DEVICES / 32) + return 0; + if (parent) + return parent->get_deleg_mask(idx); + return deleg_mask[idx]; + } + +bool aplic_t::interrupt_enabled(uint32_t id) +{ + if (!id || id >= APLIC_MAX_DEVICES) + return false; + if (parent && !parent->delegated(id)) + return false; + // Domain interrupt enabled, source IE and source mode != inactive (0) + return (domaincfg & DOMAINCFG_IE_MASK) && (ie[id / 32] & (1 << (id % 32))) && (sourcecfg[id] & SOURCECFG_SM_MASK); +} + +bool aplic_t::accessible(uint32_t id) +{ + if (!id || id >= APLIC_MAX_DEVICES) + return false; + if (!parent) + return true; + return parent->delegated(id); +} + +void aplic_t::set_interrupt_level(uint32_t id, int lvl) +{ + if (child && delegated(id)) { + child->set_interrupt_level(id, lvl); + return; + } + + if (!accessible(id)) + return; + + uint32_t mask = 1 << (id % 32); + level[id / 32] &= ~mask; + level[id / 32] |= lvl ? mask : 0; + + update_interrupt(id); +} + +void aplic_t::send_msi(uint32_t proc_id, uint32_t guest, uint32_t eiid) +{ + if (!eiid || proc_id >= procs.size()) + return; + + auto proc = procs[proc_id]; + if (!parent) { + proc->imsic->m->pendei(eiid); + } else if (guest) { + if (proc->imsic->vs.count(guest)) + proc->imsic->vs[guest]->pendei(eiid); + } else { + proc->imsic->s->pendei(eiid); + } +} + +void aplic_t::send_msi(uint32_t id) +{ + if (id >= APLIC_MAX_DEVICES) + return; + auto tgt = target[id]; + send_msi(get_field(tgt, TARGET_HART_MASK), get_field(tgt, TARGET_GUEST_MASK), get_field(tgt, TARGET_EIID_MASK)); +} + +void aplic_t::update_interrupt(uint32_t id) +{ + // check level and if interrupt enabled, send MSI if necessary + if (id >= APLIC_MAX_DEVICES) + return; + bool lvl = level[id / 32] & (1 << (id % 32)); + if (lvl && interrupt_enabled(id)) + send_msi(id); +} + +void aplic_t::update_interrupt_masked(uint32_t idx, uint32_t mask) +{ + if (idx >= APLIC_MAX_DEVICES / 32) + return; + while(mask) { + auto id = ctz(mask); + update_interrupt(idx * 32 + id); + mask &= ~(1 << id); + } +} + +bool aplic_t::load(reg_t addr, size_t len, uint8_t* bytes) +{ + uint32_t val = 0; + + if (len != 4) { + return false; + } + + addr &= ~reg_t(3); + + if (addr == DOMAINCFG) { + val = domaincfg; + } else if (addr >= SOURCECFG_BASE && addr < MMSIADDRCFG) { + auto idx = (addr - SOURCECFG_BASE) / 4 + 1; + if (accessible(idx)) + val = sourcecfg[idx]; + } else if (addr == MMSIADDRCFGH) { + val = mmsiaddrcfgh; + } else if (addr >= IN_CLRIP_BASE && addr < CLRIPNUM) { + auto idx = (addr - IN_CLRIP_BASE) / 4; + val = level[idx]; + } else if (addr >= SETIE_BASE && addr < SETIENUM) { + auto idx = (addr - SETIE_BASE) / 4; + val = ie[idx]; + } else if (addr == GENMSI) { + val = genmsi; + } else if (addr >= TARGET_BASE && addr < IDC) { + auto idx = (addr - TARGET_BASE) / 4 + 1; + if (accessible(idx)) + val = target[idx]; + } + + memcpy(bytes, (uint8_t *)&val, len); + + return true; +} + +bool aplic_t::store(reg_t addr, size_t len, const uint8_t* bytes) +{ + uint32_t val = 0; + + if (len != 4) { + return false; + } + + addr &= ~reg_t(3); + memcpy((uint8_t *)&val, bytes, len); + + if (addr == DOMAINCFG) { + domaincfg &= ~DOMAINCFG_IE_MASK; + domaincfg |= val & DOMAINCFG_IE_MASK; + } else if (addr >= SOURCECFG_BASE && addr < MMSIADDRCFG) { + auto idx = (addr - SOURCECFG_BASE) / 4 + 1; + // write to D bit sets child's sourcecfg to 0 + // SM = inactive (0) or Level1 (6) + if (accessible(idx)) { + if (!child && (val & SOURCECFG_D_MASK)) + val = 0; + else if (child) + delegate(idx, val & SOURCECFG_D_MASK); + + // force SM to be 6 if non-zero + if (val & SOURCECFG_SM_MASK) + val = set_field(val, SOURCECFG_SM_MASK, 6); + + sourcecfg[idx] = val; + } + } else if (addr >= SETIP_BASE && addr < SETIPNUM) { + auto idx = (addr - SETIP_BASE) / 4; + val &= get_deleg_mask(idx); + update_interrupt_masked(idx, val); + } else if (addr == SETIPNUM) { + update_interrupt(val); + } else if (addr >= SETIE_BASE && addr < SETIENUM) { + auto idx = (addr - SETIE_BASE) / 4; + val &= get_deleg_mask(idx); + ie[idx] |= val; + } else if (addr == SETIENUM) { + if (accessible(val)) + ie[val / 32] |= 1 << (val % 32); + } else if (addr >= CLRIE_BASE && addr < CLRIENUM) { + auto idx = (addr - CLRIE_BASE) / 4; + val &= get_deleg_mask(idx); + ie[idx] &= ~val; + } else if (addr == CLRIENUM) { + if (accessible(val)) + ie[val / 32] &= ~(1 << (val % 32)); + } else if (addr == GENMSI) { + genmsi = val & (GENMSI_HART_MASK | GENMSI_EIID_MASK); + send_msi(get_field(genmsi, GENMSI_HART_MASK), 0, get_field(genmsi, GENMSI_EIID_MASK)); + } else if (addr >= TARGET_BASE && addr < IDC) { + auto idx = (addr - TARGET_BASE) / 4 + 1; + if (accessible(val)) + target[idx] = val; + } + + return true; +} + +std::string aplic_generate_dts(const sim_t* sim, const std::vector& sargs UNUSED) +{ + auto cfg = sim->get_cfg(); + isa_parser_t isa(cfg.isa, cfg.priv); + std::stringstream s; + if (isa.extension_enabled(EXT_SMAIA)) { + s << std::hex + << " APLIC_M: aplic@" << APLIC_M_BASE << " {\n" + " riscv,delegate = <&APLIC_S 0x01 0x35>;\n" + " riscv,children = <&APLIC_S>;\n" + " riscv,num-sources = <0x35>;\n" + " reg = <0x00 0x" << APLIC_M_BASE << " 0x00 0x" << APLIC_SIZE << ">;\n" + " msi-parent = <&IMSIC_M>;\n" + " interrupt-controller;\n" + " #interrupt-cells = <0x02>;\n" + " compatible = \"riscv,aplic\";\n" + " };\n"; + } + if (isa.extension_enabled(EXT_SSAIA)) { + s << std::hex + << " APLIC_S: aplic@" << APLIC_S_BASE << " {\n" + " riscv,num-sources = <0x35>;\n" + " reg = <0x00 0x" << APLIC_S_BASE << " 0x00 0x" << APLIC_SIZE << ">;\n" + " msi-parent = <&IMSIC_S>;\n" + " interrupt-controller;\n" + " #interrupt-cells = <0x02>;\n" + " compatible = \"riscv,aplic\";\n" + " };\n"; + } + return s.str(); +} + +aplic_t* aplic_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, const std::vector& sargs UNUSED) +{ + return nullptr; +} + +REGISTER_DEVICE(aplic, aplic_parse_from_fdt, aplic_generate_dts) diff --git a/riscv/devices.h b/riscv/devices.h index ccb5c9befa..84b0e4d6cb 100644 --- a/riscv/devices.h +++ b/riscv/devices.h @@ -159,6 +159,40 @@ class plic_t : public abstract_device_t, public abstract_interrupt_controller_t reg_t offset, uint32_t val); }; +#define APLIC_MAX_DEVICES 1024 +class aplic_t : public abstract_device_t, public abstract_interrupt_controller_t { + public: + aplic_t(std::vector&, aplic_t *parent); + bool load(reg_t addr, size_t len, uint8_t* bytes); + bool store(reg_t addr, size_t len, const uint8_t* bytes); + void set_interrupt_level(uint32_t id, int lvl); + reg_t size() { return APLIC_SIZE; } + void set_child(aplic_t *c) { child = c; } + void delegate(uint32_t id, bool dm); + bool delegated(uint32_t id); + uint32_t get_deleg_mask(uint32_t idx); + private: + std::vector& procs; + class aplic_t *parent; + class aplic_t *child; + uint32_t domaincfg; + uint32_t sourcecfg[APLIC_MAX_DEVICES]; + uint32_t mmsiaddrcfgh; + uint32_t ie[APLIC_MAX_DEVICES / 32]; + uint32_t target[APLIC_MAX_DEVICES]; + uint32_t level[APLIC_MAX_DEVICES / 32]; + uint32_t genmsi; + // deleg_mask can be directly applied to other packed registers + uint32_t deleg_mask[APLIC_MAX_DEVICES / 32]; + + bool interrupt_enabled(uint32_t id); + bool accessible(uint32_t id); + void send_msi(uint32_t proc_id, uint32_t guest, uint32_t eiid); + void send_msi(uint32_t id); + void update_interrupt(uint32_t id); + void update_interrupt_masked(uint32_t idx, uint32_t mask); +}; + class ns16550_t : public abstract_device_t { public: ns16550_t(abstract_interrupt_controller_t *intctrl, diff --git a/riscv/dts.cc b/riscv/dts.cc index 78a17b5d29..f266d9bf22 100644 --- a/riscv/dts.cc +++ b/riscv/dts.cc @@ -446,7 +446,6 @@ int fdt_parse_imsics(const void *fdt, reg_t *imsic_m_addr, reg_t *imsic_s_addr, { int nodeoffset = -1, len, rc; const fdt32_t *p; - reg_t addr = 0; int val; for (int i = 0; i < 2; i++) { @@ -454,6 +453,7 @@ int fdt_parse_imsics(const void *fdt, reg_t *imsic_m_addr, reg_t *imsic_s_addr, if (nodeoffset < 0) return nodeoffset; + reg_t addr = 0; rc = fdt_get_node_addr_size(fdt, nodeoffset, &addr, NULL, "reg"); if (rc < 0) return -ENODEV; @@ -470,3 +470,29 @@ int fdt_parse_imsics(const void *fdt, reg_t *imsic_m_addr, reg_t *imsic_s_addr, } return 0; } + +int fdt_parse_aplic(const void *fdt, reg_t *aplic_m_addr, reg_t *aplic_s_addr, const char *compatible) +{ + int nodeoffset = -1, len, rc; + const fdt32_t *p; + + for (int i = 0; i < 2; i++) { + nodeoffset = fdt_node_offset_by_compatible(fdt, nodeoffset, compatible); + if (nodeoffset < 0) + return nodeoffset; + + reg_t addr = 0; + rc = fdt_get_node_addr_size(fdt, nodeoffset, &addr, NULL, "reg"); + if (rc < 0) + return -ENODEV; + + p = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "riscv,children", &len); + + if (p && aplic_m_addr) + *aplic_m_addr = addr; + else if (!p && aplic_s_addr) + *aplic_s_addr = addr; + } + + return 0; +} diff --git a/riscv/dts.h b/riscv/dts.h index a0a5724207..8852d7723b 100644 --- a/riscv/dts.h +++ b/riscv/dts.h @@ -33,4 +33,5 @@ int fdt_parse_mmu_type(const void *fdt, int cpu_offset, const char **mmu_type); int fdt_parse_isa(const void *fdt, int cpu_offset, const char **isa_str); int fdt_parse_hartid(const void *fdt, int cpu_offset, uint32_t *hartid); int fdt_parse_imsics(const void *fdt, reg_t *imsic_m_addr, reg_t *imsic_s_addr, const char *compatible); +int fdt_parse_aplic(const void *fdt, reg_t *aplic_m_addr, reg_t *aplic_s_addr, const char *compatible); #endif diff --git a/riscv/ns16550.cc b/riscv/ns16550.cc index 15e087332c..16d9eabed4 100644 --- a/riscv/ns16550.cc +++ b/riscv/ns16550.cc @@ -330,13 +330,18 @@ void ns16550_t::tick(reg_t UNUSED rtc_ticks) std::string ns16550_generate_dts(const sim_t* sim, const std::vector& sargs UNUSED) { + auto cfg = sim->get_cfg(); + isa_parser_t isa(cfg.isa, cfg.priv); std::stringstream s; s << std::hex << " SERIAL0: ns16550@" << NS16550_BASE << " {\n" " compatible = \"ns16550a\";\n" - " clock-frequency = <" << std::dec << (sim->CPU_HZ/sim->INSNS_PER_RTC_TICK) << ">;\n" - " interrupt-parent = <&PLIC>;\n" - " interrupts = <" << std::dec << NS16550_INTERRUPT_ID; + " clock-frequency = <" << std::dec << (sim->CPU_HZ/sim->INSNS_PER_RTC_TICK) << ">;\n"; + if (isa.extension_enabled(EXT_SSAIA)) + s << " interrupt-parent = <&APLIC_S>;\n"; + else + s << " interrupt-parent = <&PLIC>;\n"; + s << " interrupts = <" << std::dec << NS16550_INTERRUPT_ID; reg_t ns16550bs = NS16550_BASE; reg_t ns16550sz = NS16550_SIZE; s << std::hex << ">;\n" diff --git a/riscv/platform.h b/riscv/platform.h index 794f8a8b4a..ec358c1245 100644 --- a/riscv/platform.h +++ b/riscv/platform.h @@ -18,6 +18,9 @@ #define PLIC_SIZE 0x01000000 #define PLIC_NDEV 31 #define PLIC_PRIO_BITS 4 +#define APLIC_M_BASE 0x0c000000 +#define APLIC_S_BASE 0x0d000000 +#define APLIC_SIZE 0x00008000 #define NS16550_BASE 0x10000000 #define NS16550_SIZE 0x100 #define NS16550_REG_SHIFT 0 diff --git a/riscv/riscv.mk.in b/riscv/riscv.mk.in index c0c78fd542..820da1c58a 100644 --- a/riscv/riscv.mk.in +++ b/riscv/riscv.mk.in @@ -77,6 +77,7 @@ riscv_srcs = \ vector_unit.cc \ socketif.cc \ cfg.cc \ + aplic.cc \ $(riscv_gen_srcs) \ riscv_test_srcs = \ diff --git a/riscv/sim.cc b/riscv/sim.cc index 030f4f2f1f..c5180f29a7 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -35,6 +35,7 @@ const size_t sim_t::INTERLEAVE; extern device_factory_t* clint_factory; extern device_factory_t* plic_factory; +extern device_factory_t* aplic_factory; extern device_factory_t* ns16550_factory; extern device_factory_t* imsic_mmio_factory; @@ -123,6 +124,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, {clint_factory, {}}, // clint must be element 0 {plic_factory, {}}, // plic must be element 1 {imsic_mmio_factory, {}}, + {aplic_factory, {}}, {ns16550_factory, {}}}; device_factories.insert(device_factories.end(), plugin_device_factories.begin(), @@ -140,9 +142,13 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, dtb = strstream.str(); dts = dtb_to_dts(dtb); } else { + isa_parser_t isa(cfg->isa, cfg->priv); std::string device_nodes; for (const device_factory_sargs_t& factory_sargs: device_factories) { const device_factory_t* factory = factory_sargs.first; + // skip PLIC if SSAIA + if (factory == plic_factory && isa.extension_enabled(EXT_SSAIA)) + continue; const std::vector& sargs = factory_sargs.second; device_nodes.append(factory->generate_dts(this, sargs)); } @@ -272,6 +278,21 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, } } + // create aplic + reg_t aplic_m_base, aplic_s_base; + if (fdt_parse_aplic(fdt, &aplic_m_base, &aplic_s_base, "riscv,aplic") == 0) { + if (aplic_m_base) { + aplic_m.reset(new aplic_t(procs, nullptr)); + bus.add_device(aplic_m_base, aplic_m.get()); + } + if (aplic_s_base) { + aplic_s.reset(new aplic_t(procs, aplic_m.get())); + bus.add_device(aplic_s_base, aplic_s.get()); + if (aplic_m) + aplic_m->set_child(aplic_s.get()); + } + } + // must be located after procs/harts are set (devices might use sim_t get_* member functions) for (size_t i = 0; i < device_factories.size(); i++) { const device_factory_t* factory = device_factories[i].first; diff --git a/riscv/sim.h b/riscv/sim.h index da04a88284..6552680f25 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -56,7 +56,12 @@ class sim_t : public htif_t, public simif_t } const char* get_dts() { return dts.c_str(); } processor_t* get_core(size_t i) { return procs.at(i); } - abstract_interrupt_controller_t* get_intctrl() const { assert(plic.get()); return plic.get(); } + abstract_interrupt_controller_t* get_intctrl() const { + if (aplic_s) + return aplic_s.get(); + assert(plic.get()); + return plic.get(); + } virtual const cfg_t &get_cfg() const override { return *cfg; } virtual const std::map& get_harts() const override { return harts; } @@ -80,6 +85,8 @@ class sim_t : public htif_t, public simif_t std::vector> devices; std::shared_ptr clint; std::shared_ptr plic; + std::shared_ptr aplic_m; + std::shared_ptr aplic_s; bus_t bus; log_file_t log_file; From 197ac7d103e671c02aee125ec4294bdb8ee0b98e Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Thu, 29 May 2025 10:06:29 -0700 Subject: [PATCH 13/21] AIA: refactor APLIC init --- riscv/aplic.cc | 47 +++++++++++++++++++++++++++++++++++++++++------ riscv/devices.h | 4 ++-- riscv/sim.cc | 25 ++++++++----------------- riscv/sim.h | 4 ++-- 4 files changed, 53 insertions(+), 27 deletions(-) diff --git a/riscv/aplic.cc b/riscv/aplic.cc index ae82e9a739..a6601111c5 100644 --- a/riscv/aplic.cc +++ b/riscv/aplic.cc @@ -3,6 +3,7 @@ #include "processor.h" #include "arith.h" #include "sim.h" +#include "dts.h" #define DOMAINCFG 0x0 #define SOURCECFG_BASE 0x4 @@ -39,7 +40,7 @@ #define TARGET_GUEST_MASK 0x3f000 #define TARGET_EIID_MASK 0x7ff -aplic_t::aplic_t(std::vector& procs, aplic_t *parent) : procs(procs), parent(parent), child(nullptr), domaincfg((0x80 << 24) | DOMAINCFG_DM_MASK), sourcecfg(), mmsiaddrcfgh(MMSIADDRCFGH_L_MASK), ie(), target(), level(), genmsi(0), deleg_mask() +aplic_t::aplic_t(const simif_t *simif, aplic_t *parent) : simif(simif), parent(parent), child(nullptr), domaincfg((0x80 << 24) | DOMAINCFG_DM_MASK), sourcecfg(), mmsiaddrcfgh(MMSIADDRCFGH_L_MASK), ie(), target(), level(), genmsi(0), deleg_mask() { } @@ -113,10 +114,12 @@ void aplic_t::set_interrupt_level(uint32_t id, int lvl) void aplic_t::send_msi(uint32_t proc_id, uint32_t guest, uint32_t eiid) { - if (!eiid || proc_id >= procs.size()) + auto &procs = simif->get_harts(); + auto it = procs.find(proc_id); + if (!eiid || it == procs.end()) return; - auto proc = procs[proc_id]; + processor_t *proc = it->second; if (!parent) { proc->imsic->m->pendei(eiid); } else if (guest) { @@ -255,7 +258,7 @@ bool aplic_t::store(reg_t addr, size_t len, const uint8_t* bytes) return true; } -std::string aplic_generate_dts(const sim_t* sim, const std::vector& sargs UNUSED) +std::string aplic_m_generate_dts(const sim_t* sim, const std::vector& sargs UNUSED) { auto cfg = sim->get_cfg(); isa_parser_t isa(cfg.isa, cfg.priv); @@ -273,6 +276,14 @@ std::string aplic_generate_dts(const sim_t* sim, const std::vector& " compatible = \"riscv,aplic\";\n" " };\n"; } + return s.str(); +} + +std::string aplic_s_generate_dts(const sim_t* sim, const std::vector& sargs UNUSED) +{ + auto cfg = sim->get_cfg(); + isa_parser_t isa(cfg.isa, cfg.priv); + std::stringstream s; if (isa.extension_enabled(EXT_SSAIA)) { s << std::hex << " APLIC_S: aplic@" << APLIC_S_BASE << " {\n" @@ -287,9 +298,33 @@ std::string aplic_generate_dts(const sim_t* sim, const std::vector& return s.str(); } -aplic_t* aplic_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, const std::vector& sargs UNUSED) +typedef aplic_t aplic_m_t; +typedef aplic_t aplic_s_t; +aplic_m_t* aplic_m_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, const std::vector& sargs UNUSED) { + reg_t aplic_m_base, aplic_s_base; + if (fdt_parse_aplic(fdt, &aplic_m_base, &aplic_s_base, "riscv,aplic") == 0) { + if (aplic_m_base) { + *base = aplic_m_base; + return new aplic_t(sim, nullptr); + } + } return nullptr; } -REGISTER_DEVICE(aplic, aplic_parse_from_fdt, aplic_generate_dts) +aplic_s_t* aplic_s_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, const std::vector& sargs UNUSED) +{ + reg_t aplic_m_base, aplic_s_base; + if (fdt_parse_aplic(fdt, &aplic_m_base, &aplic_s_base, "riscv,aplic") == 0) { + if (aplic_s_base) { + *base = aplic_s_base; + auto *ptr = new aplic_t(sim, sim->aplic_m.get()); + if (sim->aplic_m) + sim->aplic_m->set_child(ptr); + return ptr; + } + } + return nullptr; +} +REGISTER_DEVICE(aplic_m, aplic_m_parse_from_fdt, aplic_m_generate_dts) +REGISTER_DEVICE(aplic_s, aplic_s_parse_from_fdt, aplic_s_generate_dts) diff --git a/riscv/devices.h b/riscv/devices.h index 84b0e4d6cb..f594544b66 100644 --- a/riscv/devices.h +++ b/riscv/devices.h @@ -162,7 +162,7 @@ class plic_t : public abstract_device_t, public abstract_interrupt_controller_t #define APLIC_MAX_DEVICES 1024 class aplic_t : public abstract_device_t, public abstract_interrupt_controller_t { public: - aplic_t(std::vector&, aplic_t *parent); + aplic_t(const simif_t*, aplic_t *parent); bool load(reg_t addr, size_t len, uint8_t* bytes); bool store(reg_t addr, size_t len, const uint8_t* bytes); void set_interrupt_level(uint32_t id, int lvl); @@ -172,7 +172,7 @@ class aplic_t : public abstract_device_t, public abstract_interrupt_controller_t bool delegated(uint32_t id); uint32_t get_deleg_mask(uint32_t idx); private: - std::vector& procs; + const simif_t *simif; class aplic_t *parent; class aplic_t *child; uint32_t domaincfg; diff --git a/riscv/sim.cc b/riscv/sim.cc index c5180f29a7..cbc5859792 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -35,7 +35,8 @@ const size_t sim_t::INTERLEAVE; extern device_factory_t* clint_factory; extern device_factory_t* plic_factory; -extern device_factory_t* aplic_factory; +extern device_factory_t* aplic_m_factory; +extern device_factory_t* aplic_s_factory; extern device_factory_t* ns16550_factory; extern device_factory_t* imsic_mmio_factory; @@ -124,7 +125,8 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, {clint_factory, {}}, // clint must be element 0 {plic_factory, {}}, // plic must be element 1 {imsic_mmio_factory, {}}, - {aplic_factory, {}}, + {aplic_m_factory, {}}, // must be element 3 + {aplic_s_factory, {}}, // must be element 4 {ns16550_factory, {}}}; device_factories.insert(device_factories.end(), plugin_device_factories.begin(), @@ -278,21 +280,6 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, } } - // create aplic - reg_t aplic_m_base, aplic_s_base; - if (fdt_parse_aplic(fdt, &aplic_m_base, &aplic_s_base, "riscv,aplic") == 0) { - if (aplic_m_base) { - aplic_m.reset(new aplic_t(procs, nullptr)); - bus.add_device(aplic_m_base, aplic_m.get()); - } - if (aplic_s_base) { - aplic_s.reset(new aplic_t(procs, aplic_m.get())); - bus.add_device(aplic_s_base, aplic_s.get()); - if (aplic_m) - aplic_m->set_child(aplic_s.get()); - } - } - // must be located after procs/harts are set (devices might use sim_t get_* member functions) for (size_t i = 0; i < device_factories.size(); i++) { const device_factory_t* factory = device_factories[i].first; @@ -308,6 +295,10 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, clint = std::static_pointer_cast(dev_ptr); else if (i == 1) // plic_factory plic = std::static_pointer_cast(dev_ptr); + else if (i == 3) // aplic_m_factory + aplic_m = std::static_pointer_cast(dev_ptr); + else if (i == 4) // aplic_s_factory + aplic_s = std::static_pointer_cast(dev_ptr); } } } diff --git a/riscv/sim.h b/riscv/sim.h index 6552680f25..3bed383a3f 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -73,6 +73,8 @@ class sim_t : public htif_t, public simif_t static const size_t INSNS_PER_RTC_TICK = 100; // 10 MHz clock for 1 BIPS core static const size_t CPU_HZ = 1000000000; // 1GHz CPU + std::shared_ptr aplic_m; + std::shared_ptr aplic_s; private: const cfg_t * const cfg; std::vector> mems; @@ -85,8 +87,6 @@ class sim_t : public htif_t, public simif_t std::vector> devices; std::shared_ptr clint; std::shared_ptr plic; - std::shared_ptr aplic_m; - std::shared_ptr aplic_s; bus_t bus; log_file_t log_file; From fdad2560d6cc9b9df0fc346770ae994d8186601a Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Tue, 27 May 2025 10:37:36 -0700 Subject: [PATCH 14/21] AIA: implement SGEIP interrupt handling --- riscv/processor.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/riscv/processor.cc b/riscv/processor.cc index fd32815395..d200a7d279 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -264,15 +264,17 @@ reg_t processor_t::select_an_interrupt_with_default_priority(reg_t enabled_inter enabled_interrupts = MIP_SSIP; else if (enabled_interrupts & MIP_STIP) enabled_interrupts = MIP_STIP; - else if (enabled_interrupts & MIP_LCOFIP) - enabled_interrupts = MIP_LCOFIP; + else if (enabled_interrupts & MIP_SGEIP) + enabled_interrupts = MIP_SGEIP; else if (enabled_interrupts & MIP_VSEIP) enabled_interrupts = MIP_VSEIP; else if (enabled_interrupts & MIP_VSSIP) enabled_interrupts = MIP_VSSIP; else if (enabled_interrupts & MIP_VSTIP) enabled_interrupts = MIP_VSTIP; - + else if (enabled_interrupts & MIP_LCOFIP) + enabled_interrupts = MIP_LCOFIP; + else assert(0); return enabled_interrupts; } From a4b084100ce19bd93010e7def8d299960587b749 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Tue, 27 May 2025 10:53:18 -0700 Subject: [PATCH 15/21] AIA: include hypervisor interrupts in HS stopi --- riscv/csr_init.cc | 4 ++-- riscv/csrs.cc | 6 +++++- riscv/processor.h | 2 ++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc index b4f5c826e7..cf826930bb 100644 --- a/riscv/csr_init.cc +++ b/riscv/csr_init.cc @@ -155,7 +155,7 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) add_hypervisor_csr(CSR_VSIP, vsip); add_supervisor_csr(CSR_SIP, sip); } - add_hypervisor_csr(CSR_HIP, std::make_shared(proc, CSR_HIP, hip_hie_accr)); + add_hypervisor_csr(CSR_HIP, hip = std::make_shared(proc, CSR_HIP, hip_hie_accr)); hvip = std::make_shared(proc, CSR_HVIP, 0); if (xlen == 32 && proc->extension_enabled_const(EXT_SSAIA)) { add_hypervisor_csr(CSR_HVIP, std::make_shared(proc, CSR_HVIP, hvip)); @@ -176,7 +176,7 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) add_hypervisor_csr(CSR_VSIE, vsie); add_supervisor_csr(CSR_SIE, sie); } - add_hypervisor_csr(CSR_HIE, std::make_shared(proc, CSR_HIE, hip_hie_accr)); + add_hypervisor_csr(CSR_HIE, hie = std::make_shared(proc, CSR_HIE, hip_hie_accr)); add_supervisor_csr(CSR_MEDELEG, medeleg = std::make_shared(proc, CSR_MEDELEG)); mideleg = std::make_shared(proc, CSR_MIDELEG); diff --git a/riscv/csrs.cc b/riscv/csrs.cc index f3bd26dfc0..9ed86cf663 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -2141,7 +2141,11 @@ void nonvirtual_stopi_csr_t::verify_permissions(insn_t insn, bool write) const { } reg_t nonvirtual_stopi_csr_t::read() const noexcept { - reg_t enabled_interrupts = state->nonvirtual_sip->read() & state->nonvirtual_sie->read() & ~state->hideleg->read(); + reg_t enabled_interrupts = state->nonvirtual_sip->read() & state->nonvirtual_sie->read(); + // include hypervisor interrupts for HS stopi + enabled_interrupts |= state->hip->read() & state->hie->read(); + // mask out delegated interrupts + enabled_interrupts &= ~state->hideleg->read(); if (!enabled_interrupts) return 0; // no enabled pending interrupt to S-mode diff --git a/riscv/processor.h b/riscv/processor.h index 213f8b8f20..c2e8b85820 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -133,6 +133,8 @@ struct state_t csr_t_p hgatp; csr_t_p hgeie; csr_t_p hgeip; + csr_t_p hip; + csr_t_p hie; hvip_csr_t_p hvip; sstatus_csr_t_p sstatus; vsstatus_csr_t_p vsstatus; From 217285ab5a656982aad8fae1394dbd5f9b249943 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Tue, 27 May 2025 14:15:16 -0700 Subject: [PATCH 16/21] AIA: replace iprio with reserve ranges in add_ireg_proxy aia_ireg_proxy_csr_t ignores writes and reads 0 by default --- riscv/csr_init.cc | 37 ++++++++----------------------------- riscv/csrs.h | 1 + riscv/processor.h | 2 +- 3 files changed, 10 insertions(+), 30 deletions(-) diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc index cf826930bb..4b05b267c7 100644 --- a/riscv/csr_init.cc +++ b/riscv/csr_init.cc @@ -12,22 +12,12 @@ void state_t::add_csr(reg_t addr, const csr_t_p& csr) #define add_supervisor_csr(addr, csr) add_const_ext_csr('S', addr, csr) #define add_hypervisor_csr(addr, csr) add_ext_csr('H', addr, csr) -void state_t::add_ireg_proxy(processor_t* const proc, sscsrind_reg_csr_t::sscsrind_reg_csr_t_p ireg) +void state_t::add_ireg_proxy(sscsrind_reg_csr_t::sscsrind_reg_csr_t_p ireg, aia_ireg_proxy_csr_t_p aia_proxy) { - // This assumes xlen is always max_xlen, which is true today (see - // mstatus_csr_t::unlogged_write()): - auto xlen = proc->get_isa().get_max_xlen(); - - const reg_t iprio0_addr = 0x30; - for (int i=0; i<16; i+=2) { - csr_t_p iprio = std::make_shared(proc, iprio0_addr + i, 0, 0); - if (xlen == 32) { - ireg->add_ireg_proxy(iprio0_addr + i, std::make_shared(proc, iprio0_addr + i, iprio)); - ireg->add_ireg_proxy(iprio0_addr + i + 1, std::make_shared(proc, iprio0_addr + i + 1, iprio)); - } else { - ireg->add_ireg_proxy(iprio0_addr + i, iprio); - } - } + // reserved range RAZ/WI + ireg->add_ireg_proxy(0x71, aia_proxy); + for (int i = 0x73; i <= 0x7f; i++) + ireg->add_ireg_proxy(i, aia_proxy); } void state_t::csr_init(processor_t* const proc, reg_t max_isa) @@ -416,7 +406,6 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) sscsrind_reg_csr_t::sscsrind_reg_csr_t_p mireg; add_csr(CSR_MIREG, mireg = std::make_shared(proc, CSR_MIREG, miselect)); - add_ireg_proxy(proc, mireg); const reg_t mireg_csrs[] = { CSR_MIREG2, CSR_MIREG3, CSR_MIREG4, CSR_MIREG5, CSR_MIREG6 }; for (auto csr : mireg_csrs) add_csr(csr, std::make_shared(proc, csr, miselect)); @@ -427,10 +416,7 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) auto aia_mireg = std::make_shared(proc, CSR_MIREG, miselect); for (auto &csr : *aia_mireg->get_csrmap()) mireg->add_ireg_proxy(csr.first, aia_mireg); - // reserved range RAZ/WI - mireg->add_ireg_proxy(0x71, aia_mireg); - for (int i = 0x73; i <= 0x7f; i++) - mireg->add_ireg_proxy(i, aia_mireg); + add_ireg_proxy(mireg, aia_mireg); } } @@ -445,7 +431,6 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) add_hypervisor_csr(CSR_VSIREG, vsireg); auto sireg = std::make_shared(proc, CSR_SIREG, siselect); - add_ireg_proxy(proc, sireg); add_supervisor_csr(CSR_SIREG, std::make_shared(proc, sireg, vsireg)); const reg_t vsireg_csrs[] = { CSR_VSIREG2, CSR_VSIREG3, CSR_VSIREG4, CSR_VSIREG5, CSR_VSIREG6 }; @@ -515,18 +500,12 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) // csrmaps of vs files are the same as vgein = 1 for (auto &csr : *aia_vsireg->get_csrmap(1)) vsireg->add_ireg_proxy(csr.first, aia_vsireg); - // reserved range RAZ/WI - vsireg->add_ireg_proxy(0x71, aia_vsireg); - for (int i = 0x73; i <= 0x7f; i++) - vsireg->add_ireg_proxy(i, aia_vsireg); + add_ireg_proxy(vsireg, aia_vsireg); auto aia_sireg = std::make_shared(proc, CSR_SIREG, siselect); for (auto &csr : *aia_sireg->get_csrmap()) sireg->add_ireg_proxy(csr.first, aia_sireg); - // reserved range RAZ/WI - sireg->add_ireg_proxy(0x71, aia_sireg); - for (int i = 0x73; i <= 0x7f; i++) - sireg->add_ireg_proxy(i, aia_sireg); + add_ireg_proxy(sireg, aia_sireg); } } diff --git a/riscv/csrs.h b/riscv/csrs.h index 5c62fe898d..2e477c30b3 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -1029,6 +1029,7 @@ class aia_ireg_proxy_csr_t: public csr_t { bool vs; csrmap_t_p csrmap; }; +typedef std::shared_ptr aia_ireg_proxy_csr_t_p; class imsic_file_t; typedef std::shared_ptr imsic_file_t_p; diff --git a/riscv/processor.h b/riscv/processor.h index c2e8b85820..bd2d67a6d1 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -71,7 +71,7 @@ typedef std::vector> commit_log_mem_t; // architectural state of a RISC-V hart struct state_t { - void add_ireg_proxy(processor_t* const proc, sscsrind_reg_csr_t::sscsrind_reg_csr_t_p ireg); + void add_ireg_proxy(sscsrind_reg_csr_t::sscsrind_reg_csr_t_p ireg, aia_ireg_proxy_csr_t_p aia_proxy); void reset(processor_t* const proc, reg_t max_isa); void add_csr(reg_t addr, const csr_t_p& csr); From 149d82cf31cd1531067597b6086baf675d02ec6d Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Fri, 6 Jun 2025 05:09:06 -0700 Subject: [PATCH 17/21] AIA: add null pointer check to VS get_csrmap(1) --- riscv/csr_init.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc index 4b05b267c7..6099bb810e 100644 --- a/riscv/csr_init.cc +++ b/riscv/csr_init.cc @@ -498,9 +498,12 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) if (proc->extension_enabled_const(EXT_SSAIA)) { auto aia_vsireg = std::make_shared(proc, CSR_VSIREG, vsiselect); // csrmaps of vs files are the same as vgein = 1 - for (auto &csr : *aia_vsireg->get_csrmap(1)) - vsireg->add_ireg_proxy(csr.first, aia_vsireg); - add_ireg_proxy(vsireg, aia_vsireg); + auto *csrmap = aia_vsireg->get_csrmap(1); + if (csrmap) { + for (auto &csr : *csrmap) + vsireg->add_ireg_proxy(csr.first, aia_vsireg); + add_ireg_proxy(vsireg, aia_vsireg); + } auto aia_sireg = std::make_shared(proc, CSR_SIREG, siselect); for (auto &csr : *aia_sireg->get_csrmap()) From 2a5e00af00f8e3fecd13fbcb7475b8433f99c73d Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Tue, 27 May 2025 14:42:21 -0700 Subject: [PATCH 18/21] AIA: add AIA and IMSIC bits to mstateen0/hstateen0 --- riscv/csr_init.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc index 6099bb810e..9f433e5d48 100644 --- a/riscv/csr_init.cc +++ b/riscv/csr_init.cc @@ -341,7 +341,9 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) const reg_t sstateen0_mask = (proc->extension_enabled(EXT_ZFINX) ? SSTATEEN0_FCSR : 0) | (proc->extension_enabled(EXT_ZCMT) ? SSTATEEN0_JVT : 0) | SSTATEEN0_CS; - const reg_t hstateen0_mask = sstateen0_mask | HSTATEEN0_CSRIND | HSTATEEN0_SENVCFG | HSTATEEN_SSTATEEN; + const reg_t hstateen0_mask = sstateen0_mask | HSTATEEN0_SENVCFG | HSTATEEN_SSTATEEN | + (proc->extension_enabled_const(EXT_SSCSRIND) ? HSTATEEN0_CSRIND : 0) | + (proc->extension_enabled_const(EXT_SSAIA) ? HSTATEEN0_IMSIC | HSTATEEN0_AIA : 0); const reg_t mstateen0_mask = hstateen0_mask | (proc->extension_enabled(EXT_SSQOSID) ? MSTATEEN0_PRIV114 : 0); for (int i = 0; i < 4; i++) { const reg_t mstateen_mask = i == 0 ? mstateen0_mask : MSTATEEN_HSTATEEN; From bf4616ed8cadd43eeef2f41577d811bf04f4c3b7 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Tue, 24 Jun 2025 05:17:17 -0700 Subject: [PATCH 19/21] AIA: eidelivery does not gate *topei registers --- riscv/csrs.cc | 2 +- riscv/imsic.cc | 4 +--- riscv/imsic.h | 1 + 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 9ed86cf663..8861ea82f3 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -2259,7 +2259,7 @@ reg_t hgeip_csr_t::read() const noexcept { // scan through all VGEINs reg_t v = 0; for (auto &i: proc->imsic->vs) { - if (i.second->topei()) + if (i.second->delivery() && i.second->topei()) v |= reg_t(1) << i.first; } return v; diff --git a/riscv/imsic.cc b/riscv/imsic.cc index ed1fccf40a..7096d29c12 100644 --- a/riscv/imsic.cc +++ b/riscv/imsic.cc @@ -48,8 +48,6 @@ imsic_file_t::imsic_file_t(processor_t* const proc, reg_t mip_mask, size_t num_r } reg_t imsic_file_t::topei() { - if (eidelivery->read() != 1) - return 0; reg_t thd = eithreshold->read(); for (size_t i = 0; i < IMSIC_NUM_EI_REGS; i++) { reg_t ints = eip[i]->read() & eie[i]->read(); @@ -81,7 +79,7 @@ void imsic_file_t::pendei(reg_t intr) { } void imsic_file_t::update_mip() { - reg_t iid = topei(); + reg_t iid = eidelivery->read() ? topei() : 0; if (v) { // Privileged 9.2.4: Register hgeie selects the subset of guest external interrupts that cause a supervisor-level (HS-level) guest external interrupt. bool sgeip = proc->get_state()->hgeie->read() & proc->get_state()->hgeip->read(); diff --git a/riscv/imsic.h b/riscv/imsic.h index dcfdedab67..d25db05af0 100644 --- a/riscv/imsic.h +++ b/riscv/imsic.h @@ -44,6 +44,7 @@ class imsic_file_t { void claimei(reg_t intr); void pendei(reg_t intr); void update_mip(); + bool delivery() { return eidelivery->read(); } csr_t_p get_reg(reg_t reg) { return csrmap.count(reg) ? csrmap[reg] : nullptr; } csrmap_t csrmap; From 7f4b9ffaca08b9b83c1b8a02fab0f30692fe3bcf Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Thu, 1 May 2025 16:56:19 -0700 Subject: [PATCH 20/21] Sstc: enable Zicntr with Sstc --- disasm/isa_parser.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/disasm/isa_parser.cc b/disasm/isa_parser.cc index 24eb5f284f..3f8ee13d73 100644 --- a/disasm/isa_parser.cc +++ b/disasm/isa_parser.cc @@ -328,7 +328,8 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) extension_table[EXT_ZVQDOTQ] = true; } else if (ext_str == "zvkt") { } else if (ext_str == "sstc") { - extension_table[EXT_SSTC] = true; + extension_table[EXT_SSTC] = true; + extension_table[EXT_ZICNTR] = true; } else if (ext_str == "smcsrind") { extension_table[EXT_SMCSRIND] = true; } else if (ext_str == "sscsrind") { From 199efd9c0bac74223d9ded3cb791a3a0cce5d290 Mon Sep 17 00:00:00 2001 From: Ian Huang Date: Thu, 1 May 2025 19:10:18 -0700 Subject: [PATCH 21/21] uart: add interrupt-high (4) to device tree --- riscv/ns16550.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/riscv/ns16550.cc b/riscv/ns16550.cc index 16d9eabed4..d657dfe59a 100644 --- a/riscv/ns16550.cc +++ b/riscv/ns16550.cc @@ -344,7 +344,7 @@ std::string ns16550_generate_dts(const sim_t* sim, const std::vector;\n" + s << std::hex << " 0x4>;\n" " reg = <0x" << (ns16550bs >> 32) << " 0x" << (ns16550bs & (uint32_t)-1) << " 0x" << (ns16550sz >> 32) << " 0x" << (ns16550sz & (uint32_t)-1) << ">;\n" " reg-shift = <0x" << NS16550_REG_SHIFT << ">;\n"