1#![cfg_attr(not(target_arch = "riscv32"), allow(unused_unsafe, unused_variables, unused_mut))]
26
27pub use crate::soc::ws63::Interrupt;
28
29const SYS_VECTOR_CNT: u16 = 26;
32const LOCAL_IRQ_VECTOR_CNT: u16 = 32;
34const LOCIEN_IRQ_NUM: u16 = 32;
36const LOCIPRI_IRQ_NUM: u16 = 8;
38const LOCIPRI_IRQ_BITS: u16 = 4;
39const LOCIPRI_FIELD_MASK: u32 = 0xF;
40const PRIORITY_IRQ_END: u16 = SYS_VECTOR_CNT + 16 * LOCIPRI_IRQ_NUM;
42const LOCIPRI_DEFAULT_VAL: u32 = 0x1111_1111;
44
45#[cfg(target_arch = "riscv32")]
55macro_rules! csr_set {
56 ($csr:literal, $v:expr) => {
57 core::arch::asm!(concat!("csrs ", $csr, ", {0}"), in(reg) $v, options(nomem, nostack))
58 };
59}
60#[cfg(target_arch = "riscv32")]
61macro_rules! csr_clear {
62 ($csr:literal, $v:expr) => {
63 core::arch::asm!(concat!("csrc ", $csr, ", {0}"), in(reg) $v, options(nomem, nostack))
64 };
65}
66#[cfg(target_arch = "riscv32")]
67macro_rules! csr_write {
68 ($csr:literal, $v:expr) => {
69 core::arch::asm!(concat!("csrw ", $csr, ", {0}"), in(reg) $v, options(nomem, nostack))
70 };
71}
72#[cfg(target_arch = "riscv32")]
73macro_rules! csr_read {
74 ($csr:literal) => {{
75 let v: u32;
76 core::arch::asm!(concat!("csrr {0}, ", $csr), out(reg) v, options(nomem, nostack));
77 v
78 }};
79}
80
81#[cfg(not(target_arch = "riscv32"))]
82macro_rules! csr_set {
83 ($csr:literal, $v:expr) => {{
84 let _ = $v;
85 }};
86}
87#[cfg(not(target_arch = "riscv32"))]
88macro_rules! csr_clear {
89 ($csr:literal, $v:expr) => {{
90 let _ = $v;
91 }};
92}
93#[cfg(not(target_arch = "riscv32"))]
94macro_rules! csr_write {
95 ($csr:literal, $v:expr) => {{
96 let _ = $v;
97 }};
98}
99#[cfg(not(target_arch = "riscv32"))]
100macro_rules! csr_read {
101 ($csr:literal) => {{ 0u32 }};
102}
103
104#[inline]
106unsafe fn locien_write(idx: u16, mask: u32, set: bool) {
107 unsafe {
108 match (idx, set) {
109 (0, true) => csr_set!("0xbe0", mask),
110 (0, false) => csr_clear!("0xbe0", mask),
111 (1, true) => csr_set!("0xbe1", mask),
112 (1, false) => csr_clear!("0xbe1", mask),
113 (2, true) => csr_set!("0xbe2", mask),
114 (2, false) => csr_clear!("0xbe2", mask),
115 _ => {}
116 }
117 }
118}
119
120#[inline]
121fn locien_read(idx: u16) -> u32 {
122 unsafe {
123 match idx {
124 0 => csr_read!("0xbe0"),
125 1 => csr_read!("0xbe1"),
126 2 => csr_read!("0xbe2"),
127 _ => 0,
128 }
129 }
130}
131
132#[inline]
133fn locipd_read(idx: u16) -> u32 {
134 unsafe {
135 match idx {
136 0 => csr_read!("0xbe8"),
137 1 => csr_read!("0xbe9"),
138 2 => csr_read!("0xbea"),
139 _ => 0,
140 }
141 }
142}
143
144#[inline]
148fn locipri_set_field(idx: u16, shift: u16, value: u32) {
149 let clear = LOCIPRI_FIELD_MASK << shift;
150 let set = (value & LOCIPRI_FIELD_MASK) << shift;
151 unsafe {
152 macro_rules! rmw {
153 ($csr:literal) => {{
154 csr_clear!($csr, clear);
155 csr_set!($csr, set);
156 }};
157 }
158 match idx {
159 0 => rmw!("0xbc0"),
160 1 => rmw!("0xbc1"),
161 2 => rmw!("0xbc2"),
162 3 => rmw!("0xbc3"),
163 4 => rmw!("0xbc4"),
164 5 => rmw!("0xbc5"),
165 6 => rmw!("0xbc6"),
166 7 => rmw!("0xbc7"),
167 8 => rmw!("0xbc8"),
168 9 => rmw!("0xbc9"),
169 10 => rmw!("0xbca"),
170 11 => rmw!("0xbcb"),
171 12 => rmw!("0xbcc"),
172 13 => rmw!("0xbcd"),
173 14 => rmw!("0xbce"),
174 15 => rmw!("0xbcf"),
175 _ => {}
176 }
177 }
178}
179
180#[inline]
181fn locipri_read(idx: u16) -> u32 {
182 unsafe {
183 match idx {
184 0 => csr_read!("0xbc0"),
185 1 => csr_read!("0xbc1"),
186 2 => csr_read!("0xbc2"),
187 3 => csr_read!("0xbc3"),
188 4 => csr_read!("0xbc4"),
189 5 => csr_read!("0xbc5"),
190 6 => csr_read!("0xbc6"),
191 7 => csr_read!("0xbc7"),
192 8 => csr_read!("0xbc8"),
193 9 => csr_read!("0xbc9"),
194 10 => csr_read!("0xbca"),
195 11 => csr_read!("0xbcb"),
196 12 => csr_read!("0xbcc"),
197 13 => csr_read!("0xbcd"),
198 14 => csr_read!("0xbce"),
199 15 => csr_read!("0xbcf"),
200 _ => 0,
201 }
202 }
203}
204
205#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
211pub struct Priority(u8);
212
213impl Priority {
214 pub const P1: Self = Priority(1);
215 pub const P2: Self = Priority(2);
216 pub const P3: Self = Priority(3);
217 pub const P4: Self = Priority(4);
218 pub const P5: Self = Priority(5);
219 pub const P6: Self = Priority(6);
220 pub const P7: Self = Priority(7);
221
222 pub const LOWEST: Self = Priority(1);
224 pub const HIGHEST: Self = Priority(7);
226
227 pub const fn new(level: u8) -> Self {
229 let l = if level < 1 {
230 1
231 } else if level > 7 {
232 7
233 } else {
234 level
235 };
236 Priority(l)
237 }
238
239 pub const fn level(self) -> u8 {
241 self.0
242 }
243}
244
245#[inline]
246fn irq_num(irq: Interrupt) -> u16 {
247 irq as u16
248}
249
250pub unsafe fn enable(irq: Interrupt) {
263 let n = irq_num(irq);
264 if (SYS_VECTOR_CNT..LOCAL_IRQ_VECTOR_CNT).contains(&n) {
265 unsafe { csr_set!("mie", 1u32 << n) };
266 } else if n >= LOCAL_IRQ_VECTOR_CNT {
267 let bit = (n - LOCAL_IRQ_VECTOR_CNT) % LOCIEN_IRQ_NUM;
268 let reg = (n - LOCAL_IRQ_VECTOR_CNT) / LOCIEN_IRQ_NUM;
269 unsafe { locien_write(reg, 1u32 << bit, true) };
270 }
271}
272
273pub unsafe fn disable(irq: Interrupt) {
280 let n = irq_num(irq);
281 if (SYS_VECTOR_CNT..LOCAL_IRQ_VECTOR_CNT).contains(&n) {
282 unsafe { csr_clear!("mie", 1u32 << n) };
283 } else if n >= LOCAL_IRQ_VECTOR_CNT {
284 let bit = (n - LOCAL_IRQ_VECTOR_CNT) % LOCIEN_IRQ_NUM;
285 let reg = (n - LOCAL_IRQ_VECTOR_CNT) / LOCIEN_IRQ_NUM;
286 unsafe { locien_write(reg, 1u32 << bit, false) };
287 }
288 clear_pending(irq);
289}
290
291pub fn is_enabled(irq: Interrupt) -> bool {
293 let n = irq_num(irq);
294 if (SYS_VECTOR_CNT..LOCAL_IRQ_VECTOR_CNT).contains(&n) {
295 let mie: u32 = unsafe { csr_read!("mie") };
296 (mie & (1u32 << n)) != 0
297 } else if n >= LOCAL_IRQ_VECTOR_CNT {
298 let bit = (n - LOCAL_IRQ_VECTOR_CNT) % LOCIEN_IRQ_NUM;
299 let reg = (n - LOCAL_IRQ_VECTOR_CNT) / LOCIEN_IRQ_NUM;
300 (locien_read(reg) & (1u32 << bit)) != 0
301 } else {
302 false
303 }
304}
305
306pub fn set_priority(irq: Interrupt, priority: Priority) {
311 let n = irq_num(irq);
312 if (SYS_VECTOR_CNT..PRIORITY_IRQ_END).contains(&n) {
313 let order = (n - SYS_VECTOR_CNT) % LOCIPRI_IRQ_NUM;
314 let reg = (n - SYS_VECTOR_CNT) / LOCIPRI_IRQ_NUM;
315 locipri_set_field(reg, order * LOCIPRI_IRQ_BITS, priority.0 as u32);
316 }
317}
318
319pub fn priority(irq: Interrupt) -> Priority {
321 let n = irq_num(irq);
322 if (SYS_VECTOR_CNT..PRIORITY_IRQ_END).contains(&n) {
323 let order = (n - SYS_VECTOR_CNT) % LOCIPRI_IRQ_NUM;
324 let reg = (n - SYS_VECTOR_CNT) / LOCIPRI_IRQ_NUM;
325 let shift = order * LOCIPRI_IRQ_BITS;
326 let field = (locipri_read(reg) >> shift) & LOCIPRI_FIELD_MASK;
327 Priority::new(field as u8)
328 } else {
329 Priority::LOWEST
330 }
331}
332
333pub fn set_threshold(level: u8) {
337 unsafe { csr_write!("0xbfe", (level & 0x7) as u32) };
338}
339
340pub fn threshold() -> u8 {
342 (unsafe { csr_read!("0xbfe") } & 0x7) as u8
343}
344
345pub fn clear_pending(irq: Interrupt) {
350 let n = irq_num(irq) as u32;
351 unsafe {
352 #[cfg(target_arch = "riscv32")]
353 core::arch::asm!("fence", options(nostack));
354 csr_write!("0xbf0", n);
355 #[cfg(target_arch = "riscv32")]
356 core::arch::asm!("fence", options(nostack));
357 }
358}
359
360pub fn is_pending(irq: Interrupt) -> bool {
363 let n = irq_num(irq);
364 if (SYS_VECTOR_CNT..LOCAL_IRQ_VECTOR_CNT).contains(&n) {
365 let mip: u32 = unsafe { csr_read!("mip") };
366 (mip & (1u32 << n)) != 0
367 } else if n >= LOCAL_IRQ_VECTOR_CNT {
368 let bit = (n - LOCAL_IRQ_VECTOR_CNT) % LOCIEN_IRQ_NUM;
369 let reg = (n - LOCAL_IRQ_VECTOR_CNT) / LOCIEN_IRQ_NUM;
370 (locipd_read(reg) & (1u32 << bit)) != 0
371 } else {
372 false
373 }
374}
375
376pub fn init() {
382 unsafe {
383 csr_write!("0xbc0", LOCIPRI_DEFAULT_VAL);
384 csr_write!("0xbc1", LOCIPRI_DEFAULT_VAL);
385 csr_write!("0xbc2", LOCIPRI_DEFAULT_VAL);
386 csr_write!("0xbc3", LOCIPRI_DEFAULT_VAL);
387 csr_write!("0xbc4", LOCIPRI_DEFAULT_VAL);
388 csr_write!("0xbc5", LOCIPRI_DEFAULT_VAL);
389 csr_write!("0xbc6", LOCIPRI_DEFAULT_VAL);
390 csr_write!("0xbc7", LOCIPRI_DEFAULT_VAL);
391 csr_write!("0xbc8", LOCIPRI_DEFAULT_VAL);
392 csr_write!("0xbc9", LOCIPRI_DEFAULT_VAL);
393 csr_write!("0xbca", LOCIPRI_DEFAULT_VAL);
394 csr_write!("0xbcb", LOCIPRI_DEFAULT_VAL);
395 csr_write!("0xbcc", LOCIPRI_DEFAULT_VAL);
396 csr_write!("0xbcd", LOCIPRI_DEFAULT_VAL);
397 csr_write!("0xbce", LOCIPRI_DEFAULT_VAL);
398 csr_write!("0xbcf", LOCIPRI_DEFAULT_VAL);
399 }
400}
401
402pub unsafe fn enable_global() {
408 #[cfg(target_arch = "riscv32")]
409 unsafe {
410 core::arch::asm!("csrsi mstatus, 0x8", options(nomem, nostack))
411 };
412}
413
414pub fn disable_global() {
416 #[cfg(target_arch = "riscv32")]
417 unsafe {
418 core::arch::asm!("csrci mstatus, 0x8", options(nomem, nostack))
419 };
420}
421
422pub fn free<F, R>(f: F) -> R
425where
426 F: FnOnce() -> R,
427{
428 #[cfg(target_arch = "riscv32")]
429 let prev: usize;
430 #[cfg(target_arch = "riscv32")]
431 unsafe {
432 core::arch::asm!("csrrci {0}, mstatus, 0x8", out(reg) prev, options(nomem, nostack))
433 };
434 let r = f();
435 #[cfg(target_arch = "riscv32")]
436 if prev & 0x8 != 0 {
437 unsafe { core::arch::asm!("csrsi mstatus, 0x8", options(nomem, nostack)) };
438 }
439 r
440}