From 4b854a58cce3087e6404c80d0602ee310b33222e Mon Sep 17 00:00:00 2001 From: Eyck-Alexander Jentzsch Date: Sun, 14 Dec 2025 15:31:51 +0100 Subject: [PATCH 1/7] reworks mstatus handling, this introduces a hierarchical approach to the masking of the lower priv level status views --- src/iss/arch/riscv_hart_common.h | 5 ++ src/iss/arch/riscv_hart_m_p.h | 87 +++++++++++++++++++------------- src/iss/arch/riscv_hart_msu_vp.h | 61 +++++++++++++--------- src/iss/arch/riscv_hart_mu_p.h | 86 ++++++++++++------------------- 4 files changed, 127 insertions(+), 112 deletions(-) diff --git a/src/iss/arch/riscv_hart_common.h b/src/iss/arch/riscv_hart_common.h index 0e74270..a61804c 100644 --- a/src/iss/arch/riscv_hart_common.h +++ b/src/iss/arch/riscv_hart_common.h @@ -308,6 +308,11 @@ template struct priv_if { }; template struct riscv_hart_common : public BASE, public mem::memory_elem { + // Extension status bits (SD needs to be set when writing FS / VS / XS): + // TODO implement XS + static constexpr uint32_t extension_status_mask = + (traits::FP_REGS_SIZE ? (0b11u << 13) : 0u) | (traits::V_REGS_SIZE ? (0b11u << 9) : 0u); + const std::array lvl = {{'U', 'S', 'H', 'M'}}; const std::array trap_str = {{"" "Instruction address misaligned", // 0 diff --git a/src/iss/arch/riscv_hart_m_p.h b/src/iss/arch/riscv_hart_m_p.h index 3e74d3b..e144505 100644 --- a/src/iss/arch/riscv_hart_m_p.h +++ b/src/iss/arch/riscv_hart_m_p.h @@ -63,46 +63,65 @@ template class riscv_hart_m_p : pub using reg_t = typename core::reg_t; using phys_addr_t = typename core::phys_addr_t; + // Notation for differing fields is: 32 bits / 64 bits + static constexpr uint32_t lower_half = 0b00000000000000000001100010001000; + // ||||||||||||||||/|/|/|/||||||||| + // |||||||||||||||| | | | ||||||||+-- UIE + // |||||||||||||||| | | | |||||||+--- SIE + // |||||||||||||||| | | | ||||||+---- WPRI + // |||||||||||||||| | | | |||||+----- MIE + // |||||||||||||||| | | | ||||+------ UPIE + // |||||||||||||||| | | | |||+------- SPIE + // |||||||||||||||| | | | ||+-------- UBE + // |||||||||||||||| | | | |+--------- MPIE + // |||||||||||||||| | | | +---------- SPP + // |||||||||||||||| | | +------------ VS + // |||||||||||||||| | +-------------- MPP + // |||||||||||||||| +---------------- FS + // |||||||||||||||+------------------ XS + // ||||||||||||||+------------------- MPRV + // |||||||||||||+-------------------- SUM + // ||||||||||||+--------------------- MXR + // |||||||||||+---------------------- TVM + // ||||||||||+----------------------- TW + // |||||||||+------------------------ TSR + // ||||||||+------------------------- SPELP + // |||||||+-------------------------- SDT + // ||||||+--------------------------- WPRI + // +--------------------------------- SD / WPRI + + // upper half corresponds to mstatush bit meanings + static constexpr uint32_t upper_half = 0b00000000000000000000000000000000; + // |||||||||||||||||||||||||||||/|/ + // ||||||||||||||||||||||||||||| +--- WPRI / UXL + // ||||||||||||||||||||||||||||+----- WPRI / SXL + // |||||||||||||||||||||||||||+------ SBE + // |||||||||||||||||||||||||+-------- MBE + // ||||||||||||||||||||||||+--------- GVA + // |||||||||||||||||||||||+---------- MPV + // ||||||||||||||||||||||+----------- WPRI + // |||||||||||||||||||||+------------ MPELP + // ||||||||||||||||||||+------------- MDT + // +--------------------------------- WPRI / SD + static constexpr reg_t get_mstatus_mask() { - if(sizeof(reg_t) == 4) - // return 0x807ff988UL; // 0b1000 0000 0111 1111 1111 1000 1000 1000 // only machine mode is supported - // +-SD - // | +-TSR - // | |+-TW - // | ||+-TVM - // | |||+-MXR - // | ||||+-SUM - // | |||||+-MPRV - // | |||||| +-XS - // | |||||| | +-FS - // | |||||| | | +-MPP - // | |||||| | | | +-SPP - // | |||||| | | | |+-MPIE - // | ||||||/|/|/| || +-MIE - return 0b00000000000000000001100010001000; - else if(sizeof(reg_t) == 8) - // return 0x8000000f007ff9ddULL; // 0b1...0 1111 0000 0000 0111 1111 1111 1001 1011 1011 - // - // +-TSR - // |+-TW - // ||+-TVM - // |||+-MXR - // ||||+-SUM - // |||||+-MPRV - // |||||| +-XS - // |||||| | +-FS - // |||||| | | +-MPP - // |||||| | | | +-SPP - // |||||| | | | |+-MPIE - // ||||||/|/|/| || +-MIE - return 0b00000000000000000001100010001000; + if constexpr(sizeof(reg_t) == 4) + return lower_half | riscv_hart_common::extension_status_mask; + else if constexpr(sizeof(reg_t) == 8) + return static_cast(upper_half) << 32 | lower_half | riscv_hart_common::extension_status_mask; else - assert(false && "Unsupported XLEN value"); + static_assert("Unsupported XLEN value"); } void write_mstatus(reg_t val) { - auto mask = get_mstatus_mask() & 0xff; // MPP is hardcoded as 0x3 + constexpr auto mask = get_mstatus_mask(); auto new_val = (this->state.mstatus() & ~mask) | (val & mask); + if constexpr(riscv_hart_common::extension_status_mask) + // set SD bit if any of FS or VS are dirty + // FIXME: this wont work if XS is 01 and FS is 10 + if(reg_t masked = new_val & riscv_hart_common::extension_status_mask; masked & (masked >> 1)) + new_val |= reg_t(1) << (sizeof(reg_t) * 8 - 1); + this->state.mstatus = new_val; } diff --git a/src/iss/arch/riscv_hart_msu_vp.h b/src/iss/arch/riscv_hart_msu_vp.h index f5cdab2..0a48108 100644 --- a/src/iss/arch/riscv_hart_msu_vp.h +++ b/src/iss/arch/riscv_hart_msu_vp.h @@ -35,6 +35,7 @@ #ifndef _RISCV_HART_MSU_VP_H #define _RISCV_HART_MSU_VP_H +#include "iss/arch/riscv_hart_mu_p.h" #include "iss/arch/traits.h" #include "iss/vm_if.h" #include "iss/vm_types.h" @@ -66,32 +67,33 @@ template class riscv_hart_msu_vp : using this_class = riscv_hart_msu_vp; using reg_t = typename core::reg_t; using phys_addr_t = typename core::phys_addr_t; - + static constexpr uint32_t s_mask_lower = 0b00000000011111100000000100100010; + // ||||||||||||||||/|/|/|/||||||||| + // |||||||||||||||| | | | ||||||||+-- UIE + // |||||||||||||||| | | | |||||||+--- SIE + // |||||||||||||||| | | | ||||||+---- WPRI + // |||||||||||||||| | | | |||||+----- MIE + // |||||||||||||||| | | | ||||+------ UPIE + // |||||||||||||||| | | | |||+------- SPIE + // |||||||||||||||| | | | ||+-------- UBE + // |||||||||||||||| | | | |+--------- MPIE + // |||||||||||||||| | | | +---------- SPP + // |||||||||||||||| | | +------------ VS + // |||||||||||||||| | +-------------- MPP + // |||||||||||||||| +---------------- FS + // |||||||||||||||+------------------ XS + // ||||||||||||||+------------------- MPRV + // |||||||||||||+-------------------- SUM + // ||||||||||||+--------------------- MXR + // |||||||||||+---------------------- TVM + // ||||||||||+----------------------- TW + // |||||||||+------------------------ TSR + // ||||||||+------------------------- SPELP + // |||||||+-------------------------- SDT + // ||||||+--------------------------- WPRI + // +--------------------------------- SD / WPRI static constexpr reg_t get_mstatus_mask(unsigned priv_lvl) { - if(sizeof(reg_t) == 4) { -#if __cplusplus < 201402L - return priv_lvl == PRIV_U ? 0x80000011UL : priv_lvl == PRIV_S ? 0x800de133UL : 0x807ff9ddUL; -#else - switch(priv_lvl) { - case PRIV_U: - return 0x80000000UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001 - case PRIV_S: - return 0x800de762UL; // 0b1000 0000 0000 1101 1110 0001 0011 0011 - default: - return 0x801fffeaUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011 - } -#endif - } else if(sizeof(reg_t) == 8) { - switch(priv_lvl) { - case PRIV_U: - return 0x8000000f00000000ULL; // 0b1...0 1111 0000 0000 0111 1111 1111 1001 1011 1011 - case PRIV_S: - return 0x80000003000de762ULL; // 0b1...0 0011 0000 0000 0000 1101 1110 0111 0110 0010 - default: - return 0x80000030001fffeaULL; // 0b1...0 0000 0000 0000 0001 1111 1111 1111 1110 1010 - } - } else - assert(false && "Unsupported XLEN value"); + return riscv_hart_mu_p::get_mstatus_mask(priv_lvl) | ((priv_lvl >= PRIV_S) ? s_mask_lower : 0); } static constexpr reg_t get_mstatus_rd_mask(unsigned priv_lvl) { if(sizeof(reg_t) == 4) { @@ -115,6 +117,11 @@ template class riscv_hart_msu_vp : reg_t old_val = this->state.mstatus; auto mask = get_mstatus_mask(priv_lvl); auto new_val = (old_val & ~mask) | (val & mask); + if constexpr(riscv_hart_common::extension_status_mask) + // set SD bit if any of FS or VS are dirty + // FIXME: this wont work if XS is 01 and FS is 10 + if(reg_t masked = new_val & riscv_hart_common::extension_status_mask && masked & (masked >> 1)) + new_val |= reg_t(1) << (sizeof(reg_t) * 8 - 1); this->state.mstatus = new_val; } @@ -129,6 +136,10 @@ template class riscv_hart_msu_vp : if((new_val & this->state.mstatus.UXL.Mask) == 0) { new_val |= old_val & this->state.mstatus.UXL.Mask; } + if constexpr(riscv_hart_common::extension_status_mask) + if(new_val && riscv_hart_common::extension_status_mask) + // set SD bit if any of FS, VS and XS are set + new_val |= reg_t(1) << (sizeof(reg_t) * 8 - 1); this->state.mstatus = new_val; } diff --git a/src/iss/arch/riscv_hart_mu_p.h b/src/iss/arch/riscv_hart_mu_p.h index 525eeb1..cf0c4d5 100644 --- a/src/iss/arch/riscv_hart_mu_p.h +++ b/src/iss/arch/riscv_hart_mu_p.h @@ -35,6 +35,7 @@ #ifndef _RISCV_HART_MU_P_H #define _RISCV_HART_MU_P_H +#include "iss/arch/riscv_hart_m_p.h" #include "iss/arch/traits.h" #include "iss/vm_if.h" #include "iss/vm_types.h" @@ -42,6 +43,7 @@ #include "util/logging.h" #include #include +#include #include #include #include @@ -64,65 +66,43 @@ template class riscv_hart_mu_p : pu using reg_t = typename core::reg_t; using phys_addr_t = typename core::phys_addr_t; + static constexpr uint32_t u_mask_lower = 0b00000000000000000000000000010001; + // ||||||||||||||||/|/|/|/||||||||| + // |||||||||||||||| | | | ||||||||+-- UIE + // |||||||||||||||| | | | |||||||+--- SIE + // |||||||||||||||| | | | ||||||+---- WPRI + // |||||||||||||||| | | | |||||+----- MIE + // |||||||||||||||| | | | ||||+------ UPIE + // |||||||||||||||| | | | |||+------- SPIE + // |||||||||||||||| | | | ||+-------- UBE + // |||||||||||||||| | | | |+--------- MPIE + // |||||||||||||||| | | | +---------- SPP + // |||||||||||||||| | | +------------ VS + // |||||||||||||||| | +-------------- MPP + // |||||||||||||||| +---------------- FS + // |||||||||||||||+------------------ XS + // ||||||||||||||+------------------- MPRV + // |||||||||||||+-------------------- SUM + // ||||||||||||+--------------------- MXR + // |||||||||||+---------------------- TVM + // ||||||||||+----------------------- TW + // |||||||||+------------------------ TSR + // ||||||||+------------------------- SPELP + // |||||||+-------------------------- SDT + // ||||||+--------------------------- WPRI + // +--------------------------------- SD / WPRI static constexpr reg_t get_mstatus_mask(unsigned priv_lvl) { - if(sizeof(reg_t) == 4) { -#if __cplusplus < 201402L - return priv_lvl == PRIV_U ? 0x80000011UL : priv_lvl == PRIV_S ? 0x800de133UL : 0x807ff9ddUL; -#else - switch(priv_lvl) { - case PRIV_U: - return FEAT & features_e::FEAT_EXT_N ? 0x00000011UL : 0UL; // 0b1...0 0001 0001 - default: - // +-SD - // | +-TSR - // | |+-TW - // | ||+-TVM - // | |||+-MXR - // | ||||+-SUM - // | |||||+-MPRV - // | |||||| +-XS - // | |||||| | +-FS - // | |||||| | | +-MPP - // | |||||| | | | +-SPP - // | |||||| | | | |+-MPIE - // | |||||| | | | || +-UPIE - // | ||||||/|/|/| || |+-MIE - // | ||||||/|/|/| || || +-UIE - return 0b10000000001000000001100010011001; - } -#endif - } else if(sizeof(reg_t) == 8) { -#if __cplusplus < 201402L - return priv_lvl == PRIV_U ? 0x011ULL : priv_lvl == PRIV_S ? 0x000de133ULL : 0x007ff9ddULL; -#else - switch(priv_lvl) { - case PRIV_U: - return FEAT & features_e::FEAT_EXT_N ? 0x8000000000000011ULL : 0ULL; // 0b1...0 0001 0001 - default: - // +-TSR - // |+-TW - // ||+-TVM - // |||+-MXR - // ||||+-SUM - // |||||+-MPRV - // |||||| +-XS - // |||||| | +-FS - // |||||| | | +-MPP - // |||||| | | | +-SPP - // |||||| | | | |+-MPIE - // |||||| | | | || +-UPIE - // ||||||/|/|/| || |+-MIE - // ||||||/|/|/| || || +-UIE - return 0b00000000001000000001100010011001 | 0x8000000000000000ULL; - } -#endif - } else - assert(false && "Unsupported XLEN value"); + return u_mask_lower | (priv_lvl >= PRIV_M ? riscv_hart_m_p::get_mstatus_mask() : 0); } void write_mstatus(reg_t val, unsigned priv_lvl) { auto mask = get_mstatus_mask(priv_lvl); auto new_val = (this->state.mstatus() & ~mask) | (val & mask); + if constexpr(riscv_hart_common::extension_status_mask) + // set SD bit if any of FS or VS are dirty + // FIXME: this wont work if XS is 01 and FS is 10 + if(reg_t masked = new_val & riscv_hart_common::extension_status_mask && masked & (masked >> 1)) + new_val |= reg_t(1) << (sizeof(reg_t) * 8 - 1); this->state.mstatus = new_val; } From cf5f0815e03c03069789a91c7021c6da471e50f2 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Sun, 14 Dec 2025 17:06:49 +0100 Subject: [PATCH 2/7] fixes CLINT interrupt handling --- src/sysc/core2sc_adapter.h | 23 +++++------------------ src/sysc/core_complex.cpp | 6 +++--- src/sysc/core_complex.h | 7 +------ 3 files changed, 9 insertions(+), 27 deletions(-) diff --git a/src/sysc/core2sc_adapter.h b/src/sysc/core2sc_adapter.h index 754cc21..32b3fd7 100644 --- a/src/sysc/core2sc_adapter.h +++ b/src/sysc/core2sc_adapter.h @@ -35,8 +35,6 @@ #ifndef _SYSC_CORE2SC_ADAPTER_H_ #define _SYSC_CORE2SC_ADAPTER_H_ -#include "core_complex.h" -#include "iss/log_categories.h" #include "sc2core_if.h" #include "util/delegate.h" #include "util/logging.h" @@ -48,6 +46,7 @@ #include #include #include +#include #include #include @@ -245,7 +244,7 @@ template class core2sc_adapter : public PLAT, public sc2core_if void wait_until(uint64_t flags) { SCCDEBUG(owner->hier_name()) << "Sleeping until interrupt"; PLAT::wait_until(flags); - while(this->reg.pending_trap == 0 && (this->csr[iss::arch::mip] & this->csr[iss::arch::mie]) == 0) { + while((this->csr[iss::arch::mip] & this->csr[iss::arch::mie]) == 0) { sc_core::wait(wfi_evt); } } @@ -289,21 +288,8 @@ template class core2sc_adapter : public PLAT, public sc2core_if void _local_irq(short id, bool value) { reg_t mask = 0; - switch(id) { - case 3: // SW - mask = 1 << 3; - break; - case 7: // timer - mask = 1 << 7; - break; - case 11: // external - mask = 1 << 11; - break; - default: - if(id > 15) - mask = 1 << id; - break; - } + assert(id < 32 && "CLINT cannot handle more tahn 32 irq"); + mask = 1 << id; if(value) { this->csr[iss::arch::mip] |= mask; wfi_evt.notify(); @@ -313,6 +299,7 @@ template class core2sc_adapter : public PLAT, public sc2core_if if(value) SCCTRACE(owner->hier_name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap; } + void _local_irq_mt(short id, bool value) { std::unique_lock lock(sync_mtx); _local_irq(id, value); diff --git a/src/sysc/core_complex.cpp b/src/sysc/core_complex.cpp index 22e1cf7..1f38c7e 100644 --- a/src/sysc/core_complex.cpp +++ b/src/sysc/core_complex.cpp @@ -231,8 +231,8 @@ template void core_complex::i }); #else SC_METHOD(clint_irq_cb); - for(auto pin : clint_irq_i) - sensitive << pin; + dont_initialize(); + sensitive << clint_irq_i; #endif SC_METHOD(forward); @@ -359,7 +359,7 @@ template void core_complex::r template void core_complex::clint_irq_cb() { for(auto i = 0U; i < clint_irq_i.size(); ++i) { if(clint_irq_i[i].event()) { - core->local_irq(16 + i, clint_irq_i[i].read()); + core->local_irq(i, clint_irq_i[i].read()); } } } diff --git a/src/sysc/core_complex.h b/src/sysc/core_complex.h index f371057..e0e884c 100644 --- a/src/sysc/core_complex.h +++ b/src/sysc/core_complex.h @@ -97,7 +97,7 @@ class core_complex : public sc_core::sc_module, public scc::traceable, public co sc_core::sc_in rst_i{"rst_i"}; - sc_core::sc_vector clint_irq_i{"local_irq_i", 16}; + sc_core::sc_vector clint_irq_i{"clint_irq_i", 32}; #ifndef CWR_SYSTEMC sc_core::sc_in clk_i{"clk_i"}; @@ -186,11 +186,6 @@ class core_complex : public sc_core::sc_module, public scc::traceable, public co void sync(uint64_t cycle) override { auto core_inc = curr_clk * (cycle - last_sync_cycle); quantum_keeper.check_and_sync(core_inc); - // quantum_keeper.inc(core_inc); - // if(quantum_keeper.need_sync()) { - // wait(quantum_keeper.get_local_time()); - // quantum_keeper.reset(); - // } last_sync_cycle = cycle; } From 0f4bb16b1aac26f3b2686419821b033de335c83c Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Mon, 15 Dec 2025 11:25:11 +0100 Subject: [PATCH 3/7] adds initiator id for bus accesses --- src/sysc/core_complex.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/sysc/core_complex.cpp b/src/sysc/core_complex.cpp index 1f38c7e..46984fa 100644 --- a/src/sysc/core_complex.cpp +++ b/src/sysc/core_complex.cpp @@ -41,6 +41,7 @@ #include "iss_factory.h" #include "tlm/scc/quantum_keeper.h" #include "sysc/memspace_extension.h" +#include "tlm/scc/tlm_id.h" #include "util/range_lut.h" #include #include @@ -418,8 +419,11 @@ bool core_complex::read_mem(const addr_t& addr, unsigned length, u gp.set_data_length(length); gp.set_streaming_width(length); sc_time delay = quantum_keeper.get_local_time(); + sysc::memspace::tlm_memspace_extension<> mem_spc(static_cast(addr.space)); if(!is_fetch) - gp.set_extension(new sysc::memspace::tlm_memspace_extension<>(static_cast(addr.space))); + gp.set_extension(&mem_spc); + tlm::scc::initiator_id_extension id_ext{mhartid.get_value()}; + gp.set_extension(&id_ext); auto pre_delay = delay; exec_b_transport(gp, delay, is_fetch); if(pre_delay > delay) { @@ -447,6 +451,8 @@ bool core_complex::read_mem(const addr_t& addr, unsigned length, u dmi_lut.addEntry(dmi_data, dmi_data.get_start_address(), dmi_data.get_end_address() - dmi_data.get_start_address() + 1); } } + gp.set_extension(nullptr); + gp.set_extension>(nullptr); return true; } } @@ -476,7 +482,10 @@ bool core_complex::write_mem(const addr_t& addr, unsigned length, gp.set_data_length(length); gp.set_streaming_width(length); sc_time delay = quantum_keeper.get_local_time(); - gp.set_extension(new sysc::memspace::tlm_memspace_extension<>(static_cast(addr.space))); + sysc::memspace::tlm_memspace_extension<> mem_spc(static_cast(addr.space)); + gp.set_extension(&mem_spc); + tlm::scc::initiator_id_extension id_ext{mhartid.get_value()}; + gp.set_extension(&id_ext); auto pre_delay = delay; exec_b_transport(gp, delay); if(pre_delay > delay) @@ -500,6 +509,8 @@ bool core_complex::write_mem(const addr_t& addr, unsigned length, .addEntry(dmi_data, dmi_data.get_start_address(), dmi_data.get_end_address() - dmi_data.get_start_address() + 1); } } + gp.set_extension(nullptr); + gp.set_extension>(nullptr); return true; } } From 605c236f0366c9740edf2f51c322cb4078ece79f Mon Sep 17 00:00:00 2001 From: Eyck-Alexander Jentzsch Date: Tue, 16 Dec 2025 09:04:54 +0100 Subject: [PATCH 4/7] changes mstatus default value for 64 bits to implement UXL and SXL reads --- src/iss/arch/mstatus.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iss/arch/mstatus.h b/src/iss/arch/mstatus.h index 1795f0c..0a67596 100644 --- a/src/iss/arch/mstatus.h +++ b/src/iss/arch/mstatus.h @@ -238,7 +238,7 @@ template class hart_state Date: Tue, 16 Dec 2025 09:23:03 +0100 Subject: [PATCH 5/7] moves mask generation for mstatus into common, --- src/iss/arch/riscv_hart_common.h | 77 ++++++++++++++++++++++++++++---- src/iss/arch/riscv_hart_m_p.h | 62 ++----------------------- src/iss/arch/riscv_hart_msu_vp.h | 77 ++++---------------------------- src/iss/arch/riscv_hart_mu_p.h | 40 ++--------------- 4 files changed, 85 insertions(+), 171 deletions(-) diff --git a/src/iss/arch/riscv_hart_common.h b/src/iss/arch/riscv_hart_common.h index a61804c..9a76d3e 100644 --- a/src/iss/arch/riscv_hart_common.h +++ b/src/iss/arch/riscv_hart_common.h @@ -308,11 +308,78 @@ template struct priv_if { }; template struct riscv_hart_common : public BASE, public mem::memory_elem { - // Extension status bits (SD needs to be set when writing FS / VS / XS): + + constexpr static unsigned MEM = traits::MEM; + + using core = BASE; + using this_class = riscv_hart_common; + using reg_t = typename core::reg_t; + + using rd_csr_f = std::function; + using wr_csr_f = std::function; + + // Extension status bits (SD needs to be set when any of FS / VS / XS are dirty [0b11]): // TODO implement XS static constexpr uint32_t extension_status_mask = (traits::FP_REGS_SIZE ? (0b11u << 13) : 0u) | (traits::V_REGS_SIZE ? (0b11u << 9) : 0u); + // Notation for differing fields is: 32 bits / 64 bits + static constexpr uint32_t mstatus_lower = 0b00000000000000000001100010001000; + static constexpr uint32_t sstatus_lower = 0b00000000011111100000000100100010; + static constexpr uint32_t ustatus_lower = 0b00000000000000000000000000010001; + // ||||||/|||||||||/|/|/|/||||||||| + // |||||/ ||||||||| | | | ||||||||+-- UIE + // ||||/||||||||||| | | | |||||||+--- SIE + // |||/|||||||||||| | | | ||||||+---- WPRI + // ||/||||||||||||| | | | |||||+----- MIE + // |||||||||||||||| | | | ||||+------ UPIE + // |||||||||||||||| | | | |||+------- SPIE + // |||||||||||||||| | | | ||+-------- UBE + // |||||||||||||||| | | | |+--------- MPIE + // |||||||||||||||| | | | +---------- SPP + // |||||||||||||||| | | +------------ VS + // |||||||||||||||| | +-------------- MPP + // |||||||||||||||| +---------------- FS + // |||||||||||||||+------------------ XS + // ||||||||||||||+------------------- MPRV + // |||||||||||||+-------------------- SUM + // ||||||||||||+--------------------- MXR + // |||||||||||+---------------------- TVM + // ||||||||||+----------------------- TW + // |||||||||+------------------------ TSR + // ||||||||+------------------------- SPELP + // |||||||+-------------------------- SDT + // |++++++--------------------------- WPRI + // +--------------------------------- SD / WPRI + + // upper half does not correspond to mstatush bit meanings (UXL and SXL) + static constexpr uint32_t mstatus_upper = 0b00000000000000000000000000001111; + static constexpr uint32_t sstatus_upper = 0b00000000000000000000000000000011; + // |||||||||||||||||||||||||||||/|/ + // ||||||||||||||||||||||||||||| +--- WPRI / UXL + // ||||||||||||||||||||||||||||+----- WPRI / SXL + // |||||||||||||||||||||||||||+------ SBE + // |||||||||||||||||||||||||+-------- MBE + // ||||||||||||||||||||||||+--------- GVA + // |||||||||||||||||||||||+---------- MPV + // ||||||||||||||||||||||+----------- WPRI + // |||||||||||||||||||||+------------ MPELP + // ||||||||||||||||||||+------------- MDT + // |+++++++++++++++++++-------------- WPRI + // +--------------------------------- WPRI / SD + + static constexpr reg_t get_mstatus_mask() { + if constexpr(sizeof(reg_t) == 4) + return mstatus_lower | riscv_hart_common::extension_status_mask; + else if constexpr(sizeof(reg_t) == 8) + return static_cast(mstatus_upper) << 32 | mstatus_lower | riscv_hart_common::extension_status_mask; + else + static_assert("Unsupported XLEN value"); + } + static constexpr reg_t get_mu_status_mask(unsigned priv_lvl) { return ustatus_lower | (priv_lvl >= PRIV_M ? get_mstatus_mask() : 0); } + static constexpr reg_t get_msu_status_mask(unsigned priv_lvl) { + return get_mu_status_mask(priv_lvl) | ((priv_lvl >= PRIV_S) ? sstatus_lower : 0); + } const std::array lvl = {{'U', 'S', 'H', 'M'}}; const std::array trap_str = {{"" "Instruction address misaligned", // 0 @@ -335,14 +402,6 @@ template struct riscv_hart_common : public BAS "Machine software interrupt", "User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt", "User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}}; - constexpr static unsigned MEM = traits::MEM; - - using core = BASE; - using this_class = riscv_hart_common; - using reg_t = typename core::reg_t; - - using rd_csr_f = std::function; - using wr_csr_f = std::function; #define MK_CSR_RD_CB(FCT) [this](unsigned a, reg_t& r) -> iss::status { return this->FCT(a, r); }; #define MK_CSR_WR_CB(FCT) [this](unsigned a, reg_t r) -> iss::status { return this->FCT(a, r); }; diff --git a/src/iss/arch/riscv_hart_m_p.h b/src/iss/arch/riscv_hart_m_p.h index e144505..7e40196 100644 --- a/src/iss/arch/riscv_hart_m_p.h +++ b/src/iss/arch/riscv_hart_m_p.h @@ -38,7 +38,6 @@ #include "iss/arch/traits.h" #include "iss/vm_if.h" #include "iss/vm_types.h" -#include "riscv_hart_common.h" #include "util/logging.h" #include #include @@ -63,65 +62,12 @@ template class riscv_hart_m_p : pub using reg_t = typename core::reg_t; using phys_addr_t = typename core::phys_addr_t; - // Notation for differing fields is: 32 bits / 64 bits - static constexpr uint32_t lower_half = 0b00000000000000000001100010001000; - // ||||||||||||||||/|/|/|/||||||||| - // |||||||||||||||| | | | ||||||||+-- UIE - // |||||||||||||||| | | | |||||||+--- SIE - // |||||||||||||||| | | | ||||||+---- WPRI - // |||||||||||||||| | | | |||||+----- MIE - // |||||||||||||||| | | | ||||+------ UPIE - // |||||||||||||||| | | | |||+------- SPIE - // |||||||||||||||| | | | ||+-------- UBE - // |||||||||||||||| | | | |+--------- MPIE - // |||||||||||||||| | | | +---------- SPP - // |||||||||||||||| | | +------------ VS - // |||||||||||||||| | +-------------- MPP - // |||||||||||||||| +---------------- FS - // |||||||||||||||+------------------ XS - // ||||||||||||||+------------------- MPRV - // |||||||||||||+-------------------- SUM - // ||||||||||||+--------------------- MXR - // |||||||||||+---------------------- TVM - // ||||||||||+----------------------- TW - // |||||||||+------------------------ TSR - // ||||||||+------------------------- SPELP - // |||||||+-------------------------- SDT - // ||||||+--------------------------- WPRI - // +--------------------------------- SD / WPRI - - // upper half corresponds to mstatush bit meanings - static constexpr uint32_t upper_half = 0b00000000000000000000000000000000; - // |||||||||||||||||||||||||||||/|/ - // ||||||||||||||||||||||||||||| +--- WPRI / UXL - // ||||||||||||||||||||||||||||+----- WPRI / SXL - // |||||||||||||||||||||||||||+------ SBE - // |||||||||||||||||||||||||+-------- MBE - // ||||||||||||||||||||||||+--------- GVA - // |||||||||||||||||||||||+---------- MPV - // ||||||||||||||||||||||+----------- WPRI - // |||||||||||||||||||||+------------ MPELP - // ||||||||||||||||||||+------------- MDT - // +--------------------------------- WPRI / SD - - static constexpr reg_t get_mstatus_mask() { - if constexpr(sizeof(reg_t) == 4) - return lower_half | riscv_hart_common::extension_status_mask; - else if constexpr(sizeof(reg_t) == 8) - return static_cast(upper_half) << 32 | lower_half | riscv_hart_common::extension_status_mask; - else - static_assert("Unsupported XLEN value"); - } - void write_mstatus(reg_t val) { - constexpr auto mask = get_mstatus_mask(); + constexpr auto mask = base::get_mstatus_mask(); auto new_val = (this->state.mstatus() & ~mask) | (val & mask); - if constexpr(riscv_hart_common::extension_status_mask) - // set SD bit if any of FS or VS are dirty - // FIXME: this wont work if XS is 01 and FS is 10 - if(reg_t masked = new_val & riscv_hart_common::extension_status_mask; masked & (masked >> 1)) + if constexpr(base::extension_status_mask) + if((new_val & base::extension_status_mask) == base::extension_status_mask) new_val |= reg_t(1) << (sizeof(reg_t) * 8 - 1); - this->state.mstatus = new_val; } @@ -351,7 +297,7 @@ iss::status riscv_hart_m_p::write(const addr_t& a, const unsigned le } template iss::status riscv_hart_m_p::read_status(unsigned addr, reg_t& val) { - val = this->state.mstatus & get_mstatus_mask(); + val = this->state.mstatus & base::get_mstatus_mask(); return iss::Ok; } diff --git a/src/iss/arch/riscv_hart_msu_vp.h b/src/iss/arch/riscv_hart_msu_vp.h index 0a48108..9edb2e4 100644 --- a/src/iss/arch/riscv_hart_msu_vp.h +++ b/src/iss/arch/riscv_hart_msu_vp.h @@ -35,7 +35,6 @@ #ifndef _RISCV_HART_MSU_VP_H #define _RISCV_HART_MSU_VP_H -#include "iss/arch/riscv_hart_mu_p.h" #include "iss/arch/traits.h" #include "iss/vm_if.h" #include "iss/vm_types.h" @@ -67,78 +66,20 @@ template class riscv_hart_msu_vp : using this_class = riscv_hart_msu_vp; using reg_t = typename core::reg_t; using phys_addr_t = typename core::phys_addr_t; - static constexpr uint32_t s_mask_lower = 0b00000000011111100000000100100010; - // ||||||||||||||||/|/|/|/||||||||| - // |||||||||||||||| | | | ||||||||+-- UIE - // |||||||||||||||| | | | |||||||+--- SIE - // |||||||||||||||| | | | ||||||+---- WPRI - // |||||||||||||||| | | | |||||+----- MIE - // |||||||||||||||| | | | ||||+------ UPIE - // |||||||||||||||| | | | |||+------- SPIE - // |||||||||||||||| | | | ||+-------- UBE - // |||||||||||||||| | | | |+--------- MPIE - // |||||||||||||||| | | | +---------- SPP - // |||||||||||||||| | | +------------ VS - // |||||||||||||||| | +-------------- MPP - // |||||||||||||||| +---------------- FS - // |||||||||||||||+------------------ XS - // ||||||||||||||+------------------- MPRV - // |||||||||||||+-------------------- SUM - // ||||||||||||+--------------------- MXR - // |||||||||||+---------------------- TVM - // ||||||||||+----------------------- TW - // |||||||||+------------------------ TSR - // ||||||||+------------------------- SPELP - // |||||||+-------------------------- SDT - // ||||||+--------------------------- WPRI - // +--------------------------------- SD / WPRI - static constexpr reg_t get_mstatus_mask(unsigned priv_lvl) { - return riscv_hart_mu_p::get_mstatus_mask(priv_lvl) | ((priv_lvl >= PRIV_S) ? s_mask_lower : 0); - } - static constexpr reg_t get_mstatus_rd_mask(unsigned priv_lvl) { - if(sizeof(reg_t) == 4) { - return get_mstatus_mask(priv_lvl); - } else if(sizeof(reg_t) == 8) { - auto wr_mask = get_mstatus_mask(priv_lvl); - switch(priv_lvl) { - case PRIV_U: - return wr_mask; - case PRIV_S: - return wr_mask |= 0x300000000; - default: - return wr_mask |= 0xf00000000; - } - } else - assert(false && "Unsupported XLEN value"); - } - template ::value>* = nullptr> - void write_mstatus(T_ val, unsigned priv_lvl) { + void write_mstatus(reg_t val, unsigned priv_lvl) { reg_t old_val = this->state.mstatus; - auto mask = get_mstatus_mask(priv_lvl); + auto mask = base::get_msu_status_mask(priv_lvl); auto new_val = (old_val & ~mask) | (val & mask); - if constexpr(riscv_hart_common::extension_status_mask) - // set SD bit if any of FS or VS are dirty - // FIXME: this wont work if XS is 01 and FS is 10 - if(reg_t masked = new_val & riscv_hart_common::extension_status_mask && masked & (masked >> 1)) - new_val |= reg_t(1) << (sizeof(reg_t) * 8 - 1); - this->state.mstatus = new_val; - } - - template ::value>* = nullptr> - void write_mstatus(T_ val, unsigned priv_lvl) { - reg_t old_val = this->state.mstatus; - auto mask = get_mstatus_mask(priv_lvl); - auto new_val = (old_val & ~mask) | (val & mask); - if((new_val & this->state.mstatus.SXL.Mask) == 0) { + if constexpr(sizeof(reg_t) == 8) { + // Retain previous SXL and UXL value new_val |= old_val & this->state.mstatus.SXL.Mask; - } - if((new_val & this->state.mstatus.UXL.Mask) == 0) { + new_val |= old_val & this->state.mstatus.UXL.Mask; } - if constexpr(riscv_hart_common::extension_status_mask) - if(new_val && riscv_hart_common::extension_status_mask) - // set SD bit if any of FS, VS and XS are set + + if constexpr(base::extension_status_mask) + if((new_val & base::extension_status_mask) == base::extension_status_mask) new_val |= reg_t(1) << (sizeof(reg_t) * 8 - 1); this->state.mstatus = new_val; } @@ -439,7 +380,7 @@ iss::status riscv_hart_msu_vp::write(const addr_t& a, const unsigned template iss::status riscv_hart_msu_vp::read_status(unsigned addr, reg_t& val) { auto req_priv_lvl = (addr >> 8) & 0x3; - val = this->state.mstatus & get_mstatus_rd_mask(req_priv_lvl); + val = this->state.mstatus & base::get_msu_status_mask(req_priv_lvl); return iss::Ok; } diff --git a/src/iss/arch/riscv_hart_mu_p.h b/src/iss/arch/riscv_hart_mu_p.h index cf0c4d5..032ff17 100644 --- a/src/iss/arch/riscv_hart_mu_p.h +++ b/src/iss/arch/riscv_hart_mu_p.h @@ -35,7 +35,6 @@ #ifndef _RISCV_HART_MU_P_H #define _RISCV_HART_MU_P_H -#include "iss/arch/riscv_hart_m_p.h" #include "iss/arch/traits.h" #include "iss/vm_if.h" #include "iss/vm_types.h" @@ -66,42 +65,11 @@ template class riscv_hart_mu_p : pu using reg_t = typename core::reg_t; using phys_addr_t = typename core::phys_addr_t; - static constexpr uint32_t u_mask_lower = 0b00000000000000000000000000010001; - // ||||||||||||||||/|/|/|/||||||||| - // |||||||||||||||| | | | ||||||||+-- UIE - // |||||||||||||||| | | | |||||||+--- SIE - // |||||||||||||||| | | | ||||||+---- WPRI - // |||||||||||||||| | | | |||||+----- MIE - // |||||||||||||||| | | | ||||+------ UPIE - // |||||||||||||||| | | | |||+------- SPIE - // |||||||||||||||| | | | ||+-------- UBE - // |||||||||||||||| | | | |+--------- MPIE - // |||||||||||||||| | | | +---------- SPP - // |||||||||||||||| | | +------------ VS - // |||||||||||||||| | +-------------- MPP - // |||||||||||||||| +---------------- FS - // |||||||||||||||+------------------ XS - // ||||||||||||||+------------------- MPRV - // |||||||||||||+-------------------- SUM - // ||||||||||||+--------------------- MXR - // |||||||||||+---------------------- TVM - // ||||||||||+----------------------- TW - // |||||||||+------------------------ TSR - // ||||||||+------------------------- SPELP - // |||||||+-------------------------- SDT - // ||||||+--------------------------- WPRI - // +--------------------------------- SD / WPRI - static constexpr reg_t get_mstatus_mask(unsigned priv_lvl) { - return u_mask_lower | (priv_lvl >= PRIV_M ? riscv_hart_m_p::get_mstatus_mask() : 0); - } - void write_mstatus(reg_t val, unsigned priv_lvl) { - auto mask = get_mstatus_mask(priv_lvl); + auto mask = base::get_mu_status_mask(priv_lvl); auto new_val = (this->state.mstatus() & ~mask) | (val & mask); - if constexpr(riscv_hart_common::extension_status_mask) - // set SD bit if any of FS or VS are dirty - // FIXME: this wont work if XS is 01 and FS is 10 - if(reg_t masked = new_val & riscv_hart_common::extension_status_mask && masked & (masked >> 1)) + if constexpr(base::extension_status_mask) + if((new_val & base::extension_status_mask) == base::extension_status_mask) new_val |= reg_t(1) << (sizeof(reg_t) * 8 - 1); this->state.mstatus = new_val; } @@ -358,7 +326,7 @@ iss::status riscv_hart_mu_p::write(const addr_t& a, const unsigned l } template iss::status riscv_hart_mu_p::read_status(unsigned addr, reg_t& val) { - val = this->state.mstatus & get_mstatus_mask((addr >> 8) & 0x3); + val = this->state.mstatus & base::get_mu_status_mask((addr >> 8) & 0x3); return iss::Ok; } From 84017d2f3f93f4e24a50e611fdb68d80b9d87cb1 Mon Sep 17 00:00:00 2001 From: Eyck-Alexander Jentzsch Date: Tue, 16 Dec 2025 11:27:24 +0100 Subject: [PATCH 6/7] introduces bandaid fix for mstatus rst val --- src/iss/arch/mstatus.h | 10 +++++++++- src/iss/arch/riscv_hart_msu_vp.h | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/iss/arch/mstatus.h b/src/iss/arch/mstatus.h index 0a67596..2ea36d3 100644 --- a/src/iss/arch/mstatus.h +++ b/src/iss/arch/mstatus.h @@ -73,6 +73,8 @@ template struct status(v); }; // machine previous privilege static inline unsigned MPP(T v) { return bit_sub<11, 2>(v); }; + // vector unit status Off/Initial/Clean/Dirty + static inline unsigned VS(T v) { return bit_sub<9, 2>(v); }; // supervisor previous privilege static inline unsigned SPP(T v) { return bit_sub<8, 1>(v); }; // previous machine interrupt-enable @@ -121,6 +123,8 @@ template struct status(v); }; // machine previous privilege static inline unsigned MPP(T v) { return bit_sub<11, 2>(v); }; + // vector unit status Off/Initial/Clean/Dirty + static inline unsigned VS(T v) { return bit_sub<9, 2>(v); }; // supervisor previous privilege static inline unsigned SPP(T v) { return bit_sub<8, 1>(v); }; // previous machine interrupt-enable @@ -165,6 +169,8 @@ template class hart_state class hart_state class hart_state riscv_hart_msu_vp::riscv_hart_msu_vp() : mmu(base::get_priv_if()) , default_mem(base::get_priv_if()) { + if constexpr(sizeof(reg_t) == 8) + // set UXL and SXL to indicate 64 bits + // FIXME: this value is not preserved in resets + this->state.mstatus.backing.val |= 0x500000000; // common regs const std::array rwaddrs{ {mepc, mtvec, mscratch, mcause, mtval, sepc, stvec, sscratch, scause, stval, sscratch, uepc, utvec, uscratch, ucause, utval}}; From 2ca7c803813ec9d0145956e62c640eaa30a66d55 Mon Sep 17 00:00:00 2001 From: Eyck-Alexander Jentzsch Date: Tue, 16 Dec 2025 11:27:48 +0100 Subject: [PATCH 7/7] caches conan dependencies in github action --- .github/workflows/ci-compile.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci-compile.yml b/.github/workflows/ci-compile.yml index b053839..97c9fe6 100644 --- a/.github/workflows/ci-compile.yml +++ b/.github/workflows/ci-compile.yml @@ -31,6 +31,12 @@ jobs: - name: Update submodules run: git submodule update --init --recursive + + - name: Cache Conan + uses: actions/cache@v4 + with: + path: ~/.conan2 + key: conan-${{ runner.os }}-unit-cpp${{ matrix.cpp_std }}-${{ hashFiles('conanfile.py') }} - name: Install dependencies run: |