Landin library reference discuss source

platform/riscv/riscv.ldn

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