/* {{ir.license_text}} */ // Generated from SVD {{ir.version}}, with svd2pac {{svd2pac_version}} on {{now}} use ::core::convert::From; use ::core::marker::PhantomData; {% if tracing %} #[cfg(feature = "tracing")] use crate::tracing; {% endif %} #[derive(Copy, Clone, PartialEq, Eq)] pub struct RW; #[derive(Copy, Clone, PartialEq, Eq)] pub struct R; #[derive(Copy, Clone, PartialEq, Eq)] pub struct W; pub(crate) mod sealed { use super::*; pub trait Access {} impl Access for R {} impl Access for W {} impl Access for RW {} use ::core::ops::{BitAnd, BitAndAssign, BitOrAssign, Not, Shl, Shr}; // It would be better with const fn // waiting for RFC: const functions in traits #3490 pub trait CastFrom { fn cast_from(val: A) -> Self; } impl CastFrom for u8 { #[inline(always)] fn cast_from(val: u64) -> Self { val as Self } } impl CastFrom for u16 { #[inline(always)] fn cast_from(val: u64) -> Self { val as Self } } impl CastFrom for u32 { #[inline(always)] fn cast_from(val: u64) -> Self { val as Self } } impl CastFrom for u64 { #[inline(always)] fn cast_from(val: u64) -> Self { val as Self } } pub trait RegNumberT: Copy + From + Into + CastFrom + Shr + Shl + BitAndAssign + BitAnd + Not + BitOrAssign { } impl RegNumberT for u8 {} impl RegNumberT for u16 {} impl RegNumberT for u32 {} impl RegNumberT for u64 {} pub trait RegSpec { type DataType: RegNumberT; } } pub trait Access: sealed::Access + Copy {} impl Access for R {} impl Access for W {} impl Access for RW {} pub trait Read: Access {} impl Read for RW {} impl Read for R {} pub trait Write: Access {} impl Write for RW {} impl Write for W {} #[derive(Copy, Clone, PartialEq, Eq)] pub struct Reg { ptr: *mut u8, phantom: PhantomData<*mut (T, A)>, } unsafe impl Send for Reg {} unsafe impl Sync for Reg {} use sealed::CastFrom; use sealed::{RegNumberT, RegSpec}; #[doc(hidden)] #[derive(Copy, Clone)] pub struct RegValueT { pub(crate) data: Reg::DataType, pub(crate) mask: Reg::DataType, } pub trait RegisterValue { /// Create a register value that could be written to a register from raw integer /// /// ```rust, ignore /// // example with generic names /// // needs: use test_pac::{timer, RegisterValue, TIMER} /// let to_write = timer::BitfieldReg::new(0xdeadbeef); /// TIMER.bitfield_reg().write(to_write); /// let to_write = to_write.boolw().set(true); /// TIMER.bitfield_reg().write(to_write); /// ``` #[must_use] fn new(data: T::DataType) -> Self; /// Get raw integer from value read from register /// /// ```rust,ignore /// // example with generic names /// // needs: use pac::{RegisterValue, TIMER} /// let x = TIMER.bitfield_reg().read().get_raw(); /// ``` #[must_use] fn get_raw(&self) -> T::DataType; /// Prepare a register value that could be written to a register with an arbitrary value /// /// Use this function for setting a register to a custom value, independent /// of bitfields, enumerations, etc. No checks are performed on the passed /// value. The whole register is updated on write. /// /// ```rust,ignore /// // example with generic names /// // needs: use pac::{RegisterValue, TIMER} /// TIMER.bitfield_reg().init(|r| r.set_raw(0xdeadbeef)) /// ``` #[must_use] fn set_raw(self, value: T::DataType) -> Self; } impl RegisterValue for RegValueT { /// Create a register value that could be written to a register from raw integer /// /// ```rust, ignore /// // example with generic names /// // needs: use pac::{timer, RegisterValue, TIMER} /// let to_write = timer::BitfieldReg::new(0xdeadbeef); /// TIMER.bitfield_reg().write(to_write); /// let to_write = to_write.boolw().set(true); /// TIMER.bitfield_reg().write(to_write); /// ``` #[inline(always)] fn new(data: T::DataType) -> RegValueT { Self { data, mask: 0x0u8.into(), } } /// Get raw integer from value read from register /// /// ```rust,ignore /// // example with generic names /// // needs: use pac::{RegisterValue, TIMER} /// let x = TIMER.bitfield_reg().read().get_raw(); /// ``` #[inline(always)] fn get_raw(&self) -> T::DataType { self.data } /// Prepare a register value that could be written to a register with an arbitrary value /// /// Use this function for setting a register to a custom value, independent /// of bitfields, enumerations, etc. No checks are performed on the passed /// value. /// /// ```rust,ignore /// // example with generic names /// // needs: use pac::{RegisterValue, TIMER} /// TIMER.bitfield_reg().init(|r| r.set_raw(0xdeadbeef)) /// ``` #[inline(always)] fn set_raw(mut self, value: T::DataType) -> Self { self.data = value; self.mask = !(Into::::into(0x0u8)); self } } pub trait NoBitfieldReg: RegisterValue where Self: Sized, { /// Get value read from register /// /// ```rust,ignore /// // example with generic names /// // needs: use pac::{NoBitfieldReg, TIMER} /// let x = TIMER.nobitfield_reg().read().get(); /// ``` #[inline(always)] #[must_use] fn get(&self) -> Reg::DataType { self.get_raw() } /// Prepare value to be written to register /// /// ```rust,ignore /// // example with generic names /// // needs: use pac::{NoBitfieldReg, TIMER} /// TIMER.nobitfield_reg().init(|r| r.set(0xc0ffee)); /// ``` #[inline(always)] #[must_use] fn set(self, value: Reg::DataType) -> Self { self.set_raw(value) } } impl Reg where T: RegSpec, A: Access, { #[inline(always)] #[must_use] pub(crate) const fn from_ptr(ptr: *mut u8) -> Self { Self { ptr, phantom: PhantomData, } } #[inline(always)] #[must_use] pub const fn ptr(&self) -> *mut T::DataType { self.ptr as _ } {% if tracing %} /// Returns the address of the register. pub fn addr(&self) -> usize { self.ptr as usize } {% endif %} } impl Reg where T: RegSpec, A: Read, { /// Read register and return a register value /// /// # Safety /// Read operation could cause undefined behavior for some peripheral. Developer shall read device user manual. /// Register is Send and Sync to allow complete freedom. Developer is responsible of proper use in interrupt and thread. /// /// # Example /// ```rust,ignore /// // example with generic names /// let reg = unsafe { TIMER.bitfield_reg().read() }; /// if reg.boolr().get() { /* ... */ } /// ``` #[inline(always)] #[must_use] pub unsafe fn read(&self) -> RegValueT { {% if tracing %} #[cfg(feature = "tracing")] let val = { let mut buf: u64 = 0x0; tracing::READ_FN.with(|rf| { if let Some(rf) = rf.get() { buf = rf(self.addr(), std::mem::size_of::()); } else { #[cfg(not(feature = "tracing_dummy"))] panic!("Please, provide an handler for read with tracing::set_read_fn(callback);"); } }); T::DataType::cast_from(buf) }; #[cfg(not(feature = "tracing"))] {% endif %} let val = (self.ptr as *mut T::DataType).read_volatile(); RegValueT::::new(val) } } impl Reg where T: RegSpec, A: Write, { /// Write register value back to register /// /// # Arguments /// /// * `reg_value` - A string slice that holds the name of the person /// /// # Safety /// Write operation could cause undefined behavior for some peripheral. Developer shall read device user manual. /// Register is Send and Sync to allow complete freedom. Developer is responsible of proper use in interrupt and thread. /// /// # Example /// ```rust,ignore /// // example with generic names /// // write with a previously read value /// let reg = unsafe { TIMER.bitfield_reg().read() }; /// // or start with a known value /// let reg = timer::BitfieldReg::new(0).bitfieldw().set(0x55); /// // or start with the register default /// let reg = timer::BitfieldReg::default(); /// /// let reg = reg.bitfieldrw().set(0x77); /// /// // no change has taken place to the register due to `set` calls - do that now by writing back the result /// unsafe { TIMER.bitfield_reg().write(reg) } /// ``` /// See also: [`Reg::init`] which provides the default value to a closure #[inline(always)] pub unsafe fn write(&self, reg_value: RegValueT) { {% if tracing %} #[cfg(feature = "tracing")] tracing::WRITE_FN.with(|wf| { if let Some(wf) = wf.get() { wf( self.addr(), std::mem::size_of::(), reg_value.data.into(), ) } else { #[cfg(not(feature = "tracing_dummy"))] panic!("Please, provide an handler for read with tracing::set_read_fn(callback);"); } }); #[cfg(not(feature = "tracing"))] {% endif %} (self.ptr as *mut T::DataType).write_volatile(reg_value.data); } } impl Reg where T: RegSpec, A: Write, RegValueT: Default, { /// Write register with register value built from default register value /// /// # Arguments /// /// * `f` - Closure that receive as input a register value initialized with register value at Power On Reset. /// /// # Safety /// Write operation could cause undefined behavior for some peripheral. Developer shall read device user manual. /// Register is Send and Sync to allow complete freedom. Developer is responsible of proper use in interrupt and thread. /// /// # Example /// ```rust,ignore /// // example with generic names /// TIMER /// .bitfield_reg() /// .init(|r| r.bitfieldw().set(0b1010).boolw().set(true)); /// ``` #[inline(always)] /// Write value computed by closure that receive as input the reset value of register pub unsafe fn init(&self, f: impl FnOnce(RegValueT) -> RegValueT) { let val = RegValueT::::default(); let res = f(val); self.write(res); } } impl Reg where T: RegSpec, A: Read + Write, { /// Read/modify/write register /// /// # Arguments /// /// * `f` - Closure that receive as input a register value read from register. The result of the closure /// is written back to the register. /// /// # Safety /// Write operation could cause undefined behavior for some peripheral. Developer shall read device user manual. /// Register is Send and Sync to allow complete freedom. Developer is responsible of proper use in interrupt and thread. /// /// # Example /// ```rust,ignore /// // example with generic names /// TIMER /// .bitfield_reg() /// .modify(|r| r.boolrw().set(!r.boolrw().get())); /// ``` #[inline(always)] pub unsafe fn modify(&self, f: impl FnOnce(RegValueT) -> RegValueT) { let val = self.read(); let res = f(val); self.write(res); } } {% if target=="Aurix" %} impl Reg where T: RegSpec, RegValueT: Default, A: Write, { /// Read/modify/write register atomically /// /// Only the bitfield updated by closure are written back to the register. /// `modify_atomic` use `ldmst` assembly instruction that stall the bus until update completion. /// This function can be used only with 32 bits register. /// /// # Arguments /// /// * `f` - Closure that receive as input register value initialized with register value at Power On Reset. /// /// # Safety /// Write operation could cause undefined behavior for some peripheral. Developer shall read device user manual. /// Register is Send and Sync to allow complete freedom. Developer is responsible of proper use in interrupt and thread. /// /// # Example /// ```rust,ignore /// // example with generic names /// TIMER /// .bitfield_reg() /// .modify_atomic(|r| r.boolrw().set(!r.boolrw().get())); /// ``` #[inline(always)] pub unsafe fn modify_atomic(&self, f: impl FnOnce(RegValueT) -> RegValueT) { let val = RegValueT::::default(); let res = f(val); {% if tracing %} #[cfg(feature="tracing")] tracing::LDMST.with(|ldmstf| { if let Some(ldmstf) = ldmstf.get() { ldmstf(self.addr(), res.data as u64 | ((res.mask as u64) << 32)) } else { #[cfg(not(feature = "tracing_dummy"))] panic!("Please, provide an handler for ldmst with tracing::set_ldmst_fn(callback);"); } }); #[cfg(not(feature="tracing"))] {% endif -%} unsafe { ::core::arch::tricore::intrinsics::__ldmst(self.ptr as *mut u32, res.data, res.mask); } } } #[cfg(not(feature="tracing"))] use ::core::arch::tricore::intrinsics::{__mfcr, __mtcr}; /// Type of core special register of Aurix (CSFR) pub struct RegCore { phantom: PhantomData<*mut (T, A)>, } impl RegCore { pub const unsafe fn new() -> Self { RegCore { phantom: PhantomData, } } } unsafe impl Send for RegCore {} unsafe impl Sync for RegCore {} impl, A: Access, const ADDR: u16> RegCore { /// Read Aurix core register (32 bit wide) and return a register value /// /// # Safety /// Read operation could cause undefined behavior for some core register. Developer shall read device user manual. /// Function must be executed from proper core. /// Register is Send and Sync to allow complete freedom. Developer is responsible of proper use in interrupt and thread. /// /// # Example /// ```rust,ignore /// // example with generic names /// let id = CSFR_CPU.cpu_id().read(); /// if id.mod_rev().get() == 0 { /* ... */ } /// ``` #[inline(always)] #[must_use] pub unsafe fn read(&self) -> RegValueT where A: Read, { #[cfg(feature = "tracing")] let val = { let mut buf: u64 = 0x0; tracing::READ_FN.with(|rf| { buf = rf.get().unwrap()(ADDR as usize, std::mem::size_of::()); }); T::DataType::cast_from(buf) }; #[cfg(not(feature = "tracing"))] let val: T::DataType = __mfcr::(); RegValueT::::new(val) } /// Write Aurix core register (32 bit wide) value back to register /// /// # Arguments /// /// * `reg_value` - A string slice that holds the name of the person /// /// # Safety /// Write operation could cause undefined behavior for some core register. Developer shall read device user manual. /// Function must be executed from proper core. /// Register is Send and Sync to allow complete freedom. Developer is responsible of proper use in interrupt and thread. /// /// # Example /// ```rust,ignore /// // example with generic names /// // write with value read from register earlier /// let dy0 = CSFR_CPU.dy0().read().data().get() + 1; /// CSFR_CPU.dy0().write(dy0); /// /// // or write with new value /// let dy0 = csfr_cpu0::Dy0::new(0x1234); /// CSFR_CPU.dy0().write(dy0); /// ``` #[inline(always)] pub unsafe fn write(&self, reg_value: RegValueT) where A: Write, { #[cfg(feature = "tracing")] tracing::WRITE_FN.with(|wf| { wf.get().unwrap()( ADDR as usize, std::mem::size_of::(), reg_value.data.into(), ) }); #[cfg(not(feature = "tracing"))] __mtcr::(reg_value.data); } /// Write Aurix core register (32 bit wide) with value built from default register value /// /// # Arguments /// /// * `f` - Closure that receive as input a register value initialized with register value at Power On Reset. /// /// # Safety /// Write operation could cause undefined behavior for some peripheral. Developer shall read device user manual. /// Register is Send and Sync to allow complete freedom. Developer is responsible of proper use in interrupt and thread. /// /// # Example /// ```rust,ignore /// // example with generic names /// CSFR_CPU.dy0().init(|r| r.data().set(0x1234_5678)); /// ``` #[inline(always)] pub unsafe fn init(&self, f: impl FnOnce(RegValueT) -> RegValueT) where A: Write, RegValueT: Default, { let val = Default::default(); let res = f(val); self.write(res); } /// Read/modify/write Aurix core register (32 bit wide) /// /// # Arguments /// /// * `f` - Closure that receive as input a register value read from register. /// /// # Safety /// Write operation could cause undefined behavior for some peripheral. Developer shall read device user manual. /// Register is Send and Sync to allow complete freedom. Developer is responsible of proper use in interrupt and thread. /// /// # Example /// ```rust,ignore /// // example with generic names /// CSFR_CPU /// .dy0() /// .modify(|r| r.data().set(r.data().get() + 0x1234_5678)); /// ``` #[inline(always)] pub unsafe fn modify(&self, f: impl FnOnce(RegValueT) -> RegValueT) where A: Read + Write, { let val = self.read(); let res = f(val); self.write(res); } } {% endif %} /// Proxy struct for enumerated bitfields #[repr(transparent)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] pub struct EnumBitfieldStruct(pub Q, PhantomData); impl EnumBitfieldStruct { pub const fn new(value: Q) -> Self { Self(value, PhantomData) } } impl From> for u64 { #[inline(always)] fn from(value: EnumBitfieldStruct) -> Self { value.0.into() } } impl CastFrom for EnumBitfieldStruct { #[inline(always)] fn cast_from(val: u64) -> Self { Self(Q::cast_from(val), PhantomData) } } impl From for EnumBitfieldStruct { #[inline(always)] fn from(value: Q) -> Self { Self(value, PhantomData) } } /// Proxy struct for numeric bitfields pub struct RegisterField< const START_OFFSET: usize, const MASK: u64, const DIM: u8, const DIM_INCREMENT: u8, ValueType, T, A, > where T: RegSpec, A: Access, { data: RegValueT, index: u8, marker: PhantomData<(ValueType, A)>, } impl< const START_OFFSET: usize, const MASK: u64, const DIM: u8, const DIM_INCREMENT: u8, ValueType, T, A, > RegisterField where T: RegSpec, A: Access, { #[allow(dead_code)] #[inline(always)] pub(crate) fn from_register(data: RegValueT, index: u8) -> Self { Self { data, index, marker: PhantomData, } } /// Get mask for bitfield, the mask is unshifted and at offset 0 /// /// Prefer the use of [`RegisterField::get()`] to /// extract a bitfield value. #[inline(always)] #[must_use] pub fn mask(&self) -> T::DataType { T::DataType::cast_from(MASK) } /// Get offset of bitfield in containing register /// /// Prefer the use of [`RegisterField::get()`] to /// extract a bitfield value. #[inline(always)] #[must_use] pub const fn offset(&self) -> usize { START_OFFSET + (self.index * DIM_INCREMENT) as usize } } impl< const START_OFFSET: usize, const MASK: u64, const DIM: u8, const DIM_INCREMENT: u8, ValueType, T, A, > RegisterField where T: RegSpec, A: Read, ValueType: CastFrom, { /// Extract bitfield from read register value #[inline(always)] pub fn get(&self) -> ValueType { let offset = START_OFFSET + (self.index * DIM_INCREMENT) as usize; let filtered: T::DataType = (self.data.data >> offset) & T::DataType::cast_from(MASK); ValueType::cast_from(filtered.into()) } } impl< const START_OFFSET: usize, const MASK: u64, const DIM: u8, const DIM_INCREMENT: u8, ValueType, T, A, > RegisterField where T: RegSpec, A: Write, u64: From, { /// Prepare bitfield value that could be written to register /// /// # Example /// ```rust,ignore /// // example with generic names /// // get an instance by reading /// let values = TIMER.bitfield_reg().read(); /// // or by starting with a known value /// let value = timer::BitfieldReg::new(0); /// // or by starting with the default /// let value = timer::BitfieldReg::default(); /// /// // set bitfields /// let value = value /// // set numeric bitfield /// .bitfieldw() /// .set(0x55) /// // set enumerated bitfield with enumeration /// .bitfieldenumerated() /// .set(timer::bitfield_reg::BitfieldEnumerated::GPIOA_0) /// // set enumerated bitfield from integer /// .bitfieldenumerated() /// .set(1.into()); /// /// // up until now no hardware change has taken place, do that now by writing /// TIMER.bitfield_reg().write(value); /// ``` #[inline(always)] #[must_use] pub fn set(mut self, value: ValueType) -> RegValueT { let mask = T::DataType::cast_from(MASK); let value: T::DataType = T::DataType::cast_from(Into::::into(value)) & mask; let offset = START_OFFSET + (self.index * DIM_INCREMENT) as usize; let masked_offset: T::DataType = mask << offset; self.data.mask |= masked_offset; self.data.data &= !masked_offset; self.data.data |= value << offset; self.data } } /// Proxy struct for boolean bitfields pub struct RegisterFieldBool< const START_OFFSET: usize, const DIM: u8, const DIM_INCREMENT: u8, T, A, > where T: RegSpec, A: Access, { data: RegValueT, index: u8, marker: PhantomData, } impl RegisterFieldBool where T: RegSpec, A: Read, { /// Extract bitfield from read register value #[inline(always)] pub fn get(&self) -> bool { let offset = START_OFFSET + (self.index * DIM_INCREMENT) as usize; let filtered = (self.data.data.into() >> offset) & 1; filtered == 1 } } impl RegisterFieldBool where T: RegSpec, A: Write, { /// Prepare bitfield value to be written to register /// /// # Example /// ```rust,ignore /// // example with generic names /// // get an instance by reading /// let values = TIMER.bitfield_reg().read(); /// // or by starting with a known value /// let value = timer::BitfieldReg::new(0); /// // or by starting with the default /// let value = timer::BitfieldReg::default(); /// /// // set bitfield /// let value = value /// .boolrw() /// .set(true); /// /// // up until now no hardware change has taken place, do that now by writing /// TIMER.bitfield_reg().write(value); /// ``` #[inline(always)] #[must_use] pub fn set(mut self, value: bool) -> RegValueT { let value: T::DataType = if value { T::DataType::cast_from(1u64) } else { T::DataType::cast_from(0u64) }; let offset = START_OFFSET + (self.index * DIM_INCREMENT) as usize; let masked_offset = T::DataType::cast_from(0x1u64) << offset; self.data.mask |= masked_offset; self.data.data &= !masked_offset; self.data.data |= value << offset; self.data } } impl RegisterFieldBool where T: RegSpec, A: Access, { #[inline(always)] #[allow(dead_code)] pub(crate) fn from_register(data: RegValueT, index: u8) -> Self { Self { data, index, marker: PhantomData, } } /// Get mask for bitfield, the mask is unshifted and at offset 0 /// /// Prefer the use of [`RegisterField::get()`] to /// extract a bitfield value. #[inline(always)] #[must_use] pub fn mask(&self) -> T::DataType { T::DataType::cast_from(1) } /// Get offset of bitfield in containing register /// /// Prefer the use of [`RegisterField::get()`] to /// extract a bitfield value. #[inline(always)] #[must_use] pub const fn offset(&self) -> usize { START_OFFSET + (self.index * DIM_INCREMENT) as usize } }