From 03e56ecc8023b28ac8823a6279686a7441c712a9 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Sun, 1 Sep 2024 17:28:29 +0100 Subject: [PATCH] Fix powman_test so it runs on Arm and RISC-V. 1) Use the Machine Timer, not the cycle counter 2) Use the hal::arch module to control interrupts 3) Write a MachineExternal interrupt handler which asks Xh3irq which interrupt to run next, and then runs it. Note: we lose the macros that do that static-mut hack for us. Maybe we can add that back in later. --- rp235x-hal-examples/riscv_examples.txt | 1 + rp235x-hal-examples/rp235x_riscv.x | 45 ++ rp235x-hal-examples/src/bin/powman_test.rs | 59 +-- rp235x-hal/src/arch.rs | 543 +++++++++++++++++++-- 4 files changed, 569 insertions(+), 79 deletions(-) diff --git a/rp235x-hal-examples/riscv_examples.txt b/rp235x-hal-examples/riscv_examples.txt index 9dc23f7b0..adda18eaa 100644 --- a/rp235x-hal-examples/riscv_examples.txt +++ b/rp235x-hal-examples/riscv_examples.txt @@ -17,6 +17,7 @@ pio_dma pio_proc_blink pio_side_set pio_synchronized +powman_test pwm_blink pwm_blink_embedded_hal_1 rom_funcs diff --git a/rp235x-hal-examples/rp235x_riscv.x b/rp235x-hal-examples/rp235x_riscv.x index ac355eab4..aa2ce9d1f 100644 --- a/rp235x-hal-examples/rp235x_riscv.x +++ b/rp235x-hal-examples/rp235x_riscv.x @@ -80,6 +80,51 @@ PROVIDE(__pre_init = default_pre_init); /* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */ PROVIDE(_setup_interrupts = default_setup_interrupts); +PROVIDE(TIMER0_IRQ_0 = DefaultIrqHandler); +PROVIDE(TIMER0_IRQ_1 = DefaultIrqHandler); +PROVIDE(TIMER0_IRQ_2 = DefaultIrqHandler); +PROVIDE(TIMER0_IRQ_3 = DefaultIrqHandler); +PROVIDE(TIMER1_IRQ_0 = DefaultIrqHandler); +PROVIDE(TIMER1_IRQ_1 = DefaultIrqHandler); +PROVIDE(TIMER1_IRQ_2 = DefaultIrqHandler); +PROVIDE(TIMER1_IRQ_3 = DefaultIrqHandler); +PROVIDE(PWM_IRQ_WRAP_0 = DefaultIrqHandler); +PROVIDE(PWM_IRQ_WRAP_1 = DefaultIrqHandler); +PROVIDE(DMA_IRQ_0 = DefaultIrqHandler); +PROVIDE(DMA_IRQ_1 = DefaultIrqHandler); +PROVIDE(DMA_IRQ_2 = DefaultIrqHandler); +PROVIDE(DMA_IRQ_3 = DefaultIrqHandler); +PROVIDE(USBCTRL_IRQ = DefaultIrqHandler); +PROVIDE(PIO0_IRQ_0 = DefaultIrqHandler); +PROVIDE(PIO0_IRQ_1 = DefaultIrqHandler); +PROVIDE(PIO1_IRQ_0 = DefaultIrqHandler); +PROVIDE(PIO1_IRQ_1 = DefaultIrqHandler); +PROVIDE(PIO2_IRQ_0 = DefaultIrqHandler); +PROVIDE(PIO2_IRQ_1 = DefaultIrqHandler); +PROVIDE(IO_IRQ_BANK0 = DefaultIrqHandler); +PROVIDE(IO_IRQ_BANK0_NS = DefaultIrqHandler); +PROVIDE(IO_IRQ_QSPI = DefaultIrqHandler); +PROVIDE(IO_IRQ_QSPI_NS = DefaultIrqHandler); +PROVIDE(SIO_IRQ_FIFO = DefaultIrqHandler); +PROVIDE(SIO_IRQ_BELL = DefaultIrqHandler); +PROVIDE(SIO_IRQ_FIFO_NS = DefaultIrqHandler); +PROVIDE(SIO_IRQ_BELL_NS = DefaultIrqHandler); +PROVIDE(SIO_IRQ_MTIMECMP = DefaultIrqHandler); +PROVIDE(CLOCKS_IRQ = DefaultIrqHandler); +PROVIDE(SPI0_IRQ = DefaultIrqHandler); +PROVIDE(SPI1_IRQ = DefaultIrqHandler); +PROVIDE(UART0_IRQ = DefaultIrqHandler); +PROVIDE(UART1_IRQ = DefaultIrqHandler); +PROVIDE(ADC_IRQ_FIFO = DefaultIrqHandler); +PROVIDE(I2C0_IRQ = DefaultIrqHandler); +PROVIDE(I2C1_IRQ = DefaultIrqHandler); +PROVIDE(OTP_IRQ = DefaultIrqHandler); +PROVIDE(TRNG_IRQ = DefaultIrqHandler); +PROVIDE(PLL_SYS_IRQ = DefaultIrqHandler); +PROVIDE(PLL_USB_IRQ = DefaultIrqHandler); +PROVIDE(POWMAN_IRQ_POW = DefaultIrqHandler); +PROVIDE(POWMAN_IRQ_TIMER = DefaultIrqHandler); + /* # Multi-processing hook function fn _mp_hook() -> bool; diff --git a/rp235x-hal-examples/src/bin/powman_test.rs b/rp235x-hal-examples/src/bin/powman_test.rs index 80a517ee0..9a24f2fa6 100644 --- a/rp235x-hal-examples/src/bin/powman_test.rs +++ b/rp235x-hal-examples/src/bin/powman_test.rs @@ -13,9 +13,6 @@ use rp235x_hal::{ uart::{DataBits, StopBits, UartConfig, UartPeripheral}, }; -use cortex_m_rt::exception; -use pac::interrupt; - // Some traits we need use core::fmt::Write; use hal::fugit::RateExtU32; @@ -67,7 +64,7 @@ impl GlobalUart { /// Entry point to our bare-metal application. /// -/// The `#[hal::entry]` macro ensures the Cortex-M start-up code calls this function +/// The `#[hal::entry]` macro ensures the start-up code calls this function /// as soon as all global variables and the spinlock are initialised. /// /// The function configures the rp235x peripherals, then writes to the UART in @@ -76,11 +73,6 @@ impl GlobalUart { fn main() -> ! { // Grab our singleton objects let mut pac = pac::Peripherals::take().unwrap(); - let mut cp = cortex_m::Peripherals::take().unwrap(); - - // Enable the cycle counter - cp.DCB.enable_trace(); - cp.DWT.enable_cycle_counter(); // Set up the watchdog driver - needed by the clock setup code let mut watchdog = hal::Watchdog::new(pac.WATCHDOG); @@ -99,6 +91,8 @@ fn main() -> ! { // The single-cycle I/O block controls our GPIO pins let sio = hal::Sio::new(pac.SIO); + let mut mtimer = sio.machine_timer; + mtimer.set_enabled(true); // Set the pins to their default state let pins = gpio::Pins::new( @@ -131,29 +125,30 @@ fn main() -> ! { _ = writeln!(&GLOBAL_UART, "AOT time: 0x{:016x}", powman.aot_get_time()); unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::POWMAN_IRQ_TIMER); + hal::arch::interrupt_unmask(pac::Interrupt::POWMAN_IRQ_TIMER); + hal::arch::interrupt_enable(); } _ = writeln!(&GLOBAL_UART, "Starting AOT..."); powman.aot_start(); // we don't know what oscillator we're on, so give it time to start whatever it is - cortex_m::asm::delay(150_000); + hal::arch::delay(150_000); print_aot_status(&mut powman); rollover_test(&mut powman); - loop_test(&mut powman); + loop_test(&mut powman, &mtimer); alarm_test(&mut powman); let source = AotClockSource::Xosc(FractionalFrequency::from_hz(12_000_000)); _ = writeln!(&GLOBAL_UART, "Switching AOT to {}", source); powman.aot_set_clock(source).expect("selecting XOSC"); print_aot_status(&mut powman); - loop_test(&mut powman); + loop_test(&mut powman, &mtimer); let source = AotClockSource::Lposc(FractionalFrequency::from_hz(32768)); _ = writeln!(&GLOBAL_UART, "Switching AOT to {}", source); powman.aot_set_clock(source).expect("selecting LPOSC"); print_aot_status(&mut powman); - loop_test(&mut powman); + loop_test(&mut powman, &mtimer); _ = writeln!(&GLOBAL_UART, "Rebooting now"); @@ -202,7 +197,7 @@ fn rollover_test(powman: &mut Powman) { } /// In this function, we see how long it takes to pass a certain number of ticks. -fn loop_test(powman: &mut Powman) { +fn loop_test(powman: &mut Powman, mtimer: &hal::sio::MachineTimer) { let start_loop = 0; let end_loop = 2_000; // 2 seconds _ = writeln!( @@ -214,24 +209,24 @@ fn loop_test(powman: &mut Powman) { powman.aot_set_time(start_loop); powman.aot_start(); - let start_clocks = cortex_m::peripheral::DWT::cycle_count(); + let start_clocks = mtimer.read(); loop { let now = powman.aot_get_time(); if now == end_loop { break; } } - let end_clocks = cortex_m::peripheral::DWT::cycle_count(); - // Compare our AOT against our CPU clock speed - let delta_clocks = end_clocks.wrapping_sub(start_clocks) as u64; + let end_clocks = mtimer.read(); + // Compare our AOT against our Machine Timer + let delta_clocks = end_clocks.wrapping_sub(start_clocks); let delta_ticks = end_loop - start_loop; let cycles_per_tick = delta_clocks / delta_ticks; - // Assume we're running at 150 MHz - let ms_per_tick = (cycles_per_tick as f32 * 1000.0) / 150_000_000.0; + // Assume we're running at 1 MHz MTimer + let ms_per_tick = (cycles_per_tick as f32 * 1000.0) / 1_000_000.0; let percent = ((ms_per_tick - 1.0) / 1.0) * 100.0; _ = writeln!( &GLOBAL_UART, - "Loop complete ... {delta_ticks} ticks in {delta_clocks} CPU clock cycles = {cycles_per_tick} cycles/tick ~= {ms_per_tick} ms/tick ({percent:.3}%)", + "Loop complete ... {delta_ticks} ticks in {delta_clocks} MTimer cycles = {cycles_per_tick} cycles/tick ~= {ms_per_tick} ms/tick ({percent:.3}%)", ) ; } @@ -258,8 +253,9 @@ fn alarm_test(powman: &mut Powman) { &GLOBAL_UART, "Sleeping until alarm (* = wakeup, ! = POWMAN interrupt)...", ); + while !powman.aot_alarm_ringing() { - cortex_m::asm::wfe(); + hal::arch::wfe(); _ = write!(&GLOBAL_UART, "*",); } @@ -278,25 +274,12 @@ fn alarm_test(powman: &mut Powman) { _ = writeln!(&GLOBAL_UART, "Alarm cleared OK"); } -#[interrupt] +#[no_mangle] #[allow(non_snake_case)] fn POWMAN_IRQ_TIMER() { Powman::static_aot_alarm_interrupt_disable(); _ = write!(&GLOBAL_UART, "!"); - cortex_m::asm::sev(); -} - -#[exception] -unsafe fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! { - let _ = writeln!(&GLOBAL_UART, "HARD FAULT:\n{:#?}", ef); - - hal::reboot::reboot( - hal::reboot::RebootKind::BootSel { - msd_disabled: false, - picoboot_disabled: false, - }, - hal::reboot::RebootArch::Normal, - ); + hal::arch::sev(); } #[panic_handler] diff --git a/rp235x-hal/src/arch.rs b/rp235x-hal/src/arch.rs index a87fe9bc6..1fa9bffbd 100644 --- a/rp235x-hal/src/arch.rs +++ b/rp235x-hal/src/arch.rs @@ -4,42 +4,78 @@ #[cfg(all(target_arch = "arm", target_os = "none"))] mod inner { + #[doc(inline)] pub use cortex_m::asm::{delay, dsb, nop, sev, wfe, wfi}; + + #[doc(inline)] pub use cortex_m::interrupt::{disable as interrupt_disable, enable as interrupt_enable}; - /// Are interrupts current enabled? + /// Are interrupts currently enabled? pub fn interrupts_enabled() -> bool { cortex_m::register::primask::read().is_active() } - /// Run the closure without interrupts + /// Check if an IRQ is pending + pub fn interrrupt_is_pending(irq: rp235x_pac::Interrupt) -> bool { + cortex_m::peripheral::NVIC::is_pending(irq) + } + + /// Enable an RP235x IRQ /// - /// No critical-section token because we haven't blocked the second core - pub fn interrupt_free(f: F) -> T - where - F: FnOnce() -> T, - { - let active = interrupts_enabled(); - if active { - interrupt_disable(); - } - let t = f(); - if active { - unsafe { - interrupt_enable(); - } - } - t + /// # Safety + /// + /// This function is unsafe because it can break mask-based critical + /// sections. Do not call inside a critical section. + pub unsafe fn interrupt_unmask(irq: rp235x_pac::Interrupt) { + unsafe { cortex_m::peripheral::NVIC::unmask(irq) } + } + + /// Disable an RP235x IRQ + pub fn interrupt_mask(irq: rp235x_pac::Interrupt) { + cortex_m::peripheral::NVIC::mask(irq) + } + + /// Check if an RP235x IRQ is enabled + pub fn interrupt_is_enabled(irq: rp235x_pac::Interrupt) -> bool { + cortex_m::peripheral::NVIC::is_enabled(irq) + } + + /// Mark an RP235x IRQ as pending + pub fn interrupt_pend(irq: rp235x_pac::Interrupt) { + cortex_m::peripheral::NVIC::pend(irq) } } #[cfg(all(target_arch = "riscv32", target_os = "none"))] mod inner { + #[doc(inline)] pub use riscv::asm::{delay, nop, wfi}; - pub use riscv::interrupt::machine::{ - disable as interrupt_disable, enable as interrupt_enable, free as interrupt_free, + + #[doc(inline)] + pub use riscv::interrupt::machine::disable as interrupt_disable; + + #[doc(inline)] + pub use crate::xh3irq::{ + is_enabled as interrupt_is_enabled, is_pending as interrrupt_is_pending, + mask as interrupt_mask, pend as interrupt_pend, unmask as interrupt_unmask, }; + /// Enable interrupts + /// + /// Enable the Machine External interrupt as well as the global interrupt + /// flag. + /// + /// # Safety + /// + /// Do not call from inside a critical section. + #[inline(always)] + pub unsafe fn interrupt_enable() { + unsafe { + riscv::register::mie::set_mext(); + riscv::interrupt::machine::enable(); + } + } + /// Send Event #[inline(always)] pub fn sev() { @@ -50,18 +86,10 @@ mod inner { } /// Wait for Event - /// - /// This is the interrupt-safe version of WFI. pub fn wfe() { - let active = interrupts_enabled(); - if active { - interrupt_disable(); - } - wfi(); - if active { - unsafe { - interrupt_enable(); - } + unsafe { + // This is how h3.block is encoded. + core::arch::asm!("slt x0, x0, x0"); } } @@ -73,43 +101,476 @@ mod inner { core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst); } - /// Are interrupts current enabled? + /// Are interrupts currently enabled? #[inline(always)] pub fn interrupts_enabled() -> bool { riscv::register::mstatus::read().mie() } + + #[no_mangle] + #[allow(non_snake_case)] + fn MachineExternal() { + loop { + let Some(irq) = crate::xh3irq::get_next_interrupt() else { + return; + }; + match irq { + rp235x_pac::Interrupt::TIMER0_IRQ_0 => { + extern "Rust" { + fn TIMER0_IRQ_0(); + } + unsafe { + TIMER0_IRQ_0(); + } + } + rp235x_pac::Interrupt::TIMER0_IRQ_1 => { + extern "Rust" { + fn TIMER0_IRQ_1(); + } + unsafe { + TIMER0_IRQ_1(); + } + } + rp235x_pac::Interrupt::TIMER0_IRQ_2 => { + extern "Rust" { + fn TIMER0_IRQ_2(); + } + unsafe { + TIMER0_IRQ_2(); + } + } + rp235x_pac::Interrupt::TIMER0_IRQ_3 => { + extern "Rust" { + fn TIMER0_IRQ_3(); + } + unsafe { + TIMER0_IRQ_3(); + } + } + rp235x_pac::Interrupt::TIMER1_IRQ_0 => { + extern "Rust" { + fn TIMER1_IRQ_0(); + } + unsafe { + TIMER1_IRQ_0(); + } + } + rp235x_pac::Interrupt::TIMER1_IRQ_1 => { + extern "Rust" { + fn TIMER1_IRQ_1(); + } + unsafe { + TIMER1_IRQ_1(); + } + } + rp235x_pac::Interrupt::TIMER1_IRQ_2 => { + extern "Rust" { + fn TIMER1_IRQ_2(); + } + unsafe { + TIMER1_IRQ_2(); + } + } + rp235x_pac::Interrupt::TIMER1_IRQ_3 => { + extern "Rust" { + fn TIMER1_IRQ_3(); + } + unsafe { + TIMER1_IRQ_3(); + } + } + rp235x_pac::Interrupt::PWM_IRQ_WRAP_0 => { + extern "Rust" { + fn PWM_IRQ_WRAP_0(); + } + unsafe { + PWM_IRQ_WRAP_0(); + } + } + rp235x_pac::Interrupt::PWM_IRQ_WRAP_1 => { + extern "Rust" { + fn PWM_IRQ_WRAP_1(); + } + unsafe { + PWM_IRQ_WRAP_1(); + } + } + rp235x_pac::Interrupt::DMA_IRQ_0 => { + extern "Rust" { + fn DMA_IRQ_0(); + } + unsafe { + DMA_IRQ_0(); + } + } + rp235x_pac::Interrupt::DMA_IRQ_1 => { + extern "Rust" { + fn DMA_IRQ_1(); + } + unsafe { + DMA_IRQ_1(); + } + } + rp235x_pac::Interrupt::DMA_IRQ_2 => { + extern "Rust" { + fn DMA_IRQ_2(); + } + unsafe { + DMA_IRQ_2(); + } + } + rp235x_pac::Interrupt::DMA_IRQ_3 => { + extern "Rust" { + fn DMA_IRQ_3(); + } + unsafe { + DMA_IRQ_3(); + } + } + rp235x_pac::Interrupt::USBCTRL_IRQ => { + extern "Rust" { + fn USBCTRL_IRQ(); + } + unsafe { + USBCTRL_IRQ(); + } + } + rp235x_pac::Interrupt::PIO0_IRQ_0 => { + extern "Rust" { + fn PIO0_IRQ_0(); + } + unsafe { + PIO0_IRQ_0(); + } + } + rp235x_pac::Interrupt::PIO0_IRQ_1 => { + extern "Rust" { + fn PIO0_IRQ_1(); + } + unsafe { + PIO0_IRQ_1(); + } + } + rp235x_pac::Interrupt::PIO1_IRQ_0 => { + extern "Rust" { + fn PIO1_IRQ_0(); + } + unsafe { + PIO1_IRQ_0(); + } + } + rp235x_pac::Interrupt::PIO1_IRQ_1 => { + extern "Rust" { + fn PIO1_IRQ_1(); + } + unsafe { + PIO1_IRQ_1(); + } + } + rp235x_pac::Interrupt::PIO2_IRQ_0 => { + extern "Rust" { + fn PIO2_IRQ_0(); + } + unsafe { + PIO2_IRQ_0(); + } + } + rp235x_pac::Interrupt::PIO2_IRQ_1 => { + extern "Rust" { + fn PIO2_IRQ_1(); + } + unsafe { + PIO2_IRQ_1(); + } + } + rp235x_pac::Interrupt::IO_IRQ_BANK0 => { + extern "Rust" { + fn IO_IRQ_BANK0(); + } + unsafe { + IO_IRQ_BANK0(); + } + } + rp235x_pac::Interrupt::IO_IRQ_BANK0_NS => { + extern "Rust" { + fn IO_IRQ_BANK0_NS(); + } + unsafe { + IO_IRQ_BANK0_NS(); + } + } + rp235x_pac::Interrupt::IO_IRQ_QSPI => { + extern "Rust" { + fn IO_IRQ_QSPI(); + } + unsafe { + IO_IRQ_QSPI(); + } + } + rp235x_pac::Interrupt::IO_IRQ_QSPI_NS => { + extern "Rust" { + fn IO_IRQ_QSPI_NS(); + } + unsafe { + IO_IRQ_QSPI_NS(); + } + } + rp235x_pac::Interrupt::SIO_IRQ_FIFO => { + extern "Rust" { + fn SIO_IRQ_FIFO(); + } + unsafe { + SIO_IRQ_FIFO(); + } + } + rp235x_pac::Interrupt::SIO_IRQ_BELL => { + extern "Rust" { + fn SIO_IRQ_BELL(); + } + unsafe { + SIO_IRQ_BELL(); + } + } + rp235x_pac::Interrupt::SIO_IRQ_FIFO_NS => { + extern "Rust" { + fn SIO_IRQ_FIFO_NS(); + } + unsafe { + SIO_IRQ_FIFO_NS(); + } + } + rp235x_pac::Interrupt::SIO_IRQ_BELL_NS => { + extern "Rust" { + fn SIO_IRQ_BELL_NS(); + } + unsafe { + SIO_IRQ_BELL_NS(); + } + } + rp235x_pac::Interrupt::SIO_IRQ_MTIMECMP => { + extern "Rust" { + fn SIO_IRQ_MTIMECMP(); + } + unsafe { + SIO_IRQ_MTIMECMP(); + } + } + rp235x_pac::Interrupt::CLOCKS_IRQ => { + extern "Rust" { + fn CLOCKS_IRQ(); + } + unsafe { + CLOCKS_IRQ(); + } + } + rp235x_pac::Interrupt::SPI0_IRQ => { + extern "Rust" { + fn SPI0_IRQ(); + } + unsafe { + SPI0_IRQ(); + } + } + rp235x_pac::Interrupt::SPI1_IRQ => { + extern "Rust" { + fn SPI1_IRQ(); + } + unsafe { + SPI1_IRQ(); + } + } + rp235x_pac::Interrupt::UART0_IRQ => { + extern "Rust" { + fn UART0_IRQ(); + } + unsafe { + UART0_IRQ(); + } + } + rp235x_pac::Interrupt::UART1_IRQ => { + extern "Rust" { + fn UART1_IRQ(); + } + unsafe { + UART1_IRQ(); + } + } + rp235x_pac::Interrupt::ADC_IRQ_FIFO => { + extern "Rust" { + fn ADC_IRQ_FIFO(); + } + unsafe { + ADC_IRQ_FIFO(); + } + } + rp235x_pac::Interrupt::I2C0_IRQ => { + extern "Rust" { + fn I2C0_IRQ(); + } + unsafe { + I2C0_IRQ(); + } + } + rp235x_pac::Interrupt::I2C1_IRQ => { + extern "Rust" { + fn I2C1_IRQ(); + } + unsafe { + I2C1_IRQ(); + } + } + rp235x_pac::Interrupt::OTP_IRQ => { + extern "Rust" { + fn OTP_IRQ(); + } + unsafe { + OTP_IRQ(); + } + } + rp235x_pac::Interrupt::TRNG_IRQ => { + extern "Rust" { + fn TRNG_IRQ(); + } + unsafe { + TRNG_IRQ(); + } + } + rp235x_pac::Interrupt::PLL_SYS_IRQ => { + extern "Rust" { + fn PLL_SYS_IRQ(); + } + unsafe { + PLL_SYS_IRQ(); + } + } + rp235x_pac::Interrupt::PLL_USB_IRQ => { + extern "Rust" { + fn PLL_USB_IRQ(); + } + unsafe { + PLL_USB_IRQ(); + } + } + rp235x_pac::Interrupt::POWMAN_IRQ_POW => { + extern "Rust" { + fn POWMAN_IRQ_POW(); + } + unsafe { + POWMAN_IRQ_POW(); + } + } + rp235x_pac::Interrupt::POWMAN_IRQ_TIMER => { + extern "Rust" { + fn POWMAN_IRQ_TIMER(); + } + unsafe { + POWMAN_IRQ_TIMER(); + } + } + } + } + } + + /// Our default IRQ handler. + /// + /// Just panics. + /// + /// # Safety + /// + /// Do not call this function - it is called automatically when our + /// `MachineExternal` interrupt handler can't find anything better to call. + #[no_mangle] + #[allow(non_snake_case)] + unsafe fn DefaultIrqHandler() { + panic!(); + } } #[cfg(not(all(any(target_arch = "arm", target_arch = "riscv32"), target_os = "none")))] mod inner { /// Placeholder function to disable interrupts pub fn interrupt_disable() {} + /// Placeholder function to enable interrupts - pub fn interrupt_enable() {} + /// + /// # Safety + /// + /// Do not call from inside a critical section. + pub unsafe fn interrupt_enable() {} + /// Placeholder function to check if interrupts are enabled pub fn interrupts_enabled() -> bool { false } + + /// Placeholder function to wait for an interrupt + pub fn wfi() {} + /// Placeholder function to wait for an event pub fn wfe() {} + /// Placeholder function to do nothing pub fn nop() {} + /// Placeholder function to emit a data synchronisation barrier pub fn dsb() {} - /// Placeholder function to run a closure with interrupts disabled - pub fn interrupt_free(f: F) -> T - where - F: FnOnce() -> T, - { - f() - } + /// Placeholder function to wait for some clock cycles pub fn delay(_: u32) {} + /// Placeholder function to emit an event pub fn sev() {} + + /// Placeholder function to check if an IRQ is pending + pub fn interrrupt_is_pending(_irq: rp235x_pac::Interrupt) -> bool { + false + } + + /// Placeholder function to enable an IRQ + /// + /// # Safety + /// + /// This function is unsafe because it can break mask-based critical + /// sections. Do not call inside a critical section. + pub unsafe fn interrupt_unmask(_irq: rp235x_pac::Interrupt) {} + + /// Placeholder function to disable an IRQ + pub fn interrupt_mask(_irq: rp235x_pac::Interrupt) {} + + /// Placeholder function to check if an IRQ is enabled + pub fn interrupt_is_enabled(_irq: rp235x_pac::Interrupt) -> bool { + false + } + + /// Placeholder function to mark an IRQ as pending + pub fn interrupt_pend(_irq: rp235x_pac::Interrupt) {} } -pub use inner::*; +#[doc(inline)] +pub use inner::{ + delay, dsb, interrrupt_is_pending, interrupt_disable, interrupt_enable, interrupt_is_enabled, + interrupt_mask, interrupt_pend, interrupt_unmask, interrupts_enabled, nop, sev, wfe, wfi, +}; + +/// Run the closure without interrupts +/// +/// No critical-section token because we haven't blocked the second core +pub fn interrupt_free(f: F) -> T +where + F: FnOnce() -> T, +{ + let active = interrupts_enabled(); + if active { + interrupt_disable(); + } + let t = f(); + if active { + unsafe { + interrupt_enable(); + } + } + t +} /// Create a static variable which we can grab a mutable reference to exactly once. #[macro_export]