1#include "pico/asm_helper.S"
2
3// Support for breaking out individual RISC-V exception causes to handlers
4// implemented as normal C functions. Note the handler is still responsible
5// for incrementing `mepc` before return, if it intends to return to the
6// instruction after the one that caused the exception.
7
8.macro decl_isr name
9.weak \name
10\name:
11.endm
12
13// must be in RAM due to branches from vector table
14.section .time_critical.hardware_exception
15
16.p2align 2
17.global __riscv_exception_table
18__riscv_exception_table:
19.word isr_riscv_machine_instr_align_exception
20.word isr_riscv_machine_instr_fault_exception
21.word isr_riscv_machine_instr_illegal_exception
22.word isr_riscv_machine_ebreak_exception
23.word isr_riscv_machine_load_align_exception
24.word isr_riscv_machine_load_fault_exception
25.word isr_riscv_machine_store_align_exception
26.word isr_riscv_machine_store_fault_exception
27.word isr_riscv_machine_ecall_umode_exception
28.word isr_riscv_machine_ecall_smode_exception
29.word __unhandled_exception // reserved
30.word isr_riscv_machine_ecall_mmode_exception
31
32// mscratch = 0 outside of exception handler. mscratch = user ra during
33// exception handler. Assume 0 is not a valid ra.
34.global isr_riscv_machine_exception
35// still allow override just in case hardware_exception is pulled in by a library
36// note: that when LIX_HARDWARE_EXCEPTION=1, crt0_riscv.S does not define its own weak method
37.weak isr_riscv_machine_exception
38isr_riscv_machine_exception:
39    csrrw ra, mscratch, ra
40    bnez ra, __nested_exception
41    // Exception handler runs on foreground stack: this may fault, but we will
42    // catch the fault and go to __nested_exception.
43    addi sp, sp, -64
44    // Work downward, to ensure that after tripping a stack guard PMP region
45    // we re-trip it before trashing memory below the guard.
46    sw t6, 60(sp)
47    sw t5, 56(sp)
48    sw t4, 52(sp)
49    sw t3, 48(sp)
50    sw a7, 44(sp)
51    sw a6, 40(sp)
52    sw a5, 36(sp)
53    sw a4, 32(sp)
54    sw a3, 28(sp)
55    sw a2, 24(sp)
56    sw a1, 20(sp)
57    sw a0, 16(sp)
58    sw t2, 12(sp)
59    sw t1,  8(sp)
60    sw t0,  4(sp)
61    // ra already saved
62
63    // Using unsigned comparison for double-ended bounds check
64    csrr ra, mcause
65    li t6, 11 // XCAUSE_ECALL_M
66    bltu t6, ra, __unhandled_exception
67
68    // Enter exception through table
69    la t6, __riscv_exception_table
70    sh2add ra, ra, t6
71    lw ra, (ra)
72    jalr ra, ra
73
74    // Restore saved registers
75    lw t6, 60(sp)
76    lw t5, 56(sp)
77    lw t4, 52(sp)
78    lw t3, 48(sp)
79    lw a7, 44(sp)
80    lw a6, 40(sp)
81    lw a5, 36(sp)
82    lw a4, 32(sp)
83    lw a3, 28(sp)
84    lw a2, 24(sp)
85    lw a1, 20(sp)
86    lw a0, 16(sp)
87    lw t2, 12(sp)
88    lw t1,  8(sp)
89    lw t0,  4(sp)
90    // ra restored from mscratch
91    addi sp, sp, 64
92
93    // Restore mscratch to 0 to avoid tripping next exception
94    csrrw ra, mscratch, zero
95    mret
96
97decl_isr isr_riscv_machine_instr_align_exception
98decl_isr isr_riscv_machine_instr_fault_exception
99decl_isr isr_riscv_machine_instr_illegal_exception
100decl_isr isr_riscv_machine_ebreak_exception
101decl_isr isr_riscv_machine_load_align_exception
102decl_isr isr_riscv_machine_load_fault_exception
103decl_isr isr_riscv_machine_store_align_exception
104decl_isr isr_riscv_machine_store_fault_exception
105decl_isr isr_riscv_machine_ecall_umode_exception
106decl_isr isr_riscv_machine_ecall_smode_exception
107decl_isr isr_riscv_machine_ecall_mmode_exception
108    // fall through
109
110// Reach here when executing an exception that did not have a non-default
111// handler assigned. Since a breakpoint will cause another exception if the
112// debugger is not connected, we can't have an ebreak here. Just spin the
113// core forever. You can check `mcause` and `mepc` to see what happened and
114// where.
115.global __unhandled_exception
116__unhandled_exception:
117    // Restore original registers and stack pointer so debugger can backtrace
118    csrr ra, mscratch
119    lw t6, 60(sp)
120    addi sp, sp, -64
121    // Second symbol here just to make it clearer in the debugger why you got
122    // here; the entry point can appear labelled with the name of any one of the
123    // unhandled exceptions, which is less clear.
124.global __halt_on_unhandled_exception
125__halt_on_unhandled_exception:
1261:
127    j 1b
128
129// Detected an exception occurring whilst running an exception handler. State
130// of original exception was trashed by new exception, so this is not
131// recoverable. Best we can do is to halt now to avoid further trashing.
132__nested_exception:
1331:
134    j 1b
135
136