From 3dcea0e86e4f4982102ff72e01e5e705d0521848 Mon Sep 17 00:00:00 2001 From: 0xllx0 Date: Wed, 10 Sep 2025 23:54:51 +0000 Subject: [PATCH 01/76] register: add `miselect` CSR Adds the `miselect` register for selecting an indirect CSR according to the `Smcsrind` extension. Reference: --- riscv/src/register.rs | 3 +++ riscv/src/register/miselect.rs | 47 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 riscv/src/register/miselect.rs diff --git a/riscv/src/register.rs b/riscv/src/register.rs index cabd1922..2dc9f534 100644 --- a/riscv/src/register.rs +++ b/riscv/src/register.rs @@ -117,6 +117,9 @@ pub mod mseccfg; #[cfg(any(test, target_arch = "riscv32"))] pub mod mseccfgh; +// Machine indirect access +pub mod miselect; + #[cfg(test)] mod tests; diff --git a/riscv/src/register/miselect.rs b/riscv/src/register/miselect.rs new file mode 100644 index 00000000..abdd3341 --- /dev/null +++ b/riscv/src/register/miselect.rs @@ -0,0 +1,47 @@ +//! `miselect` register. + +const MASK: usize = usize::MAX; + +read_write_csr! { + /// `miselect` register. + Miselect: 0x350, + mask: MASK, +} + +#[cfg(target_arch = "riscv32")] +read_write_csr_field! { + Miselect, + /// Returns whether `miselect` is for custom use of indirect CSRs. + is_custom: 31, +} + +#[cfg(not(target_arch = "riscv32"))] +read_write_csr_field! { + Miselect, + /// Returns whether `miselect` is for custom use of indirect CSRs. + is_custom: 63, +} + +#[cfg(target_arch = "riscv32")] +read_write_csr_field! { + Miselect, + /// Gets the value stored in the `miselect` CSR. + /// + /// # Note + /// + /// The semantics of the value depend on the extension for the referenced CSR, + /// and the relevant `mireg*` value. + value: [0:30], +} + +#[cfg(not(target_arch = "riscv32"))] +read_write_csr_field! { + Miselect, + /// Gets the value stored in the `miselect` CSR. + /// + /// # Note + /// + /// The semantics of the value depend on the extension for the referenced CSR, + /// and the relevant `mireg*` value. + value: [0:62], +} From b4385d05642536ccb652377b4ef6ca6d0d86087a Mon Sep 17 00:00:00 2001 From: 0xllx0 Date: Fri, 12 Sep 2025 00:32:31 +0000 Subject: [PATCH 02/76] test: add unit test for `miselect` Adds a basic unit test for the `miselect` CSR. --- riscv/CHANGELOG.md | 4 ++++ riscv/src/register/miselect.rs | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 59dc1adb..a405c5ad 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added + +- Add `miselect` CSR + ## [v0.15.0] - 2025-09-08 ### Added diff --git a/riscv/src/register/miselect.rs b/riscv/src/register/miselect.rs index abdd3341..50aa624f 100644 --- a/riscv/src/register/miselect.rs +++ b/riscv/src/register/miselect.rs @@ -45,3 +45,20 @@ read_write_csr_field! { /// and the relevant `mireg*` value. value: [0:62], } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test() { + (0..=usize::BITS) + .map(|r| ((1u128 << r) - 1) as usize) + .for_each(|bits| { + let mut miselect = Miselect::from_bits(bits); + + test_csr_field!(miselect, is_custom); + test_csr_field!(miselect, value: [0, usize::BITS - 2], 0); + }); + } +} From dbb57e918f1f470c8017c80a875ec5765d38d2d7 Mon Sep 17 00:00:00 2001 From: 0xllx0 Date: Fri, 12 Sep 2025 00:32:31 +0000 Subject: [PATCH 03/76] test: add unit test for `miselect` Adds a basic unit test for the `miselect` CSR. asm: Improve documentation and code quality for RISC-V instructions - Remove redundant unimplemented!() calls on non-RISC-V targets since functions are already properly gated with cfg attributes - Add comprehensive safety documentation explaining when and why instructions are unsafe (ebreak, ecall) - Enhance behavior descriptions with practical use cases and performance considerations for fence operations - Add preserves_flags option to instructions that don't modify flags (nop, wfi, ebreak, ecall) - Fix sfence_vma() assembly template to use idiomatic {} syntax - Strengthen delay() function warnings about timing accuracy limitations and recommend proper timer peripherals for precise delays - Add examples for sfence_vma() showing ASID and address targeting - Improve multiprocessor considerations documentation for fence_i - Standardize documentation format with consistent Safety, Behavior, and Use Cases sections These changes maintain full backward compatibility while significantly improving developer experience and preventing common usage mistakes. Add CHANGELOG.md register: add dcsr CSR support Re-added unimplemented!(), and removed SAFETY comments Fixed CHANGELOG.md Resolve merge conflict Update CHANGELOG.md Resolve merge conflict Added back spaces Removed unneeded files Delete CHANGELOG.md Resolve merge conflict Fix indentations Refactor unimplemented!() calls and update documentation for EBREAK instruction. Added the initial sections of the CHANGELOG.md Added a changelog to document notable changes and adhere to versioning standards. Fix formatting in asm! macro usage Update CHANGELOG.md --- riscv/CHANGELOG.md | 17 ++++++- riscv/src/asm.rs | 81 ++++++++++++++++++++++------------ riscv/src/register/miselect.rs | 17 +++++++ 3 files changed, 85 insertions(+), 30 deletions(-) diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 59dc1adb..daed563c 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Improved assembly macro handling in asm.rs + +### Added + +- Add `miselect` CSR + +## [v0.15.0] - 2025-09-08 + + +### Added + +- Add `miselect` CSR +- Improved assembly macro handling in asm.rs + ## [v0.15.0] - 2025-09-08 ### Added @@ -112,6 +126,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Export `riscv::register::macros` module macros for external use - Add `riscv::register::mcountinhibit` module for `mcountinhibit` CSR - Add `Mcounteren` in-memory update functions +- Add `Mcounteren` in-memory update functions - Add `Mstatus` vector extension support - Add fallible counterparts to all functions that `panic` - Add `riscv-pac` as a dependency @@ -279,4 +294,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/). [v0.7.0]: https://github.com/rust-embedded/riscv/compare/v0.6.0...v0.7.0 [v0.6.0]: https://github.com/rust-embedded/riscv/compare/v0.5.6...v0.6.0 [v0.5.6]: https://github.com/rust-embedded/riscv/compare/v0.5.5...v0.5.6 -[v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5 +[v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5 \ No newline at end of file diff --git a/riscv/src/asm.rs b/riscv/src/asm.rs index 5e471ff1..d75c3408 100644 --- a/riscv/src/asm.rs +++ b/riscv/src/asm.rs @@ -20,45 +20,70 @@ macro_rules! instruction { #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))] unimplemented!(); } - ); + ) } instruction!( - /// `nop` instruction wrapper + /// `NOP` instruction wrapper /// /// The `NOP` instruction does not change any architecturally visible state, except for - /// advancing the pc and incrementing any applicable performance counters. + /// advancing the PC and incrementing any applicable performance counters. /// /// This function generates a no-operation; it's useful to prevent delay loops from being /// optimized away. - , nop, "nop", options(nomem, nostack)); + , nop, "nop", options(nomem, nostack, preserves_flags)); instruction!( /// `WFI` instruction wrapper /// - /// Provides a hint to the implementation that the current hart can be stalled until an interrupt might need servicing. - /// The WFI instruction is just a hint, and a legal implementation is to implement WFI as a NOP. - , wfi, "wfi", options(nomem, nostack)); + /// Provides a hint to the implementation that the current hart can be stalled until an + /// interrupt might need servicing. The WFI instruction is just a hint, and a legal + /// implementation is to implement WFI as a NOP. + /// + /// # Behavior + /// + /// - May cause the hart to enter a low-power state + /// - Will be interrupted by any enabled interrupt + /// - No guarantee of actual power savings (implementation-dependent) + ,wfi, "wfi", options(nomem, nostack, preserves_flags)); instruction!( /// `EBREAK` instruction wrapper /// - /// Generates a breakpoint exception. - , unsafe ebreak, "ebreak", options(nomem, nostack)); + /// Generates a breakpoint exception for use by debuggers. + /// + /// # Behavior + /// + /// When executed, this instruction causes a breakpoint exception to be raised, + /// which will typically be handled by a debugger or exception handler. + /// + /// # Safety + /// + /// This function is unsafe because it unconditionally generates an exception, + /// which can disrupt normal program flow. Only call this when you intend to + /// trigger a breakpoint. + , unsafe ebreak, "ebreak", options(nomem, nostack, preserves_flags)); instruction!( /// `ECALL` instruction wrapper /// - /// Generates an exception for a service request to the execution environment. - /// When executed in U-mode, S-mode, or M-mode, it generates an environment-call-from-U-mode - /// exception, environment-call-from-S-mode exception, or environment-call-from-M-mode exception, - /// respectively, and performs no other operation. + /// Generates an environment call exception for system services. /// - /// # Note + /// # Behavior /// - /// The ECALL instruction will **NOT** save and restore the stack pointer, as it triggers an exception. - /// The stack pointer must be saved and restored accordingly by the exception handler. - , unsafe ecall, "ecall", options(nomem, nostack)); + /// When executed in different privilege modes: + /// - U-mode: Generates environment-call-from-U-mode exception + /// - S-mode: Generates environment-call-from-S-mode exception + /// - M-mode: Generates environment-call-from-M-mode exception + /// + /// # Safety + /// + /// This function is unsafe because: + /// - It unconditionally generates an exception + /// - The stack pointer is **NOT** automatically saved/restored + /// - The exception handler is responsible for proper context management + /// - Improper use can crash the system + , unsafe ecall, "ecall", options(nomem, nostack, preserves_flags)); instruction!( /// `SFENCE.VMA` instruction wrapper (all address spaces and page table levels) @@ -118,8 +143,8 @@ instruction!( pub fn sfence_vma(asid: usize, addr: usize) { #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] unsafe { - core::arch::asm!("sfence.vma {0}, {1}", in(reg) addr, in(reg) asid, options(nostack)); - }; + core::arch::asm!("sfence.vma {}, {}", in(reg) addr, in(reg) asid, options(nostack)); + } #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))] unimplemented!(); } @@ -139,21 +164,19 @@ pub fn sfence_vma(asid: usize, addr: usize) { allow(unused_variables) )] pub fn delay(cycles: u32) { - match () { - #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] - () => { - let real_cyc = 1 + cycles / 2; - unsafe { - core::arch::asm!( + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + { + let real_cyc = 1 + cycles / 2; + unsafe { + core::arch::asm!( "2:", "addi {0}, {0}, -1", "bne {0}, zero, 2b", inout(reg) real_cyc => _, options(nomem, nostack), - ); - } + ); } - #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))] - () => unimplemented!(), } + #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))] + unimplemented!(); } diff --git a/riscv/src/register/miselect.rs b/riscv/src/register/miselect.rs index abdd3341..50aa624f 100644 --- a/riscv/src/register/miselect.rs +++ b/riscv/src/register/miselect.rs @@ -45,3 +45,20 @@ read_write_csr_field! { /// and the relevant `mireg*` value. value: [0:62], } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test() { + (0..=usize::BITS) + .map(|r| ((1u128 << r) - 1) as usize) + .for_each(|bits| { + let mut miselect = Miselect::from_bits(bits); + + test_csr_field!(miselect, is_custom); + test_csr_field!(miselect, value: [0, usize::BITS - 2], 0); + }); + } +} From af134fbf448f358eec4e385a8cd5baeeaf6096ec Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Thu, 18 Sep 2025 05:24:20 +0000 Subject: [PATCH 04/76] Fix CHANGELOG.md Fix CHANGELOG.md, remove duplicates, resolve conflicts Fix CHANGELOG.md --- riscv/CHANGELOG.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index de48f1ab..8720fa10 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -7,25 +7,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] -- Improved assembly macro handling in asm.rs - ### Added - -- Add `miselect` CSR +- Improved assembly macro handling in asm.rs ## [v0.15.0] - 2025-09-08 - ### Added - Add `miselect` CSR -- Improved assembly macro handling in asm.rs - -### Added - -- Add `miselect` CSR - -## [v0.15.0] - 2025-09-08 ### Added @@ -130,7 +119,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Export `riscv::register::macros` module macros for external use - Add `riscv::register::mcountinhibit` module for `mcountinhibit` CSR - Add `Mcounteren` in-memory update functions -- Add `Mcounteren` in-memory update functions - Add `Mstatus` vector extension support - Add fallible counterparts to all functions that `panic` - Add `riscv-pac` as a dependency From a5ac148c7d61e2ad331a4a254c7c9c2e934cf03f Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Thu, 18 Sep 2025 17:09:39 +0530 Subject: [PATCH 05/76] Update CHANGELOG.md Removed duplicate entry for 'Add `miselect` CSR' in the changelog. --- riscv/CHANGELOG.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 8720fa10..67a37179 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -8,16 +8,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added + +- Add `miselect` CSR - Improved assembly macro handling in asm.rs ## [v0.15.0] - 2025-09-08 ### Added -- Add `miselect` CSR - -### Added - - New convenience `try_new` and `new` associated functions for `Mtvec` and `Stvec`. - New methods and functions for enabling core interrupts in the `mie` and `sie` registers using the `riscv_pac::CoreInterruptNumber` trait. @@ -286,4 +284,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/). [v0.7.0]: https://github.com/rust-embedded/riscv/compare/v0.6.0...v0.7.0 [v0.6.0]: https://github.com/rust-embedded/riscv/compare/v0.5.6...v0.6.0 [v0.5.6]: https://github.com/rust-embedded/riscv/compare/v0.5.5...v0.5.6 -[v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5 \ No newline at end of file +[v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5 From 84be2e4ba617656c010717cb88a5157369eca92f Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Tue, 9 Sep 2025 15:38:30 +0530 Subject: [PATCH 06/76] register: add dcsr CSR support --- riscv/src/register.rs | 3 ++- riscv/src/register/dcsr.rs | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 riscv/src/register/dcsr.rs diff --git a/riscv/src/register.rs b/riscv/src/register.rs index 2dc9f534..869fe1e6 100644 --- a/riscv/src/register.rs +++ b/riscv/src/register.rs @@ -125,4 +125,5 @@ mod tests; // TODO: Debug/Trace Registers (shared with Debug Mode) -// TODO: Debug Mode Registers +// Debug Mode Registers +pub mod dcsr; diff --git a/riscv/src/register/dcsr.rs b/riscv/src/register/dcsr.rs new file mode 100644 index 00000000..07a41fa5 --- /dev/null +++ b/riscv/src/register/dcsr.rs @@ -0,0 +1,4 @@ +//! dcsr register — Debug Control and Status Register (0x7b0) + +read_csr_as_usize!(0x7b0); +write_csr_as_usize!(0x7b0); From 47835165d1cf8d089282f950e467546b0a513235 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Tue, 9 Sep 2025 15:51:49 +0530 Subject: [PATCH 07/76] Add CHANGELOG.md --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..f328c490 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog + +## [Unreleased] + +### Added +- Added support for the RISC-V `dcsr` (Debug Control and Status Register) CSR. + - Created `src/register/dcsr.rs` + - Exposed the module in `register.rs` From 39f27591c211e39675e06e7f2990f7ae56c47de4 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Tue, 9 Sep 2025 18:05:20 +0530 Subject: [PATCH 08/76] Added riscv: add DCSR (Debug Control and Status Register) support - Implemented the dcsr CSR (0x7b0) with all fields as per RISC-V Debug Spec v0.13 - Added enums for cause and prv fields for type-safe access - Provided getters and setters for all readable/writable fields - Added unit tests for bitfields, enums, and convenience methods --- CHANGELOG.md | 2 - riscv/src/register.rs | 2 +- riscv/src/register/dcsr.rs | 214 ++++++++++++++++++++++++++++++++++++- 3 files changed, 213 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f328c490..242c1bfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,3 @@ -# Changelog - ## [Unreleased] ### Added diff --git a/riscv/src/register.rs b/riscv/src/register.rs index 869fe1e6..a20328bc 100644 --- a/riscv/src/register.rs +++ b/riscv/src/register.rs @@ -125,5 +125,5 @@ mod tests; // TODO: Debug/Trace Registers (shared with Debug Mode) -// Debug Mode Registers +// TODO: Debug Mode Registers pub mod dcsr; diff --git a/riscv/src/register/dcsr.rs b/riscv/src/register/dcsr.rs index 07a41fa5..c19cc5b5 100644 --- a/riscv/src/register/dcsr.rs +++ b/riscv/src/register/dcsr.rs @@ -1,4 +1,214 @@ //! dcsr register — Debug Control and Status Register (0x7b0) +//! +//! Provides control and status for debug mode, including cause of entry, step control, and privilege level. -read_csr_as_usize!(0x7b0); -write_csr_as_usize!(0x7b0); +read_write_csr! { + /// Debug Control and Status Register + Dcsr: 0x7b0, + mask: 0xffff_ffff, +} + +read_write_csr_field! { + Dcsr, + /// Previous privilege level when entering debug mode (bits 0..2) + prv: [0:1], +} + +read_write_csr_field! { + Dcsr, + /// Single step mode (bit 2) + step: 2, +} + +read_only_csr_field! { + Dcsr, + /// Non-maskable interrupt pending (bit 3) + nmip: 3, +} + +read_write_csr_field! { + Dcsr, + /// Use mstatus.mprv in debug mode (bit 4) + mprven: 4, +} + +read_only_csr_field! { + Dcsr, + /// Cause for entering debug mode (bits 6..8) + cause: [6:8], +} + +read_write_csr_field! { + Dcsr, + /// Stop timer increment in debug mode (bit 9) + stoptime: 9, +} + +read_write_csr_field! { + Dcsr, + /// Stop counter increment in debug mode (bit 10) + stopcount: 10, +} + +read_write_csr_field! { + Dcsr, + /// Interrupt enable during single-step (bit 11) + stepie: 11, +} + +read_write_csr_field! { + Dcsr, + /// EBREAK behavior in User mode (bit 12) + ebreaku: 12, +} + +read_write_csr_field! { + Dcsr, + /// EBREAK behavior in Supervisor mode (bit 13) + ebreaks: 13, +} + +read_write_csr_field! { + Dcsr, + /// EBREAK behavior in Machine mode (bit 15) + ebreakm: 15, +} + +read_only_csr_field! { + Dcsr, + /// Debug version (bits 28..31) + xdebugver: [28:31], +} + +/// Cause for entering debug mode +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DcsrCause { + None = 0, + Ebreak = 1, + Trigger = 2, + HaltRequest = 3, + Step = 4, + ResetHaltRequest = 5, +} + +impl DcsrCause { + pub fn from_usize(val: usize) -> Result { + match val { + 0 => Ok(Self::None), + 1 => Ok(Self::Ebreak), + 2 => Ok(Self::Trigger), + 3 => Ok(Self::HaltRequest), + 4 => Ok(Self::Step), + 5 => Ok(Self::ResetHaltRequest), + other => Err(other), + } + } +} + +/// Previous privilege level when entering debug mode +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DcsrPrv { + User = 0, + Supervisor = 1, + Machine = 3, +} + +impl DcsrPrv { + pub fn from_usize(val: usize) -> Result { + match val { + 0 => Ok(Self::User), + 1 => Ok(Self::Supervisor), + 3 => Ok(Self::Machine), + other => Err(other), + } + } +} + +impl Dcsr { + /// Returns the debug cause as an enum + pub fn debug_cause(&self) -> Result { + DcsrCause::from_usize(self.cause()) + } + + /// Returns the previous privilege level as an enum + pub fn privilege_level(&self) -> Result { + DcsrPrv::from_usize(self.prv()) + } + + /// Sets the previous privilege level + pub fn set_privilege_level(&mut self, level: DcsrPrv) { + self.set_prv(level as usize); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_dcsr_bitfields() { + let mut dcsr = Dcsr::from_bits(0); + + dcsr.set_step(true); + assert!(dcsr.step()); + dcsr.set_mprven(true); + assert!(dcsr.mprven()); + dcsr.set_stoptime(true); + assert!(dcsr.stoptime()); + dcsr.set_stopcount(true); + assert!(dcsr.stopcount()); + dcsr.set_stepie(true); + assert!(dcsr.stepie()); + dcsr.set_ebreaku(true); + assert!(dcsr.ebreaku()); + dcsr.set_ebreaks(true); + assert!(dcsr.ebreaks()); + dcsr.set_ebreakm(true); + assert!(dcsr.ebreakm()); + + dcsr.set_step(false); + assert!(!dcsr.step()); + dcsr.set_mprven(false); + assert!(!dcsr.mprven()); + dcsr.set_stoptime(false); + assert!(!dcsr.stoptime()); + dcsr.set_stopcount(false); + assert!(!dcsr.stopcount()); + dcsr.set_stepie(false); + assert!(!dcsr.stepie()); + dcsr.set_ebreaku(false); + assert!(!dcsr.ebreaku()); + dcsr.set_ebreaks(false); + assert!(!dcsr.ebreaks()); + dcsr.set_ebreakm(false); + assert!(!dcsr.ebreakm()); + } + + #[test] + fn test_dcsr_enums() { + assert_eq!(DcsrCause::from_usize(0).unwrap(), DcsrCause::None); + assert_eq!(DcsrCause::from_usize(1).unwrap(), DcsrCause::Ebreak); + assert_eq!(DcsrCause::from_usize(2).unwrap(), DcsrCause::Trigger); + assert_eq!(DcsrCause::from_usize(3).unwrap(), DcsrCause::HaltRequest); + assert_eq!(DcsrCause::from_usize(4).unwrap(), DcsrCause::Step); + assert_eq!( + DcsrCause::from_usize(5).unwrap(), + DcsrCause::ResetHaltRequest + ); + assert!(DcsrCause::from_usize(6).is_err()); + + assert_eq!(DcsrPrv::from_usize(0).unwrap(), DcsrPrv::User); + assert_eq!(DcsrPrv::from_usize(1).unwrap(), DcsrPrv::Supervisor); + assert_eq!(DcsrPrv::from_usize(3).unwrap(), DcsrPrv::Machine); + assert!(DcsrPrv::from_usize(2).is_err()); + } + + #[test] + fn test_dcsr_convenience_methods() { + let mut dcsr = Dcsr::from_bits(0); + + dcsr.set_privilege_level(DcsrPrv::Machine); + assert_eq!(dcsr.privilege_level().unwrap(), DcsrPrv::Machine); + assert_eq!(dcsr.prv(), 3); + } +} From 73d084f8dc3230c4e8a427217c2c15948c0513d1 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Tue, 9 Sep 2025 18:58:47 +0530 Subject: [PATCH 09/76] Fix CHANGELOG.md --- CHANGELOG.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 242c1bfb..f4c600f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1 @@ -## [Unreleased] - -### Added -- Added support for the RISC-V `dcsr` (Debug Control and Status Register) CSR. - - Created `src/register/dcsr.rs` - - Exposed the module in `register.rs` +Added DCSR (Debug Control and Status Register) CSR support for the RISC-V From 02c5ba8d0a8f658c329503950c1178ae4e7525d5 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Wed, 10 Sep 2025 14:46:21 +0530 Subject: [PATCH 10/76] Added CHANGELOG.md --- riscv/CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index a405c5ad..d4e15459 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -9,7 +9,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- Added DCSR (Debug Control and Status Register) CSR support for the RISC-V - Add `miselect` CSR +- Improved assembly macro handling in asm.rs ## [v0.15.0] - 2025-09-08 @@ -283,4 +285,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/). [v0.7.0]: https://github.com/rust-embedded/riscv/compare/v0.6.0...v0.7.0 [v0.6.0]: https://github.com/rust-embedded/riscv/compare/v0.5.6...v0.6.0 [v0.5.6]: https://github.com/rust-embedded/riscv/compare/v0.5.5...v0.5.6 -[v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5 +[v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5 \ No newline at end of file From d166ec03208d30af06b3c3bf809c0df0f86cc36e Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Tue, 9 Sep 2025 19:02:40 +0530 Subject: [PATCH 11/76] Update CHANGELOG.md --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4c600f2..b5798e6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,3 @@ -Added DCSR (Debug Control and Status Register) CSR support for the RISC-V +### [Unreleased] + +- Added DCSR (Debug Control and Status Register) CSR support for the RISC-V From 7fd82b32096c27c9e07cc47732e5d7974b61aa4c Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Thu, 11 Sep 2025 14:41:00 +0530 Subject: [PATCH 12/76] Update CHANGELOG.md --- CHANGELOG.md | 282 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 281 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5798e6d..66839269 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,283 @@ -### [Unreleased] +# Change Log +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +## [v0.15.0] - 2025-09-08 + +### Added - Added DCSR (Debug Control and Status Register) CSR support for the RISC-V +- New convenience `try_new` and `new` associated functions for `Mtvec` and `Stvec`. +- New methods and functions for enabling core interrupts in the `mie` and `sie` registers + using the `riscv_pac::CoreInterruptNumber` trait. +- New `riscv::interrupt::{is_interrupt_enabled, disable_interrupt, enable_interrupt}` functions. +- New methods and functions for dealing with pending interrupts in `mip` and `sip` registers + using the `riscv_pac::CoreInterruptNumber` trait. +- New `riscv::interrupt::is_interrupt_pending` function. +- New `riscv::register::xip::clear_pending` atomic function for `mip` and `sip` registers. + This function is marked as `unsafe`, as its availability depends both on the target chip + and the target interrupt source. +- Add `mseccfg` CSR +- Add `mseccfgh` CSR + +### Changed + +- Use `cfg(any(target_arch = "riscv32", target_arch = "riscv64"))` instead of `cfg(riscv)`. +- `riscv::pac_enum(unsafe CoreInterrupt)` now locates the vector table at the `.trap.vector` + section instead of `.trap`. +- Allow all bits to be set in Mcause::from_bits on 64-bit targets. + +### Removed + +- Removed custom build script, as `cfg(riscv)` is no longer necessary. +- All the fields of `Mip` and `Sip` CSR proxies are now read-only. This change is motivated + to avoid clearing unwanted interrupts triggered between CSR reads and CSR writes. + +## [v0.14.0] - 2025-06-10 + +### Added + +- CSR helper macro `write_composite_csr` for writing 64-bit CSRs on 32-bit targets. +- Write utilities for `mcycle`, `minstret` +- Add `senvcfg` CSR +- Add `scontext` CSR +- Add `mconfigptr` CSR +- Bump MSRV to 1.67.0 for `log` to `ilog` name change +- Add `mtval2` CSR + +### Changed + +- Simplify `riscv::interrupt::machine::nested` + +## [v0.13.0] - 2025-02-18 + +### Added + +- CSR helper macro to check for platform implementation + +### Changed + +- Make all CSR writes `unsafe` by default (#209) +- Use `RISCV_MTVEC_ALIGN` to control the alignment constraint of the vector table +- Simplify register macros with `cfg` field +- Align assembly functions with `cortex-m` +- Use CSR helper macros to define `marchid` register +- Re-use `try_*` functions in `mcountinhibit` +- Use CSR helper macros to define `mcause` register +- Use CSR helper macros to define `medeleg` register +- Use CSR helper macros to define `mideleg` register +- Use CSR helper macros to define `mcounteren` register +- Use CSR helper macros to define `mie` register +- Use CSR helper macros to define `mimpid` register +- Use CSR helper macros to define `misa` register +- Use CSR helper macros to define `mip` register +- Use CSR helper macros to define `mstatus` register +- Use CSR helper macros to define `mstatush` register +- Use CSR helper macros to define `mtvec` register +- Use CSR helper macros to define `mtvendorid` register +- Use CSR helper macros to define `satp` register +- Use CSR helper macros to define `pmpcfgx` field types +- Use CSR helper macros to define `scause` field types +- Use CSR helper macros to define `sie` register +- Use CSR helper macros to define `scounteren` field types +- Use CSR helper macros to define `sip` register +- Use CSR helper macros to define `sstatus` field types +- Use CSR helper macros to define `stvec` field types +- Add remaining `pmpcfg` CSRs from RISC-V privileged spec + +## [v0.12.1] - 2024-10-20 + +### Changed + +- Update critical-section to 1.2.0 + +## [v0.12.0] - 2024-10-19 + +### Added + +- `riscv-macros` crate for `riscv-pac` enums. +- Bump MSRV to 1.61. +- Implementation of `riscv-pac` traits for `Interrupt` and `Exception` enums. +- Tests for the `riscv-pac` trait implementations of `Interrupt` and `Exception` enums. +- Add `Mcause::from(usize)` for use in unit tests +- Add `Mstatus::from(usize)` for use in unit tests +- Add `Mstatus.bits()` +- Add `Eq` and `PartialEq` for `pmpcfgx::{Range, Permission}` +- Add `Mstatus::update_*` helpers to manipulate Mstatus values without touching + the CSR +- Export `riscv::register::macros` module macros for external use +- Add `riscv::register::mcountinhibit` module for `mcountinhibit` CSR +- Add `Mcounteren` in-memory update functions +- Add `Mstatus` vector extension support +- Add fallible counterparts to all functions that `panic` +- Add `riscv-pac` as a dependency +- Add CSR-defining macros to create in-memory types + +### Fixed + +- Fixed `sip::set_ssoft` and `sip::clear_ssoft` using wrong address +- Fixed assignment in `mstatus` unit tests. +- delay implementation does not use binary labels in inline assembly. + +## [v0.11.1] - 2024-02-15 + +### Changed + +- Made `asm::wfi`, `fence`, `fence_i` and `sfence` safe (ie, removed `unsafe` from their definitions) +- Made `cfg` variable selection more robust for custom targets + +## [v0.11.0] - 2024-01-14 + +### Added + +- Add `asm::ecall()`, a wrapper for implementing an `ecall` instruction +- Add `nested` function for nested ISRs in `interrupt::machine` and `interrupt::supervisor` +- `s-mode` feature for reexporting `interrupt::machine` or `interrupt::supervisor` to `interrupt` +- Support for supervisor-level interrupts in `interrupt::supervisor` +- Add CI workflow to check that CHANGELOG.md file has been modified in PRs +- Add `read_csr_as_rv32`, `set_rv32`, and `clear_rv32` macros +- Add `mstatus::uxl` and `mstatus::sxl` +- Add `mstatus::ube`, `mstatus::sbe`, and `mstatus::mbe` endianness bit fields +- Add `mstatush` registers (RISCV-32 only) +- Add `asm::fence()`, a wrapper for implementing a `fence` instruction +- Add `asm::fence_i()`, a wrapper for implementing a `fence.i` instruction +- Add `TryFrom` implementation for `mcause::{Interrupt, Exception}` and `scause::{Interrupt, Exception}` + +### Changed + +- Cargo workspace for riscv and riscv-rt +- Update `embedded-hal` dependency to v1.0.0 (bumps MSRV to 1.60) +- `misa::MXL` renamed to `misa::XLEN` +- Removed `bit_field` dependency +- CI actions updated. They now use `checkout@v3` and `dtolnay/rust-toolchain`. +- `mcause::{Interrupt, Exception}` and `scause::{Interrupt, Exception}` now implement `From` trait for `usize` +- Set safety of `asm::nop` and `asm::delay` functions to safe. + +### Fixed + +- Fix `scause::Exception` missing `LoadMisaligned` +- Fix `scause::Exception` missing `SupervisorEnvCall` +- Removed user-level interrupts from `mcause::Interrupt` and `scause::Interrupt` +- Removed user-level interrupts from `mstatus` +- Removed machine environment call delegation from `medeleg` +- Removed user-level interrupts from machine and supervisor mode interrupt-related registers. + +### Removed + +- User mode registers removed, as they are no longer supported in RISC-V +- FCSR register operations removed to avoid UB (#148) + +## [v0.10.1] - 2023-01-18 + +### Fixed + +- Fix implementation for `SingleHartCriticalSection` + +## [v0.10.0] - 2022-11-09 + +### Added + +- `critical-section-single-hart` feature which provides an implementation for the `critical_section` crate for single-hart systems, based on disabling all interrupts. + +## [v0.9.0] - 2022-10-06 + +### Fixed + +- Fix `asm::delay()` to ensure count register is always reloaded +- Fix reading marchid and mimpid (#107) + +### Removed +- `set_msoft`, `clear_msoft`, `set_mtimer` and `clear_mtimer` removed as part of fixing issue #62 + +## [v0.8.0] - 2022-04-20 + +### Added + +- Add `#[cfg(riscv32)]` to `pmpcfg1` and `pmpcfg3` modules +- Add enums `Range`, `Permission` for PMP configuration +- Add `set_pmp()` and `clear_pmp()` functions to pmpcfg(x) modules +- Add struct `Pmpcsr` and is returned from `pmpcfgx::read()` +- Add `singleton!` macro +- Add delay structure and methods using embedded-hal traits and `mcycle` register +- Add `asm::delay()` function for assembly-based busy-loops +- Add `asm::nop()`, a wrapper for implementing a `nop` instruction +- Add missing `#[inline]` attribute to register reads, type conversations and `interrupt::free` + +### Changed + +- Use new `asm!` instead of `llvm_asm!` +- Change `pmpcfgx::read()` macro to `read_csr_as!()` from `read_csr_as_usize!()` +- Inline assembly is now always used +- Update Minimum Supported Rust Version to 1.59 + +### Fixed + +- Fix `sfence.vma` operand order + +### Removed + +- Remove `inline-asm` feature which is now always enabled + +## [v0.7.0] - 2021-07-29 + +### Added + +- Add `medeleg` register +- Add `cycle[h]`, `instret[h]` and `mcounteren` +- Add additional binaries for floating-point ABIs +- Add support for `mxr` +- Add support for `mprv` + +### Changed + +- Fix `scause::set` +- Various formatting and comment fixes +- Update `bare-metal` to `v1.0.0` removing `Nr` trait +- Build targets on `docs.rs` are now RISC-V targets other than default ones + +## [v0.6.0] - 2020-06-20 + +### Changed + +- `Mtvec::trap_mode()`, `Stvec::trap_mode()` and `Utvec::trap_mode()` functions now return `Option` (breaking change) +- Updated Minimum Supported Rust Version to 1.42.0 +- Use `llvm_asm!` instead of `asm!` + +### Removed + +- vexriscv-specific registers were moved to the `vexriscv` crate + +## [v0.5.6] - 2020-03-14 + +### Added + +- Added vexriscv-specific registers + +## [v0.5.5] - 2020-02-28 + +### Added + +- Added `riscv32i-unknown-none-elf` target support +- Added user trap setup and handling registers +- Added write methods for the `mip` and `satp` registers +- Added `mideleg` register +- Added Changelog + +### Changed + +- Fixed MSRV by restricting the upper bound of `bare-metal` version +- Added DCSR (Debug Control and Status Register) CSR support for the RISC-V + +[Unreleased]: https://github.com/rust-embedded/riscv/compare/v0.10.1...HEAD +[v0.10.1]: https://github.com/rust-embedded/riscv/compare/v0.10.0...v0.10.1 +[v0.10.0]: https://github.com/rust-embedded/riscv/compare/v0.9.0...v0.10.0 +[v0.9.0]: https://github.com/rust-embedded/riscv/compare/v0.8.0...v0.9.0 +[v0.8.0]: https://github.com/rust-embedded/riscv/compare/v0.7.0...v0.8.0 +[v0.7.0]: https://github.com/rust-embedded/riscv/compare/v0.6.0...v0.7.0 +[v0.6.0]: https://github.com/rust-embedded/riscv/compare/v0.5.6...v0.6.0 +[v0.5.6]: https://github.com/rust-embedded/riscv/compare/v0.5.5...v0.5.6 +[v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5u From 5d5410b265380e86d1b4bcfa11d426ae70bf6e69 Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Tue, 16 Sep 2025 13:12:58 +0530 Subject: [PATCH 13/76] Revise CHANGELOG format and add new entries --- riscv/CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index d4e15459..e533d66e 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -16,7 +16,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [v0.15.0] - 2025-09-08 ### Added - - New convenience `try_new` and `new` associated functions for `Mtvec` and `Stvec`. - New methods and functions for enabling core interrupts in the `mie` and `sie` registers using the `riscv_pac::CoreInterruptNumber` trait. @@ -276,6 +275,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - Fixed MSRV by restricting the upper bound of `bare-metal` version +- Added DCSR (Debug Control and Status Register) CSR support for the RISC-V [Unreleased]: https://github.com/rust-embedded/riscv/compare/v0.10.1...HEAD [v0.10.1]: https://github.com/rust-embedded/riscv/compare/v0.10.0...v0.10.1 @@ -285,4 +285,5 @@ and this project adheres to [Semantic Versioning](http://semver.org/). [v0.7.0]: https://github.com/rust-embedded/riscv/compare/v0.6.0...v0.7.0 [v0.6.0]: https://github.com/rust-embedded/riscv/compare/v0.5.6...v0.6.0 [v0.5.6]: https://github.com/rust-embedded/riscv/compare/v0.5.5...v0.5.6 -[v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5 \ No newline at end of file +[v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5 +[v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5u \ No newline at end of file From 9dea17359ee6d0b5b9a6864922d8a0cfa113867c Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Tue, 16 Sep 2025 13:16:07 +0530 Subject: [PATCH 14/76] Delete CHANGELOG.md --- CHANGELOG.md | 283 --------------------------------------------------- 1 file changed, 283 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 66839269..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,283 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/) -and this project adheres to [Semantic Versioning](http://semver.org/). - -## [Unreleased] - -## [v0.15.0] - 2025-09-08 - -### Added -- Added DCSR (Debug Control and Status Register) CSR support for the RISC-V -- New convenience `try_new` and `new` associated functions for `Mtvec` and `Stvec`. -- New methods and functions for enabling core interrupts in the `mie` and `sie` registers - using the `riscv_pac::CoreInterruptNumber` trait. -- New `riscv::interrupt::{is_interrupt_enabled, disable_interrupt, enable_interrupt}` functions. -- New methods and functions for dealing with pending interrupts in `mip` and `sip` registers - using the `riscv_pac::CoreInterruptNumber` trait. -- New `riscv::interrupt::is_interrupt_pending` function. -- New `riscv::register::xip::clear_pending` atomic function for `mip` and `sip` registers. - This function is marked as `unsafe`, as its availability depends both on the target chip - and the target interrupt source. -- Add `mseccfg` CSR -- Add `mseccfgh` CSR - -### Changed - -- Use `cfg(any(target_arch = "riscv32", target_arch = "riscv64"))` instead of `cfg(riscv)`. -- `riscv::pac_enum(unsafe CoreInterrupt)` now locates the vector table at the `.trap.vector` - section instead of `.trap`. -- Allow all bits to be set in Mcause::from_bits on 64-bit targets. - -### Removed - -- Removed custom build script, as `cfg(riscv)` is no longer necessary. -- All the fields of `Mip` and `Sip` CSR proxies are now read-only. This change is motivated - to avoid clearing unwanted interrupts triggered between CSR reads and CSR writes. - -## [v0.14.0] - 2025-06-10 - -### Added - -- CSR helper macro `write_composite_csr` for writing 64-bit CSRs on 32-bit targets. -- Write utilities for `mcycle`, `minstret` -- Add `senvcfg` CSR -- Add `scontext` CSR -- Add `mconfigptr` CSR -- Bump MSRV to 1.67.0 for `log` to `ilog` name change -- Add `mtval2` CSR - -### Changed - -- Simplify `riscv::interrupt::machine::nested` - -## [v0.13.0] - 2025-02-18 - -### Added - -- CSR helper macro to check for platform implementation - -### Changed - -- Make all CSR writes `unsafe` by default (#209) -- Use `RISCV_MTVEC_ALIGN` to control the alignment constraint of the vector table -- Simplify register macros with `cfg` field -- Align assembly functions with `cortex-m` -- Use CSR helper macros to define `marchid` register -- Re-use `try_*` functions in `mcountinhibit` -- Use CSR helper macros to define `mcause` register -- Use CSR helper macros to define `medeleg` register -- Use CSR helper macros to define `mideleg` register -- Use CSR helper macros to define `mcounteren` register -- Use CSR helper macros to define `mie` register -- Use CSR helper macros to define `mimpid` register -- Use CSR helper macros to define `misa` register -- Use CSR helper macros to define `mip` register -- Use CSR helper macros to define `mstatus` register -- Use CSR helper macros to define `mstatush` register -- Use CSR helper macros to define `mtvec` register -- Use CSR helper macros to define `mtvendorid` register -- Use CSR helper macros to define `satp` register -- Use CSR helper macros to define `pmpcfgx` field types -- Use CSR helper macros to define `scause` field types -- Use CSR helper macros to define `sie` register -- Use CSR helper macros to define `scounteren` field types -- Use CSR helper macros to define `sip` register -- Use CSR helper macros to define `sstatus` field types -- Use CSR helper macros to define `stvec` field types -- Add remaining `pmpcfg` CSRs from RISC-V privileged spec - -## [v0.12.1] - 2024-10-20 - -### Changed - -- Update critical-section to 1.2.0 - -## [v0.12.0] - 2024-10-19 - -### Added - -- `riscv-macros` crate for `riscv-pac` enums. -- Bump MSRV to 1.61. -- Implementation of `riscv-pac` traits for `Interrupt` and `Exception` enums. -- Tests for the `riscv-pac` trait implementations of `Interrupt` and `Exception` enums. -- Add `Mcause::from(usize)` for use in unit tests -- Add `Mstatus::from(usize)` for use in unit tests -- Add `Mstatus.bits()` -- Add `Eq` and `PartialEq` for `pmpcfgx::{Range, Permission}` -- Add `Mstatus::update_*` helpers to manipulate Mstatus values without touching - the CSR -- Export `riscv::register::macros` module macros for external use -- Add `riscv::register::mcountinhibit` module for `mcountinhibit` CSR -- Add `Mcounteren` in-memory update functions -- Add `Mstatus` vector extension support -- Add fallible counterparts to all functions that `panic` -- Add `riscv-pac` as a dependency -- Add CSR-defining macros to create in-memory types - -### Fixed - -- Fixed `sip::set_ssoft` and `sip::clear_ssoft` using wrong address -- Fixed assignment in `mstatus` unit tests. -- delay implementation does not use binary labels in inline assembly. - -## [v0.11.1] - 2024-02-15 - -### Changed - -- Made `asm::wfi`, `fence`, `fence_i` and `sfence` safe (ie, removed `unsafe` from their definitions) -- Made `cfg` variable selection more robust for custom targets - -## [v0.11.0] - 2024-01-14 - -### Added - -- Add `asm::ecall()`, a wrapper for implementing an `ecall` instruction -- Add `nested` function for nested ISRs in `interrupt::machine` and `interrupt::supervisor` -- `s-mode` feature for reexporting `interrupt::machine` or `interrupt::supervisor` to `interrupt` -- Support for supervisor-level interrupts in `interrupt::supervisor` -- Add CI workflow to check that CHANGELOG.md file has been modified in PRs -- Add `read_csr_as_rv32`, `set_rv32`, and `clear_rv32` macros -- Add `mstatus::uxl` and `mstatus::sxl` -- Add `mstatus::ube`, `mstatus::sbe`, and `mstatus::mbe` endianness bit fields -- Add `mstatush` registers (RISCV-32 only) -- Add `asm::fence()`, a wrapper for implementing a `fence` instruction -- Add `asm::fence_i()`, a wrapper for implementing a `fence.i` instruction -- Add `TryFrom` implementation for `mcause::{Interrupt, Exception}` and `scause::{Interrupt, Exception}` - -### Changed - -- Cargo workspace for riscv and riscv-rt -- Update `embedded-hal` dependency to v1.0.0 (bumps MSRV to 1.60) -- `misa::MXL` renamed to `misa::XLEN` -- Removed `bit_field` dependency -- CI actions updated. They now use `checkout@v3` and `dtolnay/rust-toolchain`. -- `mcause::{Interrupt, Exception}` and `scause::{Interrupt, Exception}` now implement `From` trait for `usize` -- Set safety of `asm::nop` and `asm::delay` functions to safe. - -### Fixed - -- Fix `scause::Exception` missing `LoadMisaligned` -- Fix `scause::Exception` missing `SupervisorEnvCall` -- Removed user-level interrupts from `mcause::Interrupt` and `scause::Interrupt` -- Removed user-level interrupts from `mstatus` -- Removed machine environment call delegation from `medeleg` -- Removed user-level interrupts from machine and supervisor mode interrupt-related registers. - -### Removed - -- User mode registers removed, as they are no longer supported in RISC-V -- FCSR register operations removed to avoid UB (#148) - -## [v0.10.1] - 2023-01-18 - -### Fixed - -- Fix implementation for `SingleHartCriticalSection` - -## [v0.10.0] - 2022-11-09 - -### Added - -- `critical-section-single-hart` feature which provides an implementation for the `critical_section` crate for single-hart systems, based on disabling all interrupts. - -## [v0.9.0] - 2022-10-06 - -### Fixed - -- Fix `asm::delay()` to ensure count register is always reloaded -- Fix reading marchid and mimpid (#107) - -### Removed -- `set_msoft`, `clear_msoft`, `set_mtimer` and `clear_mtimer` removed as part of fixing issue #62 - -## [v0.8.0] - 2022-04-20 - -### Added - -- Add `#[cfg(riscv32)]` to `pmpcfg1` and `pmpcfg3` modules -- Add enums `Range`, `Permission` for PMP configuration -- Add `set_pmp()` and `clear_pmp()` functions to pmpcfg(x) modules -- Add struct `Pmpcsr` and is returned from `pmpcfgx::read()` -- Add `singleton!` macro -- Add delay structure and methods using embedded-hal traits and `mcycle` register -- Add `asm::delay()` function for assembly-based busy-loops -- Add `asm::nop()`, a wrapper for implementing a `nop` instruction -- Add missing `#[inline]` attribute to register reads, type conversations and `interrupt::free` - -### Changed - -- Use new `asm!` instead of `llvm_asm!` -- Change `pmpcfgx::read()` macro to `read_csr_as!()` from `read_csr_as_usize!()` -- Inline assembly is now always used -- Update Minimum Supported Rust Version to 1.59 - -### Fixed - -- Fix `sfence.vma` operand order - -### Removed - -- Remove `inline-asm` feature which is now always enabled - -## [v0.7.0] - 2021-07-29 - -### Added - -- Add `medeleg` register -- Add `cycle[h]`, `instret[h]` and `mcounteren` -- Add additional binaries for floating-point ABIs -- Add support for `mxr` -- Add support for `mprv` - -### Changed - -- Fix `scause::set` -- Various formatting and comment fixes -- Update `bare-metal` to `v1.0.0` removing `Nr` trait -- Build targets on `docs.rs` are now RISC-V targets other than default ones - -## [v0.6.0] - 2020-06-20 - -### Changed - -- `Mtvec::trap_mode()`, `Stvec::trap_mode()` and `Utvec::trap_mode()` functions now return `Option` (breaking change) -- Updated Minimum Supported Rust Version to 1.42.0 -- Use `llvm_asm!` instead of `asm!` - -### Removed - -- vexriscv-specific registers were moved to the `vexriscv` crate - -## [v0.5.6] - 2020-03-14 - -### Added - -- Added vexriscv-specific registers - -## [v0.5.5] - 2020-02-28 - -### Added - -- Added `riscv32i-unknown-none-elf` target support -- Added user trap setup and handling registers -- Added write methods for the `mip` and `satp` registers -- Added `mideleg` register -- Added Changelog - -### Changed - -- Fixed MSRV by restricting the upper bound of `bare-metal` version -- Added DCSR (Debug Control and Status Register) CSR support for the RISC-V - -[Unreleased]: https://github.com/rust-embedded/riscv/compare/v0.10.1...HEAD -[v0.10.1]: https://github.com/rust-embedded/riscv/compare/v0.10.0...v0.10.1 -[v0.10.0]: https://github.com/rust-embedded/riscv/compare/v0.9.0...v0.10.0 -[v0.9.0]: https://github.com/rust-embedded/riscv/compare/v0.8.0...v0.9.0 -[v0.8.0]: https://github.com/rust-embedded/riscv/compare/v0.7.0...v0.8.0 -[v0.7.0]: https://github.com/rust-embedded/riscv/compare/v0.6.0...v0.7.0 -[v0.6.0]: https://github.com/rust-embedded/riscv/compare/v0.5.6...v0.6.0 -[v0.5.6]: https://github.com/rust-embedded/riscv/compare/v0.5.5...v0.5.6 -[v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5u From cf2431005e4e49b5352bd632b56dbb513ed9bb30 Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Tue, 16 Sep 2025 20:53:09 +0530 Subject: [PATCH 15/76] Update riscv/CHANGELOG.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Román Cárdenas Rodríguez --- riscv/CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index e533d66e..bc721126 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -275,7 +275,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - Fixed MSRV by restricting the upper bound of `bare-metal` version -- Added DCSR (Debug Control and Status Register) CSR support for the RISC-V [Unreleased]: https://github.com/rust-embedded/riscv/compare/v0.10.1...HEAD [v0.10.1]: https://github.com/rust-embedded/riscv/compare/v0.10.0...v0.10.1 From 01f127a2e0081c6fe1abe2d30455135d0bbea32d Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Tue, 16 Sep 2025 20:53:38 +0530 Subject: [PATCH 16/76] Update riscv/src/register/dcsr.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Román Cárdenas Rodríguez --- riscv/src/register/dcsr.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/riscv/src/register/dcsr.rs b/riscv/src/register/dcsr.rs index c19cc5b5..2b5f4f2b 100644 --- a/riscv/src/register/dcsr.rs +++ b/riscv/src/register/dcsr.rs @@ -8,10 +8,24 @@ read_write_csr! { mask: 0xffff_ffff, } +csr_field_enum! { + /// Operating privilege level. + Prv { + default: Machine, + /// User/Application. + User = 0b00, + /// Supervisor. + Supervisor = 0b01, + /// Machine. + Machine = 0b11, + } +} + read_write_csr_field! { Dcsr, - /// Previous privilege level when entering debug mode (bits 0..2) - prv: [0:1], + /// Previous privilege level when entering debug mode (bits 0..1). + prv, + Prv: [0:1], } read_write_csr_field! { From 213181c58086779c25049c2dd3b9a29dcac7bb21 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Wed, 17 Sep 2025 06:41:08 +0000 Subject: [PATCH 17/76] feat(register): use field enums for DCSR cause and prv - Add csr_field_enum! { Cause } and wire cause (bits 6..8) to it - Reuse existing Prv enum for prv (bits 0..1) - Remove manual DcsrCause/DcsrPrv enums and conversions - Update convenience methods to use typed fields (try_cause, try_prv) - Adjust unit tests to validate typed field behavior This replaces manual enums with csr_field_enum! as requested. --- riscv/src/register/dcsr.rs | 121 ++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 69 deletions(-) diff --git a/riscv/src/register/dcsr.rs b/riscv/src/register/dcsr.rs index 2b5f4f2b..068042ec 100644 --- a/riscv/src/register/dcsr.rs +++ b/riscv/src/register/dcsr.rs @@ -21,6 +21,25 @@ csr_field_enum! { } } +csr_field_enum! { + /// Cause for entering debug mode. + Cause { + default: None, + /// No cause. + None = 0, + /// EBREAK instruction. + Ebreak = 1, + /// Trigger module. + Trigger = 2, + /// External halt request. + HaltRequest = 3, + /// Single-step completed. + Step = 4, + /// Reset-halt request. + ResetHaltRequest = 5, + } +} + read_write_csr_field! { Dcsr, /// Previous privilege level when entering debug mode (bits 0..1). @@ -49,7 +68,8 @@ read_write_csr_field! { read_only_csr_field! { Dcsr, /// Cause for entering debug mode (bits 6..8) - cause: [6:8], + cause, + Cause: [6:8], } read_write_csr_field! { @@ -94,70 +114,27 @@ read_only_csr_field! { xdebugver: [28:31], } -/// Cause for entering debug mode -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DcsrCause { - None = 0, - Ebreak = 1, - Trigger = 2, - HaltRequest = 3, - Step = 4, - ResetHaltRequest = 5, -} - -impl DcsrCause { - pub fn from_usize(val: usize) -> Result { - match val { - 0 => Ok(Self::None), - 1 => Ok(Self::Ebreak), - 2 => Ok(Self::Trigger), - 3 => Ok(Self::HaltRequest), - 4 => Ok(Self::Step), - 5 => Ok(Self::ResetHaltRequest), - other => Err(other), - } - } -} - -/// Previous privilege level when entering debug mode -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DcsrPrv { - User = 0, - Supervisor = 1, - Machine = 3, -} - -impl DcsrPrv { - pub fn from_usize(val: usize) -> Result { - match val { - 0 => Ok(Self::User), - 1 => Ok(Self::Supervisor), - 3 => Ok(Self::Machine), - other => Err(other), - } - } -} - impl Dcsr { /// Returns the debug cause as an enum - pub fn debug_cause(&self) -> Result { - DcsrCause::from_usize(self.cause()) + pub fn debug_cause(&self) -> crate::result::Result { + self.try_cause() } /// Returns the previous privilege level as an enum - pub fn privilege_level(&self) -> Result { - DcsrPrv::from_usize(self.prv()) + pub fn privilege_level(&self) -> crate::result::Result { + self.try_prv() } /// Sets the previous privilege level - pub fn set_privilege_level(&mut self, level: DcsrPrv) { - self.set_prv(level as usize); + pub fn set_privilege_level(&mut self, level: Prv) { + self.set_prv(level); } } #[cfg(test)] mod tests { use super::*; + use crate::result::Error; #[test] fn test_dcsr_bitfields() { @@ -200,29 +177,35 @@ mod tests { #[test] fn test_dcsr_enums() { - assert_eq!(DcsrCause::from_usize(0).unwrap(), DcsrCause::None); - assert_eq!(DcsrCause::from_usize(1).unwrap(), DcsrCause::Ebreak); - assert_eq!(DcsrCause::from_usize(2).unwrap(), DcsrCause::Trigger); - assert_eq!(DcsrCause::from_usize(3).unwrap(), DcsrCause::HaltRequest); - assert_eq!(DcsrCause::from_usize(4).unwrap(), DcsrCause::Step); - assert_eq!( - DcsrCause::from_usize(5).unwrap(), - DcsrCause::ResetHaltRequest - ); - assert!(DcsrCause::from_usize(6).is_err()); - - assert_eq!(DcsrPrv::from_usize(0).unwrap(), DcsrPrv::User); - assert_eq!(DcsrPrv::from_usize(1).unwrap(), DcsrPrv::Supervisor); - assert_eq!(DcsrPrv::from_usize(3).unwrap(), DcsrPrv::Machine); - assert!(DcsrPrv::from_usize(2).is_err()); + let mut dcsr = Dcsr::from_bits(0); + + [ + Cause::None, + Cause::Ebreak, + Cause::Trigger, + Cause::HaltRequest, + Cause::Step, + Cause::ResetHaltRequest, + ] + .into_iter() + .enumerate() + .for_each(|(val, variant)| { + dcsr = Dcsr::from_bits((val as usize) << 6); + assert_eq!(dcsr.cause(), variant); + assert_eq!(dcsr.debug_cause(), Ok(variant)); + }); + + // invalid variant value 6 + dcsr = Dcsr::from_bits(6 << 6); + assert_eq!(dcsr.try_cause(), Err(Error::InvalidVariant(6))); } #[test] fn test_dcsr_convenience_methods() { let mut dcsr = Dcsr::from_bits(0); - dcsr.set_privilege_level(DcsrPrv::Machine); - assert_eq!(dcsr.privilege_level().unwrap(), DcsrPrv::Machine); - assert_eq!(dcsr.prv(), 3); + dcsr.set_privilege_level(Prv::Machine); + assert_eq!(dcsr.privilege_level().unwrap(), Prv::Machine); + assert_eq!(dcsr.prv(), Prv::Machine); } } From 9e91acb8d39a6bc200e1e19639660c9e4f6b6630 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Tue, 23 Sep 2025 11:45:34 +0530 Subject: [PATCH 18/76] fix(dcsr): remove redundant wrapper methods and update tests - Removed `debug_cause`, `privilege_level`, and `set_privilege_level` from `Dcsr` because the macros `read_write_csr_field!` and `csr_field_enum!` already generate the necessary accessors. - Updated tests to use `try_cause()`, `try_prv()`, and `set_prv()` instead of the removed wrapper methods. --- riscv/src/register/dcsr.rs | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/riscv/src/register/dcsr.rs b/riscv/src/register/dcsr.rs index 068042ec..e64cb20c 100644 --- a/riscv/src/register/dcsr.rs +++ b/riscv/src/register/dcsr.rs @@ -5,7 +5,7 @@ read_write_csr! { /// Debug Control and Status Register Dcsr: 0x7b0, - mask: 0xffff_ffff, + mask: 0x8000_0fff, } csr_field_enum! { @@ -114,23 +114,6 @@ read_only_csr_field! { xdebugver: [28:31], } -impl Dcsr { - /// Returns the debug cause as an enum - pub fn debug_cause(&self) -> crate::result::Result { - self.try_cause() - } - - /// Returns the previous privilege level as an enum - pub fn privilege_level(&self) -> crate::result::Result { - self.try_prv() - } - - /// Sets the previous privilege level - pub fn set_privilege_level(&mut self, level: Prv) { - self.set_prv(level); - } -} - #[cfg(test)] mod tests { use super::*; @@ -192,7 +175,7 @@ mod tests { .for_each(|(val, variant)| { dcsr = Dcsr::from_bits((val as usize) << 6); assert_eq!(dcsr.cause(), variant); - assert_eq!(dcsr.debug_cause(), Ok(variant)); + assert_eq!(dcsr.try_cause(), Ok(variant)); }); // invalid variant value 6 @@ -204,8 +187,8 @@ mod tests { fn test_dcsr_convenience_methods() { let mut dcsr = Dcsr::from_bits(0); - dcsr.set_privilege_level(Prv::Machine); - assert_eq!(dcsr.privilege_level().unwrap(), Prv::Machine); + dcsr.set_prv(Prv::Machine); + assert_eq!(dcsr.try_prv().unwrap(), Prv::Machine); assert_eq!(dcsr.prv(), Prv::Machine); } } From c17410c402560b812ae3602a58fa1ffebc6e583e Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Tue, 23 Sep 2025 11:48:28 +0530 Subject: [PATCH 19/76] Fix CHANGELOG.md --- riscv/CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index bc721126..23756a28 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [v0.15.0] - 2025-09-08 ### Added + - New convenience `try_new` and `new` associated functions for `Mtvec` and `Stvec`. - New methods and functions for enabling core interrupts in the `mie` and `sie` registers using the `riscv_pac::CoreInterruptNumber` trait. @@ -116,7 +117,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). the CSR - Export `riscv::register::macros` module macros for external use - Add `riscv::register::mcountinhibit` module for `mcountinhibit` CSR -- Add `Mcounteren` in-memory update functions +- Add `Mcounteren` in-memory update functions - Add `Mstatus` vector extension support - Add fallible counterparts to all functions that `panic` - Add `riscv-pac` as a dependency @@ -285,4 +286,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/). [v0.6.0]: https://github.com/rust-embedded/riscv/compare/v0.5.6...v0.6.0 [v0.5.6]: https://github.com/rust-embedded/riscv/compare/v0.5.5...v0.5.6 [v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5 -[v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5u \ No newline at end of file +[v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5u From 02c1edf3f9eb27bc1aee6bf43384f8bfaaaca251 Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Tue, 23 Sep 2025 13:28:00 +0530 Subject: [PATCH 20/76] Update riscv/src/register/dcsr.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Román Cárdenas Rodríguez --- riscv/src/register/dcsr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/riscv/src/register/dcsr.rs b/riscv/src/register/dcsr.rs index e64cb20c..32354d72 100644 --- a/riscv/src/register/dcsr.rs +++ b/riscv/src/register/dcsr.rs @@ -5,7 +5,7 @@ read_write_csr! { /// Debug Control and Status Register Dcsr: 0x7b0, - mask: 0x8000_0fff, + mask: 0xf000_bfdf, } csr_field_enum! { From 73e32c9f8c639da994b4bae219bc49f5224ef74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Mon, 22 Sep 2025 16:05:05 +0200 Subject: [PATCH 21/76] Feature-gate trap-related code in riscv --- riscv-rt/CHANGELOG.md | 4 ++ riscv-rt/Cargo.toml | 4 +- riscv-rt/src/interrupts.rs | 2 +- riscv/CHANGELOG.md | 5 ++ riscv/Cargo.toml | 2 + riscv/macros/Cargo.toml | 4 ++ riscv/macros/src/lib.rs | 104 +++++++++++++++++++------------------ riscv/src/lib.rs | 11 ++++ 8 files changed, 83 insertions(+), 53 deletions(-) diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index 847d066b..920c9ae7 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed + +- Adapted to new `riscv` version. + ## [v0.16.0] - 2025-09-08 ### Added diff --git a/riscv-rt/Cargo.toml b/riscv-rt/Cargo.toml index da9b550c..009227be 100644 --- a/riscv-rt/Cargo.toml +++ b/riscv-rt/Cargo.toml @@ -24,7 +24,7 @@ targets = [ riscv-target-parser = { path = "../riscv-target-parser", version = "0.1.2" } [dependencies] -riscv = { path = "../riscv", version = "0.15.0" } +riscv = { path = "../riscv", version = "0.15.0", features = ["rt"] } riscv-pac = { path = "../riscv-pac", version = "0.2.0" } riscv-rt-macros = { path = "macros", version = "0.6.0" } @@ -38,7 +38,7 @@ pre-init = [] post-init = [] s-mode = ["riscv-rt-macros/s-mode"] single-hart = [] -v-trap = ["riscv-rt-macros/v-trap"] +v-trap = ["riscv-rt-macros/v-trap", "riscv/rt-v-trap"] u-boot = ["riscv-rt-macros/u-boot", "single-hart"] no-interrupts = [] no-exceptions = [] diff --git a/riscv-rt/src/interrupts.rs b/riscv-rt/src/interrupts.rs index 44561f86..71b77014 100644 --- a/riscv-rt/src/interrupts.rs +++ b/riscv-rt/src/interrupts.rs @@ -17,10 +17,10 @@ //! you may need to opt out this module. To do so, activate the `no-interrupts` feature of the //! `riscv-rt` crate. -// In vectored mode, we also must provide a vector table #[riscv::pac_enum(unsafe CoreInterruptNumber)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[allow(dead_code)] // otherwise compiler complains about Interrupt not being used enum Interrupt { SupervisorSoft = 1, MachineSoft = 3, diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 67a37179..2e2f3a93 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Add `miselect` CSR - Improved assembly macro handling in asm.rs +- New `rt` and `rt-v-trap` features to opt-in `riscv-rt`-related code in `riscv::pac_enum` macro. + +# Changed + +- Now, `riscv::pac_enum` macro only includes trap-related code if `rt` or `rt-v-trap` features are enabled. ## [v0.15.0] - 2025-09-08 diff --git a/riscv/Cargo.toml b/riscv/Cargo.toml index 0cae7f10..945a1e94 100644 --- a/riscv/Cargo.toml +++ b/riscv/Cargo.toml @@ -23,6 +23,8 @@ targets = [ default = ["riscv-macros"] s-mode = [] critical-section-single-hart = ["critical-section/restore-state-bool"] +rt = ["riscv-macros/rt"] +rt-v-trap = ["rt", "riscv-macros/rt-v-trap"] [dependencies] critical-section = "1.2.0" diff --git a/riscv/macros/Cargo.toml b/riscv/macros/Cargo.toml index 43773c7a..749d8e5e 100644 --- a/riscv/macros/Cargo.toml +++ b/riscv/macros/Cargo.toml @@ -15,6 +15,10 @@ edition = "2021" [lib] proc-macro = true +[features] +rt = [] +rt-v-trap = ["rt"] + [dependencies] proc-macro2 = "1.0" quote = "1.0" diff --git a/riscv/macros/src/lib.rs b/riscv/macros/src/lib.rs index 5f4bf8f3..3192f1ad 100644 --- a/riscv/macros/src/lib.rs +++ b/riscv/macros/src/lib.rs @@ -11,6 +11,7 @@ use syn::{ }; /// Struct to represent a function parameter. +#[cfg(feature = "rt")] struct FunctionParam { /// Name of the parameter. param_name: TokenStream2, @@ -20,6 +21,7 @@ struct FunctionParam { /// Configuration parameters of a trap. It is useful to abstract the /// differences between exception handlers and core interrupt handlers. +#[cfg(feature = "rt")] struct TrapConfig { /// Name of the default handler (e.g., `DefaultHandler` for core interrupts). default_handler: TokenStream2, @@ -31,6 +33,7 @@ struct TrapConfig { handlers_array_name: TokenStream2, } +#[cfg(feature = "rt")] impl TrapConfig { /// Vector with all the input parameters expected when declaring extern handler functions fn extern_signature(&self) -> Vec { @@ -107,6 +110,7 @@ impl PacTrait { } /// For Exception or an Interrupt enums, it returns the trap configuration details. + #[cfg(feature = "rt")] fn trap_config(&self) -> Option { match self { Self::Exception => Some(TrapConfig { @@ -163,6 +167,7 @@ impl InterruptType { } /// Returns a token stream representing the name of the array of interrupt service routines + #[cfg(feature = "rt")] fn isr_array_name(&self) -> TokenStream2 { match self { Self::Core => quote!(__CORE_INTERRUPTS), @@ -171,6 +176,7 @@ impl InterruptType { } /// Returns a token stream representing the name of the interrupt dispatch function + #[cfg(feature = "rt")] fn dispatch_fn_name(&self) -> TokenStream2 { match self { Self::Core => quote!(_dispatch_core_interrupt), @@ -239,6 +245,7 @@ impl PacEnumItem { } /// Returns a vector of token streams representing the interrupt handler functions + #[cfg(feature = "rt")] fn handlers(&self, trap_config: &TrapConfig) -> Vec { let signature = trap_config.extern_signature(); self.numbers @@ -252,6 +259,7 @@ impl PacEnumItem { /// Returns a sorted vector of token streams representing all the elements of the interrupt array. /// If an interrupt number is not present in the enum, the corresponding element is `None`. /// Otherwise, it is `Some()`. + #[cfg(feature = "rt")] fn handlers_array(&self) -> Vec { let mut vectors = vec![]; for i in 0..=self.max_number { @@ -264,6 +272,7 @@ impl PacEnumItem { vectors } + #[cfg(feature = "rt-v-trap")] fn vector_table(&self) -> TokenStream2 { let align = match std::env::var("RISCV_MTVEC_ALIGN") { Ok(x) => x.parse::().ok(), @@ -280,7 +289,7 @@ impl PacEnumItem { }; let mut asm = format!( r#" -#[cfg(all(feature = "v-trap", any(target_arch = "riscv32", target_arch = "riscv64")))] +#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] core::arch::global_asm!(" .section .trap.vector, \"ax\" .global _vector_table @@ -328,8 +337,6 @@ core::arch::global_asm!(" let max_discriminant = self.max_number; let valid_matches = self.valid_matches(); - let is_core_interrupt = matches!(attr, PacTrait::Interrupt(InterruptType::Core)); - // Push the trait implementation res.push(quote! { unsafe impl riscv::#trait_name for #name { @@ -354,54 +361,51 @@ core::arch::global_asm!(" res.push(quote! { unsafe impl riscv::#marker_trait_name for #name {} }); } + #[cfg(feature = "rt")] if let Some(trap_config) = attr.trap_config() { - let default_handler = &trap_config.default_handler; - let extern_signature = trap_config.extern_signature(); - let handler_input = trap_config.handler_input(); - let array_signature = trap_config.array_signature(); - let dispatch_fn_name = &trap_config.dispatch_fn_name; - let dispatch_fn_args = &trap_config.dispatch_fn_signature(); - let vector_table = &trap_config.handlers_array_name; - - let handlers = self.handlers(&trap_config); - let interrupt_array = self.handlers_array(); - let cfg_v_trap = match is_core_interrupt { - true => Some(quote!(#[cfg(not(feature = "v-trap"))])), - false => None, - }; - - // Push the interrupt handler functions and the interrupt array - res.push(quote! { - #cfg_v_trap - extern "C" { - #(#handlers;)* + match attr { + #[cfg(feature = "rt-v-trap")] + PacTrait::Interrupt(InterruptType::Core) => { + res.push(self.vector_table()); } - - #cfg_v_trap - #[doc(hidden)] - #[no_mangle] - pub static #vector_table: [Option; #max_discriminant + 1] = [ - #(#interrupt_array),* - ]; - - #cfg_v_trap - #[inline] - #[no_mangle] - unsafe extern "C" fn #dispatch_fn_name(#(#dispatch_fn_args),*) { - extern "C" { - fn #default_handler(#(#extern_signature),*); - } - - match #vector_table.get(code) { - Some(Some(handler)) => handler(#(#handler_input),*), - _ => #default_handler(#(#handler_input),*), - } + _ => { + let default_handler = &trap_config.default_handler; + let extern_signature = trap_config.extern_signature(); + let handler_input = trap_config.handler_input(); + let array_signature = trap_config.array_signature(); + let dispatch_fn_name = &trap_config.dispatch_fn_name; + let dispatch_fn_args = &trap_config.dispatch_fn_signature(); + let vector_table = &trap_config.handlers_array_name; + + let handlers = self.handlers(&trap_config); + let interrupt_array = self.handlers_array(); + + res.push(quote! { + extern "C" { + #(#handlers;)* + } + + #[doc(hidden)] + #[no_mangle] + pub static #vector_table: [Option; #max_discriminant + 1] = [ + #(#interrupt_array),* + ]; + + #[inline] + #[no_mangle] + unsafe extern "C" fn #dispatch_fn_name(#(#dispatch_fn_args),*) { + extern "C" { + fn #default_handler(#(#extern_signature),*); + } + + match #vector_table.get(code) { + Some(Some(handler)) => handler(#(#handler_input),*), + _ => #default_handler(#(#handler_input),*), + } + } + }); } - }); - } - - if is_core_interrupt { - res.push(self.vector_table()); + } } res @@ -413,8 +417,8 @@ core::arch::global_asm!(" /// As these traits are unsafe, the macro must be called with the `unsafe` keyword followed by the trait name. /// In this way, we warn callers that they must comply with the requirements of the trait. /// -/// The trait name must be one of `ExceptionNumber`, `InterruptNumber`, `PriorityNumber`, or `HartIdNumber`. -/// Marker traits `CoreInterruptNumber` and `ExternalInterruptNumber` cannot be implemented using this macro. +/// The trait name must be one of `ExceptionNumber`, `CoreInterruptNumber`, `ExternalInterruptNumber`, +/// `PriorityNumber`, or `HartIdNumber`. /// /// # Safety /// diff --git a/riscv/src/lib.rs b/riscv/src/lib.rs index 838c7d9a..0704f75b 100644 --- a/riscv/src/lib.rs +++ b/riscv/src/lib.rs @@ -31,6 +31,17 @@ //! and may cause functional problems in systems where some interrupts must NOT be disabled //! or critical sections are managed as part of an RTOS. In these cases, you should use //! a target-specific implementation instead, typically provided by a HAL or RTOS crate. +//! +//! ## `rt` +//! +//! This feature enables code related to [`riscv-rt`](https://github.com/rust-embedded/riscv/tree/master/riscv-rt) +//! runtime support in the `riscv::pac_enum` macro. Namely, it enables the generation of +//! trap handler functions and dispatch functions. +//! +//! ## `rt-v-trap` +//! +//! This feature enables code related to vectored trap handling in addition to the `rt` feature. +//! Namely, it enables the generation of a vector table and the corresponding assembly code for core interrupts. #![no_std] #![allow(clippy::missing_safety_doc)] From dd626f58150a9d7e32ce72510ebe77c0bfa09fe4 Mon Sep 17 00:00:00 2001 From: wisp3rwind <17089248+wisp3rwind@users.noreply.github.com> Date: Sun, 28 Sep 2025 17:54:19 +0200 Subject: [PATCH 22/76] fix: don't crash when target-feature=+relax is given This target feature is a bit unusual in that it does not refer to actual hardware features, but is rather a target-specific linker feature. See also https://github.com/rust-lang/rust/pull/109860 --- riscv-target-parser/CHANGELOG.md | 4 ++++ riscv-target-parser/src/lib.rs | 20 +++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/riscv-target-parser/CHANGELOG.md b/riscv-target-parser/CHANGELOG.md index b805fb6e..939f90ac 100644 --- a/riscv-target-parser/CHANGELOG.md +++ b/riscv-target-parser/CHANGELOG.md @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Fixed + +- Skip the 'relax' target feature when parsing extensions + ## [v0.1.2] - 2025-06-10 ### Fixed diff --git a/riscv-target-parser/src/lib.rs b/riscv-target-parser/src/lib.rs index b557d619..2d39c17a 100644 --- a/riscv-target-parser/src/lib.rs +++ b/riscv-target-parser/src/lib.rs @@ -106,6 +106,12 @@ pub struct RiscvTarget { extensions: Extensions, } +// Returns whether a target feature _might_ be an ISA extension according to a non-exhaustive list +// of known unrelated features flags. +fn is_isa_extension(feature: &str) -> bool { + feature != "relax" +} + impl RiscvTarget { /// Builds a RISC-V target from a target triple and cargo flags. /// This function is expected to be called from a build script. @@ -135,11 +141,15 @@ impl RiscvTarget { }) { if let Some(feature) = target_feature.strip_prefix('+') { - let extension = Extension::try_from(feature)?; - target.extensions.insert(extension); + if is_isa_extension(feature) { + let extension = Extension::try_from(feature)?; + target.extensions.insert(extension); + } } else if let Some(feature) = target_feature.strip_prefix('-') { - let extension = Extension::try_from(feature)?; - target.extensions.remove(&extension); + if is_isa_extension(feature) { + let extension = Extension::try_from(feature)?; + target.extensions.remove(&extension); + } } else { return Err(Error::UnknownTargetFeature(target_feature)); } @@ -246,7 +256,7 @@ mod test { #[test] fn test_parse_target() { let target = "riscv32imac-unknown-none-elf"; - let cargo_flags = "target-feature=+m,-a,+f"; + let cargo_flags = "target-feature=+m,-a,+f,+relax"; let target = super::RiscvTarget::build(target, cargo_flags).unwrap(); let rustc_flags = target.rustc_flags(); assert_eq!(rustc_flags, vec!["riscvi", "riscvm", "riscvf", "riscvc"]); From 15d4b919c7f79a313507cdeb49c57b8aeb29e2af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Mon, 29 Sep 2025 12:34:53 +0200 Subject: [PATCH 23/76] Prepare to publish riscv-target-parser patch --- riscv-target-parser/CHANGELOG.md | 2 ++ riscv-target-parser/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/riscv-target-parser/CHANGELOG.md b/riscv-target-parser/CHANGELOG.md index 939f90ac..ab82bdad 100644 --- a/riscv-target-parser/CHANGELOG.md +++ b/riscv-target-parser/CHANGELOG.md @@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.1.3] - 2025-09-29 + ### Fixed - Skip the 'relax' target feature when parsing extensions diff --git a/riscv-target-parser/Cargo.toml b/riscv-target-parser/Cargo.toml index 7612e387..02d4fad5 100644 --- a/riscv-target-parser/Cargo.toml +++ b/riscv-target-parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "riscv-target-parser" -version = "0.1.2" +version = "0.1.3" rust-version = "1.61" repository = "https://github.com/rust-embedded/riscv" authors = ["The RISC-V Team "] From e6b756f91a8c529b686e96bf412d4a313d125d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Thu, 23 Oct 2025 18:11:24 +0200 Subject: [PATCH 24/76] Bump MSRV to 1.68 --- .github/workflows/riscv-rt.yaml | 8 ++++---- .github/workflows/riscv.yaml | 4 ++-- .github/workflows/tests.yaml | 8 ++++---- riscv-rt/CHANGELOG.md | 1 + riscv-rt/Cargo.toml | 2 +- riscv/CHANGELOG.md | 1 + riscv/Cargo.toml | 2 +- 7 files changed, 14 insertions(+), 12 deletions(-) diff --git a/.github/workflows/riscv-rt.yaml b/.github/workflows/riscv-rt.yaml index 094d25a1..da2e7940 100644 --- a/.github/workflows/riscv-rt.yaml +++ b/.github/workflows/riscv-rt.yaml @@ -10,8 +10,8 @@ jobs: build-riscv: strategy: matrix: - # All generated code should be running on stable now, MRSV is 1.67.0 - toolchain: [ stable, nightly, 1.67.0 ] + # All generated code should be running on stable now, MRSV is 1.68.0 + toolchain: [ stable, nightly, 1.68.0 ] target: - riscv32i-unknown-none-elf - riscv32im-unknown-none-elf @@ -28,9 +28,9 @@ jobs: - toolchain: nightly experimental: true exclude: - - toolchain: 1.67.0 + - toolchain: 1.68.0 target: riscv32im-unknown-none-elf - - toolchain: 1.67.0 + - toolchain: 1.68.0 target: riscv32imafc-unknown-none-elf runs-on: ubuntu-latest continue-on-error: ${{ matrix.experimental || false }} diff --git a/.github/workflows/riscv.yaml b/.github/workflows/riscv.yaml index cf8a1e94..e0234580 100644 --- a/.github/workflows/riscv.yaml +++ b/.github/workflows/riscv.yaml @@ -11,8 +11,8 @@ jobs: build-riscv: strategy: matrix: - # All generated code should be running on stable now, MRSV is 1.67.0 - toolchain: [ stable, nightly, 1.67.0 ] + # All generated code should be running on stable now, MRSV is 1.68.0 + toolchain: [ stable, nightly, 1.68.0 ] target: - riscv32i-unknown-none-elf - riscv32imc-unknown-none-elf diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 2393f742..954efc2a 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -20,8 +20,8 @@ jobs: run-build: strategy: matrix: - # All generated code should be running on stable now, MRSV is 1.67.0 - toolchain: [ stable, nightly, 1.67.0 ] + # All generated code should be running on stable now, MRSV is 1.68.0 + toolchain: [ stable, nightly, 1.68.0 ] target: - riscv32i-unknown-none-elf - riscv32im-unknown-none-elf @@ -37,9 +37,9 @@ jobs: - toolchain: nightly experimental: true exclude: - - toolchain: 1.67.0 + - toolchain: 1.68.0 target: riscv32im-unknown-none-elf - - toolchain: 1.67.0 + - toolchain: 1.68.0 target: riscv32imafc-unknown-none-elf runs-on: ubuntu-latest continue-on-error: ${{ matrix.experimental || false }} diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index 920c9ae7..5b1394ac 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Bump MSRV to 1.68 for latest syn 2.0 release - Adapted to new `riscv` version. ## [v0.16.0] - 2025-09-08 diff --git a/riscv-rt/Cargo.toml b/riscv-rt/Cargo.toml index 009227be..42e9d4f7 100644 --- a/riscv-rt/Cargo.toml +++ b/riscv-rt/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "riscv-rt" version = "0.16.0" -rust-version = "1.67" +rust-version = "1.68" repository = "https://github.com/rust-embedded/riscv" authors = ["The RISC-V Team "] categories = ["embedded", "no-std"] diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 795bb67b..07d20828 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # Changed +- Bump MSRV to 1.68 for latest version of syn 2.0 - Now, `riscv::pac_enum` macro only includes trap-related code if `rt` or `rt-v-trap` features are enabled. ## [v0.15.0] - 2025-09-08 diff --git a/riscv/Cargo.toml b/riscv/Cargo.toml index 945a1e94..e3415035 100644 --- a/riscv/Cargo.toml +++ b/riscv/Cargo.toml @@ -2,7 +2,7 @@ name = "riscv" version = "0.15.0" edition = "2021" -rust-version = "1.67" +rust-version = "1.68" repository = "https://github.com/rust-embedded/riscv" authors = ["The RISC-V Team "] categories = ["embedded", "hardware-support", "no-std"] From 8b8f16b2060991acc656925ccbd08198fdf400e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Thu, 23 Oct 2025 18:19:53 +0200 Subject: [PATCH 25/76] Address CI errors --- riscv-peripheral/CHANGELOG.md | 4 ++++ riscv-peripheral/src/aclint.rs | 2 +- riscv-rt/CHANGELOG.md | 1 + riscv-rt/macros/src/lib.rs | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/riscv-peripheral/CHANGELOG.md b/riscv-peripheral/CHANGELOG.md index 244a22af..5b58fbc9 100644 --- a/riscv-peripheral/CHANGELOG.md +++ b/riscv-peripheral/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Fixed + +- Typo in documentation. + ## [v0.4.0] - 2025-09-08 ### Added diff --git a/riscv-peripheral/src/aclint.rs b/riscv-peripheral/src/aclint.rs index 998edf24..3354431a 100644 --- a/riscv-peripheral/src/aclint.rs +++ b/riscv-peripheral/src/aclint.rs @@ -1,6 +1,6 @@ //! Devices for the Core Local Interruptor (CLINT) and Advanced CLINT (ACLINT) peripherals. //! -//! CLINT pecification: +//! CLINT specification: //! ACLINT Specification: pub mod mswi; diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index 5b1394ac..91dc1516 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Fix clippy warnings in riscv_rt_macros::strip_type_path - Bump MSRV to 1.68 for latest syn 2.0 release - Adapted to new `riscv` version. diff --git a/riscv-rt/macros/src/lib.rs b/riscv-rt/macros/src/lib.rs index 53ae6e74..6db77759 100644 --- a/riscv-rt/macros/src/lib.rs +++ b/riscv-rt/macros/src/lib.rs @@ -137,7 +137,7 @@ fn strip_type_path(ty: &Type) -> Option { match ty { Type::Ptr(ty) => { let mut ty = ty.clone(); - ty.elem = Box::new(strip_type_path(&ty.elem)?); + *ty.elem = strip_type_path(&ty.elem)?; Some(Type::Ptr(ty)) } Type::Path(ty) => { From 1c72125caff2969acfc8a1d9cb7873b4b089d1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Wed, 29 Oct 2025 12:30:04 +0100 Subject: [PATCH 26/76] Run riscv tests on CI --- .github/workflows/riscv.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/riscv.yaml b/.github/workflows/riscv.yaml index e0234580..0a7ffc2b 100644 --- a/.github/workflows/riscv.yaml +++ b/.github/workflows/riscv.yaml @@ -40,7 +40,7 @@ jobs: - name: Build (all features) run: cargo build --package riscv --target ${{ matrix.target }} --all-features - # On MacOS, Ubuntu, and Windows, we at least make sure that the crate builds and links. + # On MacOS, Ubuntu, and Windows, we run tests. build-others: strategy: matrix: @@ -49,10 +49,10 @@ jobs: steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - - name: Build (no features) - run: cargo build --package riscv - - name: Build (all features) - run: cargo build --package riscv --all-features + - name: Test (no features) + run: cargo test --package riscv + - name: Test (all features) + run: cargo test --package riscv --all-features # Job to check that all the builds succeeded build-check: From 161af9c0eec00749cb19d42afa4161494e1f34f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Thu, 23 Oct 2025 18:02:43 +0200 Subject: [PATCH 27/76] Rename riscv-pac to riscv-types --- Cargo.toml | 2 + riscv-types/CHANGELOG.md | 39 +++++ riscv-types/Cargo.toml | 19 +++ riscv-types/README.md | 40 ++++++ riscv-types/src/lib.rs | 289 ++++++++++++++++++++++++++++++++++++++ riscv-types/src/result.rs | 58 ++++++++ 6 files changed, 447 insertions(+) create mode 100644 riscv-types/CHANGELOG.md create mode 100644 riscv-types/Cargo.toml create mode 100644 riscv-types/README.md create mode 100644 riscv-types/src/lib.rs create mode 100644 riscv-types/src/result.rs diff --git a/Cargo.toml b/Cargo.toml index d15e82f9..c0505280 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "riscv-rt", "riscv-semihosting", "riscv-target-parser", + "riscv-types", "tests-build", "tests-trybuild", ] @@ -17,4 +18,5 @@ default-members = [ "riscv-peripheral", "riscv-rt", "riscv-semihosting", + "riscv-types", ] diff --git a/riscv-types/CHANGELOG.md b/riscv-types/CHANGELOG.md new file mode 100644 index 00000000..79236008 --- /dev/null +++ b/riscv-types/CHANGELOG.md @@ -0,0 +1,39 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +### Changed + +- Renamed crate to `riscv-types` as per [#351](https://github.com/rust-embedded/riscv/issues/351) + +## riscv-pac [v0.2.0] - 2024-10-19 + +### Added + +- Add `result` module for `Error` and `Result` types +- Add `ExceptionNumber` trait. +- Classify interrupt numbers in `CoreInterruptNumber` and `ExternalInterruptNumber`. +- Added simple tests to illustrate how to implement all the provided traits. + +### Changed + +- All traits now work with `usize` data type. + +## riscv-pac [v0.1.1] - 2024-02-15 + +- Fix crates.io badge links + +## riscv-pac [v0.1.0] - 2024-01-14 + +### Added + +- Add `InterruptNumber`, `PriorityNumber`, and `HartIdNumber` traits. + +### Changed + +- Update `README.md` diff --git a/riscv-types/Cargo.toml b/riscv-types/Cargo.toml new file mode 100644 index 00000000..63a6afc4 --- /dev/null +++ b/riscv-types/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "riscv-types" +version = "0.1.0" +edition = "2021" +rust-version = "1.60" +repository = "https://github.com/rust-embedded/riscv" +authors = ["The RISC-V Team "] +categories = ["embedded", "hardware-support", "no-std"] +description = "Low level access to RISC-V processors" +documentation = "https://docs.rs/riscv-types" +keywords = ["riscv", "register", "peripheral"] +license = "ISC" + +[package.metadata.docs.rs] +default-target = "riscv64imac-unknown-none-elf" +targets = [ + "riscv32i-unknown-none-elf", "riscv32imc-unknown-none-elf", "riscv32imac-unknown-none-elf", + "riscv64imac-unknown-none-elf", "riscv64gc-unknown-none-elf", +] diff --git a/riscv-types/README.md b/riscv-types/README.md new file mode 100644 index 00000000..6745b98d --- /dev/null +++ b/riscv-types/README.md @@ -0,0 +1,40 @@ +[![crates.io](https://img.shields.io/crates/d/riscv-types.svg)](https://crates.io/crates/riscv-types) +[![crates.io](https://img.shields.io/crates/v/riscv-types.svg)](https://crates.io/crates/riscv-types) + +# `riscv-types` (previously `riscv-pac`) + +> Target-specific traits to be implemented by PACs + +This project is developed and maintained by the [RISC-V team][team]. + +## [Documentation](https://docs.rs/crate/riscv-types) + +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.60 and up. It *might* +compile with older versions but that may change in any new patch release. + +## License + +Copyright 2023-2025 [RISC-V team][team] + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + +## Code of Conduct + +Contribution to this crate is organized under the terms of the [Rust Code of +Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises +to intervene to uphold that code of conduct. + +[CoC]: ../CODE_OF_CONDUCT.md +[team]: https://github.com/rust-embedded/wg#the-risc-v-team diff --git a/riscv-types/src/lib.rs b/riscv-types/src/lib.rs new file mode 100644 index 00000000..f0929b3d --- /dev/null +++ b/riscv-types/src/lib.rs @@ -0,0 +1,289 @@ +#![no_std] + +pub mod result; + +use result::Result; + +/// Trait for enums of target-specific exception numbers. +/// +/// This trait should be implemented by a peripheral access crate (PAC) on its enum of available +/// exceptions for a specific device. Alternatively, the `riscv` crate provides a default +/// implementation for the RISC-V ISA. Each variant must convert to a `usize` of its exception number. +/// +/// # Safety +/// +/// * This trait must only be implemented on the `riscv` crate or on a PAC of a RISC-V target. +/// * This trait must only be implemented on enums of exceptions. +/// * Each enum variant must represent a distinct value (no duplicates are permitted), +/// * Each enum variant must always return the same value (do not change at runtime). +/// * All the exception numbers must be less than or equal to `MAX_EXCEPTION_NUMBER`. +/// * `MAX_EXCEPTION_NUMBER` must coincide with the highest allowed exception number. +pub unsafe trait ExceptionNumber: Copy { + /// Highest number assigned to an exception. + const MAX_EXCEPTION_NUMBER: usize; + + /// Converts an exception to its corresponding number. + fn number(self) -> usize; + + /// Tries to convert a number to a valid exception. + fn from_number(value: usize) -> Result; +} + +/// Trait for enums of target-specific interrupt numbers. +/// +/// This trait should be implemented by a peripheral access crate (PAC) on its enum of available +/// interrupts for a specific device. Alternatively, the `riscv` crate provides a default +/// implementation for the RISC-V ISA. Each variant must convert to a `usize` of its interrupt number. +/// +/// # Safety +/// +/// * This trait must only be implemented on the `riscv` crate or on a PAC of a RISC-V target. +/// * This trait must only be implemented on enums of interrupts. +/// * Each enum variant must represent a distinct value (no duplicates are permitted), +/// * Each enum variant must always return the same value (do not change at runtime). +/// * All the interrupt numbers must be less than or equal to `MAX_INTERRUPT_NUMBER`. +/// * `MAX_INTERRUPT_NUMBER` must coincide with the highest allowed interrupt number. +pub unsafe trait InterruptNumber: Copy { + /// Highest number assigned to an interrupt source. + const MAX_INTERRUPT_NUMBER: usize; + + /// Converts an interrupt source to its corresponding number. + fn number(self) -> usize; + + /// Tries to convert a number to a valid interrupt. + fn from_number(value: usize) -> Result; +} + +/// Marker trait for enums of target-specific core interrupt numbers. +/// +/// Core interrupts are interrupts are retrieved from the `mcause` CSR. Usually, vectored mode is +/// only available for core interrupts. The `riscv` crate provides a default implementation for +/// the RISC-V ISA. However, a PAC may override the default implementation if the target has a +/// different interrupt numbering scheme (e.g., ESP32C3). +/// +/// # Safety +/// +/// Each enum variant must represent a valid core interrupt number read from the `mcause` CSR. +pub unsafe trait CoreInterruptNumber: InterruptNumber {} + +/// Marker trait for enums of target-specific external interrupt numbers. +/// +/// External interrupts are interrupts caused by external sources (e.g., GPIO, UART, SPI). +/// External interrupts are **not** retrieved from the `mcause` CSR. +/// Instead, RISC-V processors have a single core interrupt for all external interrupts. +/// An additional peripheral (e.g., PLIC) is used to multiplex the external interrupts. +/// +/// # Safety +/// +/// Each enum variant must represent a valid external interrupt number. +pub unsafe trait ExternalInterruptNumber: InterruptNumber {} + +/// Trait for enums of priority levels. +/// +/// This trait should be implemented by a peripheral access crate (PAC) on its enum of available +/// priority numbers for a specific device. Each variant must convert to a `usize` of its priority level. +/// +/// # Safety +/// +/// * This trait must only be implemented on a PAC of a RISC-V target. +/// * This trait must only be implemented on enums of priority levels. +/// * Each enum variant must represent a distinct value (no duplicates are permitted). +/// * Each enum variant must always return the same value (do not change at runtime). +/// * All the priority level numbers must be less than or equal to `MAX_PRIORITY_NUMBER`. +/// * `MAX_PRIORITY_NUMBER` must coincide with the highest allowed priority number. +pub unsafe trait PriorityNumber: Copy { + /// Number assigned to the highest priority level. + const MAX_PRIORITY_NUMBER: usize; + + /// Converts a priority level to its corresponding number. + fn number(self) -> usize; + + /// Tries to convert a number to a valid priority level. + fn from_number(value: usize) -> Result; +} + +/// Trait for enums of HART identifiers. +/// +/// This trait should be implemented by a peripheral access crate (PAC) on its enum of available +/// HARTs for a specific device. Each variant must convert to a `usize` of its HART ID number. +/// +/// # Safety +/// +/// * This trait must only be implemented on a PAC of a RISC-V target. +/// * This trait must only be implemented on enums of HART IDs. +/// * Each enum variant must represent a distinct value (no duplicates are permitted), +/// * Each anum variant must always return the same value (do not change at runtime). +/// * All the HART ID numbers must be less than or equal to `MAX_HART_ID_NUMBER`. +/// * `MAX_HART_ID_NUMBER` must coincide with the highest allowed HART ID number. +pub unsafe trait HartIdNumber: Copy { + /// Highest number assigned to a context. + const MAX_HART_ID_NUMBER: usize; + + /// Converts a HART ID to its corresponding number. + fn number(self) -> usize; + + /// Tries to convert a number to a valid HART ID. + fn from_number(value: usize) -> Result; +} + +#[cfg(test)] +mod test { + use super::*; + use crate::result::Error; + + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + enum Exception { + E1 = 1, + E3 = 3, + } + + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + enum Interrupt { + I1 = 1, + I2 = 2, + I4 = 4, + } + + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + enum Priority { + P0 = 0, + P1 = 1, + P2 = 2, + P3 = 3, + } + + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + enum HartId { + H0 = 0, + H1 = 1, + H2 = 2, + } + + unsafe impl ExceptionNumber for Exception { + const MAX_EXCEPTION_NUMBER: usize = Self::E3 as usize; + + #[inline] + fn number(self) -> usize { + self as _ + } + + #[inline] + fn from_number(number: usize) -> Result { + match number { + 1 => Ok(Exception::E1), + 3 => Ok(Exception::E3), + _ => Err(Error::InvalidVariant(number)), + } + } + } + + unsafe impl InterruptNumber for Interrupt { + const MAX_INTERRUPT_NUMBER: usize = Self::I4 as usize; + + #[inline] + fn number(self) -> usize { + self as _ + } + + #[inline] + fn from_number(number: usize) -> Result { + match number { + 1 => Ok(Interrupt::I1), + 2 => Ok(Interrupt::I2), + 4 => Ok(Interrupt::I4), + _ => Err(Error::InvalidVariant(number)), + } + } + } + + unsafe impl PriorityNumber for Priority { + const MAX_PRIORITY_NUMBER: usize = Self::P3 as usize; + + #[inline] + fn number(self) -> usize { + self as _ + } + + #[inline] + fn from_number(number: usize) -> Result { + match number { + 0 => Ok(Priority::P0), + 1 => Ok(Priority::P1), + 2 => Ok(Priority::P2), + 3 => Ok(Priority::P3), + _ => Err(Error::InvalidVariant(number)), + } + } + } + + unsafe impl HartIdNumber for HartId { + const MAX_HART_ID_NUMBER: usize = Self::H2 as usize; + + #[inline] + fn number(self) -> usize { + self as _ + } + + #[inline] + fn from_number(number: usize) -> Result { + match number { + 0 => Ok(HartId::H0), + 1 => Ok(HartId::H1), + 2 => Ok(HartId::H2), + _ => Err(Error::InvalidVariant(number)), + } + } + } + + #[test] + fn check_exception_enum() { + assert_eq!(Exception::E1.number(), 1); + assert_eq!(Exception::E3.number(), 3); + + assert_eq!(Exception::from_number(0), Err(Error::InvalidVariant(0))); + assert_eq!(Exception::from_number(1), Ok(Exception::E1)); + assert_eq!(Exception::from_number(2), Err(Error::InvalidVariant(2))); + assert_eq!(Exception::from_number(3), Ok(Exception::E3)); + assert_eq!(Exception::from_number(4), Err(Error::InvalidVariant(4))); + } + + #[test] + fn check_interrupt_enum() { + assert_eq!(Interrupt::I1.number(), 1); + assert_eq!(Interrupt::I2.number(), 2); + assert_eq!(Interrupt::I4.number(), 4); + + assert_eq!(Interrupt::from_number(0), Err(Error::InvalidVariant(0))); + assert_eq!(Interrupt::from_number(1), Ok(Interrupt::I1)); + assert_eq!(Interrupt::from_number(2), Ok(Interrupt::I2)); + assert_eq!(Interrupt::from_number(3), Err(Error::InvalidVariant(3))); + assert_eq!(Interrupt::from_number(4), Ok(Interrupt::I4)); + assert_eq!(Interrupt::from_number(5), Err(Error::InvalidVariant(5))); + } + + #[test] + fn check_priority_enum() { + assert_eq!(Priority::P0.number(), 0); + assert_eq!(Priority::P1.number(), 1); + assert_eq!(Priority::P2.number(), 2); + assert_eq!(Priority::P3.number(), 3); + + assert_eq!(Priority::from_number(0), Ok(Priority::P0)); + assert_eq!(Priority::from_number(1), Ok(Priority::P1)); + assert_eq!(Priority::from_number(2), Ok(Priority::P2)); + assert_eq!(Priority::from_number(3), Ok(Priority::P3)); + assert_eq!(Priority::from_number(4), Err(Error::InvalidVariant(4))); + } + + #[test] + fn check_hart_id_enum() { + assert_eq!(HartId::H0.number(), 0); + assert_eq!(HartId::H1.number(), 1); + assert_eq!(HartId::H2.number(), 2); + + assert_eq!(HartId::from_number(0), Ok(HartId::H0)); + assert_eq!(HartId::from_number(1), Ok(HartId::H1)); + assert_eq!(HartId::from_number(2), Ok(HartId::H2)); + assert_eq!(HartId::from_number(3), Err(Error::InvalidVariant(3))); + } +} diff --git a/riscv-types/src/result.rs b/riscv-types/src/result.rs new file mode 100644 index 00000000..b55c8beb --- /dev/null +++ b/riscv-types/src/result.rs @@ -0,0 +1,58 @@ +use core::fmt; + +/// Convenience alias for the [Result](core::result::Result) type for the library. +pub type Result = core::result::Result; + +/// Represents error variants for the library. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Error { + /// Attempted out-of-bounds access. + IndexOutOfBounds { + index: usize, + min: usize, + max: usize, + }, + /// Invalid field value. + InvalidFieldValue { + field: &'static str, + value: usize, + bitmask: usize, + }, + /// Invalid value of a register field that does not match any known variants. + InvalidFieldVariant { field: &'static str, value: usize }, + /// Invalid value. + InvalidValue { value: usize, bitmask: usize }, + /// Invalid value that does not match any known variants. + InvalidVariant(usize), + /// Unimplemented function or type. + Unimplemented, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::IndexOutOfBounds { index, min, max } => write!( + f, + "out-of-bounds access, index: {index}, min: {min}, max: {max}" + ), + Self::InvalidFieldValue { + field, + value, + bitmask, + } => write!( + f, + "invalid {field} field value: {value:#x}, valid bitmask: {bitmask:#x}", + ), + Self::InvalidFieldVariant { field, value } => { + write!(f, "invalid {field} field variant: {value:#x}") + } + Self::InvalidValue { value, bitmask } => { + write!(f, "invalid value: {value:#x}, valid bitmask: {bitmask:#x}",) + } + Self::InvalidVariant(value) => { + write!(f, "invalid variant: {value:#x}") + } + Self::Unimplemented => write!(f, "unimplemented"), + } + } +} From ec9cb5e737a6c39704b2c4077f1d8f06c3575167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Fri, 24 Oct 2025 12:22:23 +0200 Subject: [PATCH 28/76] Add changelog CI check --- .github/workflows/changelog.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml index 109a8536..d168dfb7 100644 --- a/.github/workflows/changelog.yaml +++ b/.github/workflows/changelog.yaml @@ -29,6 +29,8 @@ jobs: - 'riscv-semihosting/**' riscv-target-parser: - 'riscv-target-parser/**' + riscv-types: + - 'riscv-types/**' - name: Check for CHANGELOG.md (riscv) if: steps.changes.outputs.riscv == 'true' @@ -77,3 +79,11 @@ jobs: changeLogPath: ./riscv-target-parser/CHANGELOG.md skipLabels: 'skip changelog' missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-target-parser/CHANGELOG.md file.' + + - name: Check for CHANGELOG.md (riscv-types) + if: steps.changes.outputs.riscv-types == 'true' + uses: dangoslen/changelog-enforcer@v3 + with: + changeLogPath: ./riscv-types/CHANGELOG.md + skipLabels: 'skip changelog' + missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-types/CHANGELOG.md file.' From e279538c49a65d622735a2b3aa7afe58658fc83c Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Fri, 31 Oct 2025 16:57:44 +0530 Subject: [PATCH 29/76] Add mtopi CSR --- riscv/CHANGELOG.md | 1 + riscv/src/register.rs | 1 + riscv/src/register/macros.rs | 8 ++++ riscv/src/register/mtopi.rs | 91 ++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+) create mode 100644 riscv/src/register/mtopi.rs diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 07d20828..4a6528c3 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- Add Mtopi - Added DCSR (Debug Control and Status Register) CSR support for the RISC-V - Add `miselect` CSR - Improved assembly macro handling in asm.rs diff --git a/riscv/src/register.rs b/riscv/src/register.rs index a20328bc..72903fc6 100644 --- a/riscv/src/register.rs +++ b/riscv/src/register.rs @@ -89,6 +89,7 @@ pub mod mepc; pub mod mip; pub mod mscratch; pub mod mtinst; +pub mod mtopi; pub mod mtval; pub mod mtval2; diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index b5c9ee8e..8e80d771 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -1070,3 +1070,11 @@ macro_rules! test_csr_field { } }}; } + +#[cfg(test)] +#[macro_export] +macro_rules! test_ro_csr_field { + ($reg:ident, $field:ident: [$start:expr, $end:expr], $expected:expr) => {{ + assert_eq!($reg.$field(), $expected); + }}; +} diff --git a/riscv/src/register/mtopi.rs b/riscv/src/register/mtopi.rs new file mode 100644 index 00000000..06c5b467 --- /dev/null +++ b/riscv/src/register/mtopi.rs @@ -0,0 +1,91 @@ +//! mtopi register — Machine Top Priority Interrupt (0x7C0) +//! +//! Provides information about the highest-priority pending interrupt when AIA (Advanced Interrupt Architecture) is supported. +//! This CSR is part of the RISC-V Advanced Interrupt Architecture extension and allows software to quickly +//! identify the most important pending interrupt without scanning through multiple interrupt pending registers. +//! +//! # Usage +//! +//! ```no_run +//! use riscv::register::mtopi; +//! +//! // Read the machine top priority interrupt register +//! let mtopi_val = mtopi::read(); +//! +//! if mtopi_val.is_interrupt_pending() { +//! let interrupt_id = mtopi_val.iid(); +//! let priority = mtopi_val.iprio(); +//! println!("Highest priority interrupt: ID={}, Priority={}", interrupt_id, priority); +//! } else { +//! println!("No interrupts pending"); +//! } +//! ``` + +read_only_csr! { + /// Machine Top Priority Interrupt Register + Mtopi: 0x7C0, + mask: 0x0FFF_00FF, +} + +read_only_csr_field! { + Mtopi, + /// Interrupt ID (bits 16..27) + /// + /// Identifies the specific interrupt source. A value of 0 indicates no interrupt is pending. + /// Non-zero values correspond to specific interrupt sources as defined by the interrupt controller. + iid: [16:27], +} + +read_only_csr_field! { + Mtopi, + /// Interrupt Priority ID (bits 0..7) + /// + /// Represents the priority level of the pending interrupt. + /// Lower numerical values indicate higher priority interrupts. + iprio: [0:7], +} + +impl Mtopi { + /// Returns true if there is a valid interrupt pending + /// + /// When this returns true, both `interrupt_id()` and `priority()` will return meaningful values. + #[inline] + pub fn is_interrupt_pending(&self) -> bool { + self.iid() != 0 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_mtopi_fields() { + let mtopi = Mtopi::from_bits(0); + + test_ro_csr_field!(mtopi, iid: [16, 27], 0x0); + test_ro_csr_field!(mtopi, iprio: [0, 7], 0x0); + + let mtopi = Mtopi::from_bits((11 << 16) | 5); + test_ro_csr_field!(mtopi, iid: [16, 27], 0xB); + test_ro_csr_field!(mtopi, iprio: [0, 7], 0x5); + + let mtopi = Mtopi::from_bits((0xFFF << 16) | 0xFF); + test_ro_csr_field!(mtopi, iid: [16, 27], 0xFFF); + test_ro_csr_field!(mtopi, iprio: [0, 7], 0xFF); + + let mtopi = Mtopi::from_bits(1 << 16); + test_ro_csr_field!(mtopi, iid: [16, 27], 0x1); + test_ro_csr_field!(mtopi, iprio: [0, 7], 0x0); + + let mtopi = Mtopi::from_bits(1); + test_ro_csr_field!(mtopi, iid: [16, 27], 0x0); + test_ro_csr_field!(mtopi, iprio: [0, 7], 0x1); + } + + #[test] + fn test_mtopi_bitmask() { + let mtopi = Mtopi::from_bits(usize::MAX); + assert_eq!(mtopi.bits(), 0x0FFF_00FFusize); + } +} From 56fe4c8bdb83fd392783148dc95bc95fb8c0b1bd Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Mon, 3 Nov 2025 18:58:24 +0530 Subject: [PATCH 30/76] Update riscv/src/register/mtopi.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Román Cárdenas Rodríguez --- riscv/src/register/mtopi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/riscv/src/register/mtopi.rs b/riscv/src/register/mtopi.rs index 06c5b467..31b192f6 100644 --- a/riscv/src/register/mtopi.rs +++ b/riscv/src/register/mtopi.rs @@ -66,7 +66,7 @@ mod tests { test_ro_csr_field!(mtopi, iid: [16, 27], 0x0); test_ro_csr_field!(mtopi, iprio: [0, 7], 0x0); - let mtopi = Mtopi::from_bits((11 << 16) | 5); + let mtopi = Mtopi::from_bits((0xB << 16) | 5); test_ro_csr_field!(mtopi, iid: [16, 27], 0xB); test_ro_csr_field!(mtopi, iprio: [0, 7], 0x5); From dec19b4fa0b76a48efc56f4d93d9bd1a98f334ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Mon, 3 Nov 2025 18:45:25 +0100 Subject: [PATCH 31/76] Mark result::Error as non-exhaustive --- riscv-types/CHANGELOG.md | 1 + riscv-types/src/result.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/riscv-types/CHANGELOG.md b/riscv-types/CHANGELOG.md index 79236008..f1637b01 100644 --- a/riscv-types/CHANGELOG.md +++ b/riscv-types/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Mark `result::Error` as `#[non_exhaustive]` to allow non-breaking new variants - Renamed crate to `riscv-types` as per [#351](https://github.com/rust-embedded/riscv/issues/351) ## riscv-pac [v0.2.0] - 2024-10-19 diff --git a/riscv-types/src/result.rs b/riscv-types/src/result.rs index b55c8beb..a099159d 100644 --- a/riscv-types/src/result.rs +++ b/riscv-types/src/result.rs @@ -5,6 +5,7 @@ pub type Result = core::result::Result; /// Represents error variants for the library. #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[non_exhaustive] pub enum Error { /// Attempted out-of-bounds access. IndexOutOfBounds { From 1b0f4088ad09dfe45885544006abda7b3591082b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Mon, 3 Nov 2025 18:46:05 +0100 Subject: [PATCH 32/76] Implement core::error::Error --- riscv-types/CHANGELOG.md | 5 +++++ riscv-types/Cargo.toml | 2 +- riscv-types/README.md | 2 +- riscv-types/src/result.rs | 2 ++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/riscv-types/CHANGELOG.md b/riscv-types/CHANGELOG.md index f1637b01..70472503 100644 --- a/riscv-types/CHANGELOG.md +++ b/riscv-types/CHANGELOG.md @@ -9,9 +9,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Bump MSRV to 1.81 due to `core::error::Error` trait - Mark `result::Error` as `#[non_exhaustive]` to allow non-breaking new variants - Renamed crate to `riscv-types` as per [#351](https://github.com/rust-embedded/riscv/issues/351) +### Added + +- Implement `core::error::Error` for `result::Error` + ## riscv-pac [v0.2.0] - 2024-10-19 ### Added diff --git a/riscv-types/Cargo.toml b/riscv-types/Cargo.toml index 63a6afc4..bfacb44b 100644 --- a/riscv-types/Cargo.toml +++ b/riscv-types/Cargo.toml @@ -2,7 +2,7 @@ name = "riscv-types" version = "0.1.0" edition = "2021" -rust-version = "1.60" +rust-version = "1.81" repository = "https://github.com/rust-embedded/riscv" authors = ["The RISC-V Team "] categories = ["embedded", "hardware-support", "no-std"] diff --git a/riscv-types/README.md b/riscv-types/README.md index 6745b98d..89f088d3 100644 --- a/riscv-types/README.md +++ b/riscv-types/README.md @@ -11,7 +11,7 @@ This project is developed and maintained by the [RISC-V team][team]. ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.60 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.81 and up. It *might* compile with older versions but that may change in any new patch release. ## License diff --git a/riscv-types/src/result.rs b/riscv-types/src/result.rs index a099159d..fa158529 100644 --- a/riscv-types/src/result.rs +++ b/riscv-types/src/result.rs @@ -57,3 +57,5 @@ impl fmt::Display for Error { } } } + +impl core::error::Error for Error {} From 78e1410d22abd669d8b60b8c95fe89d6a470bec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Mon, 3 Nov 2025 19:13:15 +0100 Subject: [PATCH 33/76] riscv-rt: fix stack allocation for targets without M extension --- riscv-rt/CHANGELOG.md | 4 ++++ riscv-rt/src/asm.rs | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index 91dc1516..111a3409 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Bump MSRV to 1.68 for latest syn 2.0 release - Adapted to new `riscv` version. +### Fixed + +- Fix stack allocation algorithm for multi-core targets without M extension + ## [v0.16.0] - 2025-09-08 ### Added diff --git a/riscv-rt/src/asm.rs b/riscv-rt/src/asm.rs index b3041bfc..f89d58e5 100644 --- a/riscv-rt/src/asm.rs +++ b/riscv-rt/src/asm.rs @@ -105,13 +105,13 @@ _abs_start: #[cfg(not(feature = "single-hart"))] { "mv t2, a0 - lui t0, %hi(_hart_stack_size) - add t0, t0, %lo(_hart_stack_size)", + lui t1, %hi(_hart_stack_size) + add t1, t1, %lo(_hart_stack_size)", #[cfg(riscvm)] - "mul t0, t2, t0", + "mul t0, t2, t1", #[cfg(not(riscvm))] - "beqz t2, 2f // skip if hart ID is 0 - mv t1, t0 + "mv t0, x0 + beqz t2, 2f // skip if hart ID is 0 1: add t0, t0, t1 addi t2, t2, -1 From 7b691f191a26a8e834caa3c5965198153dddff30 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Tue, 4 Nov 2025 17:40:23 +0530 Subject: [PATCH 34/76] Update macros.rs --- riscv/src/register/macros.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 8e80d771..b37c777e 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -1075,6 +1075,14 @@ macro_rules! test_csr_field { #[macro_export] macro_rules! test_ro_csr_field { ($reg:ident, $field:ident: [$start:expr, $end:expr], $expected:expr) => {{ - assert_eq!($reg.$field(), $expected); + let bits = $reg.bits(); + let shift = $end - $start + 1; + let mask = (1usize << shift) - 1; + let exp_val = (bits >> $start) & mask; + let val = $reg.$field(); + assert_eq!(val & !mask, 0); + assert_eq!($expected & !mask, 0); + assert_eq!(val, exp_val); + assert_eq!(val, $expected); }}; } From f1a09066531547d95a1f32b6947b393c0616a465 Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Wed, 5 Nov 2025 13:25:29 +0530 Subject: [PATCH 35/76] Update riscv/src/register/macros.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Román Cárdenas Rodríguez --- riscv/src/register/macros.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index b37c777e..51bb94d7 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -1076,9 +1076,7 @@ macro_rules! test_csr_field { macro_rules! test_ro_csr_field { ($reg:ident, $field:ident: [$start:expr, $end:expr], $expected:expr) => {{ let bits = $reg.bits(); - let shift = $end - $start + 1; - let mask = (1usize << shift) - 1; - let exp_val = (bits >> $start) & mask; + let exp_val = $crate::bits::bf_extract(bits, $start, $end - $start + 1); let val = $reg.$field(); assert_eq!(val & !mask, 0); assert_eq!($expected & !mask, 0); From 51b82ff70db7d3a5cdd76c438a2158a3eecdc2c1 Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Wed, 5 Nov 2025 13:25:42 +0530 Subject: [PATCH 36/76] Update riscv/src/register/macros.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Román Cárdenas Rodríguez --- riscv/src/register/macros.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 51bb94d7..255f0f4e 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -1078,8 +1078,6 @@ macro_rules! test_ro_csr_field { let bits = $reg.bits(); let exp_val = $crate::bits::bf_extract(bits, $start, $end - $start + 1); let val = $reg.$field(); - assert_eq!(val & !mask, 0); - assert_eq!($expected & !mask, 0); assert_eq!(val, exp_val); assert_eq!(val, $expected); }}; From e4d57d2552f19eb63d2d59b826070d5cb76d16d2 Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Wed, 5 Nov 2025 13:25:55 +0530 Subject: [PATCH 37/76] Update riscv/src/register/mtopi.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Román Cárdenas Rodríguez --- riscv/src/register/mtopi.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/riscv/src/register/mtopi.rs b/riscv/src/register/mtopi.rs index 31b192f6..859b17c2 100644 --- a/riscv/src/register/mtopi.rs +++ b/riscv/src/register/mtopi.rs @@ -62,7 +62,6 @@ mod tests { #[test] fn test_mtopi_fields() { let mtopi = Mtopi::from_bits(0); - test_ro_csr_field!(mtopi, iid: [16, 27], 0x0); test_ro_csr_field!(mtopi, iprio: [0, 7], 0x0); From a5324467649b34f2f0a2873c508fffec59845983 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Wed, 5 Nov 2025 13:49:20 +0530 Subject: [PATCH 38/76] Add APACHE 2.0 and MIT dual-license for RISC-V --- LICENSE-APACHE.md | 201 ++++++++++++++++++++++++++++++++++++++++++++++ LICENSE-MIT.md | 25 ++++++ 2 files changed, 226 insertions(+) create mode 100644 LICENSE-APACHE.md create mode 100644 LICENSE-MIT.md diff --git a/LICENSE-APACHE.md b/LICENSE-APACHE.md new file mode 100644 index 00000000..16fe87b0 --- /dev/null +++ b/LICENSE-APACHE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT.md b/LICENSE-MIT.md new file mode 100644 index 00000000..210c8349 --- /dev/null +++ b/LICENSE-MIT.md @@ -0,0 +1,25 @@ +Copyright (c) 2018-2025 The Rust-Embedded Working Group + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. From 66fabc4836f7e0cff83712d9f0926aeebf615ec8 Mon Sep 17 00:00:00 2001 From: 0xllx0 Date: Wed, 5 Nov 2025 15:36:29 +0000 Subject: [PATCH 39/76] riscv: add the `mvien` + `mvienh` CSR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the `mvien` + `mvienh` CSR to represent the `Machine Virtual Interrupt Enable` registers. Authored-by: Elle Rhumsaa Co-authored-by: Román Cárdenas Rodríguez --- riscv/CHANGELOG.md | 1 + riscv/src/register.rs | 3 + riscv/src/register/mvien.rs | 157 +++++++++++++++++++++++++++++++++++ riscv/src/register/mvienh.rs | 118 ++++++++++++++++++++++++++ typos.toml | 2 +- 5 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 riscv/src/register/mvien.rs create mode 100644 riscv/src/register/mvienh.rs diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 07d20828..15eec1cb 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Add `miselect` CSR - Improved assembly macro handling in asm.rs - New `rt` and `rt-v-trap` features to opt-in `riscv-rt`-related code in `riscv::pac_enum` macro. +- Add `mvien` + `mvienh` CSR # Changed diff --git a/riscv/src/register.rs b/riscv/src/register.rs index a20328bc..64c3b483 100644 --- a/riscv/src/register.rs +++ b/riscv/src/register.rs @@ -91,6 +91,9 @@ pub mod mscratch; pub mod mtinst; pub mod mtval; pub mod mtval2; +pub mod mvien; +#[cfg(any(test, target_arch = "riscv32"))] +pub mod mvienh; // Machine Protection and Translation mod pmpcfgx; diff --git a/riscv/src/register/mvien.rs b/riscv/src/register/mvien.rs new file mode 100644 index 00000000..af162063 --- /dev/null +++ b/riscv/src/register/mvien.rs @@ -0,0 +1,157 @@ +//! mvien register + +use crate::bits::{bf_extract, bf_insert}; +use riscv_pac::result::{Error, Result}; +use riscv_pac::InterruptNumber; + +#[cfg(target_arch = "riscv32")] +const MASK: usize = 0xffff_e222; +#[cfg(not(target_arch = "riscv32"))] +const MASK: usize = 0xffff_ffff_ffff_e222; + +read_write_csr! { + /// `mvien` register + Mvien: 0x308, + mask: MASK, +} + +read_write_csr_field! { + Mvien, + /// Alias of `mie.SSIE` + ssoft: 1, +} + +read_write_csr_field! { + Mvien, + /// Alias of `mie.STIE` + stimer: 5, +} + +read_write_csr_field! { + Mvien, + /// Alias of `mie.SEIE` + sext: 9, +} + +impl Mvien { + /// Represents the minimum interrupt of the unlabelled virtual interrupt range. + pub const MIN_INTERRUPT: usize = 13; + /// Represents the maximum interrupt of the unlabelled virtual interrupt range. + #[cfg(target_arch = "riscv32")] + pub const MAX_INTERRUPT: usize = 31; + /// Represents the maximum interrupt of the unlabelled virtual interrupt range. + #[cfg(not(target_arch = "riscv32"))] + pub const MAX_INTERRUPT: usize = 63; + + /// Gets whether the interrupt number is a valid virtual interrupt. + #[inline] + pub const fn is_valid_interrupt(int: usize) -> bool { + matches!(int, 1 | 5 | 9 | Self::MIN_INTERRUPT..=Self::MAX_INTERRUPT) + } + + /// Check if a specific core interrupt source is enabled. + /// + /// Returns `Error` if the interrupt number is invalid. + #[inline] + pub fn is_enabled(&self, interrupt: I) -> bool { + let n = interrupt.number(); + + Self::is_valid_interrupt(n) && bf_extract(self.bits, n, 1) != 0 + } + + /// Enable a specific core interrupt source. + /// + /// Returns `Error` if the interrupt number is invalid. + #[inline] + pub fn enable(&mut self, interrupt: I) -> Result<()> { + let n = interrupt.number(); + + if Self::is_valid_interrupt(n) { + self.bits = bf_insert(self.bits, n, 1, 1); + Ok(()) + } else { + Err(Error::InvalidVariant(n)) + } + } + + /// Disable a specific core interrupt source. + /// + /// Returns `Error` if the interrupt number is invalid. + #[inline] + pub fn disable(&mut self, interrupt: I) -> Result<()> { + let n = interrupt.number(); + + if Self::is_valid_interrupt(n) { + self.bits = bf_insert(self.bits, n, 1, 0); + Ok(()) + } else { + Err(Error::InvalidVariant(n)) + } + } +} + +set!(0x308); +clear!(0x308); + +set_clear_csr!( + /// Supervisor Software Interrupt Enable + , set_ssoft, clear_ssoft, 1 << 1); +set_clear_csr!( + /// Supervisor Timer Interrupt Enable + , set_stimer, clear_stimer, 1 << 5); +set_clear_csr!( + /// Supervisor External Interrupt Enable + , set_sext, clear_sext, 1 << 9); + +read_composite_csr!(super::mvienh::read().bits(), read().bits()); + +#[cfg(test)] +mod tests { + use super::*; + + /// Represents a custom set of virtual interrupts. + /// + /// NOTE: a real implementation may want to enumerate the valid virtual interrupt variants. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct VirtualInterrupt(usize); + + /// SAFETY: `VirtualInterrupt` represents the virtual RISC-V interrupts + unsafe impl InterruptNumber for VirtualInterrupt { + const MAX_INTERRUPT_NUMBER: usize = Mvien::MAX_INTERRUPT; + + #[inline] + fn number(self) -> usize { + self.0 + } + + #[inline] + fn from_number(value: usize) -> Result { + if Mvien::is_valid_interrupt(value) { + Ok(Self(value)) + } else { + Err(Error::InvalidVariant(value)) + } + } + } + + #[test] + fn test_mvien() { + let mut m = Mvien::from_bits(0); + + test_csr_field!(m, ssoft); + test_csr_field!(m, stimer); + test_csr_field!(m, sext); + + (0..=VirtualInterrupt::MAX_INTERRUPT_NUMBER) + .filter_map(|n| VirtualInterrupt::from_number(n).ok()) + .for_each(|int| { + assert!(!m.is_enabled(int)); + + assert!(m.enable(int).is_ok()); + assert!(m.is_enabled(int)); + + assert!(m.disable(int).is_ok()); + assert!(!m.is_enabled(int)); + }); + } +} diff --git a/riscv/src/register/mvienh.rs b/riscv/src/register/mvienh.rs new file mode 100644 index 00000000..9ec5438f --- /dev/null +++ b/riscv/src/register/mvienh.rs @@ -0,0 +1,118 @@ +//! mvienh register + +use crate::bits::{bf_extract, bf_insert}; +use riscv_pac::result::{Error, Result}; +use riscv_pac::InterruptNumber; + +read_write_csr! { + /// `mvienh` register + Mvienh: 0x318, + mask: 0xffff_ffff, +} + +set!(0x318); +clear!(0x318); + +impl Mvienh { + /// Represents the value to shift interrupt numbers to their relative value. + pub const INTERRUPT_SHIFT: usize = 32; + /// Represents the minimum interrupt of the unlabelled virtual interrupt range. + pub const MIN_INTERRUPT: usize = 32; + /// Represents the maximum interrupt of the unlabelled virtual interrupt range. + pub const MAX_INTERRUPT: usize = 63; + + /// Gets whether the interrupt number is a valid virtual interrupt. + #[inline] + pub const fn is_valid_interrupt(int: usize) -> bool { + matches!(int, Self::MIN_INTERRUPT..=Self::MAX_INTERRUPT) + } + + /// Shifts the high-order interrupt number bits down to their relative value. + #[inline] + pub const fn shift_interrupt(int: usize) -> usize { + int.saturating_sub(Self::INTERRUPT_SHIFT) + } + + /// Check if a specific core interrupt source is enabled. + /// + /// Returns `Error` if the interrupt number is invalid. + #[inline] + pub fn is_enabled(&self, interrupt: I) -> bool { + let n = interrupt.number(); + + Self::is_valid_interrupt(n) && bf_extract(self.bits, Self::shift_interrupt(n), 1) != 0 + } + + /// Enable a specific core interrupt source. + #[inline] + pub fn enable(&mut self, interrupt: I) -> Result<()> { + let n = interrupt.number(); + + if Self::is_valid_interrupt(n) { + self.bits = bf_insert(self.bits, Self::shift_interrupt(n), 1, 1); + Ok(()) + } else { + Err(Error::InvalidVariant(n)) + } + } + + /// Disable a specific core interrupt source. + #[inline] + pub fn disable(&mut self, interrupt: I) -> Result<()> { + let n = interrupt.number(); + + if Self::is_valid_interrupt(n) { + self.bits = bf_insert(self.bits, Self::shift_interrupt(n), 1, 0); + Ok(()) + } else { + Err(Error::InvalidVariant(n)) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Represents a custom set of virtual interrupts. + /// + /// NOTE: a real implementation may want to enumerate the valid virtual interrupt variants. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct VirtualInterrupt(usize); + + /// SAFETY: `VirtualInterrupt` represents the virtual RISC-V interrupts + unsafe impl InterruptNumber for VirtualInterrupt { + const MAX_INTERRUPT_NUMBER: usize = Mvienh::MAX_INTERRUPT; + + #[inline] + fn number(self) -> usize { + self.0 + } + + #[inline] + fn from_number(value: usize) -> Result { + if Mvienh::is_valid_interrupt(value) { + Ok(Self(value)) + } else { + Err(Error::InvalidVariant(value)) + } + } + } + + #[test] + fn test_mvienh() { + let mut m = Mvienh::from_bits(0); + + (Mvienh::MIN_INTERRUPT..=Mvienh::MAX_INTERRUPT) + .filter_map(|n| VirtualInterrupt::from_number(n).ok()) + .for_each(|int| { + assert!(!m.is_enabled(int)); + + assert!(m.enable(int).is_ok()); + assert!(m.is_enabled(int)); + + assert!(m.disable(int).is_ok()); + assert!(!m.is_enabled(int)); + }); + } +} diff --git a/typos.toml b/typos.toml index a5674cea..a4a8e72e 100644 --- a/typos.toml +++ b/typos.toml @@ -1,2 +1,2 @@ [default] -extend-ignore-re = ["[Ss][Ii][Ee]", "[Ss][Xx][Ll]", "[.]?useed[.,:]?"] +extend-ignore-re = ["[Ss][Ii][Ee]", "[Ss][Xx][Ll]", "[.]?useed[.,:]?", "[Ss][Tt][Ii][Pp]"] From 45be1f8eddf776e5b8fc211fe00378f4e1114118 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Thu, 6 Nov 2025 17:34:37 +0530 Subject: [PATCH 40/76] Update LICENSE in cargo.toml across the crate --- riscv-pac/Cargo.toml | 2 +- riscv-peripheral/Cargo.toml | 2 +- riscv-rt/Cargo.toml | 2 +- riscv-target-parser/Cargo.toml | 2 +- riscv/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/riscv-pac/Cargo.toml b/riscv-pac/Cargo.toml index b5ba86b2..18be9de1 100644 --- a/riscv-pac/Cargo.toml +++ b/riscv-pac/Cargo.toml @@ -9,7 +9,7 @@ categories = ["embedded", "hardware-support", "no-std"] description = "Low level access to RISC-V processors" documentation = "https://docs.rs/riscv-pac" keywords = ["riscv", "register", "peripheral"] -license = "ISC" +license = "MIT OR Apache-2.0" [package.metadata.docs.rs] default-target = "riscv64imac-unknown-none-elf" diff --git a/riscv-peripheral/Cargo.toml b/riscv-peripheral/Cargo.toml index c0caff29..0a7006cc 100644 --- a/riscv-peripheral/Cargo.toml +++ b/riscv-peripheral/Cargo.toml @@ -9,7 +9,7 @@ categories = ["embedded", "hardware-support", "no-std"] description = "Interfaces for standard RISC-V peripherals" documentation = "https://docs.rs/riscv-peripheral" keywords = ["riscv", "peripheral", "clint", "plic"] -license = "ISC" +license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/riscv-rt/Cargo.toml b/riscv-rt/Cargo.toml index 42e9d4f7..7afdbc76 100644 --- a/riscv-rt/Cargo.toml +++ b/riscv-rt/Cargo.toml @@ -8,7 +8,7 @@ categories = ["embedded", "no-std"] description = "Minimal runtime / startup for RISC-V CPU's" documentation = "https://docs.rs/riscv-rt" keywords = ["riscv", "runtime", "startup"] -license = "ISC" +license = "MIT OR Apache-2.0" edition = "2021" links = "riscv-rt" # Prevent multiple versions of riscv-rt being linked diff --git a/riscv-target-parser/Cargo.toml b/riscv-target-parser/Cargo.toml index 02d4fad5..bcc438cc 100644 --- a/riscv-target-parser/Cargo.toml +++ b/riscv-target-parser/Cargo.toml @@ -8,5 +8,5 @@ categories = ["embedded", "no-std"] description = "Parser for RISC-V target specifications" documentation = "https://docs.rs/riscv-target-parser" keywords = ["riscv", "build"] -license = "ISC" +license = "MIT OR Apache-2.0" edition = "2021" diff --git a/riscv/Cargo.toml b/riscv/Cargo.toml index e3415035..501f374e 100644 --- a/riscv/Cargo.toml +++ b/riscv/Cargo.toml @@ -9,7 +9,7 @@ categories = ["embedded", "hardware-support", "no-std"] description = "Low level access to RISC-V processors" documentation = "https://docs.rs/riscv" keywords = ["riscv", "register", "peripheral"] -license = "ISC" +license = "MIT OR Apache-2.0" [package.metadata.docs.rs] all-features = true From 9c5fe1427d50bb07703fadbe48fdc195e2ad7fe9 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Thu, 6 Nov 2025 17:42:27 +0530 Subject: [PATCH 41/76] Update license of riscv-types --- riscv-types/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/riscv-types/Cargo.toml b/riscv-types/Cargo.toml index 63a6afc4..29293eda 100644 --- a/riscv-types/Cargo.toml +++ b/riscv-types/Cargo.toml @@ -9,7 +9,7 @@ categories = ["embedded", "hardware-support", "no-std"] description = "Low level access to RISC-V processors" documentation = "https://docs.rs/riscv-types" keywords = ["riscv", "register", "peripheral"] -license = "ISC" +license = "MIT OR Apache-2.0" [package.metadata.docs.rs] default-target = "riscv64imac-unknown-none-elf" From e3c0f9f8f26054cb66f6af40074de4ba7fe18302 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Thu, 6 Nov 2025 19:00:17 +0530 Subject: [PATCH 42/76] Update CHANGELOG.md --- riscv-pac/CHANGELOG.md | 1 + riscv-peripheral/CHANGELOG.md | 2 ++ riscv-rt/CHANGELOG.md | 1 + riscv-target-parser/CHANGELOG.md | 2 ++ riscv/CHANGELOG.md | 1 + 5 files changed, 7 insertions(+) diff --git a/riscv-pac/CHANGELOG.md b/riscv-pac/CHANGELOG.md index 9dcfcd6a..7c72e23a 100644 --- a/riscv-pac/CHANGELOG.md +++ b/riscv-pac/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- Updated the license to `MIT or Apache-2.0` - Add `result` module for `Error` and `Result` types - Add `ExceptionNumber` trait. - Classify interrupt numbers in `CoreInterruptNumber` and `ExternalInterruptNumber`. diff --git a/riscv-peripheral/CHANGELOG.md b/riscv-peripheral/CHANGELOG.md index 5b58fbc9..f69dfc38 100644 --- a/riscv-peripheral/CHANGELOG.md +++ b/riscv-peripheral/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Update license to `MIT or Apache-2.0` + ### Fixed - Typo in documentation. diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index 91dc1516..62381030 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Update license to `MIT or Apache-2.0` - Fix clippy warnings in riscv_rt_macros::strip_type_path - Bump MSRV to 1.68 for latest syn 2.0 release - Adapted to new `riscv` version. diff --git a/riscv-target-parser/CHANGELOG.md b/riscv-target-parser/CHANGELOG.md index ab82bdad..a99fb70e 100644 --- a/riscv-target-parser/CHANGELOG.md +++ b/riscv-target-parser/CHANGELOG.md @@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Update license to `MIT or Apache 2.0` + ## [v0.1.3] - 2025-09-29 ### Fixed diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 07d20828..e2fe9d9e 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- Updated the license to `MIT or Apache-2.0` - Added DCSR (Debug Control and Status Register) CSR support for the RISC-V - Add `miselect` CSR - Improved assembly macro handling in asm.rs From 4acf38f1cdfed436c42bc64717b580563dfb37a2 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Thu, 6 Nov 2025 19:01:54 +0530 Subject: [PATCH 43/76] Update CHANGELOG.md for riscv-types --- riscv-types/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/riscv-types/CHANGELOG.md b/riscv-types/CHANGELOG.md index 79236008..9e2d80a2 100644 --- a/riscv-types/CHANGELOG.md +++ b/riscv-types/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Update license to `MIT or Apache-2.0` + ### Changed - Renamed crate to `riscv-types` as per [#351](https://github.com/rust-embedded/riscv/issues/351) From 95efb83b1a9d95b6869642be2fd537bd54654789 Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Thu, 6 Nov 2025 20:46:47 +0530 Subject: [PATCH 44/76] Update riscv-peripheral/CHANGELOG.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Román Cárdenas Rodríguez --- riscv-peripheral/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/riscv-peripheral/CHANGELOG.md b/riscv-peripheral/CHANGELOG.md index f69dfc38..51a93e53 100644 --- a/riscv-peripheral/CHANGELOG.md +++ b/riscv-peripheral/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed + - Update license to `MIT or Apache-2.0` ### Fixed From 2802b6e71c39986b96b563f18303c7ddfa742d07 Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Thu, 6 Nov 2025 20:47:18 +0530 Subject: [PATCH 45/76] Update riscv-target-parser/CHANGELOG.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Román Cárdenas Rodríguez --- riscv-target-parser/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/riscv-target-parser/CHANGELOG.md b/riscv-target-parser/CHANGELOG.md index a99fb70e..b700739d 100644 --- a/riscv-target-parser/CHANGELOG.md +++ b/riscv-target-parser/CHANGELOG.md @@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed + - Update license to `MIT or Apache 2.0` ## [v0.1.3] - 2025-09-29 From 854c0ee58c809f28cb76da2595cff5646c662434 Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Thu, 6 Nov 2025 20:47:35 +0530 Subject: [PATCH 46/76] Update riscv-types/CHANGELOG.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Román Cárdenas Rodríguez --- riscv-types/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/riscv-types/CHANGELOG.md b/riscv-types/CHANGELOG.md index 9e2d80a2..b4908ae5 100644 --- a/riscv-types/CHANGELOG.md +++ b/riscv-types/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed + - Update license to `MIT or Apache-2.0` ### Changed From 0d8556a6b0e2d889d85e56edcc49eab143414895 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Thu, 6 Nov 2025 20:50:30 +0530 Subject: [PATCH 47/76] Fix Changelog.md --- riscv-pac/CHANGELOG.md | 5 ++++- riscv/CHANGELOG.md | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/riscv-pac/CHANGELOG.md b/riscv-pac/CHANGELOG.md index 7c72e23a..606bec23 100644 --- a/riscv-pac/CHANGELOG.md +++ b/riscv-pac/CHANGELOG.md @@ -7,11 +7,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed + +- Updated the license to `MIT or Apache-2.0` + ## [v0.2.0] - 2024-10-19 ### Added -- Updated the license to `MIT or Apache-2.0` - Add `result` module for `Error` and `Result` types - Add `ExceptionNumber` trait. - Classify interrupt numbers in `CoreInterruptNumber` and `ExternalInterruptNumber`. diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index e2fe9d9e..b8bc722f 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -9,7 +9,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added -- Updated the license to `MIT or Apache-2.0` - Added DCSR (Debug Control and Status Register) CSR support for the RISC-V - Add `miselect` CSR - Improved assembly macro handling in asm.rs @@ -17,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # Changed +- Updated the license to `MIT or Apache-2.0` - Bump MSRV to 1.68 for latest version of syn 2.0 - Now, `riscv::pac_enum` macro only includes trap-related code if `rt` or `rt-v-trap` features are enabled. From 5b6d05e6489ae21a9a0c7986e6c0336c378e49b8 Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Thu, 6 Nov 2025 21:46:42 +0530 Subject: [PATCH 48/76] Update riscv-types/CHANGELOG.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Román Cárdenas Rodríguez --- riscv-types/CHANGELOG.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/riscv-types/CHANGELOG.md b/riscv-types/CHANGELOG.md index b4908ae5..bdaa295e 100644 --- a/riscv-types/CHANGELOG.md +++ b/riscv-types/CHANGELOG.md @@ -10,9 +10,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - Update license to `MIT or Apache-2.0` - -### Changed - - Renamed crate to `riscv-types` as per [#351](https://github.com/rust-embedded/riscv/issues/351) ## riscv-pac [v0.2.0] - 2024-10-19 From 12c8cc251ebcf6be3c2bad557674026ddd2c39f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Thu, 30 Oct 2025 11:45:56 +0100 Subject: [PATCH 49/76] Move riscv-macros to root directory --- .github/workflows/changelog.yaml | 10 ++++++ Cargo.toml | 2 ++ riscv-macros/CHANGELOG.md | 21 ++++++++++++ {riscv/macros => riscv-macros}/Cargo.toml | 2 +- riscv-macros/README.md | 40 +++++++++++++++++++++++ {riscv/macros => riscv-macros}/src/lib.rs | 0 riscv/CHANGELOG.md | 3 +- riscv/Cargo.toml | 2 +- 8 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 riscv-macros/CHANGELOG.md rename {riscv/macros => riscv-macros}/Cargo.toml (91%) create mode 100644 riscv-macros/README.md rename {riscv/macros => riscv-macros}/src/lib.rs (100%) diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml index d168dfb7..8081f901 100644 --- a/.github/workflows/changelog.yaml +++ b/.github/workflows/changelog.yaml @@ -19,6 +19,8 @@ jobs: filters: | riscv: - 'riscv/**' + riscv-macros: + - 'riscv-macros/**' riscv-pac: - 'riscv-pac/**' riscv-peripheral: @@ -39,6 +41,14 @@ jobs: changeLogPath: ./riscv/CHANGELOG.md skipLabels: 'skip changelog' missingUpdateErrorMessage: 'Please add a changelog entry in the riscv/CHANGELOG.md file.' + + - name: Check for CHANGELOG.md (riscv-macros) + if: steps.changes.outputs.riscv-macros == 'true' + uses: dangoslen/changelog-enforcer@v3 + with: + changeLogPath: ./riscv-macros/CHANGELOG.md + skipLabels: 'skip changelog' + missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-macros/CHANGELOG.md file.' - name: Check for CHANGELOG.md (riscv-pac) if: steps.changes.outputs.riscv-pac == 'true' diff --git a/Cargo.toml b/Cargo.toml index c0505280..c8391343 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ resolver = "2" members = [ "riscv", + "riscv-macros", "riscv-pac", "riscv-peripheral", "riscv-rt", @@ -14,6 +15,7 @@ members = [ default-members = [ "riscv", + "riscv-macros", "riscv-pac", "riscv-peripheral", "riscv-rt", diff --git a/riscv-macros/CHANGELOG.md b/riscv-macros/CHANGELOG.md new file mode 100644 index 00000000..2ff758d3 --- /dev/null +++ b/riscv-macros/CHANGELOG.md @@ -0,0 +1,21 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +### Added + +- New `rt` and `rt-v-trap` features to opt-in `riscv-rt`-related code in `riscv::pac_enum` macro. + +### Changed + +- Moved from `riscv/macros/` to `riscv-macros/` +- Now, `riscv::pac_enum` macro only includes trap-related code if `rt` or `rt-v-trap` features are enabled. + +## [v0.3.0] - 2025-09-08 + +This crate was placed inside `riscv/`. Check `riscv/CHANGELOG.md` for details diff --git a/riscv/macros/Cargo.toml b/riscv-macros/Cargo.toml similarity index 91% rename from riscv/macros/Cargo.toml rename to riscv-macros/Cargo.toml index 749d8e5e..5a9bf252 100644 --- a/riscv/macros/Cargo.toml +++ b/riscv-macros/Cargo.toml @@ -4,7 +4,7 @@ authors = [ ] categories = ["embedded", "no-std"] description = "Procedural macros re-exported in `riscv`" -documentation = "https://docs.rs/riscv" +documentation = "https://docs.rs/riscv-macros" keywords = ["riscv", "register", "peripheral"] license = "MIT OR Apache-2.0" name = "riscv-macros" diff --git a/riscv-macros/README.md b/riscv-macros/README.md new file mode 100644 index 00000000..cf5844e9 --- /dev/null +++ b/riscv-macros/README.md @@ -0,0 +1,40 @@ +[![crates.io](https://img.shields.io/crates/d/riscv-macros.svg)](https://crates.io/crates/riscv-macros) +[![crates.io](https://img.shields.io/crates/v/riscv-macros.svg)](https://crates.io/crates/riscv-macros) + +# `riscv-macros` + +> Procedural macros for the `riscv` crate. + +This project is developed and maintained by the [RISC-V team][team]. + +## [Documentation](https://docs.rs/crate/riscv) + +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.61 and up. It *might* +compile with older versions but that may change in any new patch release. + +## License + +Copyright 2024-2025 [RISC-V team][team] + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + +## Code of Conduct + +Contribution to this crate is organized under the terms of the [Rust Code of +Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises +to intervene to uphold that code of conduct. + +[CoC]: ../CODE_OF_CONDUCT.md +[team]: https://github.com/rust-embedded/wg#the-risc-v-team diff --git a/riscv/macros/src/lib.rs b/riscv-macros/src/lib.rs similarity index 100% rename from riscv/macros/src/lib.rs rename to riscv-macros/src/lib.rs diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 632e6e87..2c675c5a 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -16,8 +16,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - New `rt` and `rt-v-trap` features to opt-in `riscv-rt`-related code in `riscv::pac_enum` macro. - Add `mvien` + `mvienh` CSR -# Changed +### Changed +- Moved macros from `./macros/` to `../riscv-macros/` - Updated the license to `MIT or Apache-2.0` - Bump MSRV to 1.68 for latest version of syn 2.0 - Now, `riscv::pac_enum` macro only includes trap-related code if `rt` or `rt-v-trap` features are enabled. diff --git a/riscv/Cargo.toml b/riscv/Cargo.toml index 501f374e..f4e87491 100644 --- a/riscv/Cargo.toml +++ b/riscv/Cargo.toml @@ -30,5 +30,5 @@ rt-v-trap = ["rt", "riscv-macros/rt-v-trap"] critical-section = "1.2.0" embedded-hal = "1.0.0" riscv-pac = { path = "../riscv-pac", version = "0.2.0" } -riscv-macros = { path = "macros", version = "0.3.0", optional = true } +riscv-macros = { path = "../riscv-macros", version = "0.3.0", optional = true } paste = "1.0.15" From 5a44c41df422f7fa15bfa1f9073ad2b0c6ec3243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Mon, 3 Nov 2025 18:36:57 +0100 Subject: [PATCH 50/76] Fix new CI errors --- riscv-macros/src/lib.rs | 14 ++++++-------- typos.toml | 1 + 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/riscv-macros/src/lib.rs b/riscv-macros/src/lib.rs index 3192f1ad..d4c252d8 100644 --- a/riscv-macros/src/lib.rs +++ b/riscv-macros/src/lib.rs @@ -437,16 +437,14 @@ core::arch::global_asm!(" /// E3 = 3, /// } /// -/// fn main() { -/// assert_eq!(Exception::E1.number(), 1); -/// assert_eq!(Exception::E3.number(), 3); +/// assert_eq!(Exception::E1.number(), 1); +/// assert_eq!(Exception::E3.number(), 3); /// -/// assert_eq!(Exception::from_number(1), Ok(Exception::E1)); -/// assert_eq!(Exception::from_number(2), Err(2)); -/// assert_eq!(Exception::from_number(3), Ok(Exception::E3)); +/// assert_eq!(Exception::from_number(1), Ok(Exception::E1)); +/// assert_eq!(Exception::from_number(2), Err(2)); +/// assert_eq!(Exception::from_number(3), Ok(Exception::E3)); /// -/// assert_eq!(Exception::MAX_EXCEPTION_NUMBER, 3); -/// } +/// assert_eq!(Exception::MAX_EXCEPTION_NUMBER, 3); ///``` #[proc_macro_attribute] pub fn pac_enum(attr: TokenStream, item: TokenStream) -> TokenStream { diff --git a/typos.toml b/typos.toml index a4a8e72e..3a088783 100644 --- a/typos.toml +++ b/typos.toml @@ -1,2 +1,3 @@ [default] extend-ignore-re = ["[Ss][Ii][Ee]", "[Ss][Xx][Ll]", "[.]?useed[.,:]?", "[Ss][Tt][Ii][Pp]"] +extend-ignore-words-re = ["[Pp]endings", "PENDINGS"] From 9e6a4d0396eebcdfaf1b80ea4042b5ebd792ec7e Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Sat, 8 Nov 2025 17:35:59 +0530 Subject: [PATCH 51/76] Implement DPC CSR for RISC-V --- riscv/CHANGELOG.md | 1 + riscv/src/register.rs | 1 + riscv/src/register/dpc.rs | 25 +++++++++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 riscv/src/register/dpc.rs diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 632e6e87..6e2471db 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- Add `dpc` CSR support for RISC-V - Add Mtopi - Added DCSR (Debug Control and Status Register) CSR support for the RISC-V - Add `miselect` CSR diff --git a/riscv/src/register.rs b/riscv/src/register.rs index 08c0f1a8..4655facb 100644 --- a/riscv/src/register.rs +++ b/riscv/src/register.rs @@ -131,3 +131,4 @@ mod tests; // TODO: Debug Mode Registers pub mod dcsr; +pub mod dpc; diff --git a/riscv/src/register/dpc.rs b/riscv/src/register/dpc.rs new file mode 100644 index 00000000..501814f8 --- /dev/null +++ b/riscv/src/register/dpc.rs @@ -0,0 +1,25 @@ +//! dpc register — Debug PC (0x7b1) + +read_write_csr! { + /// Debug PC Register + Dpc: 0x7b1, + mask: !1usize, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_dpc_alignment_mask() { + let dpc = Dpc::from_bits(0x1); + assert_eq!(dpc.bits() & 1, 0); + } + + #[test] + fn test_dpc_bits_roundtrip() { + let dpc = Dpc::from_bits(0x12345); + assert_eq!(dpc.bits(), 0x12344); + assert_eq!(Dpc::from_bits(dpc.bits()).bits(), dpc.bits()); + } +} From 34f2498d5fe460911d7703dd2c77c64057a00cb9 Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Mon, 10 Nov 2025 16:21:40 +0530 Subject: [PATCH 52/76] Update riscv/src/register/dpc.rs Co-authored-by: rmsyn <117854522+rmsyn@users.noreply.github.com> --- riscv/src/register/dpc.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/riscv/src/register/dpc.rs b/riscv/src/register/dpc.rs index 501814f8..f254dec8 100644 --- a/riscv/src/register/dpc.rs +++ b/riscv/src/register/dpc.rs @@ -18,8 +18,12 @@ mod tests { #[test] fn test_dpc_bits_roundtrip() { - let dpc = Dpc::from_bits(0x12345); - assert_eq!(dpc.bits(), 0x12344); - assert_eq!(Dpc::from_bits(dpc.bits()).bits(), dpc.bits()); + (0..=usize::BITS).map(|r| ((1u128 << r) - 1) as usize).for_each(|pc| { + // ensure lowest bit is cleared + let exp_pc = pc & !1usize; + let dpc = Dpc::from_bits(pc); + assert_eq!(dpc.bits(), exp_pc); + assert_eq!(Dpc::from_bits(dpc.bits()).bits(), dpc.bits()); + }); } } From f41190ebc235b15092927d52ebee19b6c9a0327c Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Mon, 10 Nov 2025 16:42:04 +0530 Subject: [PATCH 53/76] Fix formatting --- riscv/src/register/dpc.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/riscv/src/register/dpc.rs b/riscv/src/register/dpc.rs index f254dec8..b797be02 100644 --- a/riscv/src/register/dpc.rs +++ b/riscv/src/register/dpc.rs @@ -18,12 +18,14 @@ mod tests { #[test] fn test_dpc_bits_roundtrip() { - (0..=usize::BITS).map(|r| ((1u128 << r) - 1) as usize).for_each(|pc| { - // ensure lowest bit is cleared - let exp_pc = pc & !1usize; - let dpc = Dpc::from_bits(pc); - assert_eq!(dpc.bits(), exp_pc); - assert_eq!(Dpc::from_bits(dpc.bits()).bits(), dpc.bits()); - }); + (0..=usize::BITS) + .map(|r| ((1u128 << r) - 1) as usize) + .for_each(|pc| { + // ensure lowest bit is cleared + let exp_pc = pc & !1usize; + let dpc = Dpc::from_bits(pc); + assert_eq!(dpc.bits(), exp_pc); + assert_eq!(Dpc::from_bits(dpc.bits()).bits(), dpc.bits()); + }); } } From 3e71ae395d7802c070f000b0ccaecd534db9687e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Tue, 11 Nov 2025 08:14:12 +0100 Subject: [PATCH 54/76] Fully qualified paths in riscv-macros --- riscv-macros/CHANGELOG.md | 1 + riscv-macros/src/lib.rs | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/riscv-macros/CHANGELOG.md b/riscv-macros/CHANGELOG.md index 2ff758d3..a47c1cf2 100644 --- a/riscv-macros/CHANGELOG.md +++ b/riscv-macros/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Use fully qualified paths in generated code (i.e., `::riscv` instead of `riscv`) - Moved from `riscv/macros/` to `riscv-macros/` - Now, `riscv::pac_enum` macro only includes trap-related code if `rt` or `rt-v-trap` features are enabled. diff --git a/riscv-macros/src/lib.rs b/riscv-macros/src/lib.rs index d4c252d8..40bf60dd 100644 --- a/riscv-macros/src/lib.rs +++ b/riscv-macros/src/lib.rs @@ -339,7 +339,7 @@ core::arch::global_asm!(" // Push the trait implementation res.push(quote! { - unsafe impl riscv::#trait_name for #name { + unsafe impl ::riscv::#trait_name for #name { const #const_name: usize = #max_discriminant; #[inline] @@ -348,17 +348,17 @@ core::arch::global_asm!(" } #[inline] - fn from_number(number: usize) -> riscv::result::Result { + fn from_number(number: usize) -> ::riscv::result::Result { match number { #(#valid_matches,)* - _ => Err(riscv::result::Error::InvalidVariant(number)), + _ => Err(::riscv::result::Error::InvalidVariant(number)), } } } }); if let Some(marker_trait_name) = attr.marker_trait_name() { - res.push(quote! { unsafe impl riscv::#marker_trait_name for #name {} }); + res.push(quote! { unsafe impl ::riscv::#marker_trait_name for #name {} }); } #[cfg(feature = "rt")] From 23925f7021b1e2332175c19bebc373e73b01c287 Mon Sep 17 00:00:00 2001 From: Hennadii Chernyshchuk Date: Thu, 13 Nov 2025 15:47:55 +0200 Subject: [PATCH 55/76] Feature-gate csr instructions Add `no-mhartid` and `no-xtvec`. Necessary to run on `picorv32`. --- riscv-rt/Cargo.toml | 2 ++ riscv-rt/src/asm.rs | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/riscv-rt/Cargo.toml b/riscv-rt/Cargo.toml index 7afdbc76..41890d39 100644 --- a/riscv-rt/Cargo.toml +++ b/riscv-rt/Cargo.toml @@ -42,7 +42,9 @@ v-trap = ["riscv-rt-macros/v-trap", "riscv/rt-v-trap"] u-boot = ["riscv-rt-macros/u-boot", "single-hart"] no-interrupts = [] no-exceptions = [] +no-mhartid = [] no-xie-xip = [] +no-xtvec = [] device = [] memory = [] defmt = ["dep:defmt"] diff --git a/riscv-rt/src/asm.rs b/riscv-rt/src/asm.rs index f89d58e5..66b52469 100644 --- a/riscv-rt/src/asm.rs +++ b/riscv-rt/src/asm.rs @@ -71,13 +71,17 @@ _abs_start: #[cfg(all(not(feature = "s-mode"), not(feature = "no-xie-xip")))] "csrw mie, 0 csrw mip, 0", - #[cfg(not(feature = "s-mode"))] - "csrr a0, mhartid", // Make sure that the hart ID is in a0 in M-mode + // Make sure that the hart ID is in a0 in M-mode + #[cfg(all(not(feature = "s-mode"), not(feature = "no-mhartid")))] + "csrr a0, mhartid", + #[cfg(all(not(feature = "s-mode"), feature = "no-mhartid"))] + "li a0, 0", // Set pre-init trap vector + #[cfg(not(feature = "no-xtvec"))] "la t0, _pre_init_trap", - #[cfg(feature = "s-mode")] + #[cfg(all(feature = "s-mode", not(feature = "no-xtvec")))] "csrw stvec, t0", - #[cfg(not(feature = "s-mode"))] + #[cfg(all(not(feature = "s-mode"), not(feature = "no-xtvec")))] "csrw mtvec, t0", // If multi-hart, assert that hart ID is valid #[cfg(not(feature = "single-hart"))] From c158f190a2c8670ff3af54f82cac775396a92bb9 Mon Sep 17 00:00:00 2001 From: Hennadii Chernyshchuk Date: Thu, 13 Nov 2025 21:12:11 +0200 Subject: [PATCH 56/76] Update CHANGELOG.md --- riscv-rt/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index 7fc255a1..b7a7f5ac 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added + +- New `no-mhartid` feature to load 0 to `a0` instead of reading `mhartid`. +- New `no-xtvec` feature that removes interrupt stuff. + + ### Changed - Update license to `MIT or Apache-2.0` From b71e121b53a69348fc2b6b4cede937f42e014747 Mon Sep 17 00:00:00 2001 From: Hennadii Chernyshchyk Date: Fri, 14 Nov 2025 16:58:54 +0200 Subject: [PATCH 57/76] Require `single-hart` --- riscv-rt/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/riscv-rt/Cargo.toml b/riscv-rt/Cargo.toml index 41890d39..f81c0191 100644 --- a/riscv-rt/Cargo.toml +++ b/riscv-rt/Cargo.toml @@ -42,7 +42,7 @@ v-trap = ["riscv-rt-macros/v-trap", "riscv/rt-v-trap"] u-boot = ["riscv-rt-macros/u-boot", "single-hart"] no-interrupts = [] no-exceptions = [] -no-mhartid = [] +no-mhartid = ["single-hart"] no-xie-xip = [] no-xtvec = [] device = [] From 7948f61651dcf231b6aebf4fefcbf8d87e056dce Mon Sep 17 00:00:00 2001 From: Hennadii Chernyshchyk Date: Fri, 14 Nov 2025 17:02:38 +0200 Subject: [PATCH 58/76] Refactor cfgs --- riscv-rt/src/asm.rs | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/riscv-rt/src/asm.rs b/riscv-rt/src/asm.rs index 66b52469..a11fce44 100644 --- a/riscv-rt/src/asm.rs +++ b/riscv-rt/src/asm.rs @@ -68,21 +68,26 @@ _abs_start: #[cfg(all(feature = "s-mode", not(feature = "no-xie-xip")))] "csrw sie, 0 csrw sip, 0", - #[cfg(all(not(feature = "s-mode"), not(feature = "no-xie-xip")))] - "csrw mie, 0 - csrw mip, 0", - // Make sure that the hart ID is in a0 in M-mode - #[cfg(all(not(feature = "s-mode"), not(feature = "no-mhartid")))] - "csrr a0, mhartid", - #[cfg(all(not(feature = "s-mode"), feature = "no-mhartid"))] - "li a0, 0", + #[cfg(not(feature = "s-mode"))] + { + #[cfg(not(feature = "no-xie-xip"))] + "csrw mie, 0 + csrw mip, 0", + // Make sure that the hart ID is in a0 in M-mode + #[cfg(not(feature = "no-mhartid"))] + "csrr a0, mhartid", + #[cfg(feature = "no-mhartid")] + "li a0, 0", + }, // Set pre-init trap vector #[cfg(not(feature = "no-xtvec"))] - "la t0, _pre_init_trap", - #[cfg(all(feature = "s-mode", not(feature = "no-xtvec")))] - "csrw stvec, t0", - #[cfg(all(not(feature = "s-mode"), not(feature = "no-xtvec")))] - "csrw mtvec, t0", + { + "la t0, _pre_init_trap", + #[cfg(feature = "s-mode")] + "csrw stvec, t0", + #[cfg(not(feature = "s-mode"))] + "csrw mtvec, t0", + }, // If multi-hart, assert that hart ID is valid #[cfg(not(feature = "single-hart"))] "lui t0, %hi(_max_hart_id) From 992ee1e4212a3237e20fb5182842104237fc47a6 Mon Sep 17 00:00:00 2001 From: Hennadii Chernyshchyk Date: Fri, 14 Nov 2025 17:02:52 +0200 Subject: [PATCH 59/76] Remove extra newline --- riscv-rt/CHANGELOG.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index b7a7f5ac..bb82c85d 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -12,7 +12,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - New `no-mhartid` feature to load 0 to `a0` instead of reading `mhartid`. - New `no-xtvec` feature that removes interrupt stuff. - ### Changed - Update license to `MIT or Apache-2.0` @@ -29,7 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added - New `post-init` feature to run a Rust `__post_init` function before jumping to `main`. -- New `#[riscv_rt::post_init]` attribute to aid in the definition of the `__post_init` function. +- New `#[riscv_rt::post_init]` attribute to aid in the definition of the `__post_init` function. - Added `.uninit` section to the linker file. Due to its similarities with `.bss`, the linker will place this new section in `REGION_BSS`. - Additional feature `no-xie-xip` to work on chips without the XIE and XIP CSRs (e.g. ESP32-C2, ESP32-C3) @@ -84,7 +83,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - New `device` feature to include `device.x` in `link.x`. This feature is based on the current implementation of `cortex-m-rt`. - New `memory` feature to include `memory.x` in `link.x`. This feature is based - on the current implementation of `cortex-m-rt`. However, in contrast with + on the current implementation of `cortex-m-rt`. However, in contrast with `cortex-m-rt`, including `memory.x` in the linker file is feature gated. The benefits of leaving this optional are backwards compatibility and allowing users to define less typical linker scripts that do not rely on a From 495f260c7c6fd6087a6a9a27740b4f83e7300595 Mon Sep 17 00:00:00 2001 From: Hennadii Chernyshchyk Date: Fri, 14 Nov 2025 17:04:30 +0200 Subject: [PATCH 60/76] Fix new clippy warnings --- riscv-rt/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index 4c3b79b5..f3b78339 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -729,9 +729,9 @@ pub unsafe extern "Rust" fn setup_interrupts() { let xtvec_val = match () { #[cfg(not(feature = "v-trap"))] - _ => Xtvec::new(_start_trap as usize, TrapMode::Direct), + _ => Xtvec::new(_start_trap as *const () as usize, TrapMode::Direct), #[cfg(feature = "v-trap")] - _ => Xtvec::new(_vector_table as usize, TrapMode::Vectored), + _ => Xtvec::new(_vector_table as *const () as usize, TrapMode::Vectored), }; xtvec::write(xtvec_val); } From c330ed084bd50a45b3c9cd5e35ea7b48d1d6cb98 Mon Sep 17 00:00:00 2001 From: Hennadii Chernyshchyk Date: Fri, 14 Nov 2025 18:04:06 +0200 Subject: [PATCH 61/76] Remove extra comma --- riscv-rt/src/asm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/riscv-rt/src/asm.rs b/riscv-rt/src/asm.rs index a11fce44..cef84699 100644 --- a/riscv-rt/src/asm.rs +++ b/riscv-rt/src/asm.rs @@ -78,7 +78,7 @@ _abs_start: "csrr a0, mhartid", #[cfg(feature = "no-mhartid")] "li a0, 0", - }, + } // Set pre-init trap vector #[cfg(not(feature = "no-xtvec"))] { @@ -87,7 +87,7 @@ _abs_start: "csrw stvec, t0", #[cfg(not(feature = "s-mode"))] "csrw mtvec, t0", - }, + } // If multi-hart, assert that hart ID is valid #[cfg(not(feature = "single-hart"))] "lui t0, %hi(_max_hart_id) From 7d9d09dd29c3ebd3dacef40ae2884aeb5986651a Mon Sep 17 00:00:00 2001 From: Hennadii Chernyshchyk Date: Fri, 14 Nov 2025 18:08:32 +0200 Subject: [PATCH 62/76] Add docs --- riscv-rt/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index f3b78339..8760495e 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -565,6 +565,15 @@ //! //! Saves a little code size if there is only one hart on the target. //! +//! ## `no-mhartid` +//! +//! Skips reading `mhartid` and uses 0 instead. Useful for targets that doesn't implement this instruction. +//! Automatically enables `single-hart`. +//! +//! ## `no-xtvec` +//! +//! Skips interrupts setup. +//! //! ## `s-mode` //! //! Supervisor mode. While most registers/instructions have variants for both `mcause` and From 5852eed8e3e67a3da5a73b629ec3857c9725ab6a Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Tue, 11 Nov 2025 17:05:30 +0530 Subject: [PATCH 63/76] Implement dscratch0 and dscratch1 CSRs for RISC-V --- riscv/src/register.rs | 5 +++++ riscv/src/register/dscratch0.rs | 25 +++++++++++++++++++++++++ riscv/src/register/dscratch1.rs | 25 +++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 riscv/src/register/dscratch0.rs create mode 100644 riscv/src/register/dscratch1.rs diff --git a/riscv/src/register.rs b/riscv/src/register.rs index 4655facb..bc0a240a 100644 --- a/riscv/src/register.rs +++ b/riscv/src/register.rs @@ -131,4 +131,9 @@ mod tests; // TODO: Debug Mode Registers pub mod dcsr; +<<<<<<< HEAD pub mod dpc; +======= +pub mod dscratch0; +pub mod dscratch1; +>>>>>>> d078ccf (Implement dscratch0 and dscratch1 CSRs for RISC-V) diff --git a/riscv/src/register/dscratch0.rs b/riscv/src/register/dscratch0.rs new file mode 100644 index 00000000..c20c014c --- /dev/null +++ b/riscv/src/register/dscratch0.rs @@ -0,0 +1,25 @@ +//! dscratch0 + +read_write_csr! { + /// Debug scratch register 0 + Dscratch0: 0x7b2, + mask: usize::MAX, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_dscratch0_mask() { + let reg = Dscratch0::from_bits(usize::MAX); + assert_eq!(reg.bits(), usize::MAX); + assert_eq!(Dscratch0::BITMASK, usize::MAX); + } + + #[test] + fn test_dscratch0_roundtrip() { + let reg = Dscratch0::from_bits(0xDEAD_BEEFusize); + assert_eq!(reg.bits(), 0xDEAD_BEEFusize); + } +} diff --git a/riscv/src/register/dscratch1.rs b/riscv/src/register/dscratch1.rs new file mode 100644 index 00000000..33f41279 --- /dev/null +++ b/riscv/src/register/dscratch1.rs @@ -0,0 +1,25 @@ +//! dscratch1 + +read_write_csr! { + /// Debug scratch register 1 + Dscratch1: 0x7b3, + mask: usize::MAX, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_dscratch1_mask() { + let reg = Dscratch1::from_bits(usize::MAX); + assert_eq!(reg.bits(), usize::MAX); + assert_eq!(Dscratch1::BITMASK, usize::MAX); + } + + #[test] + fn test_dscratch1_roundtrip() { + let reg = Dscratch1::from_bits(0xDEAD_BEEFusize); + assert_eq!(reg.bits(), 0xDEAD_BEEFusize); + } +} From fe00a3f8319910e5cb869eae25e5a6169d9ebb5f Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Thu, 13 Nov 2025 18:31:03 +0530 Subject: [PATCH 64/76] Update CHANGELOG.md --- riscv/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 81f03add..998f2202 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- Add `dcsratch0` and `dscratch1` CSRs - Add `dpc` CSR support for RISC-V - Add Mtopi - Added DCSR (Debug Control and Status Register) CSR support for the RISC-V From 4f9c04cf0e4ac6f7108d3d500c28e42464d40104 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Fri, 14 Nov 2025 13:30:43 +0530 Subject: [PATCH 65/76] Update macros.rs to add read_write_csr_as_usize and update dscratch0 and dcsratch1 to use them instead of read_write_csr macro --- riscv/src/register/dscratch0.rs | 6 +----- riscv/src/register/dscratch1.rs | 6 +----- riscv/src/register/macros.rs | 24 ++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/riscv/src/register/dscratch0.rs b/riscv/src/register/dscratch0.rs index c20c014c..e29a049d 100644 --- a/riscv/src/register/dscratch0.rs +++ b/riscv/src/register/dscratch0.rs @@ -1,10 +1,6 @@ //! dscratch0 -read_write_csr! { - /// Debug scratch register 0 - Dscratch0: 0x7b2, - mask: usize::MAX, -} +read_write_csr_as_usize!(Dscratch0, 0x7b2); #[cfg(test)] mod tests { diff --git a/riscv/src/register/dscratch1.rs b/riscv/src/register/dscratch1.rs index 33f41279..3361a602 100644 --- a/riscv/src/register/dscratch1.rs +++ b/riscv/src/register/dscratch1.rs @@ -1,10 +1,6 @@ //! dscratch1 -read_write_csr! { - /// Debug scratch register 1 - Dscratch1: 0x7b3, - mask: usize::MAX, -} +read_write_csr_as_usize!(Dscratch1, 0x7b3); #[cfg(test)] mod tests { diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 255f0f4e..ef291857 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -301,6 +301,30 @@ macro_rules! write_csr_as_usize_rv32 { }; } +/// Convenience macro to provide combined read/write of a CSR as a `usize`. +/// +/// This composes [`read_csr_as_usize`] and [`write_csr_as_usize`]. Use the +/// `safe` form to get safe wrappers instead of unsafe. +#[macro_export] +macro_rules! read_write_csr_as_usize { + ($csr_number:literal) => { + $crate::read_csr_as_usize!($csr_number); + $crate::write_csr_as_usize!($csr_number); + }; + (safe $csr_number:literal) => { + $crate::read_csr_as_usize!($csr_number); + $crate::write_csr_as_usize!(safe $csr_number); + }; + ($csr_number:literal, $($cfg:meta),*) => { + $crate::read_csr_as_usize!($csr_number, $($cfg),*); + $crate::write_csr_as_usize!($csr_number, $($cfg),*); + }; + (safe $csr_number:literal, $($cfg:meta),*) => { + $crate::read_csr_as_usize!($csr_number, $($cfg),*); + $crate::write_csr_as_usize!(safe $csr_number, $($cfg),*); + }; +} + /// Convenience macro around the `csrrs` assembly instruction to set the CSR register. /// /// This macro is intended for use with the [set_csr](crate::set_csr) or [set_clear_csr](crate::set_clear_csr) macros. From 4cf193a22b8b7d2ca220b7614d71b7c27879b2f2 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Fri, 14 Nov 2025 13:36:20 +0530 Subject: [PATCH 66/76] resolve conflict --- riscv/src/register.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/riscv/src/register.rs b/riscv/src/register.rs index bc0a240a..a38527db 100644 --- a/riscv/src/register.rs +++ b/riscv/src/register.rs @@ -131,9 +131,6 @@ mod tests; // TODO: Debug Mode Registers pub mod dcsr; -<<<<<<< HEAD pub mod dpc; -======= pub mod dscratch0; pub mod dscratch1; ->>>>>>> d078ccf (Implement dscratch0 and dscratch1 CSRs for RISC-V) From 8eabc412e507148ec77c37f9e0d20c99ab4e3360 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Fri, 14 Nov 2025 15:00:27 +0530 Subject: [PATCH 67/76] Fix errors --- riscv/src/register/dscratch0.rs | 18 +++++++----------- riscv/src/register/dscratch1.rs | 18 +++++++----------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/riscv/src/register/dscratch0.rs b/riscv/src/register/dscratch0.rs index e29a049d..feafb991 100644 --- a/riscv/src/register/dscratch0.rs +++ b/riscv/src/register/dscratch0.rs @@ -1,21 +1,17 @@ //! dscratch0 -read_write_csr_as_usize!(Dscratch0, 0x7b2); +read_write_csr_as_usize!(0x7b2); #[cfg(test)] mod tests { use super::*; #[test] - fn test_dscratch0_mask() { - let reg = Dscratch0::from_bits(usize::MAX); - assert_eq!(reg.bits(), usize::MAX); - assert_eq!(Dscratch0::BITMASK, usize::MAX); - } - - #[test] - fn test_dscratch0_roundtrip() { - let reg = Dscratch0::from_bits(0xDEAD_BEEFusize); - assert_eq!(reg.bits(), 0xDEAD_BEEFusize); + fn test_dscratch0_read_write() { + for i in 0..usize::BITS { + let val = 1usize << i; + let _ = unsafe { try_write(val) }; + let _ = try_read(); + } } } diff --git a/riscv/src/register/dscratch1.rs b/riscv/src/register/dscratch1.rs index 3361a602..32a4a534 100644 --- a/riscv/src/register/dscratch1.rs +++ b/riscv/src/register/dscratch1.rs @@ -1,21 +1,17 @@ //! dscratch1 -read_write_csr_as_usize!(Dscratch1, 0x7b3); +read_write_csr_as_usize!(0x7b3); #[cfg(test)] mod tests { use super::*; #[test] - fn test_dscratch1_mask() { - let reg = Dscratch1::from_bits(usize::MAX); - assert_eq!(reg.bits(), usize::MAX); - assert_eq!(Dscratch1::BITMASK, usize::MAX); - } - - #[test] - fn test_dscratch1_roundtrip() { - let reg = Dscratch1::from_bits(0xDEAD_BEEFusize); - assert_eq!(reg.bits(), 0xDEAD_BEEFusize); + fn test_dscratch1_read_write() { + for i in 0..usize::BITS { + let val = 1usize << i; + let _ = unsafe { try_write(val) }; + let _ = try_read(); + } } } From 64dec8a2ff3c78c95a9342d01ea4a02c4904ecd2 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Fri, 14 Nov 2025 21:23:41 +0530 Subject: [PATCH 68/76] Update tests --- riscv/src/register/dscratch0.rs | 5 +++-- riscv/src/register/dscratch1.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/riscv/src/register/dscratch0.rs b/riscv/src/register/dscratch0.rs index feafb991..f49687f9 100644 --- a/riscv/src/register/dscratch0.rs +++ b/riscv/src/register/dscratch0.rs @@ -5,13 +5,14 @@ read_write_csr_as_usize!(0x7b2); #[cfg(test)] mod tests { use super::*; + use crate::result::Error; #[test] fn test_dscratch0_read_write() { for i in 0..usize::BITS { let val = 1usize << i; - let _ = unsafe { try_write(val) }; - let _ = try_read(); + assert_eq!(unsafe { try_write(val) }, Err(Error::Unimplemented)); + assert_eq!(try_read(), Err(Error::Unimplemented)); } } } diff --git a/riscv/src/register/dscratch1.rs b/riscv/src/register/dscratch1.rs index 32a4a534..44db9e55 100644 --- a/riscv/src/register/dscratch1.rs +++ b/riscv/src/register/dscratch1.rs @@ -5,13 +5,14 @@ read_write_csr_as_usize!(0x7b3); #[cfg(test)] mod tests { use super::*; + use crate::result::Error; #[test] fn test_dscratch1_read_write() { for i in 0..usize::BITS { let val = 1usize << i; - let _ = unsafe { try_write(val) }; - let _ = try_read(); + assert_eq!(unsafe { try_write(val) }, Err(Error::Unimplemented)); + assert_eq!(try_read(), Err(Error::Unimplemented)); } } } From f8565d9c3e31707472ae770c768d5a4ddbd67cbd Mon Sep 17 00:00:00 2001 From: Kushal Meghani <168952248+KushalMeghani1644@users.noreply.github.com> Date: Fri, 14 Nov 2025 21:13:49 +0530 Subject: [PATCH 69/76] Update riscv/CHANGELOG.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Román Cárdenas Rodríguez --- riscv/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 998f2202..2e709014 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added - Add `dcsratch0` and `dscratch1` CSRs +- Add new `read-write_csr_as_usize` macro for registers - Add `dpc` CSR support for RISC-V - Add Mtopi - Added DCSR (Debug Control and Status Register) CSR support for the RISC-V From 2f85419e796cf9c64c3ad58fbec415a846d72a35 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Thu, 20 Nov 2025 18:19:25 +0530 Subject: [PATCH 70/76] Implement VSTOPI CSR for RISC-V --- riscv/src/register.rs | 1 + riscv/src/register/vstopi.rs | 69 ++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 riscv/src/register/vstopi.rs diff --git a/riscv/src/register.rs b/riscv/src/register.rs index a38527db..8235cb7b 100644 --- a/riscv/src/register.rs +++ b/riscv/src/register.rs @@ -63,6 +63,7 @@ pub mod sepc; pub mod sip; pub mod sscratch; pub mod stval; +pub mod vstopi; // Supervisor Protection and Translation pub mod satp; diff --git a/riscv/src/register/vstopi.rs b/riscv/src/register/vstopi.rs new file mode 100644 index 00000000..129cc6d8 --- /dev/null +++ b/riscv/src/register/vstopi.rs @@ -0,0 +1,69 @@ +//! vstopi register — Virtual Supervisor Top Priority Interrupt (0xEB0) + +read_only_csr! { + /// Virtual Supervisor Top Priority Interrupt Register + Vstopi: 0xEB0, + mask: 0x0FFF_00FF, +} + +read_only_csr_field! { + Vstopi, + /// Interrupt ID (bits 16..27) + /// + /// Identifies the specific interrupt source. A value of 0 indicates no interrupt is pending. + /// Non-zero values correspond to specific interrupt sources as defined by the interrupt controller. + iid: [16:27], +} + +read_only_csr_field! { + Vstopi, + /// Interrupt Priority ID (bits 0..7) + /// + /// Represents the priority level of the pending interrupt. + /// Lower numerical values indicate higher priority interrupts. + iprio: [0:7], +} + +impl Vstopi { + /// Returns true if there is a valid interrupt pending + /// + /// When this returns true, both `interrupt_id()` and `priority()` will return meaningful values. + #[inline] + pub fn is_interrupt_pending(&self) -> bool { + self.iid() != 0 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_vstopi_fields() { + let vstopi = Vstopi::from_bits(0); + test_ro_csr_field!(vstopi, iid: [16, 27], 0x0); + test_ro_csr_field!(vstopi, iprio: [0, 7], 0x0); + + let vstopi = Vstopi::from_bits((0xB << 16) | 5); + test_ro_csr_field!(vstopi, iid: [16, 27], 0xB); + test_ro_csr_field!(vstopi, iprio: [0, 7], 0x5); + + let vstopi = Vstopi::from_bits((0xFFF << 16) | 0xFF); + test_ro_csr_field!(vstopi, iid: [16, 27], 0xFFF); + test_ro_csr_field!(vstopi, iprio: [0, 7], 0xFF); + + let vstopi = Vstopi::from_bits(1 << 16); + test_ro_csr_field!(vstopi, iid: [16, 27], 0x1); + test_ro_csr_field!(vstopi, iprio: [0, 7], 0x0); + + let vstopi = Vstopi::from_bits(1); + test_ro_csr_field!(vstopi, iid: [16, 27], 0x0); + test_ro_csr_field!(vstopi, iprio: [0, 7], 0x1); + } + + #[test] + fn test_vstopi_bitmask() { + let vstopi = Vstopi::from_bits(usize::MAX); + assert_eq!(vstopi.bits(), 0x0FFF_00FFusize); + } +} From 770334aef1653af3c0b307e288d525f85af7e899 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Thu, 20 Nov 2025 18:31:04 +0530 Subject: [PATCH 71/76] Update CHANGELOG.md --- riscv/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 2e709014..d8c99330 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- Add `vstopi` CSR - Add `dcsratch0` and `dscratch1` CSRs - Add new `read-write_csr_as_usize` macro for registers - Add `dpc` CSR support for RISC-V From a31f5fbd3bbb9c4fbef3261a059c32b76ee2b258 Mon Sep 17 00:00:00 2001 From: Kurtis Dinelle Date: Fri, 28 Nov 2025 15:26:58 -0800 Subject: [PATCH 72/76] Fix UB in heap init example docs --- riscv-rt/CHANGELOG.md | 1 + riscv-rt/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index bb82c85d..4986a1f9 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed +- Fix undefined behavior in heap initialization example documentation - Fix stack allocation algorithm for multi-core targets without M extension ## [v0.16.0] - 2025-09-08 diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index 8760495e..1faf4284 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -279,7 +279,7 @@ //! fn main() { //! unsafe { //! let heap_bottom = riscv_rt::heap_start() as usize; -//! let heap_size = &_heap_size as *const u8 as usize; +//! let heap_size = core::ptr::addr_of!(_heap_size) as usize; //! some_allocator::initialize(heap_bottom, heap_size); //! } //! } From 4d4602232112bd0497c8a1f653279ef0d3325e51 Mon Sep 17 00:00:00 2001 From: Kurtis Dinelle Date: Sat, 29 Nov 2025 17:32:37 -0800 Subject: [PATCH 73/76] Fix v-trap core interrupt --- riscv-rt/CHANGELOG.md | 1 + riscv-rt/macros/src/lib.rs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index 4986a1f9..1c455572 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed +- Fix v-trap core interrupt so RISCV_RT_BASE_ISA must be defined - Fix undefined behavior in heap initialization example documentation - Fix stack allocation algorithm for multi-core targets without M extension diff --git a/riscv-rt/macros/src/lib.rs b/riscv-rt/macros/src/lib.rs index 6db77759..4d899bb9 100644 --- a/riscv-rt/macros/src/lib.rs +++ b/riscv-rt/macros/src/lib.rs @@ -783,6 +783,8 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { /// The argument of the macro must be a path to a variant of an enum that implements the `riscv_rt::CoreInterruptNumber` trait. /// /// If the `v-trap` feature is enabled, this macro generates the corresponding interrupt trap handler in assembly. +/// This feature relies on the `RISCV_RT_BASE_ISA` environment variable being set to one of +/// `rv32i`, `rv32e`, `rv64i`, or `rv64e`. Otherwise, this will **panic**. /// /// # Example /// @@ -795,7 +797,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { pub fn core_interrupt(args: TokenStream, input: TokenStream) -> TokenStream { let arch = match () { #[cfg(feature = "v-trap")] - () => RiscvArch::try_from_env(), + () => Some(RiscvArch::try_from_env().expect("RISCV_RT_BASE_ISA must be defined")), #[cfg(not(feature = "v-trap"))] () => None, }; From 7482ce140126d2299980944e23b2fb67e916cd01 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Fri, 5 Dec 2025 16:53:32 +0530 Subject: [PATCH 74/76] Add QEMU CI support --- .github/workflows/qemu.yaml | 59 +++++++++ Cargo.toml | 1 + ci/expected/qemu_semihosting.run | 1 + ci/expected/qemu_uart.run | 1 + riscv-rt/CHANGELOG.md | 1 + riscv-rt/Cargo.toml | 2 + riscv-rt/examples/device_virt.x | 11 ++ riscv-rt/examples/qemu_semihosting.rs | 22 ++++ riscv-rt/examples/qemu_uart.rs | 61 ++++++++++ typos.toml | 2 +- xtask/Cargo.toml | 7 ++ xtask/src/main.rs | 167 ++++++++++++++++++++++++++ 12 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/qemu.yaml create mode 100644 ci/expected/qemu_semihosting.run create mode 100644 ci/expected/qemu_uart.run create mode 100644 riscv-rt/examples/device_virt.x create mode 100644 riscv-rt/examples/qemu_semihosting.rs create mode 100644 riscv-rt/examples/qemu_uart.rs create mode 100644 xtask/Cargo.toml create mode 100644 xtask/src/main.rs diff --git a/.github/workflows/qemu.yaml b/.github/workflows/qemu.yaml new file mode 100644 index 00000000..805f00dd --- /dev/null +++ b/.github/workflows/qemu.yaml @@ -0,0 +1,59 @@ +name: QEMU tests +on: + merge_group: + pull_request: + push: + branches: + - master + +env: + CARGO_TERM_COLOR: always + +jobs: + testexamples: + name: QEMU run + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + toolchain: [stable] + target-qemu: + - target: riscv32i-unknown-none-elf + qemu: riscv32 + - target: riscv32im-unknown-none-elf + qemu: riscv32 + - target: riscv32imc-unknown-none-elf + qemu: riscv32 + - target: riscv32imac-unknown-none-elf + qemu: riscv32 + - target: riscv32imafc-unknown-none-elf + qemu: riscv32 + - target: riscv64imac-unknown-none-elf + qemu: riscv64 + - target: riscv64gc-unknown-none-elf + qemu: riscv64 + example: + - qemu_uart + - qemu_semihosting + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Configure Rust target ${{ matrix.target-qemu.target }} + run: | + rustup toolchain install ${{ matrix.toolchain }} + rustup default ${{ matrix.toolchain }} + rustup target add ${{ matrix.target-qemu.target }} + + - name: Cache Dependencies + uses: Swatinem/rust-cache@v2 + + - name: Install QEMU + run: | + sudo apt update + sudo apt install -y qemu-system-${{ matrix.target-qemu.qemu }} + + - name: Run-pass tests + run: cargo run --package xtask -- qemu --target ${{ matrix.target-qemu.target }} --example ${{ matrix.example }} + diff --git a/Cargo.toml b/Cargo.toml index c8391343..65b34667 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "riscv-types", "tests-build", "tests-trybuild", + "xtask", ] default-members = [ diff --git a/ci/expected/qemu_semihosting.run b/ci/expected/qemu_semihosting.run new file mode 100644 index 00000000..6df362d2 --- /dev/null +++ b/ci/expected/qemu_semihosting.run @@ -0,0 +1 @@ +Hello from semihosting! diff --git a/ci/expected/qemu_uart.run b/ci/expected/qemu_uart.run new file mode 100644 index 00000000..4687b774 --- /dev/null +++ b/ci/expected/qemu_uart.run @@ -0,0 +1 @@ +Hello from UART! diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index 1c455572..f4bca19c 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- Added examples for CI tests using semihosting and UART - New `no-mhartid` feature to load 0 to `a0` instead of reading `mhartid`. - New `no-xtvec` feature that removes interrupt stuff. diff --git a/riscv-rt/Cargo.toml b/riscv-rt/Cargo.toml index f81c0191..096784c8 100644 --- a/riscv-rt/Cargo.toml +++ b/riscv-rt/Cargo.toml @@ -32,6 +32,8 @@ defmt = { version = "1.0.1", optional = true } [dev-dependencies] panic-halt = "1.0.0" +riscv-semihosting = { path = "../riscv-semihosting", version = "0.2.1" } +riscv = { path = "../riscv", version = "0.15.0", features = ["critical-section-single-hart"] } [features] pre-init = [] diff --git a/riscv-rt/examples/device_virt.x b/riscv-rt/examples/device_virt.x new file mode 100644 index 00000000..ee4e920a --- /dev/null +++ b/riscv-rt/examples/device_virt.x @@ -0,0 +1,11 @@ +MEMORY +{ + RAM : ORIGIN = 0x80000000, LENGTH = 16M +} +REGION_ALIAS("REGION_TEXT", RAM); +REGION_ALIAS("REGION_RODATA", RAM); +REGION_ALIAS("REGION_DATA", RAM); +REGION_ALIAS("REGION_BSS", RAM); +REGION_ALIAS("REGION_HEAP", RAM); +REGION_ALIAS("REGION_STACK", RAM); +INCLUDE link.x diff --git a/riscv-rt/examples/qemu_semihosting.rs b/riscv-rt/examples/qemu_semihosting.rs new file mode 100644 index 00000000..52d6eb40 --- /dev/null +++ b/riscv-rt/examples/qemu_semihosting.rs @@ -0,0 +1,22 @@ +//! Semihosting example for QEMU +//! +//! This example uses RISC-V semihosting to print output and cleanly exit QEMU. +//! Run with: `qemu-system-riscv32 -machine virt -nographic -semihosting-config enable=on,target=native -bios none -kernel ` + +#![no_std] +#![no_main] + +extern crate panic_halt; + +use riscv_rt::entry; +use riscv_semihosting::{ + debug::{self, EXIT_SUCCESS}, + hprintln, +}; + +#[entry] +fn main() -> ! { + hprintln!("Hello from semihosting!"); + debug::exit(EXIT_SUCCESS); + loop {} +} diff --git a/riscv-rt/examples/qemu_uart.rs b/riscv-rt/examples/qemu_uart.rs new file mode 100644 index 00000000..81971ea7 --- /dev/null +++ b/riscv-rt/examples/qemu_uart.rs @@ -0,0 +1,61 @@ +//! UART example for QEMU virt machine +//! +//! This example demonstrates direct UART output on QEMU's virt machine. +//! It writes to the NS16550-compatible UART at 0x1000_0000. + +#![no_std] +#![no_main] + +extern crate panic_halt; + +use riscv_rt::entry; +use riscv_semihosting::debug::{self, EXIT_SUCCESS}; + +const UART_BASE: usize = 0x1000_0000; +const UART_THR: usize = UART_BASE; +const UART_IER: usize = UART_BASE + 1; +const UART_FCR: usize = UART_BASE + 2; +const UART_LCR: usize = UART_BASE + 3; +const UART_LSR: usize = UART_BASE + 5; +const LCR_DLAB: u8 = 1 << 7; +const LCR_8N1: u8 = 0x03; +const LSR_THRE: u8 = 1 << 5; + +unsafe fn uart_write_reg(off: usize, v: u8) { + (off as *mut u8).write_volatile(v); +} + +unsafe fn uart_read_reg(off: usize) -> u8 { + (off as *const u8).read_volatile() +} + +fn uart_init() { + unsafe { + uart_write_reg(UART_LCR, LCR_DLAB); + uart_write_reg(UART_THR, 0x01); + uart_write_reg(UART_IER, 0x00); + uart_write_reg(UART_LCR, LCR_8N1); + uart_write_reg(UART_FCR, 0x07); + } +} + +fn uart_write_byte(b: u8) { + unsafe { + while (uart_read_reg(UART_LSR) & LSR_THRE) == 0 {} + uart_write_reg(UART_THR, b); + } +} + +fn uart_write_str(s: &str) { + for &b in s.as_bytes() { + uart_write_byte(b); + } +} + +#[entry] +fn main() -> ! { + uart_init(); + uart_write_str("Hello from UART!\n"); + debug::exit(EXIT_SUCCESS); + loop {} +} diff --git a/typos.toml b/typos.toml index 3a088783..c05ff9cf 100644 --- a/typos.toml +++ b/typos.toml @@ -1,3 +1,3 @@ [default] extend-ignore-re = ["[Ss][Ii][Ee]", "[Ss][Xx][Ll]", "[.]?useed[.,:]?", "[Ss][Tt][Ii][Pp]"] -extend-ignore-words-re = ["[Pp]endings", "PENDINGS"] +extend-ignore-words-re = ["[Pp]endings", "PENDINGS", "THR", "THRE"] diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml new file mode 100644 index 00000000..13979c34 --- /dev/null +++ b/xtask/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "xtask" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1" diff --git a/xtask/src/main.rs b/xtask/src/main.rs new file mode 100644 index 00000000..58f7112e --- /dev/null +++ b/xtask/src/main.rs @@ -0,0 +1,167 @@ +use anyhow::{bail, Context}; +use std::{ + fs, + path::PathBuf, + process::{Command, Stdio}, + thread, + time::Duration, +}; + +fn find_golden_file(target: &str, example: &str) -> Option { + let target_specific: PathBuf = ["ci", "expected", target, &format!("{}.run", example)] + .iter() + .collect(); + if target_specific.exists() { + return Some(target_specific); + } + + let generic: PathBuf = ["ci", "expected", &format!("{}.run", example)] + .iter() + .collect(); + if generic.exists() { + return Some(generic); + } + + None +} + +fn main() -> anyhow::Result<()> { + let mut args = std::env::args().skip(1).collect::>(); + if args.is_empty() || args[0] != "qemu" { + bail!("usage: cargo run -p xtask -- qemu --target --example "); + } + args.remove(0); + let mut target = None; + let mut example = None; + let mut features: Option = None; + let mut i = 0; + while i < args.len() { + match args[i].as_str() { + "--target" => { + target = Some(args.get(i + 1).context("missing target")?.clone()); + i += 2; + } + "--example" => { + example = Some(args.get(i + 1).context("missing example")?.clone()); + i += 2; + } + "--features" => { + features = Some(args.get(i + 1).context("missing features")?.clone()); + i += 2; + } + _ => { + bail!("unknown arg {}", args[i]); + } + } + } + let target = target.context("--target required")?; + let example = example.context("--example required")?; + let mut rustflags = "-C link-arg=-Triscv-rt/examples/device_virt.x".to_string(); + if let Some(f) = &features { + if f.contains("s-mode") { + rustflags = "-C link-arg=-Triscv-rt/examples/device_virt_s.x".into(); + } + } + + let mut cmd = Command::new("cargo"); + cmd.env("RUSTFLAGS", rustflags).args([ + "build", + "--package", + "riscv-rt", + "--release", + "--target", + &target, + "--example", + &example, + ]); + cmd.apply_features(features.as_deref()); + let status = cmd.status()?; + if !status.success() { + bail!("build failed"); + } + + let qemu = if target.starts_with("riscv32") { + "qemu-system-riscv32" + } else { + "qemu-system-riscv64" + }; + let mut qemu_args = vec![ + "-machine", + "virt", + "-nographic", + "-serial", + "stdio", + "-monitor", + "none", + "-semihosting-config", + "enable=on,target=native", + ]; + if !features.as_deref().unwrap_or("").contains("s-mode") { + qemu_args.push("-bios"); + qemu_args.push("none"); + } + let kernel_path = format!("target/{}/release/examples/{}", target, example); + let mut child = Command::new(qemu) + .args(&qemu_args) + .arg("-kernel") + .arg(&kernel_path) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .context("running qemu")?; + thread::sleep(Duration::from_secs(3)); + let _ = child.kill(); + let output = child.wait_with_output()?; + let raw_stdout = String::from_utf8_lossy(&output.stdout).into_owned(); + let stdout = raw_stdout + .lines() + .filter(|l| !l.starts_with("QEMU ") && !l.contains("monitor")) + .collect::>() + .join("\n"); + let stdout = if stdout.is_empty() { + String::new() + } else { + format!("{}\n", stdout.trim()) + }; + + let expected_path = match find_golden_file(&target, &example) { + Some(p) => p, + None => { + let target_path: PathBuf = ["ci", "expected", &target, &format!("{}.run", example)] + .iter() + .collect(); + let generic_path: PathBuf = ["ci", "expected", &format!("{}.run", example)] + .iter() + .collect(); + bail!( + "golden file not found. Expected one of:\n - {}\n - {}", + target_path.display(), + generic_path.display() + ); + } + }; + let expected = fs::read_to_string(&expected_path)?; + if expected != stdout { + bail!( + "output mismatch\nexpected: {}\nactual: {}", + expected, + stdout + ); + } + if !stdout.is_empty() { + println!("{}", stdout.trim_end()); + } + Ok(()) +} + +trait CmdExt { + fn apply_features(&mut self, f: Option<&str>) -> &mut Self; +} +impl CmdExt for std::process::Command { + fn apply_features(&mut self, f: Option<&str>) -> &mut Self { + if let Some(feat) = f { + self.arg("--features").arg(feat); + } + self + } +} From 5873f9724e4ac7506368cd333a9ed0bc34ef207e Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Fri, 5 Dec 2025 17:25:04 +0530 Subject: [PATCH 75/76] remove thread::sleep(Duration::from_secs(3)) and child.kill() --- xtask/src/main.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 58f7112e..876dae51 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -3,8 +3,6 @@ use std::{ fs, path::PathBuf, process::{Command, Stdio}, - thread, - time::Duration, }; fn find_golden_file(target: &str, example: &str) -> Option { @@ -101,7 +99,7 @@ fn main() -> anyhow::Result<()> { qemu_args.push("none"); } let kernel_path = format!("target/{}/release/examples/{}", target, example); - let mut child = Command::new(qemu) + let child = Command::new(qemu) .args(&qemu_args) .arg("-kernel") .arg(&kernel_path) @@ -109,8 +107,6 @@ fn main() -> anyhow::Result<()> { .stderr(Stdio::piped()) .spawn() .context("running qemu")?; - thread::sleep(Duration::from_secs(3)); - let _ = child.kill(); let output = child.wait_with_output()?; let raw_stdout = String::from_utf8_lossy(&output.stdout).into_owned(); let stdout = raw_stdout From 460aac3df5fa34ad876e50db00f36f5c50918e80 Mon Sep 17 00:00:00 2001 From: Kurtis Dinelle Date: Sat, 6 Dec 2025 14:52:57 -0800 Subject: [PATCH 76/76] Doucment riscv-rt features and fix minor doc issues --- riscv-macros/CHANGELOG.md | 1 + riscv-macros/src/lib.rs | 2 +- riscv-rt/CHANGELOG.md | 1 + riscv-rt/src/lib.rs | 40 ++++++++++++++++++++++++++++++------ riscv/CHANGELOG.md | 1 + riscv/src/register/macros.rs | 2 +- 6 files changed, 39 insertions(+), 8 deletions(-) diff --git a/riscv-macros/CHANGELOG.md b/riscv-macros/CHANGELOG.md index a47c1cf2..f1109e1a 100644 --- a/riscv-macros/CHANGELOG.md +++ b/riscv-macros/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Fix `cargo doc` errors. - Use fully qualified paths in generated code (i.e., `::riscv` instead of `riscv`) - Moved from `riscv/macros/` to `riscv-macros/` - Now, `riscv::pac_enum` macro only includes trap-related code if `rt` or `rt-v-trap` features are enabled. diff --git a/riscv-macros/src/lib.rs b/riscv-macros/src/lib.rs index 40bf60dd..70830506 100644 --- a/riscv-macros/src/lib.rs +++ b/riscv-macros/src/lib.rs @@ -426,7 +426,7 @@ core::arch::global_asm!(" /// /// # Example /// -/// ```rust +/// ```rust,ignore,no_run /// use riscv::*; /// /// #[repr(usize)] diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index 1c455572..73e4174f 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Add features to documentation that were missing and fix `cargo doc` errors. - Update license to `MIT or Apache-2.0` - Fix clippy warnings in riscv_rt_macros::strip_type_path - Bump MSRV to 1.68 for latest syn 2.0 release diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index 1faf4284..5766daca 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -156,7 +156,7 @@ //! //! Our application would look like this: //! -//! ```no_run +//! ```ignore,no_run //! // src/main.rs //! #![no_main] //! #![no_std] @@ -269,7 +269,7 @@ //! //! ## Example //! -//! ``` no_run +//! ``` ignore,no_run //! extern crate some_allocator; // e.g., embedded_alloc::LlffHeap //! //! extern "C" { @@ -357,7 +357,7 @@ //! //! The following example shows how to implement the `_mp_hook` function in assembly. //! -//! ``` no_run +//! ``` ignore,no_run //! core::arch::global_asm!( //! r#".section .init.mp_hook, "ax" //! .global _mp_hook @@ -433,7 +433,7 @@ //! //! This function can be redefined in the following way: //! -//! ``` no_run +//! ``` ignore,no_run //! #[export_name = "ExceptionHandler"] //! fn custom_exception_handler(trap_frame: &riscv_rt::TrapFrame) -> ! { //! // ... @@ -542,7 +542,7 @@ //! //! The following example shows how to implement the `__pre_init` function in assembly. //! -//! ``` no_run +//! ``` ignore,no_run //! core::arch::global_asm!( //! r#".section .init.pre_init, "ax" //! .global __pre_init @@ -574,6 +574,20 @@ //! //! Skips interrupts setup. //! +//! ## `no-xie-xip` +//! +//! Skips disabling interrupts (to support chips without XIE/XIP CSRs). +//! +//! ## `no-interrupts` +//! +//! Opts out of the default implementation for `_dispatch_core_interrupt` to support platforms +//! with custom core interrupt sources. +//! +//! ## `no-exceptions` +//! +//! Opts out of the default implementation for `_dispatch_exception` to support platforms +//! with custom exception sources. +//! //! ## `s-mode` //! //! Supervisor mode. While most registers/instructions have variants for both `mcause` and @@ -622,7 +636,7 @@ //! //! ### Example //! -//! ```rust,no_run +//! ```rust,ignore,no_run //! core::arch::global_asm!( //! r#" //! .section .trap.start, "ax" @@ -639,6 +653,20 @@ //! "# //! ); //! ``` +//! +//! ## `device` +//! +//! Automatically includes `device.x` (typically provided by PACs to provide weak aliases to interrupt handlers) +//! in the linker script. +//! +//! ## `memory` +//! +//! Automatically includes [`memory.x`](#memoryx) (typically provided by BSPs) in the linker script. +//! +//! ## `defmt` +//! +//! Implements `defmt::Format` on certain types. +//! //! [attr-entry]: attr.entry.html //! [attr-exception]: attr.exception.html //! [attr-external-interrupt]: attr.external_interrupt.html diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index d8c99330..bb73d637 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Fix broken links in register macro doc string. - Moved macros from `./macros/` to `../riscv-macros/` - Updated the license to `MIT or Apache-2.0` - Bump MSRV to 1.68 for latest version of syn 2.0 diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index ef291857..e9e9aabc 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -303,7 +303,7 @@ macro_rules! write_csr_as_usize_rv32 { /// Convenience macro to provide combined read/write of a CSR as a `usize`. /// -/// This composes [`read_csr_as_usize`] and [`write_csr_as_usize`]. Use the +/// This composes [read_csr_as_usize](crate::read_csr_as_usize) and [write_csr_as_usize](crate::write_csr_as_usize). Use the /// `safe` form to get safe wrappers instead of unsafe. #[macro_export] macro_rules! read_write_csr_as_usize {