use super::super::{Mk20Dx128, Mk20Dx256, Mk64Fx512, Mk66Fx1M0, Mkl26Z64};
use crate::{
register::{Register, Reserved},
sync::Flag,
};
use bit_field::BitField;
use core::{marker::PhantomData, sync::atomic::Ordering};
pub unsafe trait Peripheral<T> {
const GATE: (usize, usize);
unsafe fn new(gate: Gate) -> Self;
}
#[repr(C)]
struct SimRegs {
sopt1: Register<u32>,
sopt1_cfg: Register<u32>,
_reserved_0: [Reserved<u32>; 1023],
sopt2: Register<u32>,
_reserved_1: Reserved<u32>,
sopt4: Register<u32>,
sopt5: Register<u32>,
_reserved_2: Reserved<u32>,
sopt7: Register<u32>,
_reserved_3: [Reserved<u32>; 2],
sdid: Register<u32>,
scgc: [Register<u32>; 7],
clkdiv: [Register<u32>; 2],
fcfg: [Register<u32>; 2],
uid: [Register<u32>; 4],
_reserved_4: [Reserved<u32>; 40],
copc: Register<u32>,
srvcop: Register<u32>,
}
pub struct Sim<M> {
regs: &'static mut SimRegs,
_mcu: PhantomData<M>,
}
#[derive(PartialEq)]
pub enum UsbClockSource {
UsbClkIn,
PllFll,
}
#[derive(PartialEq)]
pub enum UartClockSource {
PllFll,
Oscer,
Mcgir,
}
#[derive(PartialEq)]
pub enum PeripheralClockSource {
Fll,
Pll,
Irc48,
}
static LOCK: Flag = Flag::new(false);
impl<M> Sim<M> {
pub fn get() -> Option<Self> {
unsafe {
if LOCK.swap(true, Ordering::Acquire) {
None
} else {
Some(Self {
regs: &mut *(0x4004_7000 as *mut _),
_mcu: PhantomData,
})
}
}
}
pub fn set_usb_source(&mut self, source: UsbClockSource) {
self.regs.sopt2.update(|sopt2| {
sopt2.set_bit(18, source == UsbClockSource::PllFll);
})
}
pub fn set_peripheral_source(&mut self, source: PeripheralClockSource) {
let source = match source {
PeripheralClockSource::Fll => 0,
PeripheralClockSource::Pll => 1,
PeripheralClockSource::Irc48 => 3,
};
self.regs.sopt2.update(|sopt2| {
sopt2.set_bits(16..18, source);
});
}
pub fn enable_peripheral<P: Peripheral<M>>(&mut self) -> Option<P> {
unsafe {
let gate = bitband_address(self.regs.scgc.as_mut_ptr().add(P::GATE.0 - 1), P::GATE.1);
if core::ptr::read_volatile(gate) != 0 {
None
} else {
core::ptr::write_volatile(gate, 1);
Some(P::new(Gate(gate)))
}
}
}
}
impl Sim<Mk20Dx128> {
pub fn set_dividers(&mut self, core: u32, bus: u32, flash: u32) {
self.regs.clkdiv[0].update(|clkdiv| {
clkdiv.set_bits(28..32, core - 1);
clkdiv.set_bits(24..28, bus - 1);
clkdiv.set_bits(16..20, flash - 1);
});
}
pub fn set_usb_dividers(&mut self, numerator: u32, denominator: u32) {
self.regs.clkdiv[1].update(|clkdiv| {
clkdiv.set_bits(0..1, numerator - 1);
clkdiv.set_bits(1..4, denominator - 1);
})
}
}
impl Sim<Mk20Dx256> {
pub fn set_dividers(&mut self, core: u32, bus: u32, flash: u32) {
self.regs.clkdiv[0].update(|clkdiv| {
clkdiv.set_bits(28..32, core - 1);
clkdiv.set_bits(24..28, bus - 1);
clkdiv.set_bits(16..20, flash - 1);
});
}
pub fn set_usb_dividers(&mut self, numerator: u32, denominator: u32) {
self.regs.clkdiv[1].update(|clkdiv| {
clkdiv.set_bits(0..1, numerator - 1);
clkdiv.set_bits(1..4, denominator - 1);
})
}
}
impl Sim<Mk64Fx512> {
pub fn set_dividers(&mut self, core: u32, bus: u32, flex: u32, flash: u32) {
self.regs.clkdiv[0].update(|clkdiv| {
clkdiv.set_bits(28..32, core - 1);
clkdiv.set_bits(24..28, bus - 1);
clkdiv.set_bits(20..24, flex - 1);
clkdiv.set_bits(16..20, flash - 1);
});
}
pub fn set_usb_dividers(&mut self, numerator: u32, denominator: u32) {
self.regs.clkdiv[1].update(|clkdiv| {
clkdiv.set_bits(0..1, numerator - 1);
clkdiv.set_bits(1..4, denominator - 1);
})
}
}
impl Sim<Mk66Fx1M0> {
pub fn set_dividers(&mut self, core: u32, bus: u32, flex: u32, flash: u32) {
self.regs.clkdiv[0].update(|clkdiv| {
clkdiv.set_bits(28..32, core - 1);
clkdiv.set_bits(24..28, bus - 1);
clkdiv.set_bits(20..24, flex - 1);
clkdiv.set_bits(16..20, flash - 1);
});
}
pub fn set_usb_dividers(&mut self, numerator: u32, denominator: u32) {
self.regs.clkdiv[1].update(|clkdiv| {
clkdiv.set_bits(0..1, numerator - 1);
clkdiv.set_bits(1..4, denominator - 1);
})
}
}
impl Sim<Mkl26Z64> {
pub fn set_dividers(&mut self, core: u32, flash: u32) {
self.regs.clkdiv[0].update(|clkdiv| {
clkdiv.set_bits(28..32, core - 1);
clkdiv.set_bits(16..20, flash - 1);
});
}
pub fn disable_cop(&mut self) {
self.regs.copc.update(|copc| {
copc.set_bits(2..4, 0);
});
}
pub fn set_uart0_source(&mut self, source: Option<UartClockSource>) {
let source = match source {
None => 0,
Some(UartClockSource::PllFll) => 1,
Some(UartClockSource::Oscer) => 2,
Some(UartClockSource::Mcgir) => 3,
};
self.regs.sopt2.update(|sopt2| {
sopt2.set_bits(26..28, source);
});
}
}
impl<M> Drop for Sim<M> {
fn drop(&mut self) {
LOCK.store(false, Ordering::Release);
}
}
pub struct Gate(*mut u32);
unsafe impl Send for Gate {}
impl Drop for Gate {
fn drop(&mut self) {
unsafe {
core::ptr::write_volatile(self.0, 0);
}
}
}
unsafe fn bitband_address<T>(addr: *mut Register<T>, bit: usize) -> *mut T {
(0x4200_0000 + (addr as usize - 0x4000_0000) * 32 + bit * 4) as _
}