1use crate::{
2 access::{Read, Write},
3 endian::Endian,
4 reg::{RegInt, Register},
5};
6use core::cell::RefCell;
7use num_traits::{AsPrimitive, Bounded, ConstZero};
8
9pub trait RawRegisterIO {
13 type Error;
18
19 #[allow(clippy::missing_errors_doc)]
29 unsafe fn try_read<T: RegInt>(&self, ptr: *const T) -> Result<T, Self::Error>;
30
31 #[allow(clippy::missing_errors_doc)]
41 unsafe fn try_write<T: RegInt>(&self, ptr: *mut T, value: T) -> Result<(), Self::Error>;
42}
43
44pub trait RegisterIO {
52 type Error;
53
54 #[allow(clippy::missing_errors_doc)]
64 unsafe fn try_read_register<R: Register>(
65 &self,
66 ptr: *const R::Regwidth,
67 ) -> Result<R, Self::Error>
68 where
69 R::Access: Read;
70
71 #[allow(clippy::missing_errors_doc)]
81 unsafe fn try_write_register<R: Register>(
82 &self,
83 ptr: *mut R::Regwidth,
84 value: R,
85 ) -> Result<(), Self::Error>
86 where
87 R::Access: Write;
88}
89
90impl<T> RegisterIO for T
91where
92 T: RawRegisterIO,
93{
94 type Error = T::Error;
95
96 unsafe fn try_read_register<R: Register>(
97 &self,
98 ptr: *const R::Regwidth,
99 ) -> Result<R, Self::Error>
100 where
101 R::Access: Read,
102 {
103 let ptr = ptr.cast::<R::Accesswidth>();
104
105 let accesswidth = 8 * core::mem::size_of::<R::Accesswidth>();
106 let regwidth = 8 * core::mem::size_of::<R::Regwidth>();
107 let num_subwords = regwidth / accesswidth;
108
109 let raw_value = (0..num_subwords)
111 .map(|i| {
112 unsafe { (i, self.try_read(ptr.wrapping_add(i))) }
115 })
116 .try_fold(R::Regwidth::ZERO, |reg, (i, subword)| {
117 let significance = R::WordEndian::address_order_to_significance(i, num_subwords);
118 let subword = R::ByteEndian::from_register_endian(subword?);
119 Ok(reg | (subword.as_() << (significance * accesswidth)))
120 })?;
121 unsafe { Ok(R::from_raw(raw_value)) }
124 }
125
126 unsafe fn try_write_register<R: Register>(
127 &self,
128 ptr: *mut R::Regwidth,
129 value: R,
130 ) -> Result<(), Self::Error>
131 where
132 R::Access: Write,
133 {
134 let ptr = ptr.cast::<R::Accesswidth>();
135 let value = value.to_raw();
136
137 let accesswidth = 8 * core::mem::size_of::<R::Accesswidth>();
138 let regwidth = 8 * core::mem::size_of::<R::Regwidth>();
139 let num_subwords = regwidth / accesswidth;
140 let mask = R::Accesswidth::max_value().as_();
141
142 for i in 0..num_subwords {
144 let significance = R::WordEndian::address_order_to_significance(i, num_subwords);
145 let subword = (value >> (significance * accesswidth)) & mask;
146 let subword = R::ByteEndian::to_register_endian(subword.as_());
147 unsafe {
150 self.try_write(ptr.wrapping_add(i), subword)?;
151 }
152 }
153 Ok(())
154 }
155}
156
157pub struct PtrIO;
162
163impl RawRegisterIO for PtrIO {
164 type Error = core::convert::Infallible;
165
166 unsafe fn try_read<T: RegInt>(&self, ptr: *const T) -> Result<T, Self::Error> {
167 Ok(unsafe { ptr.read_volatile() })
168 }
169
170 unsafe fn try_write<T: RegInt>(&self, ptr: *mut T, value: T) -> Result<(), Self::Error> {
171 unsafe { ptr.write_volatile(value) };
172 Ok(())
173 }
174}
175
176pub struct MockIO<const N: usize>(RefCell<[u8; N]>);
181
182impl<const N: usize> MockIO<N> {
183 #[must_use]
185 pub fn new_zeroed() -> Self {
186 Self(RefCell::new([0; N]))
187 }
188
189 pub fn base_ptr(&self) -> *mut () {
191 0 as _
192 }
193}
194
195impl<const N: usize> RawRegisterIO for MockIO<N> {
196 type Error = core::convert::Infallible;
197
198 unsafe fn try_read<T: RegInt>(&self, ptr: *const T) -> Result<T, Self::Error> {
199 let addr = ptr.addr();
200 let size = core::mem::size_of::<T>();
201 let data = self.0.borrow();
202 let bytes = &data[addr..addr + size];
203 Ok(T::from_ne_bytes(
204 &bytes.try_into().expect("Incorrect slice length"),
205 ))
206 }
207
208 unsafe fn try_write<T: RegInt>(&self, ptr: *mut T, value: T) -> Result<(), Self::Error> {
209 let addr = ptr.addr();
210 let size = core::mem::size_of::<T>();
211 let mut data = self.0.borrow_mut();
212 let bytes = &mut data[addr..addr + size];
213 bytes.copy_from_slice(value.to_ne_bytes().as_ref());
214 Ok(())
215 }
216}