use crate::pac::INT;
use crate::pac_crate::{Reg, RegisterSpec};
use core::marker::PhantomData;
use core::ptr::{read_volatile, write_volatile};
pub use crate::pac::interrupt::InterruptSource;
pub use crate::pac::interrupt::Interrupt;
#[derive(Debug, Copy, Clone)]
pub struct PriorityConvertError;
#[derive(Copy, Clone, Debug)]
pub struct Ipl(u8);
impl TryFrom<u8> for Ipl {
type Error = PriorityConvertError;
fn try_from(ipl: u8) -> Result<Self, Self::Error> {
if ipl <= 7 {
Ok(Ipl(ipl))
} else {
Err(PriorityConvertError)
}
}
}
impl From<Ipl> for u8 {
fn from(ipl: Ipl) -> Self {
ipl.0
}
}
pub const IPL0: Ipl = Ipl(0);
pub const IPL1: Ipl = Ipl(1);
pub const IPL2: Ipl = Ipl(2);
pub const IPL3: Ipl = Ipl(3);
pub const IPL4: Ipl = Ipl(4);
pub const IPL5: Ipl = Ipl(5);
pub const IPL6: Ipl = Ipl(6);
pub const IPL7: Ipl = Ipl(7);
#[derive(Copy, Clone, Debug)]
pub struct Isl(u8);
impl TryFrom<u8> for Isl {
type Error = PriorityConvertError;
fn try_from(isl: u8) -> Result<Self, Self::Error> {
if isl <= 3 {
Ok(Isl(isl))
} else {
Err(PriorityConvertError)
}
}
}
impl From<Isl> for u8 {
fn from(isl: Isl) -> Self {
isl.0
}
}
pub const ISL0: Isl = Isl(0);
pub const ISL1: Isl = Isl(1);
pub const ISL2: Isl = Isl(2);
pub const ISL3: Isl = Isl(3);
pub struct Int {
_int: PhantomData<INT>,
}
impl Int {
pub fn new(int: INT) -> Int {
int.intconset.write(|w| w.mvec().bit(true));
Int { _int: PhantomData }
}
fn bitaddr<REG: RegisterSpec>(s: InterruptSource, breg: &Reg<REG>) -> (*mut u32, u32) {
let regndx = (s as usize) / 32;
let mask = 1 << ((s as usize) % 32);
let base = breg as *const _ as usize;
let reg = (base + regndx * 0x10) as *mut u32;
(reg, mask)
}
pub fn ei(&self, s: InterruptSource) {
let (reg, mask) = Self::bitaddr(s, unsafe { &(*INT::ptr()).iec0set });
unsafe { write_volatile(reg, mask) };
}
pub fn di(&self, s: InterruptSource) {
let (reg, mask) = Self::bitaddr(s, unsafe { &(*INT::ptr()).iec0clr });
unsafe { write_volatile(reg, mask) };
}
pub fn is_ie(&self, s: InterruptSource) -> bool {
let (reg, mask) = Self::bitaddr(s, unsafe { &(*INT::ptr()).iec0 });
unsafe { read_volatile(reg) & mask != 0 }
}
pub fn get_if(&self, s: InterruptSource) -> bool {
let (reg, mask) = Self::bitaddr(s, unsafe { &(*INT::ptr()).ifs0 });
unsafe { read_volatile(reg) & mask != 0 }
}
pub fn clear_if(&self, s: InterruptSource) {
let (reg, mask) = Self::bitaddr(s, unsafe { &(*INT::ptr()).ifs0clr });
unsafe { write_volatile(reg, mask) };
}
pub fn set_if(&self, s: InterruptSource) {
let (reg, mask) = Self::bitaddr(s, unsafe { &(*INT::ptr()).ifs0set });
unsafe { write_volatile(reg, mask) };
}
fn byteaddr<REG: RegisterSpec>(iv: Interrupt, breg: &Reg<REG>) -> (*mut u32, usize) {
let regndx = (iv as usize) / 4;
let bytepos = ((iv as usize) % 4) * 8;
let base = breg as *const _ as usize;
let reg = (base + regndx * 0x10) as *mut u32;
(reg, bytepos)
}
pub fn set_ipl(&self, iv: Interrupt, ipl: Ipl) {
let (reg, bytepos) = Self::byteaddr(iv, unsafe { &(*INT::ptr()).ipc0 });
let bitpos = bytepos + 2;
let mask = 0x07 << bitpos;
unsafe { write_volatile(reg, read_volatile(reg) & !mask | ((ipl.0 as u32) << bitpos)) };
}
pub fn ipl(&self, iv: Interrupt) -> Ipl {
let (reg, bytepos) = Self::byteaddr(iv, unsafe { &(*INT::ptr()).ipc0 });
let bitpos = bytepos + 2;
unsafe { Ipl((read_volatile(reg) >> bitpos) as u8 & 0x07) }
}
pub fn set_isl(&self, iv: Interrupt, isl: Isl) {
let (reg, bitpos) = Self::byteaddr(iv, unsafe { &(*INT::ptr()).ipc0 });
let mask = 0x03 << bitpos;
unsafe { write_volatile(reg, read_volatile(reg) & !mask | ((isl.0 as u32) << bitpos)) };
}
pub fn isl(&self, iv: Interrupt) -> Isl {
let (reg, bitpos) = Self::byteaddr(iv, unsafe { &(*INT::ptr()).ipc0 });
unsafe { Isl((read_volatile(reg) >> bitpos) as u8 & 0x03) }
}
}