Skip to main content

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    /// 在 CPU 读取前同步指定字节范围。
211    ///
212    /// 对 `FromDevice` 和 `Bidirectional` 方向,这会使对应缓存范围失效。
213    pub fn prepare_read(&self, offset: usize, size: usize) {
214        assert!(
215            offset <= self.bytes_len() && size <= self.bytes_len().saturating_sub(offset),
216            "range out of bounds, offset: {}, size: {}, bytes_len: {}",
217            offset,
218            size,
219            self.bytes_len()
220        );
221        self.data.prepare_read(offset, size);
222    }
223
224    /// 在设备读取前同步指定字节范围。
225    ///
226    /// 对 `ToDevice` 和 `Bidirectional` 方向,这会将对应缓存范围刷回内存。
227    pub fn confirm_write(&self, offset: usize, size: usize) {
228        assert!(
229            offset <= self.bytes_len() && size <= self.bytes_len().saturating_sub(offset),
230            "range out of bounds, offset: {}, size: {}, bytes_len: {}",
231            offset,
232            size,
233            self.bytes_len()
234        );
235        self.data.confirm_write(offset, size);
236    }
237
238    /// 在 CPU 读取前同步整个数组。
239    pub fn prepare_read_all(&self) {
240        self.data.prepare_read(0, self.bytes_len());
241    }
242
243    /// 在设备读取前同步整个数组。
244    pub fn confirm_write_all(&self) {
245        self.data.confirm_write_all();
246    }
247
248    /// 直接借出一段可写切片,并在闭包返回后自动同步缓存。
249    pub fn write_with<R>(&mut self, len: usize, f: impl FnOnce(&mut [T]) -> R) -> R {
250        assert!(
251            len <= self.len(),
252            "range out of bounds, len: {}, array len: {}",
253            len,
254            self.len()
255        );
256        let ret = {
257            let data = unsafe { self.as_mut_slice() };
258            f(&mut data[..len])
259        };
260        self.confirm_write(0, len * core::mem::size_of::<T>());
261        ret
262    }
263
264    /// 直接借出一段只读切片,并在闭包调用前自动同步缓存。
265    pub fn read_with<R>(&self, len: usize, f: impl FnOnce(&[T]) -> R) -> R {
266        assert!(
267            len <= self.len(),
268            "range out of bounds, len: {}, array len: {}",
269            len,
270            self.len()
271        );
272        self.prepare_read(0, len * core::mem::size_of::<T>());
273        let data = unsafe { core::slice::from_raw_parts(self.as_ptr().as_ptr(), len) };
274        f(data)
275    }
276
277    /// # Safety
278    ///
279    /// slice will not auto do cache sync operations.
280    pub unsafe fn as_mut_slice(&mut self) -> &mut [T] {
281        let ptr = self.data.handle.cpu_addr;
282        unsafe {
283            core::slice::from_raw_parts_mut(
284                ptr.as_ptr() as *mut T,
285                self.bytes_len() / core::mem::size_of::<T>(),
286            )
287        }
288    }
289
290    pub fn as_ptr(&self) -> NonNull<T> {
291        self.data.handle.as_ptr().cast::<T>()
292    }
293}
294
295pub struct DArrayIter<'a, T> {
296    array: &'a DArray<T>,
297    index: usize,
298}
299
300impl<'a, T> Iterator for DArrayIter<'a, T> {
301    type Item = T;
302
303    fn next(&mut self) -> Option<Self::Item> {
304        if self.index >= self.array.len() {
305            return None;
306        }
307        let value = self.array.read(self.index);
308        self.index += 1;
309        value
310    }
311}