rust-embedded / svd2rust

Generate Rust register maps (`struct`s) from SVD files
Apache License 2.0
687 stars 149 forks source link

Support for atomic `Peripherals::take()` #613

Closed VictorKoenders closed 1 year ago

VictorKoenders commented 2 years ago

Hello,

I'm currently working on a toy kernel on a raspberry pi, and I'm using svd2rust to generate the bindings to the aarch64 BCM2837 chip that the raspberry pi 3b is running on.

When generating the peripherals I cannot select a Target because the aarch64 is multi-core and critical sections do not work. Therefor the Peripherals::take() -> Option<Self> method won't be generated.

Currently I inject the following code into the generated output:

use core::sync::atomic::{AtomicBool, Ordering};

static LOCKED: AtomicBool = AtomicBool::new(false);

impl Peripherals {
    pub fn take() -> Option<Self> {
        let was_locked = LOCKED.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire).is_ok();
        if was_locked {
            None
        } else {
            Some(unsafe { Self::steal() })
        }
    }
}

impl Drop for Peripherals {
    fn drop(&mut self) {
        LOCKED.store(false, Ordering::Relaxed);
    }
}

I was considering porting this to svd2rust but I'm not sure how to approach this. I could:

Or maybe another approach is better. What do you think?

Emilgardis commented 2 years ago

I think it makes sense to do it the other way around, Target is the core thing, and TargetOptions is what is consumed, it has the target and its options

reitermarkus commented 2 years ago

@VictorKoenders, does https://github.com/rust-embedded/svd2rust/pull/651 fix this? You will need an implementation for critical_section that works correctly on multi-core of course.

burrbull commented 1 year ago

Closing as solved