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]
81pub fn cycle_count() -> Option<u64> {
82 #[cfg(target_arch = "arm")]
83 {
84 let count: u32;
87 unsafe {
88 core::arch::asm!(
89 "mrc p15, 0, {}, c9, c13, 0",
90 out(reg) count,
91 options(nostack, nomem, preserves_flags)
92 );
93 }
94 Some(count as u64)
95 }
96
97 #[cfg(target_arch = "aarch64")]
98 {
99 let count: u64;
101 unsafe {
102 core::arch::asm!(
103 "mrs {}, pmccntr_el0",
104 out(reg) count,
105 options(nostack, nomem, preserves_flags)
106 );
107 }
108 Some(count)
109 }
110
111 #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
112 {
113 None
114 }
115}
116
117pub mod cache {
119 use crate::error::Result;
120
121 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
127 pub unsafe fn clean_dcache(addr: usize, size: usize) -> Result<()> {
128 let cache_line_size = 64; let start = addr & !(cache_line_size - 1);
130 let end = (addr + size + cache_line_size - 1) & !(cache_line_size - 1);
131
132 let mut current = start;
133 while current < end {
134 #[cfg(target_arch = "arm")]
135 {
136 unsafe {
138 core::arch::asm!(
139 "mcr p15, 0, {}, c7, c10, 1",
140 in(reg) current,
141 options(nostack, preserves_flags)
142 );
143 }
144 }
145
146 #[cfg(target_arch = "aarch64")]
147 {
148 unsafe {
150 core::arch::asm!(
151 "dc cvac, {}",
152 in(reg) current,
153 options(nostack, preserves_flags)
154 );
155 }
156 }
157
158 current = current.wrapping_add(cache_line_size);
159 }
160
161 super::memory_barrier();
162 Ok(())
163 }
164
165 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
171 pub unsafe fn invalidate_dcache(addr: usize, size: usize) -> Result<()> {
172 let cache_line_size = 64;
173 let start = addr & !(cache_line_size - 1);
174 let end = (addr + size + cache_line_size - 1) & !(cache_line_size - 1);
175
176 let mut current = start;
177 while current < end {
178 #[cfg(target_arch = "arm")]
179 {
180 unsafe {
182 core::arch::asm!(
183 "mcr p15, 0, {}, c7, c6, 1",
184 in(reg) current,
185 options(nostack, preserves_flags)
186 );
187 }
188 }
189
190 #[cfg(target_arch = "aarch64")]
191 {
192 unsafe {
194 core::arch::asm!(
195 "dc ivac, {}",
196 in(reg) current,
197 options(nostack, preserves_flags)
198 );
199 }
200 }
201
202 current = current.wrapping_add(cache_line_size);
203 }
204
205 super::memory_barrier();
206 Ok(())
207 }
208
209 #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
211 pub unsafe fn clean_dcache(_addr: usize, _size: usize) -> Result<()> {
212 Ok(())
213 }
214
215 #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
217 pub unsafe fn invalidate_dcache(_addr: usize, _size: usize) -> Result<()> {
218 Ok(())
219 }
220}
221
222#[cfg(target_feature = "neon")]
224pub mod simd {
225 #[cfg(target_arch = "arm")]
226 use core::arch::arm::*;
227
228 #[cfg(target_arch = "arm")]
234 pub unsafe fn memcpy_neon(dst: *mut u8, src: *const u8, len: usize) {
235 let mut offset = 0;
236 let chunks = len / 16;
237
238 for _ in 0..chunks {
239 unsafe {
241 let data = vld1q_u8(src.add(offset));
242 vst1q_u8(dst.add(offset), data);
243 }
244 offset += 16;
245 }
246
247 for i in offset..len {
249 unsafe {
251 *dst.add(i) = *src.add(i);
252 }
253 }
254 }
255
256 #[cfg(target_arch = "aarch64")]
262 pub unsafe fn memcpy_neon(dst: *mut u8, src: *const u8, len: usize) {
263 use core::arch::aarch64::*;
264
265 let mut offset = 0;
266 let chunks = len / 16;
267
268 for _ in 0..chunks {
269 unsafe {
271 let data = vld1q_u8(src.add(offset));
272 vst1q_u8(dst.add(offset), data);
273 }
274 offset += 16;
275 }
276
277 for i in offset..len {
279 unsafe {
281 *dst.add(i) = *src.add(i);
282 }
283 }
284 }
285}
286
287#[cfg(test)]
288mod tests {
289 use super::*;
290
291 #[test]
292 fn test_arm_target() {
293 let target = ArmTarget;
294 assert_eq!(target.name(), "ARM");
295 assert!(target.pointer_size() > 0);
296 assert!(target.native_alignment() > 0);
297 }
298
299 #[test]
300 fn test_capabilities() {
301 let caps = get_capabilities();
302 assert!(caps.cache_line_size > 0);
303 }
304}