use atsamd_hal_macros::{hal_cfg, hal_macro_helper};
use super::super::dma_controller::ChId;
use core::marker::PhantomData;
use paste::paste;
use crate::pac::{
self, Dmac, Peripherals,
dmac::{Busych, Intstatus, Pendch, Swtrigctrl},
dmac::{
busych::BusychSpec, intstatus::IntstatusSpec, pendch::PendchSpec,
swtrigctrl::SwtrigctrlSpec,
},
};
#[hal_cfg(any("dmac-d11", "dmac-d21"))]
use pac::dmac as channel_regs;
#[hal_cfg("dmac-d5x")]
use pac::dmac::channel as channel_regs;
use channel_regs::{
Chctrla, Chctrlb, Chintenclr, Chintenset, Chintflag, Chstatus, chctrla::ChctrlaSpec,
chctrlb::ChctrlbSpec, chintenclr::ChintenclrSpec, chintenset::ChintensetSpec,
chintflag::ChintflagSpec, chstatus::ChstatusSpec,
};
#[hal_cfg("dmac-d5x")]
use pac::dmac::channel::{Chprilvl, chprilvl::ChprilvlSpec};
pub(super) trait Register<Id: ChId> {
fn dmac(&self) -> &Dmac;
#[hal_cfg(any("dmac-d11", "dmac-d21"))]
#[inline]
fn with_chid<F: FnOnce(&Dmac) -> R, R>(&mut self, fun: F) -> R {
let dmac = self.dmac();
let mut old_id = 0;
dmac.chid().modify(|r, w| {
old_id = r.id().bits();
unsafe { w.id().bits(Id::U8) }
});
let ret = fun(dmac);
unsafe { dmac.chid().write(|w| w.id().bits(old_id)) };
ret
}
#[hal_cfg("dmac-d5x")]
#[inline]
fn with_chid<F: FnOnce(&pac::dmac::Channel) -> R, R>(&mut self, fun: F) -> R {
let ch = &self.dmac().channel(Id::USIZE);
fun(ch)
}
}
macro_rules! reg_proxy {
(@new $reg:ident) => {
paste! {
pub(super) struct [< $reg:camel Proxy >]<Id: ChId, REG> {
#[allow(unused)]
dmac: Dmac,
_id: PhantomData<Id>,
_reg: PhantomData<REG>,
}
impl<Id: ChId> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> {
#[inline]
pub fn new() -> Self {
Self {
dmac: unsafe { Peripherals::steal().dmac },
_id: PhantomData,
_reg: PhantomData,
}
}
}
}
};
(@read_reg $reg:ident) => {
paste! {
impl<Id: ChId> Register<Id> for [< $reg:camel Proxy >]<Id, [< $reg:camel >]> {
fn dmac(&self) -> &Dmac {
&self.dmac
}
}
impl<Id> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> where Id: ChId, [< $reg:camel Spec>]: pac::generic::Readable {
#[inline]
#[allow(dead_code)]
pub fn read(&mut self) -> channel_regs::[< $reg:lower >]::R {
self.with_chid(|d| d.[< $reg:lower >]().read())
}
}
}
};
($reg:ident, register, r) => {
paste! {
reg_proxy!(@new $reg);
reg_proxy!(@read_reg $reg);
}
};
($reg:ident, register, rw) => {
paste! {
reg_proxy!(@new $reg);
reg_proxy!(@read_reg $reg);
impl<Id> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> where Id: ChId, [< $reg:camel Spec >]: pac::generic::Writable {
#[inline]
#[allow(dead_code)]
pub fn write<F>(&mut self, func: F)
where
for<'w> F: FnOnce(&'w mut channel_regs::[< $reg:lower >]::W) -> &'w mut channel_regs::[< $reg:lower >]::W,
{
self.with_chid(|d| d.[< $reg:lower >]().write(|w| func(w)));
}
}
impl<Id>[< $reg:camel Proxy >]<Id, [< $reg:camel >]> where
Id: ChId,
[< $reg:camel Spec >]: pac::generic::Writable + pac::generic::Readable
{
#[inline]
#[allow(dead_code)]
pub fn modify<F>(&mut self, func: F)
where
for<'w> F: FnOnce(
&channel_regs::[< $reg:lower >]::R,
&'w mut channel_regs::[< $reg:lower >]::W
) -> &'w mut channel_regs::[< $reg:lower >]::W,
{
self.with_chid(|d| d.[< $reg:lower >]().modify(|r, w| func(r, w)));
}
}
}
};
(@read_bit $reg:ident) => {
paste! {
impl<Id: ChId> Register<Id> for [< $reg:camel Proxy >]<Id, [< $reg:camel >]> {
fn dmac(&self) -> &Dmac {
&self.dmac
}
}
impl<Id> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> where Id: ChId, [< $reg:camel Spec >]: pac::generic::Readable {
#[inline]
#[allow(dead_code)]
pub fn read_bit(&self) -> bool {
self.dmac.[< $reg:lower >]().read().bits() & (1 << Id::U8) != 0
}
}
}
};
($reg:ident, bit, r) => {
paste! {
reg_proxy!(@new $reg);
reg_proxy!(@read_bit $reg);
}
};
($reg:ident, bit, rw) => {
paste! {
reg_proxy!(@new $reg);
reg_proxy!(@read_bit $reg);
impl<Id> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> where
Id: ChId,
[< $reg:camel Spec >]: pac::generic::Readable + pac::generic::Writable
{
#[inline]
#[allow(dead_code)]
pub fn set_bit(&mut self) {
unsafe {
self.dmac.[< $reg:lower >]().modify(|r, w| w.bits(r.bits() | (1 << Id::U8)));
}
}
#[inline]
#[allow(dead_code)]
pub fn clear_bit(&mut self) {
unsafe {
self.dmac.[< $reg:lower >]().modify(|r, w| w.bits(r.bits() & !(1 << Id::U8)));
}
}
}
}
};
}
reg_proxy!(chctrla, register, rw);
reg_proxy!(chctrlb, register, rw);
reg_proxy!(chintenclr, register, rw);
reg_proxy!(chintenset, register, rw);
reg_proxy!(chintflag, register, rw);
reg_proxy!(chstatus, register, r);
#[hal_cfg("dmac-d5x")]
reg_proxy!(chprilvl, register, rw);
reg_proxy!(intstatus, bit, r);
reg_proxy!(busych, bit, r);
reg_proxy!(pendch, bit, r);
reg_proxy!(swtrigctrl, bit, rw);
#[allow(dead_code)]
#[hal_macro_helper]
pub(super) struct RegisterBlock<Id: ChId> {
pub chctrla: ChctrlaProxy<Id, Chctrla>,
pub chctrlb: ChctrlbProxy<Id, Chctrlb>,
pub chintenclr: ChintenclrProxy<Id, Chintenclr>,
pub chintenset: ChintensetProxy<Id, Chintenset>,
pub chintflag: ChintflagProxy<Id, Chintflag>,
pub chstatus: ChstatusProxy<Id, Chstatus>,
pub intstatus: IntstatusProxy<Id, Intstatus>,
pub busych: BusychProxy<Id, Busych>,
pub pendch: PendchProxy<Id, Pendch>,
pub swtrigctrl: SwtrigctrlProxy<Id, Swtrigctrl>,
#[hal_cfg("dmac-d5x")]
pub chprilvl: ChprilvlProxy<Id, Chprilvl>,
}
impl<Id: ChId> RegisterBlock<Id> {
#[hal_macro_helper]
pub(super) fn new(_id: PhantomData<Id>) -> Self {
Self {
chctrla: ChctrlaProxy::new(),
chctrlb: ChctrlbProxy::new(),
chintenclr: ChintenclrProxy::new(),
chintenset: ChintensetProxy::new(),
chintflag: ChintflagProxy::new(),
chstatus: ChstatusProxy::new(),
intstatus: IntstatusProxy::new(),
busych: BusychProxy::new(),
pendch: PendchProxy::new(),
swtrigctrl: SwtrigctrlProxy::new(),
#[hal_cfg("dmac-d5x")]
chprilvl: ChprilvlProxy::new(),
}
}
}
impl<Id: ChId> Drop for RegisterBlock<Id> {
fn drop(&mut self) {
self.chctrla.modify(|_, w| w.enable().clear_bit());
while self.chctrla.read().enable().bit_is_set() {
core::hint::spin_loop();
}
core::sync::atomic::fence(core::sync::atomic::Ordering::Acquire); }
}