mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-30 20:51:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			560 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			560 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| /*
 | |
|  Copyright 2019 Espressif Systems (Shanghai) PTE LTD
 | |
| 
 | |
|  Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  you may not use this file except in compliance with the License.
 | |
|  You may obtain a copy of the License at
 | |
| 
 | |
|      http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
|  Unless required by applicable law or agreed to in writing, software
 | |
|  distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  See the License for the specific language governing permissions and
 | |
|  limitations under the License.
 | |
| */
 | |
| 
 | |
| /*
 | |
|  *  LoadStoreErrorCause:     Occurs when trying to access 32 bit addressable memory region as 8 bit or 16 bit
 | |
|  *  LoadStoreAlignmentCause: Occurs when trying to access in an unaligned manner
 | |
|  *
 | |
|  *          xxxx xxxx = imm8 field
 | |
|  *               yyyy = imm4 field
 | |
|  *               ssss = s field
 | |
|  *               tttt = t field
 | |
|  *
 | |
|  *                            16                0
 | |
|  *                            -------------------
 | |
|  *          L32I.N            yyyy ssss tttt 1000
 | |
|  *          S32I.N            yyyy ssss tttt 1001
 | |
|  *
 | |
|  *                  23                          0
 | |
|  *                  -----------------------------
 | |
|  *          L8UI    xxxx xxxx 0000 ssss tttt 0010               <- LoadStoreError
 | |
|  *          L16UI   xxxx xxxx 0001 ssss tttt 0010               <- LoadStoreError, LoadStoreAlignment
 | |
|  *          L16SI   xxxx xxxx 1001 ssss tttt 0010               <- LoadStoreError, LoadStoreAlignment
 | |
|  *          L32I    xxxx xxxx 0010 ssss tttt 0010               <- LoadStoreAlignment
 | |
|  *
 | |
|  *          S8I     xxxx xxxx 0100 ssss tttt 0010               <- LoadStoreError
 | |
|  *          S16I    xxxx xxxx 0101 ssss tttt 0010               <- LoadStoreError, LoadStoreAlignment
 | |
|  *          S32I    xxxx xxxx 0110 ssss tttt 0010               <- LoadStoreAlignment
 | |
|  *
 | |
|  *                   ******* UNSUPPORTED *******
 | |
|  *
 | |
|  *          L32E    0000 1001 rrrr ssss tttt 0000
 | |
|  *          S32E    0100 1001 rrrr ssss tttt 0000
 | |
|  *                  -----------------------------
 | |
|  */
 | |
| 
 | |
| #include "xtensa_rtos.h"
 | |
| #include "sdkconfig.h"
 | |
| #include "soc/soc.h"
 | |
| 
 | |
| #define LOADSTORE_HANDLER_STACK_SZ      8
 | |
|     .section .bss, "aw"
 | |
|     .balign 16
 | |
| LoadStoreHandlerStack:
 | |
|     .rept LOADSTORE_HANDLER_STACK_SZ
 | |
|     .word 0
 | |
|     .endr
 | |
| 
 | |
| 
 | |
| /* LoadStoreErrorCause handler:
 | |
|  *
 | |
|  * Completes 8-bit or 16-bit load/store instructions from 32-bit aligned memory region
 | |
|  * Called from UserExceptionVector if EXCCAUSE is LoadStoreErrorCause
 | |
|  */
 | |
| 
 | |
|     .global   LoadStoreErrorHandler
 | |
|     .section .iram1, "ax"
 | |
| 
 | |
|     .literal_position
 | |
| 
 | |
|     .balign 4
 | |
| LoadStoreErrorHandler:
 | |
|     .type   LoadStoreErrorHandler, @function
 | |
| 
 | |
|     wsr     a0, depc                            // Save return address in depc
 | |
|     mov     a0, sp
 | |
|     movi    sp, LoadStoreHandlerStack
 | |
|     s32i    a0, sp, 0x04                        // Since a0 contains value of a1
 | |
|     s32i    a2, sp, 0x08
 | |
|     s32i    a3, sp, 0x0c
 | |
|     s32i    a4, sp, 0x10
 | |
| 
 | |
|     rsr     a0, sar                             // Save SAR in a0 to restore later
 | |
| 
 | |
|     /* Check whether the address lies in the valid range */
 | |
|     rsr     a3, excvaddr
 | |
|     movi    a4, _iram_text_end                       // End of code section of IRAM
 | |
|     bge     a3, a4, 1f
 | |
|     movi    a4, SOC_CACHE_APP_LOW               // Check if in APP cache region
 | |
|     blt     a3, a4, .LS_wrong_opcode
 | |
|     movi    a4, SOC_CACHE_APP_HIGH
 | |
|     bge     a3, a4, .LS_wrong_opcode
 | |
|     j       2f
 | |
| 
 | |
| 1:
 | |
|     movi    a4, SOC_IRAM_HIGH                   // End of IRAM address range
 | |
|     bge     a3, a4, .LS_wrong_opcode
 | |
| 
 | |
| 2:
 | |
|     /* Examine the opcode which generated the exception */
 | |
|     /* Note: Instructions are in this order to avoid pipeline stalls. */
 | |
|     rsr     a2, epc1
 | |
|     movi    a4, ~3
 | |
|     ssa8l   a2                                  // sar is now correct shift for aligned read
 | |
|     and     a2, a2, a4                          // a2 now 4-byte aligned address of instruction
 | |
|     l32i    a4, a2, 0
 | |
|     l32i    a2, a2, 4
 | |
| 
 | |
|     src     a2, a2, a4                          // a2 now instruction that failed
 | |
|     bbci    a2, 1, .LS_wrong_opcode
 | |
|     bbsi    a2, 14, .LSE_store_op               // Store instruction
 | |
| 
 | |
|     /* l8/l16ui/l16si */
 | |
|     movi    a4, ~3
 | |
|     and     a4, a3, a4                          // a4 now word aligned read address
 | |
| 
 | |
|     ssa8l   a3                                  // sar is now shift to extract a3's byte
 | |
|     l32i    a4, a4, 0                           // perform the actual read
 | |
|     srl     a4, a4                              // shift right correct distance
 | |
|     extui   a3, a2, 12, 4
 | |
|     bnez    a3, 1f                              // l16ui/l16si
 | |
|     extui   a4, a4, 0, 8                        // mask off bits needed for an l8
 | |
|     j       2f
 | |
| 
 | |
| 1:
 | |
|     extui   a4, a4, 0, 16
 | |
|     bbci    a2, 15, 2f                          // l16ui
 | |
| 
 | |
|     /* Sign adjustment */
 | |
|     slli    a4, a4, 16
 | |
|     srai    a4, a4, 16                          // a4 contains the value
 | |
| 
 | |
| 2:
 | |
|     /* a4 contains the value */
 | |
|     rsr     a3, epc1
 | |
|     addi    a3, a3, 3
 | |
|     wsr     a3, epc1
 | |
|     wsr     a0, sar
 | |
|     rsr     a0, excsave1
 | |
| 
 | |
|     extui   a2, a2, 3, 5
 | |
|     blti    a2, 10, .LSE_stack_reg
 | |
| 
 | |
|     movi    a3, .LS_jumptable_base
 | |
|     addx8   a2, a2, a3                          // a2 is now the address to jump to
 | |
|     l32i    a3, sp, 0x0c
 | |
|     jx      a2
 | |
| 
 | |
| .LSE_stack_reg:
 | |
|     addx2   a2, a2, sp
 | |
|     s32i    a4, a2, 0
 | |
| 
 | |
|     /* Restore all values */
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a3, sp, 0x0c
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rfe
 | |
| 
 | |
| .LSE_store_op:
 | |
|     s32i    a5, a1, 0x14
 | |
|     s32i    a6, a1, 0x18
 | |
| 
 | |
|     /* a2 -> instruction that caused the error */
 | |
|     /* a3 -> unaligned address */
 | |
|     extui   a4, a2, 4, 4
 | |
|     blti    a4, 7, 1f
 | |
|     movi    a5, .LSE_store_reg
 | |
|     addx8   a5, a4, a5
 | |
|     jx      a5
 | |
| 
 | |
| 1:
 | |
|     addx4   a4, a4, sp
 | |
|     l32i    a4, a4, 0
 | |
| 
 | |
| .LSE_store_data:
 | |
|     /* a4 contains the value */
 | |
|     rsr     a6, epc1
 | |
|     addi    a6, a6, 3
 | |
|     wsr     a6, epc1
 | |
| 
 | |
|     ssa8b   a3
 | |
|     movi    a5, -1
 | |
|     bbsi    a2, 12, 1f                          // s16
 | |
|     extui   a4, a4, 0, 8
 | |
|     movi    a6, 0xff
 | |
|     j       2f
 | |
| 1:
 | |
|     extui   a4, a4, 0, 16
 | |
|     movi    a6, 0xffff
 | |
| 2:
 | |
|     sll     a4, a4                              // shift the value to proper offset
 | |
|     sll     a6, a6
 | |
|     xor     a5, a5, a6                          // a5 contains the mask
 | |
| 
 | |
|     movi    a6, ~3
 | |
|     and     a3, a3, a6                          // a3 has the aligned address
 | |
|     l32i    a6, a3, 0                           // a6 contains the data at the aligned address
 | |
|     and     a6, a6, a5
 | |
|     or      a4, a6, a4
 | |
|     s32i    a4, a3, 0
 | |
| 
 | |
|     /* Restore registers */
 | |
|     wsr     a0, sar
 | |
| 
 | |
|     l32i    a6, sp, 0x18
 | |
|     l32i    a5, sp, 0x14
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a3, sp, 0x0c
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rsr     a0, excsave1
 | |
| 
 | |
|     rfe
 | |
| 
 | |
| .LSE_store_reg:
 | |
|     .org .LSE_store_reg + (7 * 8)
 | |
|     mov     a4, a7
 | |
|     j .LSE_store_data
 | |
| 
 | |
|     .org .LSE_store_reg + (8 * 8)
 | |
|     mov     a4, a8
 | |
|     j .LSE_store_data
 | |
| 
 | |
|     .org .LSE_store_reg + (9 * 8)
 | |
|     mov     a4, a9
 | |
|     j .LSE_store_data
 | |
| 
 | |
|     .org .LSE_store_reg + (10 * 8)
 | |
|     mov     a4, a10
 | |
|     j .LSE_store_data
 | |
| 
 | |
|     .org .LSE_store_reg + (11 * 8)
 | |
|     mov     a4, a11
 | |
|     j .LSE_store_data
 | |
| 
 | |
|     .org .LSE_store_reg + (12 * 8)
 | |
|     mov     a4, a12
 | |
|     j .LSE_store_data
 | |
| 
 | |
|     .org .LSE_store_reg + (13 * 8)
 | |
|     mov     a4, a13
 | |
|     j .LSE_store_data
 | |
| 
 | |
|     .org .LSE_store_reg + (14 * 8)
 | |
|     mov     a4, a14
 | |
|     j .LSE_store_data
 | |
| 
 | |
|     .org .LSE_store_reg + (15 * 8)
 | |
|     mov     a4, a15
 | |
|     j .LSE_store_data
 | |
| 
 | |
| 
 | |
| /* LoadStoreAlignmentCause handler:
 | |
|  *
 | |
|  * Completes unaligned 16-bit and 32-bit load/store instructions from 32-bit aligned memory region
 | |
|  * Called from UserExceptionVector if EXCCAUSE is LoadStoreAlignmentCause
 | |
|  */
 | |
| 
 | |
|     .global   AlignmentErrorHandler
 | |
|     .section .iram1, "ax"
 | |
| 
 | |
|     .literal_position
 | |
| 
 | |
|     .balign 4
 | |
| AlignmentErrorHandler:
 | |
|     .type   AlignmentErrorHandler, @function
 | |
| 
 | |
|     wsr     a0, depc                            // Save return address in depc
 | |
|     mov     a0, sp
 | |
|     movi    sp, LoadStoreHandlerStack
 | |
|     s32i    a0, sp, 0x04                        // Since a0 contains value of a1
 | |
|     s32i    a2, sp, 0x08
 | |
|     s32i    a3, sp, 0x0c
 | |
|     s32i    a4, sp, 0x10
 | |
| 
 | |
|     rsr     a0, sar                             // Save SAR in a0 to restore later
 | |
| 
 | |
|     /* Check whether the address lies in the valid range */
 | |
|     rsr     a3, excvaddr
 | |
|     movi    a4, _iram_text_end                       // End of code section of IRAM
 | |
|     bge     a3, a4, 1f
 | |
|     movi    a4, SOC_CACHE_APP_LOW               // Check if in APP cache region
 | |
|     blt     a3, a4, .LS_wrong_opcode
 | |
|     movi    a4, SOC_CACHE_APP_HIGH
 | |
|     bge     a3, a4, .LS_wrong_opcode
 | |
|     j       2f
 | |
| 
 | |
| 1:
 | |
|     movi    a4, SOC_IRAM_HIGH                   // End of IRAM address range
 | |
|     bge     a3, a4, .LS_wrong_opcode
 | |
| 
 | |
| 2:
 | |
|     /* Examine the opcode which generated the exception */
 | |
|     /* Note: Instructions are in this order to avoid pipeline stalls. */
 | |
|     rsr     a2, epc1
 | |
|     movi    a4, ~3
 | |
|     ssa8l   a2                                  // sar is now correct shift for aligned read
 | |
|     and     a2, a2, a4                          // a2 now 4-byte aligned address of instruction
 | |
|     l32i    a4, a2, 0
 | |
|     l32i    a2, a2, 4
 | |
| 
 | |
|     /* a2 has the instruction that caused the error */
 | |
|     src     a2, a2, a4
 | |
|     extui   a4, a2, 0, 4
 | |
|     addi    a4, a4, -9
 | |
|     beqz    a4, .LSA_store_op
 | |
|     bbsi    a2, 14, .LSA_store_op
 | |
| 
 | |
|     ssa8l   a3                                  // a3 contains the unaligned address
 | |
|     movi    a4, ~3
 | |
|     and     a4, a3, a4                          // a4 has the aligned address
 | |
|     l32i    a3, a4, 0
 | |
|     l32i    a4, a4, 4
 | |
|     src     a4, a4, a3
 | |
| 
 | |
|     rsr     a3, epc1
 | |
|     addi    a3, a3, 2
 | |
|     bbsi    a2, 3, 1f                           // l32i.n
 | |
|     bbci    a2, 1, .LS_wrong_opcode
 | |
|     addi    a3, a3, 1
 | |
| 
 | |
|     bbsi    a2, 13, 1f                          // l32
 | |
|     extui   a4, a4, 0, 16
 | |
|     bbci    a2, 15, 1f                          // l16ui
 | |
| 
 | |
|     /* Sign adjustment */
 | |
|     slli    a4, a4, 16
 | |
|     srai    a4, a4, 16                          // a4 contains the value
 | |
| 
 | |
| 1:
 | |
|     wsr     a3, epc1
 | |
|     wsr     a0, sar
 | |
|     rsr     a0, excsave1
 | |
| 
 | |
|     extui   a2, a2, 4, 4
 | |
|     blti    a2, 5, .LSA_stack_reg               // a3 contains the target register
 | |
| 
 | |
|     movi    a3, .LS_jumptable_base
 | |
|     slli    a2, a2, 4
 | |
|     add     a2, a2, a3                          // a2 is now the address to jump to
 | |
|     l32i    a3, sp, 0x0c
 | |
|     jx      a2
 | |
| 
 | |
| .LSA_stack_reg:
 | |
|     addx4   a2, a2, sp
 | |
|     s32i    a4, a2, 0
 | |
| 
 | |
|     /* Restore all values */
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a3, sp, 0x0c
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rfe
 | |
| 
 | |
| /* Store instruction */
 | |
| .LSA_store_op:
 | |
|     s32i    a5, sp, 0x14
 | |
|     s32i    a6, sp, 0x18
 | |
|     s32i    a7, sp, 0x1c
 | |
| 
 | |
|     /* a2 -> instruction that caused the error */
 | |
|     /* a3 -> unaligned address */
 | |
|     extui   a4, a2, 4, 4
 | |
|     blti    a4, 8, 1f
 | |
|     movi    a5, .LSA_store_reg
 | |
|     addx8   a5, a4, a5
 | |
|     jx      a5
 | |
| 
 | |
| 1:
 | |
|     addx4   a4, a4, sp
 | |
|     l32i    a4, a4, 0                           // a4 contains the value
 | |
| 
 | |
| .LSA_store_data:
 | |
|     movi    a6, 0
 | |
| 
 | |
|     rsr     a7, epc1
 | |
|     addi    a7, a7 ,2
 | |
|     bbsi    a2, 3, 1f                           // s32i.n
 | |
|     bbci    a2, 1, .LS_wrong_opcode
 | |
| 
 | |
|     addi    a7, a7, 1
 | |
|     bbsi    a2, 13, 1f                          // s32i
 | |
| 
 | |
|     movi    a5, -1
 | |
|     extui   a4, a4, 0, 16
 | |
|     slli    a6, a5, 16                          // 0xffff0000
 | |
| 
 | |
| 1:
 | |
|     wsr     a7, epc1
 | |
|     movi    a5, ~3
 | |
|     and     a5, a3, a5                          // a5 has the aligned address
 | |
| 
 | |
|     ssa8b   a3
 | |
|     movi    a3, -1
 | |
|     src     a7, a6, a3
 | |
|     src     a3, a3, a6
 | |
| 
 | |
|     /* Store data on lower address */
 | |
|     l32i    a6, a5, 0
 | |
|     and     a6, a6, a7
 | |
|     sll     a7, a4
 | |
|     or      a6, a6, a7
 | |
|     s32i    a6, a5, 0
 | |
| 
 | |
|     /* Store data on higher address */
 | |
|     l32i    a7, a5, 4
 | |
|     srl     a6, a4
 | |
|     and     a3, a7, a3
 | |
|     or      a3, a3, a6
 | |
|     s32i    a3, a5, 4
 | |
| 
 | |
|     /* Restore registers */
 | |
|     wsr     a0, sar
 | |
|     rsr     a0, excsave1
 | |
| 
 | |
|     l32i    a7, sp, 0x1c
 | |
|     l32i    a6, sp, 0x18
 | |
|     l32i    a5, sp, 0x14
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a3, sp, 0x0c
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rfe
 | |
| 
 | |
| .LSA_store_reg:
 | |
|     .org .LSA_store_reg + (8 * 8)
 | |
|     mov     a4, a8
 | |
|     j       .LSA_store_data
 | |
| 
 | |
|     .org .LSA_store_reg + (9 * 8)
 | |
|     mov     a4, a9
 | |
|     j       .LSA_store_data
 | |
| 
 | |
|     .org .LSA_store_reg + (10 * 8)
 | |
|     mov     a4, a10
 | |
|     j       .LSA_store_data
 | |
| 
 | |
|     .org .LSA_store_reg + (11 * 8)
 | |
|     mov     a4, a11
 | |
|     j       .LSA_store_data
 | |
| 
 | |
|     .org .LSA_store_reg + (12 * 8)
 | |
|     mov     a4, a12
 | |
|     j       .LSA_store_data
 | |
| 
 | |
|     .org .LSA_store_reg + (13 * 8)
 | |
|     mov     a4, a13
 | |
|     j       .LSA_store_data
 | |
| 
 | |
|     .org .LSA_store_reg + (14 * 8)
 | |
|     mov     a4, a14
 | |
|     j       .LSA_store_data
 | |
| 
 | |
|     .org .LSA_store_reg + (15 * 8)
 | |
|     mov     a4, a15
 | |
|     j       .LSA_store_data
 | |
| 
 | |
| /*
 | |
|  * Common routines for both the exception handlers
 | |
|  */
 | |
|     .balign 4
 | |
| .LS_jumptable:
 | |
|     /*  The first 5 entries (80 bytes) of this table are unused (registers
 | |
|         a0..a4 are handled separately above).  Rather than have a whole bunch
 | |
|         of wasted space, just pretend that the table starts 80 bytes
 | |
|         earlier in memory. */
 | |
|     .set    .LS_jumptable_base, .LS_jumptable - (16 * 5)
 | |
| 
 | |
|     .org    .LS_jumptable_base + (16 * 5)
 | |
|     mov     a5, a4
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rfe
 | |
| 
 | |
|     .org    .LS_jumptable_base + (16 * 6)
 | |
|     mov     a6, a4
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rfe
 | |
| 
 | |
|     .org    .LS_jumptable_base + (16 * 7)
 | |
|     mov     a7, a4
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rfe
 | |
| 
 | |
|     .org    .LS_jumptable_base + (16 * 8)
 | |
|     mov     a8, a4
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rfe
 | |
| 
 | |
|     .org    .LS_jumptable_base + (16 * 9)
 | |
|     mov     a9, a4
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rfe
 | |
| 
 | |
|     .org    .LS_jumptable_base + (16 * 10)
 | |
|     mov     a10, a4
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rfe
 | |
| 
 | |
|     .org    .LS_jumptable_base + (16 * 11)
 | |
|     mov     a11, a4
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rfe
 | |
| 
 | |
|     .org    .LS_jumptable_base + (16 * 12)
 | |
|     mov     a12, a4
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rfe
 | |
| 
 | |
|     .org    .LS_jumptable_base + (16 * 13)
 | |
|     mov     a13, a4
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rfe
 | |
| 
 | |
|     .org    .LS_jumptable_base + (16 * 14)
 | |
|     mov     a14, a4
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rfe
 | |
| 
 | |
|     .org    .LS_jumptable_base + (16 * 15)
 | |
|     mov     a15, a4
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rfe
 | |
| 
 | |
| .LS_wrong_opcode:
 | |
|     /* Reaches here if the address is in invalid range or the opcode isn't supported.
 | |
|      * Restore registers and jump back to _xt_user_exc
 | |
|      */
 | |
|     wsr     a0, sar
 | |
|     l32i    a4, sp, 0x10
 | |
|     l32i    a3, sp, 0x0c
 | |
|     l32i    a2, sp, 0x08
 | |
|     l32i    a1, sp, 0x04
 | |
|     rsr     a0, depc
 | |
|     ret                                         // Equivalent to jx a0
 | 
