oxigdal_embedded/target/
riscv.rs1use super::{TargetArch, TargetCapabilities};
6use core::sync::atomic::{Ordering, fence};
7
8pub struct RiscVTarget;
10
11impl TargetArch for RiscVTarget {
12 fn name(&self) -> &'static str {
13 if cfg!(target_arch = "riscv64") {
14 "RISC-V 64"
15 } else {
16 "RISC-V 32"
17 }
18 }
19
20 fn pointer_size(&self) -> usize {
21 core::mem::size_of::<usize>()
22 }
23
24 fn native_alignment(&self) -> usize {
25 core::mem::size_of::<usize>() }
27
28 fn supports_unaligned_access(&self) -> bool {
29 false
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 = "f") || cfg!(target_feature = "d"),
47 has_simd: cfg!(target_feature = "v"), has_aes: cfg!(target_feature = "zkne") || cfg!(target_feature = "zknd"), has_crc: cfg!(target_feature = "zbkc"), cache_line_size: 64, num_cores: 1,
52 }
53}
54
55#[inline]
57pub fn memory_barrier() {
58 fence(Ordering::SeqCst);
59
60 #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
61 {
62 unsafe {
63 core::arch::asm!("fence rw, rw", options(nostack, nomem));
65 }
66 }
67}
68
69#[inline]
71pub fn cycle_count() -> Option<u64> {
72 #[cfg(target_arch = "riscv32")]
73 {
74 let low: u32;
75 let high1: u32;
76 let high2: u32;
77
78 unsafe {
79 loop {
81 core::arch::asm!(
82 "rdtimeh {high}",
83 "rdtime {low}",
84 "rdtimeh {high2}",
85 high = out(reg) high1,
86 low = out(reg) low,
87 high2 = out(reg) high2,
88 options(nostack, nomem, preserves_flags)
89 );
90
91 if high1 == high2 {
93 break;
94 }
95 }
96 }
97
98 Some(((high1 as u64) << 32) | (low as u64))
99 }
100
101 #[cfg(target_arch = "riscv64")]
102 {
103 let count: u64;
104 unsafe {
105 core::arch::asm!(
106 "rdtime {}",
107 out(reg) count,
108 options(nostack, nomem, preserves_flags)
109 );
110 }
111 Some(count)
112 }
113
114 #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
115 {
116 None
117 }
118}
119
120pub mod atomic {
122 use crate::error::{EmbeddedError, Result};
123
124 #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
130 pub unsafe fn compare_and_swap(ptr: *mut usize, old: usize, new: usize) -> Result<usize> {
131 let result: usize;
132
133 #[cfg(target_arch = "riscv32")]
134 core::arch::asm!(
135 "lr.w {tmp}, ({ptr})",
136 "bne {tmp}, {old}, 1f",
137 "sc.w {result}, {new}, ({ptr})",
138 "j 2f",
139 "1:",
140 "li {result}, 1",
141 "2:",
142 ptr = in(reg) ptr,
143 old = in(reg) old,
144 new = in(reg) new,
145 tmp = out(reg) _,
146 result = out(reg) result,
147 options(nostack)
148 );
149
150 #[cfg(target_arch = "riscv64")]
151 core::arch::asm!(
152 "lr.d {tmp}, ({ptr})",
153 "bne {tmp}, {old}, 1f",
154 "sc.d {result}, {new}, ({ptr})",
155 "j 2f",
156 "1:",
157 "li {result}, 1",
158 "2:",
159 ptr = in(reg) ptr,
160 old = in(reg) old,
161 new = in(reg) new,
162 tmp = out(reg) _,
163 result = out(reg) result,
164 options(nostack)
165 );
166
167 if result == 0 {
168 Ok(new)
169 } else {
170 Err(EmbeddedError::ResourceBusy)
171 }
172 }
173
174 #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
180 pub unsafe fn compare_and_swap(_ptr: *mut usize, _old: usize, _new: usize) -> Result<usize> {
181 Err(EmbeddedError::UnsupportedOperation)
182 }
183}
184
185pub mod cache {
187 use crate::error::Result;
188
189 #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
195 pub unsafe fn flush_icache() -> Result<()> {
196 core::arch::asm!("fence.i", options(nostack, nomem));
198 Ok(())
199 }
200
201 #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
207 pub unsafe fn flush_icache() -> Result<()> {
208 Ok(())
209 }
210
211 #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
213 pub fn dcache_fence() {
214 unsafe {
215 core::arch::asm!("fence rw, rw", options(nostack, nomem));
216 }
217 }
218
219 #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
221 pub fn dcache_fence() {}
222}
223
224pub mod power {
226 use crate::error::Result;
227
228 #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
230 pub fn wait_for_interrupt() -> Result<()> {
231 unsafe {
232 core::arch::asm!("wfi", options(nostack, nomem));
234 }
235 Ok(())
236 }
237
238 #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
240 pub fn wait_for_interrupt() -> Result<()> {
241 Ok(())
242 }
243}
244
245#[cfg(target_feature = "v")]
247pub mod vector {
248 pub fn is_available() -> bool {
250 true
252 }
253
254 #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
256 pub fn vector_length() -> usize {
257 128 / 8 }
261
262 #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
263 pub fn vector_length() -> usize {
264 0
265 }
266}
267
268#[cfg(test)]
269mod tests {
270 use super::*;
271
272 #[test]
273 fn test_riscv_target() {
274 let target = RiscVTarget;
275 assert!(target.name().contains("RISC-V"));
276 assert!(target.pointer_size() > 0);
277 assert!(target.native_alignment() > 0);
278 }
279
280 #[test]
281 fn test_capabilities() {
282 let caps = get_capabilities();
283 assert!(caps.cache_line_size > 0);
284 }
285
286 #[test]
287 fn test_memory_barrier() {
288 memory_barrier();
290 }
291}