dma_api/array.rs
1use core::{alloc::Layout, ptr::NonNull};
2
3use crate::{DeviceDma, DmaDirection, DmaError, common::DCommon};
4
5/// DMA 可访问的数组容器。
6///
7/// `DArray<T>` 提供固定大小的 DMA 可访问数组,支持自动缓存同步。
8/// 每次访问元素(`read`/`set`)时都会根据 DMA 方向自动处理缓存操作。
9///
10/// # 类型参数
11///
12/// - `T`: 数组元素类型
13///
14/// # 缓存同步
15///
16/// 缓存同步在每次元素访问时自动执行:
17/// - `read(index)`: 读取前使 CPU 缓存失效(FromDevice/Bidirectional)
18/// - `set(index, value)`: 写入后刷新 CPU 缓存(ToDevice/Bidirectional)
19/// - `copy_from_slice(slice)`: 写入后刷新整个范围
20///
21/// # 示例
22///
23/// ```rust,ignore
24/// use dma_api::{DeviceDma, DmaDirection};
25///
26/// let device = DeviceDma::new(0xFFFFFFFF, &my_dma_impl);
27///
28/// // 创建 100 个 u32 的 DMA 数组
29/// let mut dma_array = device
30/// .array_zero_with_align::<u32>(100, 64, DmaDirection::FromDevice)
31/// .expect("Failed to allocate");
32///
33/// dma_array.set(0, 0x12345678); // 写入(自动刷新缓存)
34/// let value = dma_array.read(0); // 读取(自动失效缓存)
35///
36/// let dma_addr = dma_array.dma_addr(); // 获取 DMA 地址给硬件
37/// ```
38///
39/// # 生命周期
40///
41/// `DArray` 拥有其分配的 DMA 内存,在离开作用域时自动释放。
42pub struct DArray<T> {
43 data: DCommon,
44 _phantom: core::marker::PhantomData<T>,
45}
46
47unsafe impl<T> Send for DArray<T> where T: Send {}
48
49impl<T> DArray<T> {
50 pub(crate) fn new_zero_with_align(
51 os: &DeviceDma,
52 size: usize,
53 align: usize,
54 direction: DmaDirection,
55 ) -> Result<Self, DmaError> {
56 let layout = Layout::from_size_align(
57 size * core::mem::size_of::<T>(),
58 align.max(core::mem::align_of::<T>()),
59 )?;
60 let data = DCommon::new_zero(os, layout, direction)?;
61 Ok(Self {
62 data,
63 _phantom: core::marker::PhantomData,
64 })
65 }
66
67 pub(crate) fn new_zero(
68 os: &DeviceDma,
69 size: usize,
70 direction: DmaDirection,
71 ) -> Result<Self, DmaError> {
72 Self::new_zero_with_align(os, size, core::mem::align_of::<T>(), direction)
73 }
74
75 /// 获取 DMA 地址。
76 ///
77 /// 返回设备用于访问此 DMA 缓冲区的物理/DMA 地址。
78 /// 将此地址传递给硬件设备以配置 DMA 操作。
79 ///
80 /// # 返回
81 ///
82 /// DMA 地址
83 pub fn dma_addr(&self) -> crate::DmaAddr {
84 self.data.handle.dma_addr
85 }
86
87 /// 获取数组长度(元素个数)。
88 ///
89 /// # 返回
90 ///
91 /// 数组中的元素个数
92 pub fn len(&self) -> usize {
93 self.data.handle.size() / core::mem::size_of::<T>()
94 }
95
96 /// 检查数组是否为空。
97 ///
98 /// # 返回
99 ///
100 /// 如果数组长度为 0 返回 `true`,否则返回 `false`
101 pub fn is_empty(&self) -> bool {
102 self.len() == 0
103 }
104
105 /// 获取数组的字节长度。
106 ///
107 /// # 返回
108 ///
109 /// 数组占用的总字节数
110 pub fn bytes_len(&self) -> usize {
111 self.data.handle.size()
112 }
113
114 /// 读取指定索引的元素。
115 ///
116 /// 根据 DMA 方向自动处理缓存同步:
117 /// - `FromDevice`/`Bidirectional`: 读取前使 CPU 缓存失效
118 /// - `ToDevice`: 无缓存操作
119 ///
120 /// # 参数
121 ///
122 /// - `index`: 元素索引
123 ///
124 /// # 返回
125 ///
126 /// 如果索引有效返回 `Some(T)`,否则返回 `None`
127 pub fn read(&self, index: usize) -> Option<T> {
128 if index >= self.len() {
129 return None;
130 }
131
132 unsafe {
133 let offset = index * core::mem::size_of::<T>();
134 self.data.prepare_read(offset, core::mem::size_of::<T>());
135 Some(self.data.handle.cpu_addr.cast().add(index).read())
136 }
137 }
138
139 /// 设置指定索引的元素值。
140 ///
141 /// 根据 DMA 方向自动处理缓存同步:
142 /// - `ToDevice`/`Bidirectional`: 写入后刷新 CPU 缓存
143 /// - `FromDevice`: 无缓存操作
144 ///
145 /// # 参数
146 ///
147 /// - `index`: 元素索引,必须在范围内
148 /// - `value`: 要写入的值
149 ///
150 /// # Panics
151 ///
152 /// 如果 `index >= self.len()` 则 panic
153 pub fn set(&mut self, index: usize, value: T) {
154 assert!(
155 index < self.len(),
156 "index out of range, index: {},len: {}",
157 index,
158 self.len()
159 );
160
161 unsafe {
162 let offset = index * core::mem::size_of::<T>();
163 let ptr = self.data.handle.cpu_addr.cast::<T>().add(index);
164 ptr.write(value);
165 self.data.confirm_write(offset, core::mem::size_of::<T>());
166 }
167 }
168
169 /// 创建迭代器。
170 ///
171 /// 返回一个迭代器,按顺序读取数组元素。
172 /// 每次读取都会自动处理缓存同步。
173 ///
174 /// # 返回
175 ///
176 /// `DArrayIter` 迭代器
177 pub fn iter(&self) -> DArrayIter<'_, T> {
178 DArrayIter {
179 array: self,
180 index: 0,
181 }
182 }
183
184 /// 从 slice 复制数据到数组。
185 ///
186 /// 复制完成后刷新整个数组的 CPU 缓存(ToDevice/Bidirectional)。
187 ///
188 /// # 参数
189 ///
190 /// - `src`: 源 slice,长度必须 `<= self.len()`
191 ///
192 /// # Panics
193 ///
194 /// 如果 `src.len() > self.len()` 则 panic
195 pub fn copy_from_slice(&mut self, src: &[T]) {
196 assert!(
197 src.len() <= self.len(),
198 "source slice is larger than DArray, src len: {}, DArray len: {}",
199 src.len(),
200 self.len()
201 );
202 unsafe {
203 let dst_ptr = self.data.handle.cpu_addr.as_ptr();
204 let len = core::mem::size_of_val(src);
205 dst_ptr.copy_from_nonoverlapping(src.as_ptr() as *const u8, len);
206 }
207 self.data.confirm_write_all();
208 }
209
210 /// # Safety
211 ///
212 /// slice will not auto do cache sync operations.
213 pub unsafe fn as_mut_slice(&mut self) -> &mut [T] {
214 let ptr = self.data.handle.cpu_addr;
215 unsafe {
216 core::slice::from_raw_parts_mut(
217 ptr.as_ptr() as *mut T,
218 self.bytes_len() / core::mem::size_of::<T>(),
219 )
220 }
221 }
222
223 pub fn as_ptr(&self) -> NonNull<T> {
224 self.data.handle.as_ptr().cast::<T>()
225 }
226}
227
228pub struct DArrayIter<'a, T> {
229 array: &'a DArray<T>,
230 index: usize,
231}
232
233impl<'a, T> Iterator for DArrayIter<'a, T> {
234 type Item = T;
235
236 fn next(&mut self) -> Option<Self::Item> {
237 if self.index >= self.array.len() {
238 return None;
239 }
240 let value = self.array.read(self.index);
241 self.index += 1;
242 value
243 }
244}