use super::*;
use core::convert::Infallible;
pub struct SioGpioBank0 {
_private: (),
}
pub struct SioFifo {
_private: (),
}
pub struct SioGpioQspi {
_private: (),
}
pub struct HwDivider {
_private: (),
}
pub struct DivResult<T> {
pub quotient: T,
pub remainder: T,
}
pub struct Sio {
_sio: pac::SIO,
pub gpio_bank0: SioGpioBank0,
pub gpio_qspi: SioGpioQspi,
pub hwdivider: HwDivider,
pub fifo: SioFifo,
pub interp0: Interp0,
pub interp1: Interp1,
}
impl Sio {
pub fn new(sio: pac::SIO) -> Self {
Self {
_sio: sio,
gpio_bank0: SioGpioBank0 { _private: () },
gpio_qspi: SioGpioQspi { _private: () },
fifo: SioFifo { _private: () },
hwdivider: HwDivider { _private: () },
interp0: Interp0 {
lane0: Interp0Lane0 { _private: () },
lane1: Interp0Lane1 { _private: () },
},
interp1: Interp1 {
lane0: Interp1Lane0 { _private: () },
lane1: Interp1Lane1 { _private: () },
},
}
}
pub fn core() -> u8 {
unsafe { (*pac::SIO::ptr()).cpuid.read().bits() as u8 }
}
}
impl SioFifo {
pub fn is_read_ready(&mut self) -> bool {
let sio = unsafe { &(*pac::SIO::ptr()) };
sio.fifo_st.read().vld().bit_is_set()
}
pub fn is_write_ready(&mut self) -> bool {
let sio = unsafe { &(*pac::SIO::ptr()) };
sio.fifo_st.read().rdy().bit_is_set()
}
pub fn status(&self) -> u32 {
let sio = unsafe { &(*pac::SIO::ptr()) };
sio.fifo_st.read().bits()
}
pub fn write(&mut self, value: u32) {
let sio = unsafe { &(*pac::SIO::ptr()) };
sio.fifo_wr.write(|w| unsafe { w.bits(value) });
cortex_m::asm::sev();
}
pub fn read(&mut self) -> Option<u32> {
if self.is_read_ready() {
let sio = unsafe { &(*pac::SIO::ptr()) };
Some(sio.fifo_rd.read().bits())
} else {
None
}
}
pub fn drain(&mut self) {
while self.read().is_some() {
}
}
pub fn write_blocking(&mut self, value: u32) {
while !self.is_write_ready() {
cortex_m::asm::nop();
}
self.write(value);
cortex_m::asm::sev();
}
pub fn read_blocking(&mut self) -> u32 {
loop {
if let Some(data) = self.read() {
return data;
} else {
cortex_m::asm::wfe();
}
}
}
}
#[cfg(target_arch = "arm")]
core::arch::global_asm!(
".macro hwdivider_head",
"ldr r2, =(0xd0000000)", "ldr r3, [r2, #0x078]", "lsrs r3, #2", "bcs 2f",
"1:",
".endm",
".macro hwdivider_tail",
"b 3f",
"3: b 3f",
"3: b 3f",
"3: b 3f",
"3:",
"ldr r1, [r2, #0x074]", "ldr r0, [r2, #0x070]", "bx lr",
"2:",
"push {{r4-r6, lr}}",
"ldr r3, [r2, #0x060]", "ldr r4, [r2, #0x064]", "ldr r5, [r2, #0x074]", "ldr r6, [r2, #0x070]", "bl 1b",
"str r3, [r2, #0x060]", "str r4, [r2, #0x064]", "str r5, [r2, #0x074]", "str r6, [r2, #0x070]", "pop {{r4-r6, pc}}",
".endm",
);
macro_rules! division_function {
(
$name:ident $($intrinsic:ident)* ( $argty:ty ) {
$($begin:literal),+
}
) => {
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
core::arch::global_asm!(
// Mangle the name slightly, since this is a global symbol.
concat!(".global _rphal_", stringify!($name)),
concat!(".type _rphal_", stringify!($name), ", %function"),
".align 2",
concat!("_rphal_", stringify!($name), ":"),
$(
concat!(".global ", stringify!($intrinsic)),
concat!(".type ", stringify!($intrinsic), ", %function"),
concat!(stringify!($intrinsic), ":"),
)*
"hwdivider_head",
$($begin),+ ,
"hwdivider_tail",
);
#[cfg(all(target_arch = "arm", feature = "disable-intrinsics"))]
core::arch::global_asm!(
// Mangle the name slightly, since this is a global symbol.
concat!(".global _rphal_", stringify!($name)),
concat!(".type _rphal_", stringify!($name), ", %function"),
".align 2",
concat!("_rphal_", stringify!($name), ":"),
"hwdivider_head",
$($begin),+ ,
"hwdivider_tail",
);
#[cfg(target_arch = "arm")]
extern "aapcs" {
#[link_name = concat!("_rphal_", stringify!($name)) ]
fn $name(n: $argty, d: $argty) -> u64;
}
#[cfg(not(target_arch = "arm"))]
#[allow(unused_variables)]
unsafe fn $name(n: $argty, d: $argty) -> u64 { 0 }
};
}
division_function! {
unsigned_divmod __aeabi_uidivmod __aeabi_uidiv ( u32 ) {
"str r0, [r2, #0x060]", "str r1, [r2, #0x064]" }
}
division_function! {
signed_divmod __aeabi_idivmod __aeabi_idiv ( i32 ) {
"str r0, [r2, #0x068]", "str r1, [r2, #0x06c]" }
}
fn divider_unsigned(n: u32, d: u32) -> DivResult<u32> {
let packed = unsafe { unsigned_divmod(n, d) };
DivResult {
quotient: packed as u32,
remainder: (packed >> 32) as u32,
}
}
fn divider_signed(n: i32, d: i32) -> DivResult<i32> {
let packed = unsafe { signed_divmod(n, d) };
DivResult {
quotient: packed as u32 as i32,
remainder: (packed >> 32) as u32 as i32,
}
}
impl HwDivider {
pub fn unsigned(&self, dividend: u32, divisor: u32) -> DivResult<u32> {
divider_unsigned(dividend, divisor)
}
pub fn signed(&self, dividend: i32, divisor: i32) -> DivResult<i32> {
divider_signed(dividend, divisor)
}
}
intrinsics! {
extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
divider_unsigned(n, d).quotient
}
extern "C" fn __umodsi3(n: u32, d: u32) -> u32 {
divider_unsigned(n, d).remainder
}
extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 {
let quo_rem = divider_unsigned(n, d);
if let Some(rem) = rem {
*rem = quo_rem.remainder;
}
quo_rem.quotient
}
extern "C" fn __divsi3(n: i32, d: i32) -> i32 {
divider_signed(n, d).quotient
}
extern "C" fn __modsi3(n: i32, d: i32) -> i32 {
divider_signed(n, d).remainder
}
extern "C" fn __divmodsi4(n: i32, d: i32, rem: &mut i32) -> i32 {
let quo_rem = divider_signed(n, d);
*rem = quo_rem.remainder;
quo_rem.quotient
}
}
pub trait SpinlockValid {}
pub struct Spinlock<const N: usize>(core::marker::PhantomData<()>)
where
Spinlock<N>: SpinlockValid;
impl<const N: usize> Spinlock<N>
where
Spinlock<N>: SpinlockValid,
{
pub fn try_claim() -> Option<Self> {
let sio = unsafe { &*pac::SIO::ptr() };
let lock = sio.spinlock[N].read().bits();
if lock > 0 {
Some(Self(core::marker::PhantomData))
} else {
None
}
}
pub fn claim() -> Self {
loop {
if let Some(result) = Self::try_claim() {
break result;
}
}
}
pub fn claim_async() -> nb::Result<Self, Infallible> {
Self::try_claim().ok_or(nb::Error::WouldBlock)
}
pub unsafe fn release() {
let sio = &*pac::SIO::ptr();
sio.spinlock[N].write_with_zero(|b| b.bits(1));
}
}
impl<const N: usize> Drop for Spinlock<N>
where
Spinlock<N>: SpinlockValid,
{
fn drop(&mut self) {
unsafe { Self::release() }
}
}
pub type Spinlock0 = Spinlock<0>;
impl SpinlockValid for Spinlock<0> {}
pub type Spinlock1 = Spinlock<1>;
impl SpinlockValid for Spinlock<1> {}
pub type Spinlock2 = Spinlock<2>;
impl SpinlockValid for Spinlock<2> {}
pub type Spinlock3 = Spinlock<3>;
impl SpinlockValid for Spinlock<3> {}
pub type Spinlock4 = Spinlock<4>;
impl SpinlockValid for Spinlock<4> {}
pub type Spinlock5 = Spinlock<5>;
impl SpinlockValid for Spinlock<5> {}
pub type Spinlock6 = Spinlock<6>;
impl SpinlockValid for Spinlock<6> {}
pub type Spinlock7 = Spinlock<7>;
impl SpinlockValid for Spinlock<7> {}
pub type Spinlock8 = Spinlock<8>;
impl SpinlockValid for Spinlock<8> {}
pub type Spinlock9 = Spinlock<9>;
impl SpinlockValid for Spinlock<9> {}
pub type Spinlock10 = Spinlock<10>;
impl SpinlockValid for Spinlock<10> {}
pub type Spinlock11 = Spinlock<11>;
impl SpinlockValid for Spinlock<11> {}
pub type Spinlock12 = Spinlock<12>;
impl SpinlockValid for Spinlock<12> {}
pub type Spinlock13 = Spinlock<13>;
impl SpinlockValid for Spinlock<13> {}
pub type Spinlock14 = Spinlock<14>;
impl SpinlockValid for Spinlock<14> {}
pub type Spinlock15 = Spinlock<15>;
impl SpinlockValid for Spinlock<15> {}
pub type Spinlock16 = Spinlock<16>;
impl SpinlockValid for Spinlock<16> {}
pub type Spinlock17 = Spinlock<17>;
impl SpinlockValid for Spinlock<17> {}
pub type Spinlock18 = Spinlock<18>;
impl SpinlockValid for Spinlock<18> {}
pub type Spinlock19 = Spinlock<19>;
impl SpinlockValid for Spinlock<19> {}
pub type Spinlock20 = Spinlock<20>;
impl SpinlockValid for Spinlock<20> {}
pub type Spinlock21 = Spinlock<21>;
impl SpinlockValid for Spinlock<21> {}
pub type Spinlock22 = Spinlock<22>;
impl SpinlockValid for Spinlock<22> {}
pub type Spinlock23 = Spinlock<23>;
impl SpinlockValid for Spinlock<23> {}
pub type Spinlock24 = Spinlock<24>;
impl SpinlockValid for Spinlock<24> {}
pub type Spinlock25 = Spinlock<25>;
impl SpinlockValid for Spinlock<25> {}
pub type Spinlock26 = Spinlock<26>;
impl SpinlockValid for Spinlock<26> {}
pub type Spinlock27 = Spinlock<27>;
impl SpinlockValid for Spinlock<27> {}
pub type Spinlock28 = Spinlock<28>;
impl SpinlockValid for Spinlock<28> {}
pub type Spinlock29 = Spinlock<29>;
impl SpinlockValid for Spinlock<29> {}
pub type Spinlock30 = Spinlock<30>;
impl SpinlockValid for Spinlock<30> {}
#[cfg(feature = "critical-section-impl")]
pub(crate) type Spinlock31 = Spinlock<31>;
#[cfg(not(feature = "critical-section-impl"))]
pub type Spinlock31 = Spinlock<31>;
impl SpinlockValid for Spinlock<31> {}
pub fn spinlock_state() -> [bool; 32] {
let sio = unsafe { &*pac::SIO::ptr() };
let register = sio.spinlock_st.read().bits();
let mut result = [false; 32];
#[allow(clippy::needless_range_loop)]
for i in 0..32 {
result[i] = (register & (1 << i)) > 0;
}
result
}
pub unsafe fn spinlock_reset() {
const SIO_BASE: u32 = 0xd0000000;
const SPINLOCK0_PTR: *mut u32 = (SIO_BASE + 0x100) as *mut u32;
const SPINLOCK_COUNT: usize = 32;
for i in 0..SPINLOCK_COUNT {
SPINLOCK0_PTR.wrapping_add(i).write_volatile(1);
}
}
pub struct LaneCtrl {
pub clamp: bool,
pub blend: bool,
pub force_msb: u8,
pub add_raw: bool,
pub cross_result: bool,
pub cross_input: bool,
pub signed: bool,
pub mask_msb: u8,
pub mask_lsb: u8,
pub shift: u8,
}
impl LaneCtrl {
pub const fn new() -> Self {
Self {
clamp: false,
blend: false,
force_msb: 0,
add_raw: false,
cross_result: false,
cross_input: false,
signed: false,
mask_msb: 31,
mask_lsb: 0,
shift: 0,
}
}
pub const fn encode(&self) -> u32 {
assert!(!(self.blend && self.clamp));
assert!(self.force_msb < 0b100);
assert!(self.mask_msb < 0b100000);
assert!(self.mask_lsb < 0b100000);
assert!(self.mask_msb >= self.mask_lsb);
assert!(self.shift < 0b100000);
((self.clamp as u32) << 22)
| ((self.blend as u32) << 21)
| ((self.force_msb as u32) << 19)
| ((self.add_raw as u32) << 18)
| ((self.cross_result as u32) << 17)
| ((self.cross_input as u32) << 16)
| ((self.signed as u32) << 15)
| ((self.mask_msb as u32) << 10)
| ((self.mask_lsb as u32) << 5)
| (self.shift as u32)
}
}
pub trait Lane {
fn pop(&mut self) -> u32;
fn peek(&self) -> u32;
fn set_accum(&mut self, v: u32);
fn get_accum(&self) -> u32;
fn set_base(&mut self, v: u32);
fn get_base(&self) -> u32;
fn set_ctrl(&mut self, v: u32);
fn get_ctrl(&self) -> u32;
fn add_accum(&mut self, v: u32);
fn read_raw(&self) -> u32;
}
pub trait Interp {
fn pop(&mut self) -> u32;
fn peek(&self) -> u32;
fn set_base(&mut self, v: u32);
fn get_base(&self) -> u32;
}
macro_rules! interpolators {
(
$($interp:ident : ( $( [ $lane:ident,$lane_id:expr ] ),+ ) ),+
) => {
$crate::paste::paste! {
$(
$(
#[doc = "The lane " $lane_id " of " $interp]
pub struct [<$interp $lane>]{
_private: (),
}
impl Lane for [<$interp $lane>]{
fn pop(&mut self) ->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _pop_ $lane:lower>].read().bits()
}
fn peek(&self) ->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _peek_ $lane:lower>].read().bits()
}
fn set_accum(&mut self,v:u32){
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _accum $lane_id>].write(|w| unsafe { w.bits(v) });
}
fn get_accum(&self)->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _accum $lane_id>].read().bits()
}
fn set_base(&mut self, v:u32){
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _base $lane_id>].write(|w| unsafe { w.bits(v) });
}
fn get_base(&self)->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _base $lane_id>].read().bits()
}
fn set_ctrl(&mut self, v:u32){
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _ctrl_lane $lane_id>].write(|w| unsafe { w.bits(v) });
}
fn get_ctrl(&self)->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _ctrl_lane $lane_id>].read().bits()
}
fn add_accum(&mut self, v:u32){
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _accum $lane_id _add>].write(|w| unsafe { w.bits(v) });
}
fn read_raw(&self)->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _accum $lane_id _add>].read().bits()
}
}
)+
#[doc = "Interpolator " $interp]
pub struct $interp {
$(
[<$lane:lower>]: [<$interp $lane>],
)+
}
impl $interp{
$(
pub fn [<get_ $lane:lower>](&mut self)->&mut [<$interp $lane>]{
&mut self.[<$lane:lower>]
}
)+
}
impl Interp for $interp{
fn pop(&mut self) ->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _pop_full>].read().bits()
}
fn peek(&self) ->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _peek_full>].read().bits()
}
fn set_base(&mut self, v:u32){
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _base2>].write(|w| unsafe { w.bits(v)});
}
fn get_base(&self)->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _base2>].read().bits()
}
}
)+
}
}
}
interpolators!(
Interp0 : ([Lane0,0],[Lane1,1]),
Interp1 : ([Lane0,0],[Lane1,1])
);