diff --git a/examples/versatileab/Cargo.toml b/examples/versatileab/Cargo.toml index 8ab0734..52f16f7 100644 --- a/examples/versatileab/Cargo.toml +++ b/examples/versatileab/Cargo.toml @@ -18,10 +18,11 @@ version = "0.0.0" [dependencies] aarch32-cpu = { path = "../../aarch32-cpu", features = ["critical-section-single-core"] } aarch32-rt = { path = "../../aarch32-rt" } -semihosting = { version = "0.1.18", features = ["stdio"] } -libm = "0.2.15" derive-mmio = "0.6.1" +libm = "0.2.15" +pl190-vic = "0.1.0" portable-atomic = { version = "1.11.1", features = ["critical-section"] } +semihosting = { version = "0.1.18", features = ["stdio"] } [build-dependencies] arm-targets = { version = "0.3.0", path = "../../arm-targets" } diff --git a/examples/versatileab/reference/interrupt-armv4t-none-eabi.out b/examples/versatileab/reference/interrupt-armv4t-none-eabi.out index f7caea3..51b9aea 100644 --- a/examples/versatileab/reference/interrupt-armv4t-none-eabi.out +++ b/examples/versatileab/reference/interrupt-armv4t-none-eabi.out @@ -1,3 +1,15 @@ +Setting up interrupts... Firing interrupt... -Clearing interrupt... +> interrupt_handler() +> soft_handler1() +> interrupt_handler() +> soft_handler2() +< soft_handler2() +< interrupt_handler() +< soft_handler1() +< interrupt_handler() Got interrupted :) +> interrupt_handler() +catchall_handler() fired +< interrupt_handler() +catch all works. All done! diff --git a/examples/versatileab/reference/interrupt-armv5te-none-eabi.out b/examples/versatileab/reference/interrupt-armv5te-none-eabi.out index f7caea3..51b9aea 100644 --- a/examples/versatileab/reference/interrupt-armv5te-none-eabi.out +++ b/examples/versatileab/reference/interrupt-armv5te-none-eabi.out @@ -1,3 +1,15 @@ +Setting up interrupts... Firing interrupt... -Clearing interrupt... +> interrupt_handler() +> soft_handler1() +> interrupt_handler() +> soft_handler2() +< soft_handler2() +< interrupt_handler() +< soft_handler1() +< interrupt_handler() Got interrupted :) +> interrupt_handler() +catchall_handler() fired +< interrupt_handler() +catch all works. All done! diff --git a/examples/versatileab/reference/interrupt-armv7a-none-eabi.out b/examples/versatileab/reference/interrupt-armv7a-none-eabi.out index f7caea3..51b9aea 100644 --- a/examples/versatileab/reference/interrupt-armv7a-none-eabi.out +++ b/examples/versatileab/reference/interrupt-armv7a-none-eabi.out @@ -1,3 +1,15 @@ +Setting up interrupts... Firing interrupt... -Clearing interrupt... +> interrupt_handler() +> soft_handler1() +> interrupt_handler() +> soft_handler2() +< soft_handler2() +< interrupt_handler() +< soft_handler1() +< interrupt_handler() Got interrupted :) +> interrupt_handler() +catchall_handler() fired +< interrupt_handler() +catch all works. All done! diff --git a/examples/versatileab/reference/interrupt-armv7a-none-eabihf-dp.out b/examples/versatileab/reference/interrupt-armv7a-none-eabihf-dp.out new file mode 100644 index 0000000..51b9aea --- /dev/null +++ b/examples/versatileab/reference/interrupt-armv7a-none-eabihf-dp.out @@ -0,0 +1,15 @@ +Setting up interrupts... +Firing interrupt... +> interrupt_handler() +> soft_handler1() +> interrupt_handler() +> soft_handler2() +< soft_handler2() +< interrupt_handler() +< soft_handler1() +< interrupt_handler() +Got interrupted :) +> interrupt_handler() +catchall_handler() fired +< interrupt_handler() +catch all works. All done! diff --git a/examples/versatileab/reference/interrupt-armv7a-none-eabihf.out b/examples/versatileab/reference/interrupt-armv7a-none-eabihf.out index f7caea3..51b9aea 100644 --- a/examples/versatileab/reference/interrupt-armv7a-none-eabihf.out +++ b/examples/versatileab/reference/interrupt-armv7a-none-eabihf.out @@ -1,3 +1,15 @@ +Setting up interrupts... Firing interrupt... -Clearing interrupt... +> interrupt_handler() +> soft_handler1() +> interrupt_handler() +> soft_handler2() +< soft_handler2() +< interrupt_handler() +< soft_handler1() +< interrupt_handler() Got interrupted :) +> interrupt_handler() +catchall_handler() fired +< interrupt_handler() +catch all works. All done! diff --git a/examples/versatileab/reference/interrupt-armv7r-none-eabi.out b/examples/versatileab/reference/interrupt-armv7r-none-eabi.out index f7caea3..51b9aea 100644 --- a/examples/versatileab/reference/interrupt-armv7r-none-eabi.out +++ b/examples/versatileab/reference/interrupt-armv7r-none-eabi.out @@ -1,3 +1,15 @@ +Setting up interrupts... Firing interrupt... -Clearing interrupt... +> interrupt_handler() +> soft_handler1() +> interrupt_handler() +> soft_handler2() +< soft_handler2() +< interrupt_handler() +< soft_handler1() +< interrupt_handler() Got interrupted :) +> interrupt_handler() +catchall_handler() fired +< interrupt_handler() +catch all works. All done! diff --git a/examples/versatileab/reference/interrupt-armv7r-none-eabihf.out b/examples/versatileab/reference/interrupt-armv7r-none-eabihf.out index f7caea3..51b9aea 100644 --- a/examples/versatileab/reference/interrupt-armv7r-none-eabihf.out +++ b/examples/versatileab/reference/interrupt-armv7r-none-eabihf.out @@ -1,3 +1,15 @@ +Setting up interrupts... Firing interrupt... -Clearing interrupt... +> interrupt_handler() +> soft_handler1() +> interrupt_handler() +> soft_handler2() +< soft_handler2() +< interrupt_handler() +< soft_handler1() +< interrupt_handler() Got interrupted :) +> interrupt_handler() +catchall_handler() fired +< interrupt_handler() +catch all works. All done! diff --git a/examples/versatileab/reference/interrupt-thumbv4t-none-eabi.out b/examples/versatileab/reference/interrupt-thumbv4t-none-eabi.out index f7caea3..51b9aea 100644 --- a/examples/versatileab/reference/interrupt-thumbv4t-none-eabi.out +++ b/examples/versatileab/reference/interrupt-thumbv4t-none-eabi.out @@ -1,3 +1,15 @@ +Setting up interrupts... Firing interrupt... -Clearing interrupt... +> interrupt_handler() +> soft_handler1() +> interrupt_handler() +> soft_handler2() +< soft_handler2() +< interrupt_handler() +< soft_handler1() +< interrupt_handler() Got interrupted :) +> interrupt_handler() +catchall_handler() fired +< interrupt_handler() +catch all works. All done! diff --git a/examples/versatileab/reference/interrupt-thumbv5te-none-eabi.out b/examples/versatileab/reference/interrupt-thumbv5te-none-eabi.out index f7caea3..51b9aea 100644 --- a/examples/versatileab/reference/interrupt-thumbv5te-none-eabi.out +++ b/examples/versatileab/reference/interrupt-thumbv5te-none-eabi.out @@ -1,3 +1,15 @@ +Setting up interrupts... Firing interrupt... -Clearing interrupt... +> interrupt_handler() +> soft_handler1() +> interrupt_handler() +> soft_handler2() +< soft_handler2() +< interrupt_handler() +< soft_handler1() +< interrupt_handler() Got interrupted :) +> interrupt_handler() +catchall_handler() fired +< interrupt_handler() +catch all works. All done! diff --git a/examples/versatileab/reference/svc-a32-thumbv4t-none-eabi.out b/examples/versatileab/reference/svc-a32-thumbv4t-none-eabi.out index 1eeccb9..aa7cc28 100644 --- a/examples/versatileab/reference/svc-a32-thumbv4t-none-eabi.out +++ b/examples/versatileab/reference/svc-a32-thumbv4t-none-eabi.out @@ -1,4 +1,6 @@ x = 1, y = 2, z = 3.000 +In svc_handler, with arg=0xabcdef +In svc_handler, with arg=0x456789 x = 1, y = 2, z = 3.000 PANIC: PanicInfo { message: I am an example panic, diff --git a/examples/versatileab/reference/svc-a32-thumbv5te-none-eabi.out b/examples/versatileab/reference/svc-a32-thumbv5te-none-eabi.out index 1eeccb9..aa7cc28 100644 --- a/examples/versatileab/reference/svc-a32-thumbv5te-none-eabi.out +++ b/examples/versatileab/reference/svc-a32-thumbv5te-none-eabi.out @@ -1,4 +1,6 @@ x = 1, y = 2, z = 3.000 +In svc_handler, with arg=0xabcdef +In svc_handler, with arg=0x456789 x = 1, y = 2, z = 3.000 PANIC: PanicInfo { message: I am an example panic, diff --git a/examples/versatileab/src/bin/interrupt.rs b/examples/versatileab/src/bin/interrupt.rs index 9f5774d..00c1012 100644 --- a/examples/versatileab/src/bin/interrupt.rs +++ b/examples/versatileab/src/bin/interrupt.rs @@ -6,31 +6,58 @@ use portable_atomic::{AtomicU32, Ordering::SeqCst}; use aarch32_rt::{entry, exception}; +use pl190_vic::{InterruptId, Pl190Driver, VectorId}; use semihosting::println; -use versatileab::Pl190; static MARKER: AtomicU32 = AtomicU32::new(0); +static PL190: Pl190Driver = unsafe { Pl190Driver::new_static(versatileab::PL190_BASE_ADDRESS) }; + +// We can pick any three interrupt ID values here +const TEST_INTERRUPT1: InterruptId = InterruptId::new(1); +const TEST_INTERRUPT2: InterruptId = InterruptId::new(2); +const TEST_INTERRUPT3: InterruptId = InterruptId::new(3); + +// We can pick any two vector ID values here, as long as TEST_VECTOR1 is +// higher than TEST_VECTOR2 (i.e. TEST_VECTOR2 is higher priority than +// TEST_VECTOR1). +const TEST_VECTOR1: VectorId = VectorId::new(7); +const TEST_VECTOR2: VectorId = VectorId::new(4); + /// The entry-point to the Rust application. /// /// It is called by the start-up. #[entry] fn my_main() -> ! { - let mut pl190 = Pl190::create(); - // Safety: Not in a critical-section unsafe { aarch32_cpu::interrupt::enable(); } + println!("Setting up interrupts..."); + PL190.set_handler(TEST_INTERRUPT1, TEST_VECTOR1, Some(soft_handler1)); + PL190.set_handler(TEST_INTERRUPT2, TEST_VECTOR2, Some(soft_handler2)); + PL190.set_default_handler(catchall_handler); + PL190.enable_interrupt(TEST_INTERRUPT1); + PL190.enable_interrupt(TEST_INTERRUPT2); + PL190.enable_interrupt(TEST_INTERRUPT3); + println!("Firing interrupt..."); - pl190.write_vic_intenable(1); - pl190.write_vic_softint(1); + PL190.pend_sw_interrupt(TEST_INTERRUPT1); // wait for it for _ in 0..1_000 { if MARKER.load(SeqCst) == 1 { println!("Got interrupted :)"); + // this one has no handler + PL190.pend_sw_interrupt(TEST_INTERRUPT3); + break; + } + } + + for _ in 0..1_000 { + if MARKER.load(SeqCst) == 2 { + println!("catch all works. All done!"); semihosting::process::exit(0); } } @@ -39,10 +66,37 @@ fn my_main() -> ! { semihosting::process::exit(1); } +/// Our low-prio handler re-enables interrupts and triggers a second, +/// higher-priority, handler. +fn soft_handler1() { + unsafe { + aarch32_cpu::interrupt::enable(); + } + println!("> soft_handler1()"); + PL190.clear_sw_interrupt(TEST_INTERRUPT1); + PL190.pend_sw_interrupt(TEST_INTERRUPT2); + println!("< soft_handler1()"); +} + +/// Our high-prio handler sets a global flag +fn soft_handler2() { + println!("> soft_handler2()"); + PL190.clear_sw_interrupt(TEST_INTERRUPT2); + MARKER.store(1, SeqCst); + println!("< soft_handler2()"); +} + +/// Our catch-all handler sets a global flag +fn catchall_handler() { + println!("catchall_handler() fired"); + PL190.clear_sw_interrupt(TEST_INTERRUPT3); + MARKER.store(2, SeqCst); +} + +/// Our IRQ handler asks the PL190 what to do, and does it. #[exception(Irq)] unsafe fn interrupt_handler() { - println!("Clearing interrupt..."); - let mut pl190 = Pl190::create(); - pl190.write_vic_softintclear(1); - MARKER.store(1, SeqCst); + println!("> interrupt_handler()"); + PL190.irq_process(); + println!("< interrupt_handler()"); } diff --git a/examples/versatileab/src/bin/svc-a32.rs b/examples/versatileab/src/bin/svc-a32.rs index 556c26a..3a24519 100644 --- a/examples/versatileab/src/bin/svc-a32.rs +++ b/examples/versatileab/src/bin/svc-a32.rs @@ -16,9 +16,9 @@ fn main() -> ! { let y = x + 1; let z = (y as f64) * 1.5; println!("x = {}, y = {}, z = {:0.3}", x, y, z); - #[cfg(arm_isa = "a32")] - aarch32_cpu::svc!(0xABCDEF); + do_svc1(); println!("x = {}, y = {}, z = {:0.3}", x, y, z); + panic!("I am an example panic"); } @@ -28,7 +28,22 @@ fn svc_handler(arg: u32) { println!("In svc_handler, with arg=0x{:06x}", arg); if arg == 0xABCDEF { // test nested SVC calls - #[cfg(arm_isa = "a32")] - aarch32_cpu::svc!(0x456789); + do_svc2(); } } + +#[cfg_attr( + any(arm_architecture = "v4t", arm_architecture = "v5te"), + instruction_set(arm::a32) +)] +fn do_svc1() { + aarch32_cpu::svc!(0xABCDEF); +} + +#[cfg_attr( + any(arm_architecture = "v4t", arm_architecture = "v5te"), + instruction_set(arm::a32) +)] +fn do_svc2() { + aarch32_cpu::svc!(0x456789); +} diff --git a/examples/versatileab/src/lib.rs b/examples/versatileab/src/lib.rs index 8061d92..15b797e 100644 --- a/examples/versatileab/src/lib.rs +++ b/examples/versatileab/src/lib.rs @@ -2,10 +2,8 @@ #![no_std] -mod pl190; - -#[doc(inline)] -pub use pl190::Pl190; +/// The base address of our PL190 interrupt controller +pub const PL190_BASE_ADDRESS: usize = 0x1014_0000; #[cfg(arm_architecture = "v8-r")] compile_error!("This example/board is not compatible with the ARMv8-R architecture"); diff --git a/examples/versatileab/src/pl190.rs b/examples/versatileab/src/pl190.rs deleted file mode 100644 index 174b58d..0000000 --- a/examples/versatileab/src/pl190.rs +++ /dev/null @@ -1,51 +0,0 @@ -//! The Versatile board's ARM PL190 PrimeCell Vectored Interrupt Controller - -//! Represents our interrupt controller -#[derive(derive_mmio::Mmio)] -#[repr(C)] -pub struct Pl190 { - /// IRQ Status Register - #[mmio(PureRead)] - vic_irqstatus: u32, - /// FIQ Status Register - #[mmio(PureRead)] - vic_fiqstatus: u32, - /// Raw Interrupt Status Register - #[mmio(PureRead)] - vic_rawintr: u32, - /// Interrupt Select Register - vic_intselect: u32, - /// Interrupt Enable Register - vic_intenable: u32, - /// Interrupt Enable Clear Register - #[mmio(Write)] - vic_intenclear: u32, - /// Software Interrupt Register - vic_softint: u32, - /// Software Interrupt Clear Register - #[mmio(Write)] - vic_softintclear: u32, - /// Protection Enable Register - vic_protection: u32, - /// Vector Address Register - vic_vectaddr: u32, - /// Default Vector Address Register - vic_defvectaddr: u32, - _reserved1: [u32; 50], - /// Vector Address Registers - vic_vectaddrs: [u32; 16], - _reserved2: [u32; 51], - /// Vector Control Registers - vic_vectcntl: [u32; 16], -} - -impl Pl190 { - /// Base address for the PL190 on the Versatile Application Board - pub const VERSATILE_PL190_ADDR: usize = 0x10140000; - - /// Create a new PL190 Driver - pub const fn create() -> MmioPl190<'static> { - // Safety: This is where the PL190 lives - unsafe { Pl190::new_mmio_at(Self::VERSATILE_PL190_ADDR) } - } -}