-
Notifications
You must be signed in to change notification settings - Fork 162
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 "non-standard" interrupts and exceptions #211
Conversation
This PR is being prevented from merging because it presents one of the blocking labels: work in progress, do not merge. |
I think this is a good approach once it's clean and tested. I only had time to skim through it but don't see anything "wrong" with it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes done. Please, take a look and let me know what you think. I personally think that we can improve it considerably. I will comment on the PR with my alternative idea.
Different approach: do not use generics nor enums at all in
|
Thanks for the feedback @rmsyn ! I implemented my alternative approach in the |
That makes sense to me, too. Really either one can work, because the values are read from the
🤷 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I probably need more time to review the proc-macro stuff, but it looks good to me.
After an initial review, I do like the code organization in The unification of one |
So I think the new
|
I found some time to keep working on this. In the new commit, the following code: #[pac_enum(unsafe PriorityNumber)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Priority {
P0 = 0,
P1 = 1,
P2 = 2,
P3 = 3,
} expands to: #[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Priority {
P0 = 0,
P1 = 1,
P2 = 2,
P3 = 3,
}
unsafe impl riscv_pac::PriorityNumber for Priority {
const MAX_PRIORITY_NUMBER: u8 = 3;
#[inline]
fn number(self) -> u8 {
self as _
}
#[inline]
fn from_number(number: u8) -> Result<Self, u8> {
match number {
3 => Ok(Self::P3),
0 => Ok(Self::P0),
1 => Ok(Self::P1),
2 => Ok(Self::P2),
_ => Err(number),
}
}
} On the other hand, the following code: #[pac_enum(unsafe CoreInterruptNumber)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Interrupt {
I1 = 1,
I2 = 2,
I4 = 4,
I7 = 7,
} Expands to: #[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Interrupt {
I1 = 1,
I2 = 2,
I4 = 4,
I7 = 7,
}
unsafe impl riscv_pac::InterruptNumber for Interrupt {
const MAX_INTERRUPT_NUMBER: usize = 7;
#[inline]
fn number(self) -> usize {
self as _
}
#[inline]
fn from_number(number: usize) -> Result<Self, usize> {
match number {
2 => Ok(Self::I2),
1 => Ok(Self::I1),
4 => Ok(Self::I4),
7 => Ok(Self::I7),
_ => Err(number),
}
}
}
unsafe impl riscv_pac::CoreInterruptNumber for Interrupt {} // it also implements the marker trait
// It declares the existence of all the interrupt handlers
extern "C" {
fn I2();
fn I1();
fn I4();
fn I7();
}
// It generates the array with handlers
#[no_mangle]
pub static __CORE_INTERRUPTS: [Option<unsafe extern "C" fn()>; 7 + 1] = [
None,
Some(I1),
Some(I2),
None,
Some(I4),
None,
None,
Some(I7),
];
// It implements the interrupt dispatching function
#[no_mangle]
unsafe extern "C" fn _dispatch_core_interrupt(code: usize) {
extern "C" {
fn DefaultHandler();
}
if code < __CORE_INTERRUPTS.len() {
let h = &__CORE_INTERRUPTS[code];
if let Some(handler) = h {
handler();
} else {
DefaultHandler();
}
} else {
DefaultHandler();
}
} It should work as is for direct mode. I still need to adapt this solution to vectored mode. |
3de1f9d
to
db6c2f9
Compare
It already creates the interrupt vector table. However, I think we should discuss the new approach with the @rust-embedded/tools team to align |
riscv/Cargo.toml
Outdated
@@ -26,3 +26,4 @@ critical-section-single-hart = ["critical-section/restore-state-bool"] | |||
[dependencies] | |||
critical-section = "1.1.2" | |||
embedded-hal = "1.0.0" | |||
riscv-pac = { path = "../riscv-pac", version = "0.1.2", default-features = false } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to add an extra feature
to the riscv
crate to enable the vectors feature in riscv-pac
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So far, riscv-pac
only has a default feature to opt out of procedural macros (i.e., syn
, proc-macro2
, and quote
dependencies). However, I don't know if this effort is worthy it, as in the end, you will end up using riscv-rt
, which depends on procedural macros.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we could do something like:
[features]
default = ["riscv-pac/default"]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor style nit, and a quick question about a exposing riscv-pac
features in riscv
.
LGTM
Exciting times! I think the I will wait until #222 is solved and merge the outcome, so we can adapt the work to the new approach. |
Co-authored-by: rmsyn <[email protected]>
I updated this PR to use the new features coming from #222 . This branch is quite a mess. I will divide it into small PRs so it will be easier to review. PS: Rust nightly is complaining about a bug in LLVM for inline assembly with x86 targets. I think it is a matter of time that the error message dissapears: rust-lang/rust#127935 |
One potential way to solve that issue before the fix makes it into a nightly release could be to feature-gate all assembly with: #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
... |
The thing is that it still complains for RISC-V targets :/ |
What about switching the label to |
fixed |
Closing this PR in favor of #223 , which has a cleaner commit history and cooler macros for defining interrupt and exception handlers |
Currently, the
riscv
andriscv-rt
crates assume that the interrupt and exception sources are the ones gathered in the RISCV ISA. However, we do not support target-specific sources. Moreover, some RISC-V targets do not follow the standard interrupt scheme (e.g., ESP32 C3). Another example is the E310x microcontroller, which does not support supervisor interrupt sources.Proposal
Now that we have the
riscv-pac
trait to define interrupt and exception sources, we should be able to adapt the rest of the crates to rely on generic functions with constraints to these traits. For example, themcause
register can have something like this:By default,
I
andE
should be the standard enumerations (as we are doing now). Still, PACs will be able to opt out of this default implementation and provide their custom interrupt/exception enumeration.Next, we can enrich
riscv-rt
macros to automatically generate the necessary code for letting PACs inject their custom interrupt and exception tables. Also, in the case of vectored mode, we could generate the necessary vector table and so on.NOTE THAT THIS IS JUST MY PROPOSAL, but I would love to hear your opinion as well as clever mechanisms to implement this neatly.
I will do a self-review to point out some to-dos that I would like to discuss with you.
Solves #146