1+ / * RMT ISR shim
2+ * Bridges from a high - level interrupt to the C ++ code.
3+ *
4+ * This code is largely derived from Espressif 's ' hli_vector.S' Bluetooth ISR.
5+ *
6+ * /
7+
8+ #if defined(__XTENSA__) && defined(ESP32) && !defined(CONFIG_BTDM_CTRL_HLI)
9+
10+ #include <freertos/xtensa_context.h>
11+ #include "sdkconfig.h"
12+ #include "soc/soc.h"
13+
14+ / * If the Bluetooth driver has hooked the high - priority interrupt , we piggyback on it and don't need this. * /
15+ #ifndef CONFIG_BTDM_CTRL_HLI
16+
17+ / *
18+ Select interrupt based on system check level
19+ - Base ESP32: could be 4 or 5 , depends on platform config
20+ - S2: 5
21+ - S3: 5
22+ * /
23+
24+ #if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
25+ / * Use level 4 * /
26+ #define RFI_X 4
27+ #define xt_highintx xt_highint4
28+ #else / * !CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 * /
29+ / * Use level 5 * /
30+ #define RFI_X 5
31+ #define xt_highintx xt_highint5
32+ #endif / * CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 * /
33+
34+ // Register map , based on interrupt level
35+ #define EPC_X (EPC + RFI_X)
36+ #define EXCSAVE_X (EXCSAVE + RFI_X)
37+
38+ // The sp mnemonic is used all over in ESP 's assembly, though I' m not sure where it's expected to be defined?
39+ #define sp a1
40+
41+ / * Interrupt stack size , for C code. * /
42+ #define RMT_INTR_STACK_SIZE 512
43+
44+ / * Save area for the CPU state:
45+ * - 64 words for the general purpose registers
46+ * - 7 words for some of the special registers:
47+ * - WINDOWBASE , WINDOWSTART — only WINDOWSTART is truly needed
48+ * - SAR , LBEG , LEND , LCOUNT — since the C code might use these
49+ * - EPC1 — since the C code might cause window overflow exceptions
50+ * This is not laid out as standard exception frame structure
51+ * for simplicity of the save/restore code.
52+ * /
53+ #define REG_FILE_SIZE ( 64 * 4 )
54+ #define SPECREG_OFFSET REG_FILE_SIZE
55+ #define SPECREG_SIZE ( 7 * 4 )
56+ #define REG_SAVE_AREA_SIZE (SPECREG_OFFSET + SPECREG_SIZE)
57+
58+ .data
59+ _rmt_intr_stack:
60+ .space RMT_INTR_STACK_SIZE
61+ _rmt_save_ctx:
62+ .space REG_SAVE_AREA_SIZE
63+
64+ . section .iram1 , "ax"
65+ . global xt_highintx
66+ .type xt_highintx , @function
67+ . align 4
68+
69+ xt_highintx:
70+
71+ movi a0 , _rmt_save_ctx
72+ / * save 4 lower registers * /
73+ s32i a1 , a0 , 4
74+ s32i a2 , a0 , 8
75+ s32i a3 , a0 , 12
76+ rsr a2 , EXCSAVE_X / * holds the value of a0 * /
77+ s32i a2 , a0 , 0
78+
79+ / * Save special registers * /
80+ addi a0 , a0 , SPECREG_OFFSET
81+ rsr a2 , WINDOWBASE
82+ s32i a2 , a0 , 0
83+ rsr a2 , WINDOWSTART
84+ s32i a2 , a0 , 4
85+ rsr a2 , SAR
86+ s32i a2 , a0 , 8
87+ #if XCHAL_HAVE_LOOPS
88+ rsr a2 , LBEG
89+ s32i a2 , a0 , 12
90+ rsr a2 , LEND
91+ s32i a2 , a0 , 16
92+ rsr a2 , LCOUNT
93+ s32i a2 , a0 , 20
94+ #endif
95+ rsr a2 , EPC1
96+ s32i a2 , a0 , 24
97+
98+ / * disable exception mode , window overflow * /
99+ movi a0 , PS_INTLEVEL(RFI_X + 1 ) | PS_EXCM
100+ wsr a0 , PS
101+ rsync
102+
103+ / * Save the remaining physical registers.
104+ * 4 registers are already saved , which leaves 60 registers to save.
105+ * (FIXME: consider the case when the CPU is configured with physical 32 registers)
106+ * These 60 registers are saved in 5 iterations , 12 registers at a time.
107+ * /
108+ movi a1 , 5
109+ movi a3 , _rmt_save_ctx + 4 * 4
110+
111+ / * This is repeated 5 times , each time the window is shifted by 12 registers.
112+ * We come here with a1 = downcounter , a3 = save pointer , a2 and a0 unused.
113+ * /
114+ 1 :
115+ s32i a4 , a3 , 0
116+ s32i a5 , a3 , 4
117+ s32i a6 , a3 , 8
118+ s32i a7 , a3 , 12
119+ s32i a8 , a3 , 16
120+ s32i a9 , a3 , 20
121+ s32i a10 , a3 , 24
122+ s32i a11 , a3 , 28
123+ s32i a12 , a3 , 32
124+ s32i a13 , a3 , 36
125+ s32i a14 , a3 , 40
126+ s32i a15 , a3 , 44
127+
128+ / * We are about to rotate the window , so th at a12 - a15 will become the new a0 - a3.
129+ * Copy a0 - a3 to a12 - 15 to still have access to these values.
130+ * At the same time we can decrement the counter and adjust the save area pointer
131+ * /
132+
133+ / * a0 is constant (_rmt_save_ctx) , no need to copy * /
134+ addi a13 , a1 , - 1 / * copy and decrement the downcounter * /
135+ / * a2 is scratch so no need to copy * /
136+ addi a15 , a3 , 48 / * copy and adjust the save area pointer * /
137+ beqz a13 , 2f / * have saved all registers ? * /
138+ rotw 3 / * rotate the window and go back * /
139+ j 1b
140+
141+ / * the loop is complete * /
142+ 2 :
143+ rotw 4 / * this brings us back to the original window * /
144+ / * a0 still points to _rmt_save_ctx * /
145+
146+ / * Can clear WINDOWSTART now , all registers are saved * /
147+ rsr a2 , WINDOWBASE
148+ / * WINDOWSTART = ( 1 << WINDOWBASE) * /
149+ movi a3 , 1
150+ ssl a2
151+ sll a3 , a3
152+ wsr a3 , WINDOWSTART
153+
154+ _highint_stack_switch:
155+ movi a0 , 0
156+ movi sp , _rmt_intr_stack + RMT_INTR_STACK_SIZE - 16
157+ s32e a0 , sp , - 12 / * For GDB: set null SP * /
158+ s32e a0 , sp , - 16 / * For GDB: set null PC * /
159+ movi a0 , _highint_stack_switch / * For GDB: cosmetics , for the frame where stack switch happened * /
160+
161+ / * Set up PS for C , disable all interrupts except NMI and debug , and clear EXCM. * /
162+ movi a6 , PS_INTLEVEL(RFI_X) | PS_UM | PS_WOE
163+ wsr a6 , PS
164+ rsync
165+
166+ / * Call C handler * /
167+ mov a6 , sp
168+ call4 NeoEsp32RmtMethodIsr
169+
170+ l32e sp , sp , - 12 / * switch back to the original stack * /
171+
172+ / * Done with C handler ; re-enable exception mode, disabling window overflow */
173+ movi a2 , PS_INTLEVEL(RFI_X + 1 ) | PS_EXCM / * TOCHECK * /
174+ wsr a2 , PS
175+ rsync
176+
177+ / * Restore the special registers.
178+ * WINDOWSTART will be restored near the end.
179+ * /
180+ movi a0 , _rmt_save_ctx + SPECREG_OFFSET
181+ l32i a2 , a0 , 8
182+ wsr a2 , SAR
183+ #if XCHAL_HAVE_LOOPS
184+ l32i a2 , a0 , 12
185+ wsr a2 , LBEG
186+ l32i a2 , a0 , 16
187+ wsr a2 , LEND
188+ l32i a2 , a0 , 20
189+ wsr a2 , LCOUNT
190+ #endif
191+ l32i a2 , a0 , 24
192+ wsr a2 , EPC1
193+
194+ / * Restoring the physical registers.
195+ * This is the reverse to the saving process above.
196+ * /
197+
198+ / * Rotate back to the final window , then start loading 12 registers at a time ,
199+ * in 5 iterations.
200+ * Again , a1 is the downcounter and a3 is the save area pointer.
201+ * After each rotation , a1 and a3 are copied from a13 and a15.
202+ * To simplify the loop , we put the initial values into a13 and a15.
203+ * /
204+ rotw - 4
205+ movi a15 , _rmt_save_ctx + 64 * 4 / * point to the end of the save area * /
206+ movi a13 , 5
207+
208+ 1 :
209+ / * Copy a1 and a3 from their previous location ,
210+ * at the same time decrementing and adjusting the save area pointer.
211+ * /
212+ addi a1 , a13 , - 1
213+ addi a3 , a15 , - 48
214+
215+ / * Load 12 registers * /
216+ l32i a4 , a3 , 0
217+ l32i a5 , a3 , 4
218+ l32i a6 , a3 , 8
219+ l32i a7 , a3 , 12
220+ l32i a8 , a3 , 16
221+ l32i a9 , a3 , 20
222+ l32i a10 , a3 , 24
223+ l32i a11 , a3 , 28 / * ensure PS and EPC written * /
224+ l32i a12 , a3 , 32
225+ l32i a13 , a3 , 36
226+ l32i a14 , a3 , 40
227+ l32i a15 , a3 , 44
228+
229+ / * Done with the loop ? * /
230+ beqz a1 , 2f
231+ / * If no , rotate the window and repe at * /
232+ rotw - 3
233+ j 1b
234+
235+ 2 :
236+ / * Done with the loop . Only 4 registers (a0 - a3 in the original window) remain
237+ * to be restored. Also need to restore WINDOWSTART , since all the general
238+ * registers are now in place.
239+ * /
240+ movi a0 , _rmt_save_ctx
241+
242+ l32i a2 , a0 , SPECREG_OFFSET + 4
243+ wsr a2 , WINDOWSTART
244+
245+ l32i a1 , a0 , 4
246+ l32i a2 , a0 , 8
247+ l32i a3 , a0 , 12
248+ rsr a0 , EXCSAVE_X / * holds the value of a0 before the interrupt handler * /
249+
250+ / * Return from the interrupt , restoring PS from EPS_X * /
251+ rfi RFI_X
252+
253+
254+ / * The linker has no reason to link in this file ; all symbols it exports are already defined
255+ (weakly!) in the default int handler. Define a symbol here so we can use it to have the
256+ linker inspect this anyway. * /
257+
258+ . global ld_include_hli_vectors_rmt
259+ ld_include_hli_vectors_rmt:
260+
261+
262+ #endif // CONFIG_BTDM_CTRL_HLI
263+ #endif // XTensa
0 commit comments