1-- RV32 machine-mode CPU operations. The saved state is an ordinary
2-- explicit value. Restore it in lexical reverse order; masking does not stop
3-- DMA, exceptions or a debugger.
4--
5-- Everything here is declared on rv32 only (D687), as platform/cortex_m is
6-- on an M-profile target: a program written for every target imports this
7-- module everywhere and calls it from a `fixed if compiler.arch == rv32`
8-- arm.
9
10fixed if compiler.arch == rv32 then
11 --- Clear mstatus.MIE, which masks every machine-mode interrupt, and
12 --- return its previous state. Save the result and pass it to
13 --- `restore_interrupts`, including on early returns.
14 public disable_interrupts: () -> (previous: u32) =
15 previous = assembler.block("csrrci {state}, mstatus, 8",
16 out state: u32 at general)
17 end disable_interrupts
18
19 --- Restore a state `disable_interrupts` returned: set mstatus.MIE again
20 --- only if it was set then, which preserves nesting.
21 public restore_interrupts: (previous: u32) -> none =
22 assembler.block("andi {state}, {state}, 8\ncsrs mstatus, {state}",
23 in state: u32 at general = previous)
24 end restore_interrupts
25
26 --- Read whether machine-mode interrupts are enabled: mstatus.MIE, as
27 --- 8 when they are and 0 when they are not.
28 public interrupt_mask: () -> (current: u32) =
29 current = assembler.block("csrr {state}, mstatus\nandi {state}, {state}, 8",
30 out state: u32 at general)
31 end interrupt_mask
32
33 --- Set the bits of LINES in mie, enabling those of the core's own
34 --- interrupts: machine software 0x8, timer 0x80 and external 0x800 on
35 --- the cores with the standard set. A core whose lines an interrupt
36 --- matrix or a CLIC enables, the ESP32-C3's and the ESP32-C5's, is
37 --- enabled through the chip's own registers instead.
38 public enable_lines: (lines: u32) -> none =
39 assembler.block("csrs mie, {bits}", in bits: u32 at general = lines)
40 end enable_lines
41
42 --- Clear the bits of LINES in mie.
43 public disable_lines: (lines: u32) -> none =
44 assembler.block("csrc mie, {bits}", in bits: u32 at general = lines)
45 end disable_lines
46
47 --- Order earlier memory and device accesses before the wait, then wait
48 --- for an interrupt. Wakeups can be spurious, and a pending interrupt
49 --- wakes the core even while mstatus.MIE is clear; recheck the
50 --- condition after waking.
51 public wait_for_interrupt: () -> none =
52 assembler.block("fence iorw, iorw\nwfi")
53 end wait_for_interrupt
54
55 --- Order memory and device accesses (a FENCE). This is not a proof that
56 --- a device operation completed.
57 public device_barrier: () -> none =
58 compiler.device_barrier()
59 end device_barrier
60
61 --- Wait for preceding explicit memory accesses to complete, as far as
62 --- RISC-V's FENCE orders them.
63 public completion_barrier: () -> none =
64 compiler.completion_barrier()
65 end completion_barrier
66
67 --- Prevent compiler memory knowledge from moving across this point. This
68 --- emits no device-completion protocol.
69 public compiler_barrier: () -> none =
70 compiler.compiler_barrier()
71 end compiler_barrier
72end if