oxigdal_embedded/target/
arm.rs1use super::{TargetArch, TargetCapabilities};
6use core::sync::atomic::{Ordering, fence};
7
8pub struct ArmTarget;
10
11impl TargetArch for ArmTarget {
12 fn name(&self) -> &'static str {
13 "ARM"
14 }
15
16 fn pointer_size(&self) -> usize {
17 core::mem::size_of::<usize>()
18 }
19
20 fn native_alignment(&self) -> usize {
21 4 }
23
24 fn supports_unaligned_access(&self) -> bool {
25 cfg!(any(
28 target_feature = "v7",
29 target_feature = "v8",
30 target_arch = "aarch64"
31 ))
32 }
33
34 fn memory_barrier(&self) {
35 memory_barrier();
36 }
37
38 fn cycle_count(&self) -> Option<u64> {
39 cycle_count()
40 }
41}
42
43pub fn get_capabilities() -> TargetCapabilities {
45 TargetCapabilities {
46 has_fpu: cfg!(target_feature = "vfp2")
47 || cfg!(target_feature = "vfp3")
48 || cfg!(target_feature = "vfp4"),
49 has_simd: cfg!(target_feature = "neon"),
50 has_aes: cfg!(target_feature = "aes"),
51 has_crc: cfg!(target_feature = "crc"),
52 cache_line_size: 64, num_cores: 1, }
55}
56
57#[inline]
59pub fn memory_barrier() {
60 fence(Ordering::SeqCst);
61
62 #[cfg(target_arch = "arm")]
63 {
64 unsafe {
66 core::arch::asm!("dmb", options(nostack, nomem));
67 }
68 }
69
70 #[cfg(target_arch = "aarch64")]
71 {
72 unsafe {
74 core::arch::asm!("dmb sy", options(nostack, nomem));
75 }
76 }
77}
78
79#[inline]
87pub fn cycle_count() -> Option<u64> {
88 #[cfg(all(target_arch = "arm", target_os = "none"))]
89 {
90 let count: u32;
93 unsafe {
94 core::arch::asm!(
95 "mrc p15, 0, {}, c9, c13, 0",
96 out(reg) count,
97 options(nostack, nomem, preserves_flags)
98 );
99 }
100 Some(count as u64)
101 }
102
103 #[cfg(all(target_arch = "aarch64", target_os = "none"))]
104 {
105 let count: u64;
107 unsafe {
108 core::arch::asm!(
109 "mrs {}, pmccntr_el0",
110 out(reg) count,
111 options(nostack, nomem, preserves_flags)
112 );
113 }
114 Some(count)
115 }
116
117 #[cfg(not(all(any(target_arch = "arm", target_arch = "aarch64"), target_os = "none")))]
118 {
119 None
120 }
121}
122
123pub mod cache {
125 use crate::error::Result;
126
127 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
133 pub unsafe fn clean_dcache(addr: usize, size: usize) -> Result<()> {
134 let cache_line_size = 64; let start = addr & !(cache_line_size - 1);
136 let end = (addr + size + cache_line_size - 1) & !(cache_line_size - 1);
137
138 let mut current = start;
139 while current < end {
140 #[cfg(target_arch = "arm")]
141 {
142 unsafe {
144 core::arch::asm!(
145 "mcr p15, 0, {}, c7, c10, 1",
146 in(reg) current,
147 options(nostack, preserves_flags)
148 );
149 }
150 }
151
152 #[cfg(target_arch = "aarch64")]
153 {
154 unsafe {
156 core::arch::asm!(
157 "dc cvac, {}",
158 in(reg) current,
159 options(nostack, preserves_flags)
160 );
161 }
162 }
163
164 current = current.wrapping_add(cache_line_size);
165 }
166
167 super::memory_barrier();
168 Ok(())
169 }
170
171 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
177 pub unsafe fn invalidate_dcache(addr: usize, size: usize) -> Result<()> {
178 let cache_line_size = 64;
179 let start = addr & !(cache_line_size - 1);
180 let end = (addr + size + cache_line_size - 1) & !(cache_line_size - 1);
181
182 let mut current = start;
183 while current < end {
184 #[cfg(target_arch = "arm")]
185 {
186 unsafe {
188 core::arch::asm!(
189 "mcr p15, 0, {}, c7, c6, 1",
190 in(reg) current,
191 options(nostack, preserves_flags)
192 );
193 }
194 }
195
196 #[cfg(target_arch = "aarch64")]
197 {
198 unsafe {
200 core::arch::asm!(
201 "dc ivac, {}",
202 in(reg) current,
203 options(nostack, preserves_flags)
204 );
205 }
206 }
207
208 current = current.wrapping_add(cache_line_size);
209 }
210
211 super::memory_barrier();
212 Ok(())
213 }
214
215 #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
217 pub unsafe fn clean_dcache(_addr: usize, _size: usize) -> Result<()> {
218 Ok(())
219 }
220
221 #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
223 pub unsafe fn invalidate_dcache(_addr: usize, _size: usize) -> Result<()> {
224 Ok(())
225 }
226}
227
228pub mod power {
235 use crate::error::Result;
236
237 #[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_os = "none"))]
247 pub fn wait_for_interrupt() -> Result<()> {
248 unsafe {
251 core::arch::asm!("wfi", options(nostack, nomem));
252 }
253 Ok(())
254 }
255
256 #[cfg(not(all(any(target_arch = "arm", target_arch = "aarch64"), target_os = "none")))]
258 pub fn wait_for_interrupt() -> Result<()> {
259 Ok(())
260 }
261
262 #[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_os = "none"))]
267 pub fn wait_for_event() -> Result<()> {
268 unsafe {
271 core::arch::asm!("wfe", options(nostack, nomem));
272 }
273 Ok(())
274 }
275
276 #[cfg(not(all(any(target_arch = "arm", target_arch = "aarch64"), target_os = "none")))]
278 pub fn wait_for_event() -> Result<()> {
279 Ok(())
280 }
281}
282
283#[cfg(target_feature = "neon")]
285pub mod simd {
286 #[cfg(target_arch = "arm")]
287 use core::arch::arm::*;
288
289 #[cfg(target_arch = "arm")]
295 pub unsafe fn memcpy_neon(dst: *mut u8, src: *const u8, len: usize) {
296 let mut offset = 0;
297 let chunks = len / 16;
298
299 for _ in 0..chunks {
300 unsafe {
302 let data = vld1q_u8(src.add(offset));
303 vst1q_u8(dst.add(offset), data);
304 }
305 offset += 16;
306 }
307
308 for i in offset..len {
310 unsafe {
312 *dst.add(i) = *src.add(i);
313 }
314 }
315 }
316
317 #[cfg(target_arch = "aarch64")]
323 pub unsafe fn memcpy_neon(dst: *mut u8, src: *const u8, len: usize) {
324 use core::arch::aarch64::*;
325
326 let mut offset = 0;
327 let chunks = len / 16;
328
329 for _ in 0..chunks {
330 unsafe {
332 let data = vld1q_u8(src.add(offset));
333 vst1q_u8(dst.add(offset), data);
334 }
335 offset += 16;
336 }
337
338 for i in offset..len {
340 unsafe {
342 *dst.add(i) = *src.add(i);
343 }
344 }
345 }
346}
347
348#[cfg(test)]
349mod tests {
350 use super::*;
351
352 #[test]
353 fn test_arm_target() {
354 let target = ArmTarget;
355 assert_eq!(target.name(), "ARM");
356 assert!(target.pointer_size() > 0);
357 assert!(target.native_alignment() > 0);
358 }
359
360 #[test]
361 fn test_capabilities() {
362 let caps = get_capabilities();
363 assert!(caps.cache_line_size > 0);
364 }
365}