S/W can write exception handler entry to this table. Exception handler can now reside anywhere in memory. Committed on the Free edition of March Hare Software CVSNT Server. Upgrade to CVS Suite for more features and support: http://march-hare.com/cvsnt/ git-svn-id: http://moon:8086/svn/vhdl/trunk@494 cc03376c-175c-47c8-b038-4cd826a8556b
185 lines
3.8 KiB
ArmAsm
185 lines
3.8 KiB
ArmAsm
#include <regdef.h>
|
|
#include <xcpt_asm.h>
|
|
|
|
.section .exc_vect
|
|
_xcpt_vector_tbl:
|
|
.fill 16, 4, 0
|
|
|
|
.text
|
|
|
|
LEAF(_xcpt_handler)
|
|
.set noreorder
|
|
.set noat
|
|
/* Note: exceptions do not save and restore registers k0 and k1.
|
|
* on entry, k1 = exception class.
|
|
*/
|
|
|
|
/* allocate exception stack frame (on 8-byte boundary) */
|
|
subu k1, sp, XCP_SIZE
|
|
srl k1, 3 /* shift right/left -> alligned on boundary */
|
|
sll k1, 3
|
|
|
|
/* save enough registers to get by */
|
|
sw AT, XCP_AT(k1)
|
|
sw v0, XCP_V0(k1)
|
|
sw v1, XCP_V1(k1)
|
|
sw a0, XCP_A0(k1)
|
|
sw a1, XCP_A1(k1)
|
|
sw a2, XCP_A2(k1)
|
|
sw a3, XCP_A3(k1)
|
|
sw sp, XCP_SP(k1)
|
|
sw ra, XCP_RA(k1)
|
|
|
|
/* get coprocessor 0 exception state */
|
|
mfc0 a0, CP0_CR
|
|
mfc0 a1, CP0_SR
|
|
mfc0 a2, CP0_BADDR
|
|
mfc0 a3, CP0_EPC
|
|
|
|
/* we can safely use AT now */
|
|
.set at
|
|
|
|
/* switch to using sp to point at exception frame */
|
|
move sp, k1
|
|
|
|
/* nothing sensible to store for k0/k1, store zero */
|
|
sw zero, XCP_K0(sp)
|
|
sw zero, XCP_K1(sp)
|
|
|
|
/* we are now interruptible: dump all remaining state
|
|
* into the exception stack frame.
|
|
*/
|
|
/* coprocessor exception state */
|
|
sw a0, XCP_CR(sp)
|
|
sw a1, XCP_SR(sp)
|
|
sw a2, XCP_BADDR(sp)
|
|
sw a3, XCP_EPC(sp)
|
|
|
|
/* mdhi and mdlo */
|
|
mfhi v0
|
|
mflo v1
|
|
sw v0, XCP_MDHI(sp)
|
|
sw v1, XCP_MDLO(sp)
|
|
|
|
/* Save all the other general registers.
|
|
* We save zero, s0-s7 and s8 as well, as instruction emulators (e.g. FP
|
|
* operations) and debuggers rely on all registers stored together in
|
|
* well-defined structure.
|
|
*/
|
|
sw zero, XCP_ZERO(sp)
|
|
sw t0, XCP_T0(sp)
|
|
sw t1, XCP_T1(sp)
|
|
sw t2, XCP_T2(sp)
|
|
sw t3, XCP_T3(sp)
|
|
sw t4, XCP_T4(sp)
|
|
sw t5, XCP_T5(sp)
|
|
sw t6, XCP_T6(sp)
|
|
sw t7, XCP_T7(sp)
|
|
sw s0, XCP_S0(sp)
|
|
sw s1, XCP_S1(sp)
|
|
sw s2, XCP_S2(sp)
|
|
sw s3, XCP_S3(sp)
|
|
sw s4, XCP_S4(sp)
|
|
sw s5, XCP_S5(sp)
|
|
sw s6, XCP_S6(sp)
|
|
sw s7, XCP_S7(sp)
|
|
sw t8, XCP_T8(sp)
|
|
sw t9, XCP_T9(sp)
|
|
sw gp, XCP_GP(sp)
|
|
sw s8, XCP_S8(sp)
|
|
|
|
/* I don't know what the following does. [rb] */
|
|
/* load our _gp pointer */
|
|
# la gp, _gp
|
|
|
|
/* and call the C exception handler */
|
|
move a0, sp # arg1 = &xcp
|
|
subu sp, 16 # (arg save area)
|
|
j _xcpt_call
|
|
move ra, zero # fake return address
|
|
|
|
/* This strange call to _xcpt_call with zero return address is to
|
|
* help exception-aware debuggers to trace back over the exception event.
|
|
* We are basically interposing a bogus stackframe (with a zero return
|
|
* address) between the C exception handler and the actual machine
|
|
* exception.
|
|
*/
|
|
$xcptrest:
|
|
.set noat
|
|
add AT, sp, 16
|
|
|
|
/* at points to exception frame */
|
|
$xcptrestother:
|
|
/* restore all state */
|
|
/* restore most general registers */
|
|
lw t0, XCP_T0(AT)
|
|
lw t1, XCP_T1(AT)
|
|
lw t2, XCP_T2(AT)
|
|
lw t3, XCP_T3(AT)
|
|
lw t4, XCP_T4(AT)
|
|
lw t5, XCP_T5(AT)
|
|
lw t6, XCP_T6(AT)
|
|
lw t7, XCP_T7(AT)
|
|
lw s0, XCP_S0(AT)
|
|
lw s1, XCP_S1(AT)
|
|
lw s2, XCP_S2(AT)
|
|
lw s3, XCP_S3(AT)
|
|
lw s4, XCP_S4(AT)
|
|
lw s5, XCP_S5(AT)
|
|
lw s6, XCP_S6(AT)
|
|
lw s7, XCP_S7(AT)
|
|
lw t8, XCP_T8(AT)
|
|
lw t9, XCP_T9(AT)
|
|
lw gp, XCP_GP(AT)
|
|
lw s8, XCP_S8(AT)
|
|
|
|
/* mdhi and mdlo */
|
|
lw v0, XCP_MDHI(AT)
|
|
lw v1, XCP_MDLO(AT)
|
|
mthi v0
|
|
mtlo v1
|
|
|
|
/* remaining general registers */
|
|
lw a0, XCP_A0(AT)
|
|
lw a1, XCP_A1(AT)
|
|
lw a2, XCP_A2(AT)
|
|
lw a3, XCP_A3(AT)
|
|
lw ra, XCP_RA(AT)
|
|
|
|
/* restore the exception-time status register */
|
|
.set noreorder
|
|
lw v0, XCP_SR(AT)
|
|
nop
|
|
mtc0 v0, CP0_SR
|
|
lw v1, XCP_V1(AT)
|
|
lw v0, XCP_V0(AT)
|
|
lw sp, XCP_SP(AT)
|
|
|
|
/* we are not uninterruptible and can use k1 safely */
|
|
lw k1, XCP_EPC(AT)
|
|
lw AT, XCP_AT(AT)
|
|
mtc0 k1, CP0_EPC
|
|
j k1
|
|
rfe
|
|
|
|
.set reorder
|
|
.set at
|
|
END(_xcpt_handler)
|
|
|
|
|
|
LEAF(_xcpt_call)
|
|
/* on entry: a0 == &xcp */
|
|
subu sp, 24
|
|
sw ra, 16(sp)
|
|
|
|
/* punt out to _xcpt_deliver */
|
|
jal _xcpt_deliver
|
|
nop
|
|
lw ra, 16(sp)
|
|
addu sp, 24
|
|
beqz ra, $xcptrest
|
|
nop
|
|
j ra
|
|
nop
|
|
END(_xcpt_call)
|