#include "system.h" /* * This is the exception entry point code, which saves all the caller saved * registers and then handles the appropriate exception. It should be pulled * in using a .globl from all the exception handler routines. This scheme is * used so that if an interrupt is never registered, then this code will not * appear in the generated executable, thereby improving code footprint. */ /* * Explicitly allow the use of r1 (the assembler temporary register) * within this code. This register is normally reserved for the use of * the assembler. */ .set noat /* * The top and bottom of the exception stack */ #ifdef ALT_EXCEPTION_STACK .globl __alt_exception_stack_pointer #ifdef ALT_STACK_CHECK .globl __alt_exception_stack_limit /* * We need to store the value of the stack limit after interrupt somewhere. */ .globl alt_exception_old_stack_limit #endif #endif .section .exceptions.entry.label, "xa" .globl alt_exception .type alt_exception, @function alt_exception: .section .exceptions.entry, "xa" #ifdef ALT_EXCEPTION_STACK #ifdef ALT_STACK_CHECK stw et, %gprel(alt_exception_old_stack_limit)(gp) #endif movhi et, %hiadj(__alt_exception_stack_pointer - 80) addi et, et, %lo(__alt_exception_stack_pointer - 80) stw sp, 76(et) mov sp, et #ifdef ALT_STACK_CHECK movhi et, %hiadj(__alt_exception_stack_limit) addi et, et, %lo(__alt_exception_stack_limit) stw et, %gprel(alt_stack_limit_value)(gp) #endif #else /* * Process an exception. For all exceptions we must preserve all * caller saved registers on the stack (See the Nios2 ABI * documentation for details). */ addi sp, sp, -76 #ifdef ALT_STACK_CHECK bltu sp, et, .Lstack_overflow #endif #endif stw ra, 0(sp) /* * Leave a gap in the stack frame at 4(sp) for the muldiv handler to * store zero into. */ stw r1, 8(sp) stw r2, 12(sp) stw r3, 16(sp) stw r4, 20(sp) stw r5, 24(sp) stw r6, 28(sp) stw r7, 32(sp) rdctl r5, estatus stw r8, 36(sp) stw r9, 40(sp) stw r10, 44(sp) stw r11, 48(sp) stw r12, 52(sp) stw r13, 56(sp) stw r14, 60(sp) stw r15, 64(sp) stw r5, 68(sp) addi r15, ea, -4 /* re-issue the interrupted instruction */ stw r15, 72(sp) /* * The interrupt testing code goes here. If an interrupt is active * then it stores ea-4 into 72(sp), handles the interrupt and jumps to * .exceptions.exit. If there is no interrupt then it continues */ .section .exceptions.notirq, "xa" stw ea, 72(sp) /* Return after the instruction which caused the exception */ ldw r2, -4(ea) /* * The other exception handling code goes here. */ .section .exceptions.unknown /* * If you get here then one of the following could have happened: * * - Your program could have been compiled for a full-featured Nios II * core, but it is running on a smaller core, and instruction emulation * has been disabled by defining ALT_NO_INSTRUCTION_EMULATION. * * You can work around the problem by re-enabling instruction emulation, * or you can figure out why your program is being compiled for a system * other than the one that it is running on. * * - Your program has executed a trap instruction, but has not implemented * a handler for this instruction. * * - Your program has executed an illegal instruction (one which is not * defined in the instruction set). * * - Your hardware is broken and is generating spurious interrupts (a * peripheral which deasserts its interrupt output before its interrupt * handler has been executed will cause spurious interrupts). * */ #ifdef NIOS2_HAS_DEBUG_STUB /* * Either tell the user now (if there is a debugger attached) or go into * the debug monitor which will loop until a debugger is attached. */ break #else /* * If there is no debug stub then a BREAK will probably cause a reboot. * An infinate loop will probably be more useful. */ 0: br 0b #endif .section .exceptions.exit, "xa" /* * Restore the saved registers, so that all general purpose registers * have been restored to their state at the time the interrupt occured. */ ldw r5, 68(sp) ldw ea, 72(sp) ldw ra, 0(sp) wrctl estatus, r5 ldw r1, 8(sp) ldw r2, 12(sp) ldw r3, 16(sp) ldw r4, 20(sp) ldw r5, 24(sp) ldw r6, 28(sp) ldw r7, 32(sp) #ifdef ALT_EXCEPTION_STACK #ifdef ALT_STACK_CHECK ldw et, %gprel(alt_exception_old_stack_limit)(gp) #endif #endif ldw r8, 36(sp) ldw r9, 40(sp) ldw r10, 44(sp) ldw r11, 48(sp) ldw r12, 52(sp) ldw r13, 56(sp) ldw r14, 60(sp) ldw r15, 64(sp) #ifdef ALT_EXCEPTION_STACK #ifdef ALT_STACK_CHECK stw et, %gprel(alt_stack_limit_value)(gp) stw zero, %gprel(alt_exception_old_stack_limit)(gp) #endif ldw sp, 76(sp) #else addi sp, sp, 76 #endif /* * Return to the interrupted instruction. */ eret #ifdef ALT_STACK_CHECK .Lstack_overflow: break 3 #endif
Maintained by John Loomis, updated Tue Nov 13 2008