Skip to content

Commit ce9a296

Browse files
committed
Update docs
1 parent a84b43d commit ce9a296

14 files changed

+91
-85
lines changed

riscv-rt/src/lib.rs

+46-70
Original file line numberDiff line numberDiff line change
@@ -270,34 +270,24 @@
270270
//! ### Core exception handlers
271271
//!
272272
//! This functions are called when corresponding exception occurs.
273-
//! You can define an exception handler with one of the following names:
274-
//! * `InstructionMisaligned`
275-
//! * `InstructionFault`
276-
//! * `IllegalInstruction`
277-
//! * `Breakpoint`
278-
//! * `LoadMisaligned`
279-
//! * `LoadFault`
280-
//! * `StoreMisaligned`
281-
//! * `StoreFault`
282-
//! * `UserEnvCall`
283-
//! * `SupervisorEnvCall`
284-
//! * `MachineEnvCall`
285-
//! * `InstructionPageFault`
286-
//! * `LoadPageFault`
287-
//! * `StorePageFault`
273+
//! You can define an exception handler with the [`exception`] attribute.
274+
//! The attribute expects the path to the exception source as an argument.
275+
//!
276+
//! The [`exception`] attribute ensures at compile time that there is a valid
277+
//! exception source for the given handler.
288278
//!
289279
//! For example:
290280
//! ``` no_run
291-
//! #[export_name = "MachineEnvCall"]
292-
//! fn custom_menv_call_handler(trap_frame: &riscv_rt::TrapFrame) {
293-
//! // ...
281+
//! use riscv::interrupt::Exception; // or a target-specific exception enum
282+
//!
283+
//! #[riscv_rt::exception(Exception::MachineEnvCall)]
284+
//! fn custom_menv_call_handler(trap_frame: &mut riscv_rt::TrapFrame) {
285+
//! todo!()
294286
//! }
295-
//! ```
296-
//! or
297-
//! ``` no_run
298-
//! #[no_mangle]
299-
//! fn MachineEnvCall(trap_frame: &riscv_rt::TrapFrame) -> ! {
300-
//! // ...
287+
//!
288+
//! #[riscv_rt::exception(Exception::LoadFault)]
289+
//! fn custom_load_fault_handler() -> ! {
290+
//! loop {}
301291
//! }
302292
//! ```
303293
//!
@@ -320,72 +310,73 @@
320310
//! or
321311
//! ``` no_run
322312
//! #[no_mangle]
323-
//! fn ExceptionHandler(trap_frame: &riscv_rt::TrapFrame) -> ! {
313+
//! fn ExceptionHandler(trap_frame: &mut riscv_rt::TrapFrame) {
324314
//! // ...
325315
//! }
326316
//! ```
327317
//!
328318
//! Default implementation of this function stucks in a busy-loop.
329319
//!
330-
//!
331320
//! ### Core interrupt handlers
332321
//!
333322
//! This functions are called when corresponding interrupt is occured.
334-
//! You can define an interrupt handler with one of the following names:
335-
//! * `SupervisorSoft`
336-
//! * `MachineSoft`
337-
//! * `SupervisorTimer`
338-
//! * `MachineTimer`
339-
//! * `SupervisorExternal`
340-
//! * `MachineExternal`
323+
//! You can define a core interrupt handler with the [`core_interrupt`] attribute.
324+
//! The attribute expects the path to the interrupt source as an argument.
325+
//!
326+
//! The [`core_interrupt`] attribute ensures at compile time that there is a valid
327+
//! core interrupt source for the given handler.
341328
//!
342329
//! For example:
343330
//! ``` no_run
344-
//! #[export_name = "MachineTimer"]
345-
//! fn custom_timer_handler() {
346-
//! // ...
331+
//! use riscv::interrupt::Interrupt; // or a target-specific core interrupt enum
332+
//!
333+
//! #[riscv_rt::core_interrupt(Interrupt::MachineSoft)]
334+
//! unsafe fn custom_machine_soft_handler() {
335+
//! todo!()
347336
//! }
348-
//! ```
349-
//! or
350-
//! ``` no_run
351-
//! #[no_mangle]
352-
//! fn MachineTimer() {
353-
//! // ...
337+
//!
338+
//! #[riscv_rt::core_interrupt(Interrupt::MachineTimer)]
339+
//! fn custom_machine_timer_handler() -> ! {
340+
//! loop {}
354341
//! }
355342
//! ```
356343
//!
357-
//! You can also use the `#[interrupt]` macro to define interrupt handlers:
344+
//! In vectored mode, this macro will also generate a proper trap handler for the interrupt.
358345
//!
359-
//! ``` no_run
360-
//! #[riscv_rt::interrupt]
361-
//! fn MachineTimer() {
362-
//! // ...
363-
//! }
364-
//! ```
346+
//! If interrupt handler is not explicitly defined, `DefaultHandler` is called.
347+
//!
348+
//! ### External interrupt handlers
349+
//!
350+
//! This functions are called when corresponding interrupt is occured.
351+
//! You can define an external interrupt handler with the [`external_interrupt`] attribute.
352+
//! The attribute expects the path to the interrupt source as an argument.
365353
//!
366-
//! In direct mode, this macro is equivalent to defining a function with the same name.
367-
//! However, in vectored mode, this macro will generate a proper trap handler for the interrupt.
354+
//! The [`external_interrupt`] attribute ensures at compile time that there is a valid
355+
//! external interrupt source for the given handler.
356+
//! Note that external interrupts are target-specific and may not be available on all platforms.
368357
//!
369358
//! If interrupt handler is not explicitly defined, `DefaultHandler` is called.
370359
//!
371360
//! ### `DefaultHandler`
372361
//!
373362
//! This function is called when interrupt without defined interrupt handler is occured.
374363
//! The interrupt reason can be decoded from the `mcause`/`scause` register.
364+
//! If it is an external interrupt, the interrupt reason can be decoded from a
365+
//! target-specific peripheral interrupt controller.
375366
//!
376367
//! This function can be redefined in the following way:
377368
//!
378369
//! ``` no_run
379370
//! #[export_name = "DefaultHandler"]
380-
//! fn custom_interrupt_handler() {
371+
//! unsafe fn custom_interrupt_handler() {
381372
//! // ...
382373
//! }
383374
//! ```
384375
//! or
385376
//! ``` no_run
386377
//! #[no_mangle]
387-
//! fn DefaultHandler() {
388-
//! // ...
378+
//! fn DefaultHandler() -> ! {
379+
//! loop {}
389380
//! }
390381
//! ```
391382
//!
@@ -436,22 +427,7 @@
436427
//! riscv-rt = {features=["v-trap"]}
437428
//! ```
438429
//! When the vectored trap feature is enabled, the trap vector is set to `_vector_table` in vectored mode.
439-
//! This table is a list of `j _start_INTERRUPT_trap` instructions, where `INTERRUPT` is the name of the interrupt.
440-
//!
441-
//! ### Defining interrupt handlers in vectored mode
442-
//!
443-
//! In vectored mode, each interrupt must also have a corresponding trap handler.
444-
//! Therefore, using `export_name` or `no_mangle` is not enough to define an interrupt handler.
445-
//! The [`interrupt`] macro will generate the trap handler for the interrupt:
446-
//!
447-
//! ``` no_run
448-
//! #[riscv_rt::interrupt]
449-
//! fn MachineTimer() {
450-
//! // ...
451-
//! }
452-
//! ```
453-
//!
454-
//! This will generate a function named `_start_MachineTimer_trap` that calls the interrupt handler `MachineTimer`.
430+
//! This table is a list of `j _start_INTERRUPT_trap` instructions, where `INTERRUPT` is the name of the core interrupt.
455431
//!
456432
//! ## `u-boot`
457433
//!

riscv/Cargo.toml

-4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,3 @@ critical-section = "1.1.2"
2929
embedded-hal = "1.0.0"
3030
riscv-pac = { path = "../riscv-pac", version = "0.2.0" }
3131
riscv-macros = { path = "macros", version = "0.1.0", optional = true }
32-
33-
[dev-dependencies]
34-
trybuild = "1.0"
35-
riscv-rt = { path = "../riscv-rt", version = "0.13.0" }

riscv/src/interrupt.rs

+31-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,37 @@ pub use machine::*;
1515
#[cfg(feature = "s-mode")]
1616
pub use supervisor::*;
1717

18-
/// Trap Cause
18+
/// Trap Cause.
19+
///
20+
/// This enum represents the cause of a trap. It can be either an interrupt or an exception.
21+
/// The [`mcause`](crate::register::mcause::Mcause::cause) and
22+
/// [`scause`](crate::register::scause::Scause::cause) registers return a value of this type.
23+
/// However, the trap cause is represented as raw numbers. To get a target-specific trap cause,
24+
/// use [`Trap::try_into`] with your target-specific M-Mode or S-Mode trap cause types.
25+
///
26+
/// # Example
27+
///
28+
/// In targets that comply with the RISC-V standard, you can use the standard
29+
/// [`Interrupt`] and [`Exception`] enums to represent the trap cause:
30+
///
31+
/// ```no_run
32+
/// use riscv::interrupt::{Trap, Interrupt, Exception};
33+
/// use riscv::register::mcause;
34+
///
35+
/// let raw_trap: Trap<usize, usize> = mcause::read().cause();
36+
/// let standard_trap: Trap<Interrupt, Exception> = raw_trap.try_into().unwrap();
37+
/// ```
38+
///
39+
/// Targets that do not comply with the RISC-V standard usually have their own interrupt and exceptions.
40+
/// You can find these types in the target-specific PAC. If it has been generated with `svd2rust`,
41+
/// you can use the `pac::interrupt::CoreInterrupt` and `pac::interrupt::Exception` enums:
42+
///
43+
/// ```ignore,no_run
44+
/// use riscv::interrupt::Trap;
45+
/// use pac::interrupt::{CoreInterrupt, Exception}; // pac is the target-specific PAC
46+
///
47+
/// let standard_trap: Trap<CoreInterrupt, Exception> = pac::interrupt::cause();
48+
/// ```
1949
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2050
pub enum Trap<I, E> {
2151
Interrupt(I),

riscv/src/interrupt/supervisor.rs

+1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ where
153153
}
154154

155155
/// Execute closure `f` with interrupts enabled in the current hart (supervisor mode).
156+
///
156157
/// This method is assumed to be called within an interrupt handler, and allows
157158
/// nested interrupts to occur. After the closure `f` is executed, the [`sstatus`]
158159
/// and [`sepc`] registers are properly restored to their previous values.

riscv/tests/test.rs

-6
This file was deleted.

tests/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ edition = "2021"
55

66
[dependencies]
77
riscv = { path = "../riscv", version = "0.12.0" }
8-
riscv-rt = { path = "../riscv-rt", version = "0.13.0" }
8+
riscv-rt = { path = "../riscv-rt", version = "0.13.0", features = ["no-exceptions", "no-interrupts"]}
99
trybuild = "1.0"

riscv/tests/ui/fail_empty_macro.stderr renamed to tests/tests/riscv/fail_empty_macro.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: unexpected end of input, expected `unsafe`
2-
--> tests/ui/fail_empty_macro.rs:1:1
2+
--> tests/riscv/fail_empty_macro.rs:1:1
33
|
44
1 | #[riscv::pac_enum]
55
| ^^^^^^^^^^^^^^^^^^
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: expected `unsafe`
2-
--> tests/ui/fail_no_unsafe.rs:1:19
2+
--> tests/riscv/fail_no_unsafe.rs:1:19
33
|
44
1 | #[riscv::pac_enum(InterruptNumber)]
55
| ^^^^^^^^^^^^^^^
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: Unknown trait name. Expected: 'ExceptionNumber', 'CoreInterruptNumber', 'ExternalInterruptNumber', 'PriorityNumber', or 'HartIdNumber'
2-
--> tests/ui/fail_unknown_trait.rs:1:26
2+
--> tests/riscv/fail_unknown_trait.rs:1:26
33
|
44
1 | #[riscv::pac_enum(unsafe InterruptNumber)]
55
| ^^^^^^^^^^^^^^^
File renamed without changes.

tests/tests/test.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
#[test]
2+
fn riscv() {
3+
let t = trybuild::TestCases::new();
4+
5+
t.compile_fail("tests/riscv/fail_*.rs");
6+
t.pass("tests/riscv/pass_*.rs");
7+
}
8+
19
#[test]
210
fn riscv_rt() {
311
let t = trybuild::TestCases::new();
12+
413
t.compile_fail("tests/riscv-rt/*/fail_*.rs");
514
t.pass("tests/riscv-rt/*/pass_*.rs");
615
}

0 commit comments

Comments
 (0)