Skip to content

Commit

Permalink
Update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
romancardenas committed Aug 21, 2024
1 parent 27dbf23 commit c298a2f
Show file tree
Hide file tree
Showing 12 changed files with 84 additions and 84 deletions.
116 changes: 46 additions & 70 deletions riscv-rt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,34 +270,24 @@
//! ### Core exception handlers
//!
//! This functions are called when corresponding exception occurs.
//! You can define an exception handler with one of the following names:
//! * `InstructionMisaligned`
//! * `InstructionFault`
//! * `IllegalInstruction`
//! * `Breakpoint`
//! * `LoadMisaligned`
//! * `LoadFault`
//! * `StoreMisaligned`
//! * `StoreFault`
//! * `UserEnvCall`
//! * `SupervisorEnvCall`
//! * `MachineEnvCall`
//! * `InstructionPageFault`
//! * `LoadPageFault`
//! * `StorePageFault`
//! You can define an exception handler with the [`exception`] attribute.
//! The attribute expects the path to the exception source as an argument.
//!
//! The [`exception`] attribute ensures at compile time that there is a valid
//! exception source for the given handler.
//!
//! For example:
//! ``` no_run
//! #[export_name = "MachineEnvCall"]
//! fn custom_menv_call_handler(trap_frame: &riscv_rt::TrapFrame) {
//! // ...
//! use riscv::interrupt::Exception; // or a target-specific exception enum
//!
//! #[riscv_rt::exception(Exception::MachineEnvCall)]
//! fn custom_menv_call_handler(trap_frame: &mut riscv_rt::TrapFrame) {
//! todo!()
//! }
//! ```
//! or
//! ``` no_run
//! #[no_mangle]
//! fn MachineEnvCall(trap_frame: &riscv_rt::TrapFrame) -> ! {
//! // ...
//!
//! #[riscv_rt::exception(Exception::LoadFault)]
//! fn custom_load_fault_handler() -> ! {
//! loop {}
//! }
//! ```
//!
Expand All @@ -320,72 +310,73 @@
//! or
//! ``` no_run
//! #[no_mangle]
//! fn ExceptionHandler(trap_frame: &riscv_rt::TrapFrame) -> ! {
//! fn ExceptionHandler(trap_frame: &mut riscv_rt::TrapFrame) {
//! // ...
//! }
//! ```
//!
//! Default implementation of this function stucks in a busy-loop.
//!
//!
//! ### Core interrupt handlers
//!
//! This functions are called when corresponding interrupt is occured.
//! You can define an interrupt handler with one of the following names:
//! * `SupervisorSoft`
//! * `MachineSoft`
//! * `SupervisorTimer`
//! * `MachineTimer`
//! * `SupervisorExternal`
//! * `MachineExternal`
//! You can define a core interrupt handler with the [`core_interrupt`] attribute.
//! The attribute expects the path to the interrupt source as an argument.
//!
//! The [`core_interrupt`] attribute ensures at compile time that there is a valid
//! core interrupt source for the given handler.
//!
//! For example:
//! ``` no_run
//! #[export_name = "MachineTimer"]
//! fn custom_timer_handler() {
//! // ...
//! use riscv::interrupt::Interrupt; // or a target-specific core interrupt enum
//!
//! #[riscv_rt::core_interrupt(Interrupt::MachineSoft)]
//! unsafe fn custom_machine_soft_handler() {
//! todo!()
//! }
//! ```
//! or
//! ``` no_run
//! #[no_mangle]
//! fn MachineTimer() {
//! // ...
//!
//! #[riscv_rt::core_interrupt(Interrupt::MachineTimer)]
//! fn custom_machine_timer_handler() -> ! {
//! loop {}
//! }
//! ```
//!
//! You can also use the `#[interrupt]` macro to define interrupt handlers:
//! In vectored mode, this macro will also generate a proper trap handler for the interrupt.
//!
//! ``` no_run
//! #[riscv_rt::interrupt]
//! fn MachineTimer() {
//! // ...
//! }
//! ```
//! If interrupt handler is not explicitly defined, `DefaultHandler` is called.
//!
//! ### External interrupt handlers
//!
//! This functions are called when corresponding interrupt is occured.
//! You can define an external interrupt handler with the [`external_interrupt`] attribute.
//! The attribute expects the path to the interrupt source as an argument.
//!
//! In direct mode, this macro is equivalent to defining a function with the same name.
//! However, in vectored mode, this macro will generate a proper trap handler for the interrupt.
//! The [`external_interrupt`] attribute ensures at compile time that there is a valid
//! external interrupt source for the given handler.
//! Note that external interrupts are target-specific and may not be available on all platforms.
//!
//! If interrupt handler is not explicitly defined, `DefaultHandler` is called.
//!
//! ### `DefaultHandler`
//!
//! This function is called when interrupt without defined interrupt handler is occured.
//! The interrupt reason can be decoded from the `mcause`/`scause` register.
//! If it is an external interrupt, the interrupt reason can be decoded from a
//! target-specific peripheral interrupt controller.
//!
//! This function can be redefined in the following way:
//!
//! ``` no_run
//! #[export_name = "DefaultHandler"]
//! fn custom_interrupt_handler() {
//! unsafe fn custom_interrupt_handler() {
//! // ...
//! }
//! ```
//! or
//! ``` no_run
//! #[no_mangle]
//! fn DefaultHandler() {
//! // ...
//! fn DefaultHandler() -> ! {
//! loop {}
//! }
//! ```
//!
Expand Down Expand Up @@ -436,22 +427,7 @@
//! riscv-rt = {features=["v-trap"]}
//! ```
//! When the vectored trap feature is enabled, the trap vector is set to `_vector_table` in vectored mode.
//! This table is a list of `j _start_INTERRUPT_trap` instructions, where `INTERRUPT` is the name of the interrupt.
//!
//! ### Defining interrupt handlers in vectored mode
//!
//! In vectored mode, each interrupt must also have a corresponding trap handler.
//! Therefore, using `export_name` or `no_mangle` is not enough to define an interrupt handler.
//! The [`interrupt`] macro will generate the trap handler for the interrupt:
//!
//! ``` no_run
//! #[riscv_rt::interrupt]
//! fn MachineTimer() {
//! // ...
//! }
//! ```
//!
//! This will generate a function named `_start_MachineTimer_trap` that calls the interrupt handler `MachineTimer`.
//! This table is a list of `j _start_INTERRUPT_trap` instructions, where `INTERRUPT` is the name of the core interrupt.

// NOTE: Adapted from cortex-m/src/lib.rs
#![no_std]
Expand Down
4 changes: 0 additions & 4 deletions riscv/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,3 @@ critical-section = "1.1.2"
embedded-hal = "1.0.0"
riscv-pac = { path = "../riscv-pac", version = "0.2.0" }
riscv-macros = { path = "macros", version = "0.1.0", optional = true }

[dev-dependencies]
trybuild = "1.0"
riscv-rt = { path = "../riscv-rt", version = "0.13.0" }
32 changes: 31 additions & 1 deletion riscv/src/interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,37 @@ pub use machine::*;
#[cfg(feature = "s-mode")]
pub use supervisor::*;

/// Trap Cause
/// Trap Cause.
///
/// This enum represents the cause of a trap. It can be either an interrupt or an exception.
/// The [`mcause`](crate::register::mcause::Mcause::cause) and
/// [`scause`](crate::register::scause::Scause::cause) registers return a value of this type.
/// However, the trap cause is represented as raw numbers. To get a target-specific trap cause,
/// use [`Trap::try_into`] with your target-specific M-Mode or S-Mode trap cause types.
///
/// # Example
///
/// In targets that comply with the RISC-V standard, you can use the standard
/// [`Interrupt`] and [`Exception`] enums to represent the trap cause:
///
/// ```no_run
/// use riscv::interrupt::{Trap, Interrupt, Exception};
/// use riscv::register::mcause;
///
/// let raw_trap: Trap<usize, usize> = mcause::read().cause();
/// let standard_trap: Trap<Interrupt, Exception> = raw_trap.try_into().unwrap();
/// ```
///
/// Targets that do not comply with the RISC-V standard usually have their own interrupt and exceptions.
/// You can find these types in the target-specific PAC. If it has been generated with `svd2rust`,
/// you can use the `pac::interrupt::CoreInterrupt` and `pac::interrupt::Exception` enums:
///
/// ```ignore,no_run
/// use riscv::interrupt::Trap;
/// use pac::interrupt::{CoreInterrupt, Exception}; // pac is the target-specific PAC
///
/// let standard_trap: Trap<CoreInterrupt, Exception> = pac::interrupt::cause();
/// ```
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Trap<I, E> {
Interrupt(I),
Expand Down
6 changes: 0 additions & 6 deletions riscv/tests/test.rs

This file was deleted.

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: unexpected end of input, expected `unsafe`
--> tests/ui/fail_empty_macro.rs:1:1
--> tests/riscv/fail_empty_macro.rs:1:1
|
1 | #[riscv::pac_enum]
| ^^^^^^^^^^^^^^^^^^
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: expected `unsafe`
--> tests/ui/fail_no_unsafe.rs:1:19
--> tests/riscv/fail_no_unsafe.rs:1:19
|
1 | #[riscv::pac_enum(InterruptNumber)]
| ^^^^^^^^^^^^^^^
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: Unknown trait name. Expected: 'ExceptionNumber', 'CoreInterruptNumber', 'ExternalInterruptNumber', 'PriorityNumber', or 'HartIdNumber'
--> tests/ui/fail_unknown_trait.rs:1:26
--> tests/riscv/fail_unknown_trait.rs:1:26
|
1 | #[riscv::pac_enum(unsafe InterruptNumber)]
| ^^^^^^^^^^^^^^^
File renamed without changes.
4 changes: 4 additions & 0 deletions tests/tests/test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#[test]
fn riscv_rt() {
let t = trybuild::TestCases::new();

t.compile_fail("tests/riscv/fail_*.rs");
t.pass("tests/riscv/pass_*.rs");

t.compile_fail("tests/riscv-rt/*/fail_*.rs");
t.pass("tests/riscv-rt/*/pass_*.rs");
}

0 comments on commit c298a2f

Please sign in to comment.