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

riscv-rt: Implement support for hardware interrupt dispatching #158

Closed
dvc94ch opened this issue Feb 23, 2018 · 5 comments · Fixed by #200
Closed

riscv-rt: Implement support for hardware interrupt dispatching #158

dvc94ch opened this issue Feb 23, 2018 · 5 comments · Fixed by #200

Comments

@dvc94ch
Copy link
Member

dvc94ch commented Feb 23, 2018

Currently there is a single interrupt entry point. RISCV CPU's also have a hardware dispatching mode.

@Disasm
Copy link
Member

Disasm commented Mar 15, 2019

I see two cons for using hardware interrupt dispatching:

  • For each vectored interrupt handler you have to declare register handling code like in asm.S/_start_trap, which will cause additional size overhead.
  • Vectored interrupts are not supported in priv spec 1.9 since they arrived only in priv spec 1.10.

Nevertheless, it's easy to implement "fake" vectored interrupt dispatching with a single trap entry point and two arrays of handler pointers.

@allexoll
Copy link

i've opened an issue over at svd2rust about producing a device.x that could be used for this.

Also, i think the vectored IRQ would break the current trap implementation since pc would jump to BASE+4*cause. I think currently the trap reads the cause and then jumps to the correct handler in the vector table.

the vectored IRQ would use non-vectortable addresses.

bors bot referenced this issue in rust-embedded/svd2rust May 29, 2021
527: add device.x  for riscv targets, and provides __EXTERNAL_INTERRUPTS r=therealprof a=allexoll

This PR is a proposal to address #526 . 

`__EXTERNAL_INTERRUPTS` is the symbol used since `__INTERRUPTS` is used by [riscv-rt](https://github.com/rust-embedded/riscv-rt/blob/47ece5f5163a2e38ce5e4685b5d3145713d7954a/src/lib.rs#L505)

I think it fits because the peripheral interrupts are supposed to be pending through the external interrupt. 

This provides hals with information to manage interrupt request. either through a PLIC or trough the vectored interrupt when that is implemented (in [riscv-rt](https://github.com/rust-embedded/riscv-rt/issues/1) i suppose).

Remarks welcome

Co-authored-by: Alexis Marquet <alexis@alexismarquet.com>
@hegza
Copy link

hegza commented Dec 20, 2022

We stumbled into this in our project. We're using a version of lowRISC Ibex which doesn't support direct mode interrupts at all.

I patched an implementation of riscv-rt that defaults to vectored interrupts and that one seems to be working out for us.

@Disasm Do you think it would be useful work for me to see if some of it can be upstreamed?

If it happens that the implementation causes code bloat, it could be gated with a feature-flag such as "default-vector-traps".

Related: any advice for how to pass user-picked Rust feature-flags as preproc. defines for the assembly compilation unit? I guess the SMODE-feature/define uses something like that?

@romancardenas
Copy link
Contributor

romancardenas commented Mar 13, 2023

I propose a modification to this crate to ease vector-like handling of the external interrupts.
Right now, svd2rust will generate a __EXTERNAL_INTERRUPTS table with all the handlers for the external interrupts of a board. Thus, we could define a DefaultMachineExternal function that takes advantage of this. We would need the following symbols:

  • extern "C" static mut _n_external_interrupts: u16: a symbol that tells the size of the external interrupt array. By default, it can be set to 0. This symbol would be generated by svd2rust.
  • __EXTERNAL_INTERRUPTS: [unsafe extern "C" fn(); _n_external_interrupts]: Array with the handlers of each external interrupt. This can also be generated by svd2rust.
  • fn _get_external_interrupt_n() -> u16: Returns the number of the pending external interrupt with the highest priority. By default, it just returns 0 (i.e., no interrupt). Each PAC should implement its own function. For instance, e310x would call the claim method of the PLIC.
  • fn _clear_external_interrupt(interrupt_n: u16): Helper function to clear the interrupt once it is attended. Each PAC should implement its own function. For instance, e310x would call the complete method of the PLIC.

Having this, we could do a default implementation that looks like this:

#[no_mangle]
fn DefaultMachineExternalHandler() {
    let interrupt_n = _get_external_interrupt_n();
    if interrupt_n < __EXTERNAL_INTERRUPTS.len() {
        __EXTERNAL_INTERRUPTS[interrupt_n]();
       _clear_external_interrupt(interrupt_n);
   } else {
       DefaultInterruptHandler();
   }
}

What do you think?

@romancardenas
Copy link
Contributor

It turns out that my proposed approach wasn't that easy to implement. I developed a macro for doing the same. You can check it in rust-embedded/riscv-rt#113

@romancardenas romancardenas transferred this issue from rust-embedded/riscv-rt Nov 28, 2023
@romancardenas romancardenas changed the title Implement support for hardware interrupt dispatching riscv-rt: Implement support for hardware interrupt dispatching Nov 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants