esp-open-rtos/core/exception_vectors.S
Angus Gratton e4c76b488c Remove the unaligned load handler to its own source file as it was getting quite complex
The downside here is needing to use #include so the 'beq' in the
exception vector can land on it directly, save an instruction.

There might be a better way to do this, but it seems hard to "curate"
the order that symbols appear in each section.
2015-09-15 11:34:21 +10:00

247 lines
6 KiB
ArmAsm
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Xtensa Exception (ie interrupt) Vectors & low-level handler code
Core exception handler code is placed in the .vecbase section,
which gets picked up specially in the linker script and placed
at beginning of IRAM.
The actual VecBase symbol should be the first thing in .vecbase
(this is not strictly important as it gets set by symbol lookup not
by hardcoded address, but having it at 0x40100000 means that the
exception vectors have memorable offsets, which match the default
Boot ROM vector offsets. So convenient for human understanding.
Part of esp-open-rtos
Original vector contents Copyright (C) 2014-2015 Espressif Systems
Additions Copyright (C) Superhouse Automation Pty Ltd and Angus Gratton
BSD Licensed as described in the file LICENSE
*/
#include "led_debug.s"
/* Some UserException causes, see table Table 464 in ISA reference */
#define CAUSE_SYSCALL 1
#define CAUSE_LOADSTORE 3
#define CAUSE_LVL1INT 4
.text
.section .vecbase.text, "x"
.global VecBase
.type VecBase, @function /* it's not really a function, but treat it like one */
.org 0
VecBase:
/* IMPORTANT: exception vector literals will go here, but we
can't have more than 4 otherwise we push DebugExceptionVector past
offset 0x10 relative to VecBase. There should be ways to avoid this,
and also keep the VecBase offsets easy to read, but this works for now.
*/
.literal_position
.org 0x10
DebugExceptionVector:
wsr.excsave2 a0
call0 sdk_user_fatal_exception_handler
rfi 2
.org 0x20
NMIExceptionVector:
wsr.excsave3 a0
call0 CallNMIExceptionHandler
rfi 3 /* CallNMIExceptionHandler should call rfi itself */
.org 0x30
KernelExceptionVector:
break 1, 0
call0 sdk_user_fatal_exception_handler
rfe
.org 0x50
UserExceptionVector:
wsr.excsave1 a0
rsr.exccause a0
beqi a0, CAUSE_LOADSTORE, UserExceptionLoadStoreHandler
j UserExceptionHandler
.org 0x70
DoubleExceptionVector:
break 1, 4
rsr.exccause a0
beqi a0, CAUSE_LOADSTORE, DoubleExceptionLoadStoreHandler
call0 sdk_user_fatal_exception_handler
/* Reset vector would go here at offset 0x80 but should be unused,
as vecbase goes back to mask ROM vectors on reset */
/***** end of exception vectors *****/
/* We include this here so UserExceptionLoadStoreHandler is within
the range of a 'beq' instruction jump.
*/
#include "exception_unaligned_load.S.inc"
.section .bss
NMIHandlerStack: /* stack space for NMI handler */
.skip 4*0x100
.LNMIHandlerStackTop:
NMIRegisterSaved: /* register space for saving NMI registers */
.skip 4*(16 + 6)
/* Save register relative to a0 */
.macro SAVE_REG register, regnum
s32i \register, a0, (0x20 + 4 * \regnum)
.endm
/* Load register relative to sp */
.macro LOAD_REG register, regnum
l32i \register, sp, (0x20 + 4 * \regnum)
.endm
.text
.section .vecbase.text
.literal_position
.align 4
.global call_user_start
.type call_user_start, @function
call_user_start:
movi a2, VecBase
wsr.vecbase a2
call0 sdk_user_start
.literal_position
.align 16
.type CallNMIExceptionHandler, @function
CallNMIExceptionHandler:
movi a0, NMIRegisterSaved
SAVE_REG a2, 2
SAVE_REG sp, 1
SAVE_REG a3, 3
rsr.excsave3 a2 /* a2 is now former a0 */
SAVE_REG a4, 4
SAVE_REG a2, 0
rsr.epc1 a3
rsr.exccause a4
SAVE_REG a3, -5
SAVE_REG a4, -4
rsr.excvaddr a3
SAVE_REG a3, -3
rsr.excsave1 a3
SAVE_REG a3, -2
SAVE_REG a5, 5
SAVE_REG a6, 6
SAVE_REG a7, 7
SAVE_REG a8, 8
SAVE_REG a9, 9
SAVE_REG a10, 10
SAVE_REG a11, 11
SAVE_REG a12, 12
SAVE_REG a13, 13
SAVE_REG a14, 14
SAVE_REG a15, 15
movi sp, .LNMIHandlerStackTop
movi a0, 0
movi a2, 0x23 /* argument for handler */
wsr.ps a2
rsync
rsr.sar a14
s32i a14, sp, 0 /* this is also NMIRegisterSaved+0 */
call0 sdk_wDev_ProcessFiq
l32i a15, sp, 0
wsr.sar a15
movi a2, 0x33
wsr.ps a2
rsync
LOAD_REG a4, 4
LOAD_REG a5, 5
LOAD_REG a6, 6
LOAD_REG a7, 7
LOAD_REG a8, 8
LOAD_REG a9, 9
LOAD_REG a10, 10
LOAD_REG a11, 11
LOAD_REG a12, 12
LOAD_REG a13, 13
LOAD_REG a14, 14
LOAD_REG a15, 15
LOAD_REG a2, -5
LOAD_REG a3, -4
wsr.epc1 a2
wsr.exccause a3
LOAD_REG a2, -3
LOAD_REG a3, -2
wsr.excvaddr a2
wsr.excsave1 a3
LOAD_REG a0, 0
/* set dport nmi status bit 0 (wDev_ProcessFiq clears & verifies this bit stays cleared,
see http://esp8266-re.foogod.com/wiki/WDev_ProcessFiq_%28IoT_RTOS_SDK_0.9.9%29) */
movi a2, 0x3ff00000
movi a3, 0x1
s32i a3, a2, 0
LOAD_REG a2, 2
LOAD_REG a3, 3
LOAD_REG a1, 1
rfi 0x3
.type UserExceptionHandler, @function
UserExceptionHandler:
mov a0, sp /* a0 was saved in UserExceptionVector */
addi sp, sp, -0x50
s32i a0, sp, 0x10
rsr.ps a0
s32i a0, sp, 0x08
rsr.epc1 a0
s32i a0, sp, 0x04
rsr.excsave1 a0
s32i a0, sp, 0x0c
movi a0, _xt_user_exit
s32i a0, sp, 0x0
call0 sdk__xt_int_enter
movi a0, 0x23
wsr.ps a0
rsync
rsr.exccause a2
beqi a2, CAUSE_LVL1INT, UserHandleInterrupt
/* Any UserException cause other than level 1 interrupt triggers a panic */
UserFailOtherExceptionCause:
break 1, 1
call0 sdk_user_fatal_exception_handler
UserHandleInterrupt:
rsil a0, 1
rsr.intenable a2
rsr.interrupt a3
movi a4, 0x3fff
and a2, a2, a3
and a2, a2, a4 /* a2 = 0x3FFF & INTENABLE & INTERRUPT */
UserHandleTimer:
movi a3, 0xffbf
and a3, a2, a3 /* a3 = a2 & 0xFFBF, ie remove 0x40 from a2 if set */
bnez a3, UserTimerDone /* bits other than 0x40 are set */
movi a3, 0x40
sub a12, a2, a3 /* a12 - a2 - 0x40 - I think a12 _must_ be zero here? */
call0 sdk__xt_timer_int /* tick timer interrupt */
mov a2, a12 /* restore a2 from a12, ie zero */
beqz a2, UserIntDone
UserTimerDone:
call0 _xt_isr_handler
bnez a2, UserHandleTimer
UserIntDone:
beqz a2, UserIntExit
break 1, 1 /* non-zero remnant in a2 means fail */
call0 sdk_user_fatal_exception_handler
UserIntExit:
call0 sdk__xt_int_exit /* calls rfi */
/* _xt_user_exit is used to exit interrupt context.
TODO: Find a better place for this to live.
*/
.text
.section .text
.global _xt_user_exit
.type _xt_user_exit, @function
_xt_user_exit:
l32i a0, sp, 0x8
wsr.ps a0
l32i a0, sp, 0x4
wsr.epc1 a0
l32i a0, sp, 0xc
l32i sp, sp, 0x10
rsync
rfe