Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for non-standard exception and interrupts (clean) #223

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

romancardenas
Copy link
Contributor

@romancardenas romancardenas commented Jul 19, 2024

First PR resulting from #211

This PR presents the last version of riscv-pac. Namely, we have a new ExceptionNumber trait.
Also, the InterruptNumber trait now comes with two new marker traits: CoreInterruptNumber and ExternalInterruptNumber.
This will allow us to filter interrupt sources.

Another change is that the InterruptNumber trait now deals with usize instead of u16.
The motivation of this change is the RISC-V ISA specification (there is more information about this in #211)

As a side effect, I also updated the riscv-peripheral trait to use the new approach.

@romancardenas romancardenas requested a review from a team as a code owner July 19, 2024 15:31
@romancardenas romancardenas changed the title riscv-pac: New ExceptionNumber and *InterruptNumber traits riscv-pac: New ExceptionNumber, CoreInterruptNumber, and ExternalInterruptNumber traits Jul 19, 2024
@romancardenas
Copy link
Contributor Author

My only doubt is: should PriorityNumber and HartIdNumber traits work with usize?

I guess u8 and u16 are more than enough for these traits. The PLIC peripheral uses these data formats. However, it is better to make them usize and let each peripheral/library cast them to a smaller data type than adding a breaking change in the future if we eventually find out that the current data types are not enough.

Let me know what you think and I will update this PR accordingly.

@romancardenas romancardenas force-pushed the riscv-pac-only branch 2 times, most recently from 3c24f5e to 7a98baa Compare July 28, 2024 18:06
@romancardenas romancardenas changed the title riscv-pac: New ExceptionNumber, CoreInterruptNumber, and ExternalInterruptNumber traits Support for non-standard exception and interrupts (clean) Jul 28, 2024
@romancardenas
Copy link
Contributor Author

In the end, I pushed all the changes of #211 to this PR, but with a cleaner commit history.

In my last commit, I also added three attribute-like macros in riscv-rt: core_interrupt, external_interrupt, and exception. These macros:

  • Expect an argument with the path to the corresponding interrupt/exception source. This path is used to check at compile time that the item implements the riscv_pac::CoreInterruptNumber, riscv_pac::ExternalInterruptNumber, orriscv_pac::ExceptionNumber, respectively.
  • Check that the signature of the function is correct. In interrupts, there must not be any input parameter. In exceptions, it may be an input parameter with an (mutable) reference to a TrapFrame.
  • It uses the export_name label to set the name of the function to the name of the interrupt/exception source. With this, we can use a more Rustacean name for these functions (i.e., snake_case). Here are a few examples from the empty.rs example of riscv-rt:
use riscv_rt::{core_interrupt, entry, exception, external_interrupt};

use riscv::interrupt::{Exception, Interrupt}; // standard enums that implement the riscv-pac traits

#[core_interrupt(Interrupt::SupervisorTimer)]
unsafe fn supervisor_timer() -> ! {
    // do something here
    loop {}
}

// this won't compile, cause ExternalInterruptNumber trait is not implemented!
// #[external_interrupt(Interrupt::SupervisorSoft)]
// fn supervisor_soft() {
//     // do something here
//     loop {}
// }

#[exception(Exception::Breakpoint)]
unsafe fn breakpoint(_trap: &mut riscv_rt::TrapFrame) -> ! {
    // do something here
    loop {}
}

@rmsyn
Copy link
Contributor

rmsyn commented Jul 28, 2024

My only doubt is: should PriorityNumber and HartIdNumber traits work with usize?

I guess u8 and u16 are more than enough for these traits.

My recommendation would be to stick with usize, since the values read/written by CSRs are usize. Just a suggestion though, no hard preference either way.

riscv-rt/src/exceptions.rs Outdated Show resolved Hide resolved
riscv-rt/src/interrupts.rs Outdated Show resolved Hide resolved
riscv/macros/src/lib.rs Outdated Show resolved Hide resolved
Comment on lines +186 to +190
if sstatus.spie() {
sstatus::set_spie();
}
sstatus::set_spp(sstatus.spp());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar suggestion to the machine interrupt handler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, not sure about what is wrong with the current implementation

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, not sure about what is wrong with the current implementation

Nothing, on second inspection I saw the call to csrrs. I was mistaken before, and thought csrrw was called.

Copy link
Contributor

@rmsyn rmsyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor style suggestions, and a couple suggestions for not clobbering CSR fields in machine + supervisor nested interrupt handlers.

@romancardenas
Copy link
Contributor Author

Ok, so the only thing that I miss is improving the pac_enum macro for custom exceptions, so it also implements the _dispatch_exception function following the same fashion.

I will also use usize for all the riscv-pac traits, I think it will simplify the code.

@romancardenas romancardenas force-pushed the riscv-pac-only branch 2 times, most recently from e36fdc0 to 274df75 Compare August 13, 2024 09:53
@romancardenas
Copy link
Contributor Author

Sorry for the delay, I took a few days off to disconnect.

New stuff in riscv

the pac_enum macro now works for exceptions and interrupts properly. When used in a PAC, the macro will implement the corresponding trait and it will also add the dispatch_* function to work with riscv-rt. In the case of core interrupts, it also generates a vector table, gated under the v-trap feature.

New stuff in riscv-pac

All traits work with usize. Each party can then cast these numbers to the appropriate format for their target.

New stuff in riscv-rt

I added the exception, core_interrupt, and external_interrupt macros to help users define their trap handler functions. These macros expect an input argument with a path to a variant of an enum that must implement the corresponding riscv-pac trait. This is very useful to guarantee at compile time that there is in fact an interrupt/exception source with the name given by the caller.

Another small (but cool) change is that now the link section directive in start_trap_rust only applies to riscv targets. This change allows us to compile riscv-rt on native OSs for further testing (which is the next point).

New internal tests crate

I also wanted to add a few try-build test cases to show how the macros work (as well as having a more robust CI). However, try-build and examples do not get along well in the embedded world. Thus, I thought the easiest way to deal with this is by adding a new crate with all the tests that use try-build. We can sort test cases according to which crate we are testing (so far, I am only using riscv-rt in tests, but we can easily move the riscv test cases there).

Let me know what you think!

Comment on lines +19 to +53
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Trap<I, E> {
Interrupt(I),
Exception(E),
}
Copy link
Contributor

@rmsyn rmsyn Aug 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason you decided to redefine Trap using generics for the interrupt and exception variants?

If this is to allow external users to use a custom Interrupt and Exception type, maybe we could also provide a top-level alias that defaults to the local Interrupt and Exception type?

Something like:

pub type DefaultTrap = Trap<Interrupt, Exception>;

Another option could be to call the generic:

pub enum GenericTrap<I, E> {
// ...
}

with the alias as:

pub type Trap = GenericTrap<Interrupt, Exception>;

With some notes in the docs, I think the custom implementation would be easy to figure out for those that want it.

Using the latter would minimize the effort of integrating the breaking changes, while still allowing external users to define their own Trap type for non-standard interrupts/exceptions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the idea now is updating svd2rust so PACs do this kind of type binding in pac::interrupt. PACs could either re-export the Exception and CoreInterrupt enums that are in riscv or define their custom type. Also the interface with mcause can be adjusted to hide this complexity to final users.

I'll do a PoC and share it with you.

@romancardenas
Copy link
Contributor Author

My PR for svd2rust is already updated and generates a proper pac::interrupt module.

You can check the outcome for the E310x chip here.

@rmsyn , this is perhaps the most interesting fragment of the module:

pub use riscv::{
    interrupt::{disable, enable, free, nested},
    CoreInterruptNumber, ExceptionNumber, HartIdNumber, PriorityNumber,
};
pub type Trap = riscv::interrupt::Trap<CoreInterrupt, Exception>;
#[doc = r" Retrieves the cause of a trap in the current hart."]
#[doc = r""]
#[doc = r" If the raw cause is not a valid interrupt or exception for the target, it returns an error."]
#[inline]
pub fn try_cause() -> riscv::result::Result<Trap> {
    riscv::interrupt::try_cause()
}
#[doc = r" Retrieves the cause of a trap in the current hart (machine mode)."]
#[doc = r""]
#[doc = r" If the raw cause is not a valid interrupt or exception for the target, it panics."]
#[inline]
pub fn cause() -> Trap {
    try_cause().unwrap()
}

The idea is "substituting"/adapting riscv::interrupt to the target. Hope it looks good to you!

@rmsyn
Copy link
Contributor

rmsyn commented Aug 21, 2024

The idea is "substituting"/adapting riscv::interrupt to the target. Hope it looks good to you!

Yes, everything looks awesome!

This is exactly what I was suggesting, except the location of the alias is up a level of abstraction.

I got a little confused when trying to directly upgrade while playing around with the code. Given the context of including these changes in svd2rust and generated pac crates, it makes sense to do the aliasing where you do.

Maybe for those using the riscv registers/functions directly, we could still provide an alias for the defaults inside that crate?

At least, maybe some doc-tests on the pub enum Trap<I, E> type explaining usage?

@romancardenas
Copy link
Contributor Author

I added new docs for riscv::interrupt::Trap<I, E>. I also updated riscv-rt docs to push users to use the riscv_rt::{core_interrupt, exception, external_interrupt} macros instead of #[no_mangle]. Let me know what you think!

Copy link
Contributor

@rmsyn rmsyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know what you think!

LGTM. Awesome work @romancardenas

@romancardenas
Copy link
Contributor Author

I'm enumerating working examples with this PR in svd2rust

@romancardenas
Copy link
Contributor Author

@rust-embedded/riscv I've been updating some crates I work with and everything works fine. I'd say it is ready to merge 😀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RFC: Platform-specific exception codes
2 participants