Skip to content

Commit

Permalink
fix nested interrupts
Browse files Browse the repository at this point in the history
  • Loading branch information
romancardenas committed Jun 22, 2023
1 parent 359e21b commit f3a98f7
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 12 deletions.
29 changes: 21 additions & 8 deletions hifive1-test/examples/hifive1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,48 @@ use riscv_rt::entry;

// generate SLIC code for this example, only adding a HW binding for RTC
// and a purely software SoftLow interrupt
riscv_slic::codegen!(e310x, [RTC], [SoftLow]);
riscv_slic::codegen!(e310x, [RTC], [SoftLow, SoftHigh]);
use slic::Interrupt; // Re-export of automatically generated enum of interrupts in previous macro

/// HW handler for clearing RTC.
/// We must define a ClearX handler for every bypassed HW interrupt
#[allow(non_snake_case)]
#[no_mangle]
unsafe fn ClearRTC() {
sprintln!("!start ClearRTC");
// increase rtccmp to clear HW interrupt
let rtc = DeviceResources::steal().peripherals.RTC;
let rtccmp = rtc.rtccmp.read().bits();
sprintln!("clear RTC (rtccmp = {})", rtccmp);
rtc.rtccmp.write(|w| w.bits(rtccmp + 65536));
// we also pend the lowest priority SW task before the RTC SW task is automatically pended
riscv_slic::pend(Interrupt::SoftLow);
rtc.rtccmp.write(|w| w.bits(rtccmp + 65536 * 2));
sprintln!("!stop ClearRTC (rtccmp = {})", rtccmp);
}

/// SW handler for RTC.
/// This task is automatically pended right after executing ClearRTC.
#[allow(non_snake_case)]
#[no_mangle]
unsafe fn RTC() {
sprintln!("software RTC");
sprintln!(" start RTC");
riscv_slic::pend(Interrupt::SoftLow);
sprintln!(" middle RTC");
riscv_slic::pend(Interrupt::SoftHigh);
sprintln!(" stop RTC");
}

/// SW handler for SoftLow (low priority task with no HW binding).
#[allow(non_snake_case)]
#[no_mangle]
unsafe fn SoftLow() {
sprintln!("software SoftLow");
sprintln!("start SoftLow");
sprintln!("stop SoftLow");
}

/// SW handler for SoftHigh (high priority task with no HW binding).
#[allow(non_snake_case)]
#[no_mangle]
unsafe fn SoftHigh() {
sprintln!(" start SoftHigh");
sprintln!(" stop SoftHigh");
}

#[entry]
Expand Down Expand Up @@ -73,7 +85,8 @@ fn main() -> ! {
// Configure SLIC
unsafe {
riscv_slic::set_priority(Interrupt::SoftLow, 1); // low priority
riscv_slic::set_priority(Interrupt::RTC, 2); // high priority
riscv_slic::set_priority(Interrupt::RTC, 2); // medium priority
riscv_slic::set_priority(Interrupt::SoftHigh, 3); // high priority
}

// Configure RTC
Expand Down
10 changes: 6 additions & 4 deletions riscv-slic-macros/src/swi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ pub fn swi_mod(swi_handlers: &[Ident]) -> TokenStream {
#[no_mangle]
#[allow(non_snake_case)]
pub unsafe fn MachineSoft() {
swi_clear(); // We clear the interrupt flag at the beginning to allow nested interrupts
while let Some((priority, interrupt)) = __SLIC.pop() {
riscv_slic::run(priority, || __SOFTWARE_INTERRUPTS[interrupt as usize]());
}
swi_clear(); // We clear the software interrupt flag to allow nested interrupts
riscv_slic::nested_isr(|| {
while let Some((priority, interrupt)) = __SLIC.pop() {
riscv_slic::run(priority, || __SOFTWARE_INTERRUPTS[interrupt as usize]());
}
});
}
)
}
19 changes: 19 additions & 0 deletions riscv-slic/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,25 @@ pub unsafe fn set_interrupts() {
mie::set_msoft();
}

/// Utility function to call an ISR while enabling nested interrupts.
/// Source: https://www.five-embeddev.com/code/2022/06/29/nested-interrupts/
pub unsafe fn nested_isr(f: impl FnOnce()) {
// store mstatus and mepc
let mstatus = riscv::register::mstatus::read();
let mepc = riscv::register::mepc::read();

riscv::register::mstatus::set_mie(); // re-enable interrupts
f(); // call the ISR
riscv::register::mstatus::clear_mie(); // disable interrupts

// restore mstatus and mepc
if mstatus.mpie() {
riscv::register::mstatus::set_mpie();
}
riscv::register::mstatus::set_mpp(mstatus.mpp());
riscv::register::mepc::write(mepc);
}

/// Stabilized API for changing the threshold of the SLIC.
///
/// # Safety
Expand Down

0 comments on commit f3a98f7

Please sign in to comment.