1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
#![cfg_attr(feature = "std", allow(unreachable_code, unused_mut))]

use crate::{
    map::{
        periph::{mpu::MpuPeriph, thr::ThrPeriph},
        reg::{mpu, scb},
    },
    reg::prelude::*,
    thr::ThrTokens,
};

/// A set of register tokens returned by `thr::init!` macro.
#[allow(missing_docs)]
pub struct ThrInitPeriph {
    pub scb_ccr_bfhfnmign: scb::ccr::Bfhfnmign<Srt>,
    pub scb_ccr_div_0_trp: scb::ccr::Div0Trp<Srt>,
    pub scb_ccr_unalign_trp: scb::ccr::UnalignTrp<Srt>,
    pub scb_ccr_usersetmpend: scb::ccr::Usersetmpend<Srt>,
}

static MPU_RESET_TABLE: [u32; 16] = [
    rbar_reset(0),
    0,
    rbar_reset(1),
    0,
    rbar_reset(2),
    0,
    rbar_reset(3),
    0,
    rbar_reset(4),
    0,
    rbar_reset(5),
    0,
    rbar_reset(6),
    0,
    rbar_reset(7),
    0,
];

#[doc(hidden)]
#[macro_export]
macro_rules! thr_init {
    ($reg:ident, $thr_tokens:ident) => {
        $crate::thr::init::<$thr_tokens>(
            $crate::map::periph::mpu::periph_mpu!($reg),
            $crate::map::periph::thr::periph_thr!($reg),
        )
    };
}

#[doc(hidden)]
#[inline]
pub fn init<T: ThrTokens>(mpu: MpuPeriph, thr: ThrPeriph) -> (T, ThrInitPeriph) {
    let ThrPeriph { scb_ccr } = thr;
    scb_ccr.store(|r| r.set_stkalign().set_nonbasethrdena());
    let scb::Ccr {
        stkalign,
        bfhfnmign: scb_ccr_bfhfnmign,
        div_0_trp: scb_ccr_div_0_trp,
        unalign_trp: scb_ccr_unalign_trp,
        usersetmpend: scb_ccr_usersetmpend,
        nonbasethrdena,
    } = scb_ccr;
    unsafe {
        mpu_reset(&mpu);
        drop(mpu);
        drop(stkalign);
        drop(nonbasethrdena);
        (T::take(), ThrInitPeriph {
            scb_ccr_bfhfnmign,
            scb_ccr_div_0_trp,
            scb_ccr_unalign_trp,
            scb_ccr_usersetmpend,
        })
    }
}

#[allow(unused_assignments, unused_variables)]
unsafe fn mpu_reset(mpu: &MpuPeriph) {
    #[cfg(feature = "std")]
    return unimplemented!();
    let mut table_ptr = &MPU_RESET_TABLE;
    if mpu.mpu_type.load().dregion() == 0 {
        return;
    }
    mpu.mpu_ctrl.reset();
    asm!("
        ldmia $0!, {r5-r12}
        stmia $1, {r5-r12}
        ldmia $0!, {r5-r12}
        stmia $1, {r5-r12}
    "   : "+&rm"(table_ptr)
        : "r"(mpu::Rbar::<Srt>::ADDRESS)
        : "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
        : "volatile"
    );
}

#[allow(clippy::cast_lossless)]
const fn rbar_reset(region: u8) -> u32 {
    1 << 4 | region as u32 & 0b1111
}