xref: /Kernel-v10.6.2/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_loadstore_handler.S (revision 4a490d64a5ee7c09af96cc77f4151f56cbd776c3)
1/*
2 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7/*
8 *  LoadStoreErrorCause:     Occurs when trying to access 32 bit addressable memory region as 8 bit or 16 bit
9 *  LoadStoreAlignmentCause: Occurs when trying to access in an unaligned manner
10 *
11 *          xxxx xxxx = imm8 field
12 *               yyyy = imm4 field
13 *               ssss = s field
14 *               tttt = t field
15 *
16 *                            16                0
17 *                            -------------------
18 *          L32I.N            yyyy ssss tttt 1000
19 *          S32I.N            yyyy ssss tttt 1001
20 *
21 *                  23                          0
22 *                  -----------------------------
23 *          L8UI    xxxx xxxx 0000 ssss tttt 0010               <- LoadStoreError
24 *          L16UI   xxxx xxxx 0001 ssss tttt 0010               <- LoadStoreError, LoadStoreAlignment
25 *          L16SI   xxxx xxxx 1001 ssss tttt 0010               <- LoadStoreError, LoadStoreAlignment
26 *          L32I    xxxx xxxx 0010 ssss tttt 0010               <- LoadStoreAlignment
27 *
28 *          S8I     xxxx xxxx 0100 ssss tttt 0010               <- LoadStoreError
29 *          S16I    xxxx xxxx 0101 ssss tttt 0010               <- LoadStoreError, LoadStoreAlignment
30 *          S32I    xxxx xxxx 0110 ssss tttt 0010               <- LoadStoreAlignment
31 *
32 *                   ******* UNSUPPORTED *******
33 *
34 *          L32E    0000 1001 rrrr ssss tttt 0000
35 *          S32E    0100 1001 rrrr ssss tttt 0000
36 *                  -----------------------------
37 */
38
39#include "xtensa_rtos.h"
40#include "sdkconfig.h"
41#include "soc/soc.h"
42
43#define LOADSTORE_HANDLER_STACK_SZ      8
44    .section .bss, "aw"
45    .balign 16
46LoadStoreHandlerStack:
47    .rept LOADSTORE_HANDLER_STACK_SZ
48    .word 0
49    .endr
50
51
52/* LoadStoreErrorCause handler:
53 *
54 * Completes 8-bit or 16-bit load/store instructions from 32-bit aligned memory region
55 * Called from UserExceptionVector if EXCCAUSE is LoadStoreErrorCause
56 */
57
58    .global   LoadStoreErrorHandler
59    .section .iram1, "ax"
60
61    .literal_position
62
63    .balign 4
64LoadStoreErrorHandler:
65    .type   LoadStoreErrorHandler, @function
66
67    wsr     a0, depc                            // Save return address in depc
68    mov     a0, sp
69    movi    sp, LoadStoreHandlerStack
70    s32i    a0, sp, 0x04                        // Since a0 contains value of a1
71    s32i    a2, sp, 0x08
72    s32i    a3, sp, 0x0c
73    s32i    a4, sp, 0x10
74
75    rsr     a0, sar                             // Save SAR in a0 to restore later
76
77    /* Check whether the address lies in the valid range */
78    rsr     a3, excvaddr
79    movi    a4, _iram_text_end                  // End of code section of IRAM
80    bge     a3, a4, 1f
81    movi    a4, SOC_CACHE_APP_LOW               // Check if in APP cache region
82    blt     a3, a4, .LS_wrong_opcode
83    movi    a4, SOC_CACHE_APP_HIGH
84    bge     a3, a4, .LS_wrong_opcode
85    j       2f
86
871:
88    movi    a4, SOC_IRAM_HIGH                   // End of IRAM address range
89    bge     a3, a4, .LS_wrong_opcode
90
912:
92    /* Examine the opcode which generated the exception */
93    /* Note: Instructions are in this order to avoid pipeline stalls. */
94    rsr     a2, epc1
95    movi    a4, ~3
96    ssa8l   a2                                  // sar is now correct shift for aligned read
97    and     a2, a2, a4                          // a2 now 4-byte aligned address of instruction
98    l32i    a4, a2, 0
99    l32i    a2, a2, 4
100
101    src     a2, a2, a4                          // a2 now instruction that failed
102    bbci    a2, 1, .LS_wrong_opcode
103    bbsi    a2, 14, .LSE_store_op               // Store instruction
104
105    /* l8/l16ui/l16si */
106    movi    a4, ~3
107    and     a4, a3, a4                          // a4 now word aligned read address
108
109    ssa8l   a3                                  // sar is now shift to extract a3's byte
110    l32i    a4, a4, 0                           // perform the actual read
111    srl     a4, a4                              // shift right correct distance
112    extui   a3, a2, 12, 4
113    bnez    a3, 1f                              // l16ui/l16si
114    extui   a4, a4, 0, 8                        // mask off bits needed for an l8
115    j       2f
116
1171:
118    extui   a4, a4, 0, 16
119    bbci    a2, 15, 2f                          // l16ui
120
121    /* Sign adjustment */
122    slli    a4, a4, 16
123    srai    a4, a4, 16                          // a4 contains the value
124
1252:
126    /* a4 contains the value */
127    rsr     a3, epc1
128    addi    a3, a3, 3
129    wsr     a3, epc1
130    wsr     a0, sar
131    rsr     a0, excsave1
132
133    extui   a2, a2, 3, 5
134    blti    a2, 10, .LSE_stack_reg
135
136    movi    a3, .LS_jumptable_base
137    addx8   a2, a2, a3                          // a2 is now the address to jump to
138    l32i    a3, sp, 0x0c
139    jx      a2
140
141.LSE_stack_reg:
142    addx2   a2, a2, sp
143    s32i    a4, a2, 0
144
145    /* Restore all values */
146    l32i    a4, sp, 0x10
147    l32i    a3, sp, 0x0c
148    l32i    a2, sp, 0x08
149    l32i    a1, sp, 0x04
150    rfe
151
152.LSE_store_op:
153    s32i    a5, a1, 0x14
154    s32i    a6, a1, 0x18
155
156    /* a2 -> instruction that caused the error */
157    /* a3 -> unaligned address */
158    extui   a4, a2, 4, 4
159    blti    a4, 7, 1f
160    movi    a5, .LSE_store_reg
161    addx8   a5, a4, a5
162    jx      a5
163
1641:
165    addx4   a4, a4, sp
166    l32i    a4, a4, 0
167
168.LSE_store_data:
169    /* a4 contains the value */
170    rsr     a6, epc1
171    addi    a6, a6, 3
172    wsr     a6, epc1
173
174    ssa8b   a3
175    movi    a5, -1
176    bbsi    a2, 12, 1f                          // s16
177    extui   a4, a4, 0, 8
178    movi    a6, 0xff
179    j       2f
1801:
181    extui   a4, a4, 0, 16
182    movi    a6, 0xffff
1832:
184    sll     a4, a4                              // shift the value to proper offset
185    sll     a6, a6
186    xor     a5, a5, a6                          // a5 contains the mask
187
188    movi    a6, ~3
189    and     a3, a3, a6                          // a3 has the aligned address
190    l32i    a6, a3, 0                           // a6 contains the data at the aligned address
191    and     a6, a6, a5
192    or      a4, a6, a4
193    s32i    a4, a3, 0
194
195    /* Restore registers */
196    wsr     a0, sar
197
198    l32i    a6, sp, 0x18
199    l32i    a5, sp, 0x14
200    l32i    a4, sp, 0x10
201    l32i    a3, sp, 0x0c
202    l32i    a2, sp, 0x08
203    l32i    a1, sp, 0x04
204    rsr     a0, excsave1
205
206    rfe
207
208.LSE_store_reg:
209    .org .LSE_store_reg + (7 * 8)
210    mov     a4, a7
211    j .LSE_store_data
212
213    .org .LSE_store_reg + (8 * 8)
214    mov     a4, a8
215    j .LSE_store_data
216
217    .org .LSE_store_reg + (9 * 8)
218    mov     a4, a9
219    j .LSE_store_data
220
221    .org .LSE_store_reg + (10 * 8)
222    mov     a4, a10
223    j .LSE_store_data
224
225    .org .LSE_store_reg + (11 * 8)
226    mov     a4, a11
227    j .LSE_store_data
228
229    .org .LSE_store_reg + (12 * 8)
230    mov     a4, a12
231    j .LSE_store_data
232
233    .org .LSE_store_reg + (13 * 8)
234    mov     a4, a13
235    j .LSE_store_data
236
237    .org .LSE_store_reg + (14 * 8)
238    mov     a4, a14
239    j .LSE_store_data
240
241    .org .LSE_store_reg + (15 * 8)
242    mov     a4, a15
243    j .LSE_store_data
244
245
246/* LoadStoreAlignmentCause handler:
247 *
248 * Completes unaligned 16-bit and 32-bit load/store instructions from 32-bit aligned memory region
249 * Called from UserExceptionVector if EXCCAUSE is LoadStoreAlignmentCause
250 */
251
252    .global   AlignmentErrorHandler
253    .section .iram1, "ax"
254
255    .literal_position
256
257    .balign 4
258AlignmentErrorHandler:
259    .type   AlignmentErrorHandler, @function
260
261    wsr     a0, depc                            // Save return address in depc
262    mov     a0, sp
263    movi    sp, LoadStoreHandlerStack
264    s32i    a0, sp, 0x04                        // Since a0 contains value of a1
265    s32i    a2, sp, 0x08
266    s32i    a3, sp, 0x0c
267    s32i    a4, sp, 0x10
268
269    rsr     a0, sar                             // Save SAR in a0 to restore later
270
271    /* Check whether the address lies in the valid range */
272    rsr     a3, excvaddr
273    movi    a4, _iram_text_end                  // End of code section of IRAM
274    bge     a3, a4, 1f
275    movi    a4, SOC_CACHE_APP_LOW               // Check if in APP cache region
276    blt     a3, a4, .LS_wrong_opcode
277    movi    a4, SOC_CACHE_APP_HIGH
278    bge     a3, a4, .LS_wrong_opcode
279    j       2f
280
2811:
282    movi    a4, SOC_IRAM_HIGH                   // End of IRAM address range
283    bge     a3, a4, .LS_wrong_opcode
284
2852:
286    /* Examine the opcode which generated the exception */
287    /* Note: Instructions are in this order to avoid pipeline stalls. */
288    rsr     a2, epc1
289    movi    a4, ~3
290    ssa8l   a2                                  // sar is now correct shift for aligned read
291    and     a2, a2, a4                          // a2 now 4-byte aligned address of instruction
292    l32i    a4, a2, 0
293    l32i    a2, a2, 4
294
295    /* a2 has the instruction that caused the error */
296    src     a2, a2, a4
297    extui   a4, a2, 0, 4
298    addi    a4, a4, -9
299    beqz    a4, .LSA_store_op
300    bbsi    a2, 14, .LSA_store_op
301
302    ssa8l   a3                                  // a3 contains the unaligned address
303    movi    a4, ~3
304    and     a4, a3, a4                          // a4 has the aligned address
305    l32i    a3, a4, 0
306    l32i    a4, a4, 4
307    src     a4, a4, a3
308
309    rsr     a3, epc1
310    addi    a3, a3, 2
311    bbsi    a2, 3, 1f                           // l32i.n
312    bbci    a2, 1, .LS_wrong_opcode
313    addi    a3, a3, 1
314
315    bbsi    a2, 13, 1f                          // l32
316    extui   a4, a4, 0, 16
317    bbci    a2, 15, 1f                          // l16ui
318
319    /* Sign adjustment */
320    slli    a4, a4, 16
321    srai    a4, a4, 16                          // a4 contains the value
322
3231:
324    wsr     a3, epc1
325    wsr     a0, sar
326    rsr     a0, excsave1
327
328    extui   a2, a2, 4, 4
329    blti    a2, 5, .LSA_stack_reg               // a3 contains the target register
330
331    movi    a3, .LS_jumptable_base
332    slli    a2, a2, 4
333    add     a2, a2, a3                          // a2 is now the address to jump to
334    l32i    a3, sp, 0x0c
335    jx      a2
336
337.LSA_stack_reg:
338    addx4   a2, a2, sp
339    s32i    a4, a2, 0
340
341    /* Restore all values */
342    l32i    a4, sp, 0x10
343    l32i    a3, sp, 0x0c
344    l32i    a2, sp, 0x08
345    l32i    a1, sp, 0x04
346    rfe
347
348/* Store instruction */
349.LSA_store_op:
350    s32i    a5, sp, 0x14
351    s32i    a6, sp, 0x18
352    s32i    a7, sp, 0x1c
353
354    /* a2 -> instruction that caused the error */
355    /* a3 -> unaligned address */
356    extui   a4, a2, 4, 4
357    blti    a4, 8, 1f
358    movi    a5, .LSA_store_reg
359    addx8   a5, a4, a5
360    jx      a5
361
3621:
363    addx4   a4, a4, sp
364    l32i    a4, a4, 0                           // a4 contains the value
365
366.LSA_store_data:
367    movi    a6, 0
368
369    rsr     a7, epc1
370    addi    a7, a7 ,2
371    bbsi    a2, 3, 1f                           // s32i.n
372    bbci    a2, 1, .LS_wrong_opcode
373
374    addi    a7, a7, 1
375    bbsi    a2, 13, 1f                          // s32i
376
377    movi    a5, -1
378    extui   a4, a4, 0, 16
379    slli    a6, a5, 16                          // 0xffff0000
380
3811:
382    wsr     a7, epc1
383    movi    a5, ~3
384    and     a5, a3, a5                          // a5 has the aligned address
385
386    ssa8b   a3
387    movi    a3, -1
388    src     a7, a6, a3
389    src     a3, a3, a6
390
391    /* Store data on lower address */
392    l32i    a6, a5, 0
393    and     a6, a6, a7
394    sll     a7, a4
395    or      a6, a6, a7
396    s32i    a6, a5, 0
397
398    /* Store data on higher address */
399    l32i    a7, a5, 4
400    srl     a6, a4
401    and     a3, a7, a3
402    or      a3, a3, a6
403    s32i    a3, a5, 4
404
405    /* Restore registers */
406    wsr     a0, sar
407    rsr     a0, excsave1
408
409    l32i    a7, sp, 0x1c
410    l32i    a6, sp, 0x18
411    l32i    a5, sp, 0x14
412    l32i    a4, sp, 0x10
413    l32i    a3, sp, 0x0c
414    l32i    a2, sp, 0x08
415    l32i    a1, sp, 0x04
416    rfe
417
418.LSA_store_reg:
419    .org .LSA_store_reg + (8 * 8)
420    mov     a4, a8
421    j       .LSA_store_data
422
423    .org .LSA_store_reg + (9 * 8)
424    mov     a4, a9
425    j       .LSA_store_data
426
427    .org .LSA_store_reg + (10 * 8)
428    mov     a4, a10
429    j       .LSA_store_data
430
431    .org .LSA_store_reg + (11 * 8)
432    mov     a4, a11
433    j       .LSA_store_data
434
435    .org .LSA_store_reg + (12 * 8)
436    mov     a4, a12
437    j       .LSA_store_data
438
439    .org .LSA_store_reg + (13 * 8)
440    mov     a4, a13
441    j       .LSA_store_data
442
443    .org .LSA_store_reg + (14 * 8)
444    mov     a4, a14
445    j       .LSA_store_data
446
447    .org .LSA_store_reg + (15 * 8)
448    mov     a4, a15
449    j       .LSA_store_data
450
451/*
452 * Common routines for both the exception handlers
453 */
454    .balign 4
455.LS_jumptable:
456    /*  The first 5 entries (80 bytes) of this table are unused (registers
457        a0..a4 are handled separately above).  Rather than have a whole bunch
458        of wasted space, just pretend that the table starts 80 bytes
459        earlier in memory. */
460    .set    .LS_jumptable_base, .LS_jumptable - (16 * 5)
461
462    .org    .LS_jumptable_base + (16 * 5)
463    mov     a5, a4
464    l32i    a4, sp, 0x10
465    l32i    a2, sp, 0x08
466    l32i    a1, sp, 0x04
467    rfe
468
469    .org    .LS_jumptable_base + (16 * 6)
470    mov     a6, a4
471    l32i    a4, sp, 0x10
472    l32i    a2, sp, 0x08
473    l32i    a1, sp, 0x04
474    rfe
475
476    .org    .LS_jumptable_base + (16 * 7)
477    mov     a7, a4
478    l32i    a4, sp, 0x10
479    l32i    a2, sp, 0x08
480    l32i    a1, sp, 0x04
481    rfe
482
483    .org    .LS_jumptable_base + (16 * 8)
484    mov     a8, a4
485    l32i    a4, sp, 0x10
486    l32i    a2, sp, 0x08
487    l32i    a1, sp, 0x04
488    rfe
489
490    .org    .LS_jumptable_base + (16 * 9)
491    mov     a9, a4
492    l32i    a4, sp, 0x10
493    l32i    a2, sp, 0x08
494    l32i    a1, sp, 0x04
495    rfe
496
497    .org    .LS_jumptable_base + (16 * 10)
498    mov     a10, a4
499    l32i    a4, sp, 0x10
500    l32i    a2, sp, 0x08
501    l32i    a1, sp, 0x04
502    rfe
503
504    .org    .LS_jumptable_base + (16 * 11)
505    mov     a11, a4
506    l32i    a4, sp, 0x10
507    l32i    a2, sp, 0x08
508    l32i    a1, sp, 0x04
509    rfe
510
511    .org    .LS_jumptable_base + (16 * 12)
512    mov     a12, a4
513    l32i    a4, sp, 0x10
514    l32i    a2, sp, 0x08
515    l32i    a1, sp, 0x04
516    rfe
517
518    .org    .LS_jumptable_base + (16 * 13)
519    mov     a13, a4
520    l32i    a4, sp, 0x10
521    l32i    a2, sp, 0x08
522    l32i    a1, sp, 0x04
523    rfe
524
525    .org    .LS_jumptable_base + (16 * 14)
526    mov     a14, a4
527    l32i    a4, sp, 0x10
528    l32i    a2, sp, 0x08
529    l32i    a1, sp, 0x04
530    rfe
531
532    .org    .LS_jumptable_base + (16 * 15)
533    mov     a15, a4
534    l32i    a4, sp, 0x10
535    l32i    a2, sp, 0x08
536    l32i    a1, sp, 0x04
537    rfe
538
539.LS_wrong_opcode:
540    /* Reaches here if the address is in invalid range or the opcode isn't supported.
541     * Restore registers and jump back to _xt_user_exc
542     */
543    wsr     a0, sar
544    l32i    a4, sp, 0x10
545    l32i    a3, sp, 0x0c
546    l32i    a2, sp, 0x08
547    l32i    a1, sp, 0x04
548    rsr     a0, depc
549    ret                                         // Equivalent to jx a0
550