231 lines
6.9 KiB
ArmAsm
231 lines
6.9 KiB
ArmAsm
/* exceptions-asm.S -- exception handling for OpenRISC 1000.
|
|
*
|
|
* Copyright (c) 2011, 2014 Authors
|
|
*
|
|
* Contributor Julius Baxter <juliusbaxter@gmail.com>
|
|
* Contributor Stefan Wallentowitz <stefan.wallentowitz@tum.de>
|
|
*
|
|
* The authors hereby grant permission to use, copy, modify, distribute,
|
|
* and license this software and its documentation for any purpose, provided
|
|
* that existing copyright notices are retained in all copies and that this
|
|
* notice is included verbatim in any distributions. No written agreement,
|
|
* license, or royalty fee is required for any of the authorized uses.
|
|
* Modifications to this software may be copyrighted by their authors
|
|
* and need not follow the licensing terms described here, provided that
|
|
* the new terms are clearly indicated on the first page of each file where
|
|
* they apply.
|
|
*/
|
|
|
|
#include "include/or1k-asm.h"
|
|
#include "include/or1k-sprs.h"
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/*!Generic exception handler function
|
|
*/
|
|
/* -------------------------------------------------------------------------- */
|
|
// Warning - this must be the same as specified in crt0.S
|
|
#define EXCEPTION_STACK_SIZE 136
|
|
|
|
.extern _or1k_exception_handler_table
|
|
.extern _or1k_exception_level
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/*!Function to call appropriate exception handler
|
|
*/
|
|
/* -------------------------------------------------------------------------- */
|
|
.section .text
|
|
.global _or1k_exception_handler
|
|
.type _or1k_exception_handler,@function
|
|
|
|
/*
|
|
r3 = address of exception vector
|
|
r4 = address where exception occurred
|
|
*/
|
|
|
|
#define GPR_BUF_OFFSET(x) (x << 2)
|
|
|
|
_or1k_exception_handler:
|
|
/* Store remainder of state (r3,r4 stored in vector entry)*/
|
|
l.sw GPR_BUF_OFFSET(2)(r1),r2
|
|
l.sw GPR_BUF_OFFSET(5)(r1),r5
|
|
l.sw GPR_BUF_OFFSET(6)(r1),r6
|
|
l.sw GPR_BUF_OFFSET(7)(r1),r7
|
|
l.sw GPR_BUF_OFFSET(8)(r1),r8
|
|
l.sw GPR_BUF_OFFSET(9)(r1),r9
|
|
l.sw GPR_BUF_OFFSET(10)(r1),r10
|
|
l.sw GPR_BUF_OFFSET(11)(r1),r11
|
|
l.sw GPR_BUF_OFFSET(12)(r1),r12
|
|
l.sw GPR_BUF_OFFSET(13)(r1),r13
|
|
l.sw GPR_BUF_OFFSET(14)(r1),r14
|
|
l.sw GPR_BUF_OFFSET(15)(r1),r15
|
|
l.sw GPR_BUF_OFFSET(16)(r1),r16
|
|
l.sw GPR_BUF_OFFSET(17)(r1),r17
|
|
l.sw GPR_BUF_OFFSET(18)(r1),r18
|
|
l.sw GPR_BUF_OFFSET(19)(r1),r19
|
|
l.sw GPR_BUF_OFFSET(20)(r1),r20
|
|
l.sw GPR_BUF_OFFSET(21)(r1),r21
|
|
l.sw GPR_BUF_OFFSET(22)(r1),r22
|
|
l.sw GPR_BUF_OFFSET(23)(r1),r23
|
|
l.sw GPR_BUF_OFFSET(24)(r1),r24
|
|
l.sw GPR_BUF_OFFSET(25)(r1),r25
|
|
l.sw GPR_BUF_OFFSET(26)(r1),r26
|
|
l.sw GPR_BUF_OFFSET(27)(r1),r27
|
|
l.sw GPR_BUF_OFFSET(28)(r1),r28
|
|
l.sw GPR_BUF_OFFSET(29)(r1),r29
|
|
l.sw GPR_BUF_OFFSET(30)(r1),r30
|
|
l.sw GPR_BUF_OFFSET(31)(r1),r31
|
|
l.mfspr r14,r0,OR1K_SPR_SYS_EPCR_BASE
|
|
l.sw 0x80(r1),r14
|
|
l.mfspr r14,r0,OR1K_SPR_SYS_ESR_BASE
|
|
l.sw 0x84(r1),r14
|
|
|
|
/* Replace impure pointer for exception */
|
|
l.movhi r20,hi(_or1k_exception_impure_ptr)
|
|
l.ori r20,r20,lo(_or1k_exception_impure_ptr)
|
|
#ifdef __OR1K_MULTICORE__
|
|
l.lwz r20,0(r20)
|
|
l.mfspr r22,r0,OR1K_SPR_SYS_COREID_ADDR
|
|
l.slli r22,r22,2
|
|
l.add r20,r20,r22
|
|
#endif
|
|
l.lwz r20,0(r20)
|
|
|
|
l.movhi r21,hi(_or1k_current_impure_ptr)
|
|
l.ori r21,r21,lo(_or1k_current_impure_ptr)
|
|
#ifdef __OR1K_MULTICORE__
|
|
l.lwz r21,0(r21)
|
|
l.add r21,r21,r22
|
|
#endif
|
|
l.sw 0(r21),r20
|
|
|
|
/* Determine offset in table of exception handler using r3*/
|
|
l.andi r13,r3,0xff00
|
|
l.srli r13,r13,6
|
|
/* Substract 2 words, as we have no vector at 0 and no reset handler */
|
|
l.addi r13,r13,-8
|
|
/* r13 now contains offset in or1k_exception_handler_table for
|
|
function
|
|
*/
|
|
/* Get or1k_exception_handler_table address */
|
|
l.movhi r14,hi(_or1k_exception_handler_table)
|
|
l.ori r14,r14,lo(_or1k_exception_handler_table)
|
|
#ifdef __OR1K_MULTICORE__
|
|
/* Read the address of the array of cores */
|
|
/* r14 = (*or1k_exception_handler_table) */
|
|
l.lwz r14,0(r14)
|
|
/* Generate core offset in array (off = coreid*30*4 = coreid*120) */
|
|
/* r15 = coreid */
|
|
l.mfspr r15,r0,OR1K_SPR_SYS_COREID_ADDR
|
|
/* r16 = coreid * 128 */
|
|
l.slli r16,r15,7
|
|
/* r15 = coreid * 8 */
|
|
l.slli r15,r15,3
|
|
/* r15 = coreid*128 - coreid*8 = coreid*120 = off */
|
|
l.sub r15,r16,r15
|
|
/* r14 = (*or1k_exception_handler_table)[coreid] = r14 + off */
|
|
l.add r14,r14,r15
|
|
#endif
|
|
/* r14 now contains base of exception handler table */
|
|
/* add offset of exception vector */
|
|
l.add r14,r14,r13
|
|
/* load handler address from table */
|
|
l.lwz r13, 0(r14)
|
|
|
|
/* Check to see if this handler has been set yet */
|
|
l.sfne r13,r0
|
|
OR1K_DELAYED_NOP(OR1K_INST(l.bnf exception_exit))
|
|
|
|
/* Call exception handler, copy EPCR to r3 */
|
|
OR1K_DELAYED(
|
|
OR1K_INST(l.or r3,r4,r4),
|
|
OR1K_INST(l.jalr r13)
|
|
)
|
|
|
|
/* Restore impure pointer */
|
|
l.movhi r20,hi(_or1k_impure_ptr)
|
|
l.ori r20,r20,lo(_or1k_impure_ptr)
|
|
#ifdef __OR1K_MULTICORE__
|
|
l.lwz r20,0(r20)
|
|
l.mfspr r22,r0,OR1K_SPR_SYS_COREID_ADDR
|
|
l.slli r22,r22,2
|
|
l.add r20,r20,r22
|
|
#endif
|
|
l.lwz r20,0(r20)
|
|
|
|
l.movhi r21,hi(_or1k_current_impure_ptr)
|
|
l.ori r21,r21,lo(_or1k_current_impure_ptr)
|
|
#ifdef __OR1K_MULTICORE__
|
|
l.lwz r21,0(r21)
|
|
l.add r21,r21,r22
|
|
#endif
|
|
l.sw 0(r21),r20
|
|
|
|
/* Decrement the exception nesting level */
|
|
// Load the exception level entry
|
|
l.movhi r2,hi(_or1k_exception_level)
|
|
l.ori r2,r2,lo(_or1k_exception_level)
|
|
#ifdef __OR1K_MULTICORE__
|
|
// In multicore this is the pointer to an array
|
|
// Load pointer value
|
|
l.lwz r2,0(r2)
|
|
// Add word offset of this core's nesting level
|
|
l.add r2,r2,r22
|
|
#endif
|
|
// Load the nesting level entry
|
|
l.lwz r3,0(r2)
|
|
// Decrement nesting level
|
|
l.addi r3,r3,-1
|
|
// Store back the nesting level
|
|
l.sw 0(r2),r3
|
|
|
|
/* Restore state */
|
|
l.lwz r2,0x80(r1)
|
|
l.mtspr r0,r2,OR1K_SPR_SYS_EPCR_BASE
|
|
|
|
l.lwz r2,0x84(r1)
|
|
l.mtspr r0,r2,OR1K_SPR_SYS_ESR_BASE
|
|
|
|
l.lwz r2,GPR_BUF_OFFSET(2)(r1)
|
|
l.lwz r3,GPR_BUF_OFFSET(3)(r1)
|
|
l.lwz r4,GPR_BUF_OFFSET(4)(r1)
|
|
l.lwz r5,GPR_BUF_OFFSET(5)(r1)
|
|
l.lwz r6,GPR_BUF_OFFSET(6)(r1)
|
|
l.lwz r7,GPR_BUF_OFFSET(7)(r1)
|
|
l.lwz r8,GPR_BUF_OFFSET(8)(r1)
|
|
l.lwz r9,GPR_BUF_OFFSET(9)(r1)
|
|
l.lwz r10,GPR_BUF_OFFSET(10)(r1)
|
|
l.lwz r11,GPR_BUF_OFFSET(11)(r1)
|
|
l.lwz r12,GPR_BUF_OFFSET(12)(r1)
|
|
l.lwz r13,GPR_BUF_OFFSET(13)(r1)
|
|
l.lwz r14,GPR_BUF_OFFSET(14)(r1)
|
|
l.lwz r15,GPR_BUF_OFFSET(15)(r1)
|
|
l.lwz r16,GPR_BUF_OFFSET(16)(r1)
|
|
l.lwz r17,GPR_BUF_OFFSET(17)(r1)
|
|
l.lwz r18,GPR_BUF_OFFSET(18)(r1)
|
|
l.lwz r19,GPR_BUF_OFFSET(19)(r1)
|
|
l.lwz r20,GPR_BUF_OFFSET(20)(r1)
|
|
l.lwz r21,GPR_BUF_OFFSET(21)(r1)
|
|
l.lwz r22,GPR_BUF_OFFSET(22)(r1)
|
|
l.lwz r23,GPR_BUF_OFFSET(23)(r1)
|
|
l.lwz r24,GPR_BUF_OFFSET(24)(r1)
|
|
l.lwz r25,GPR_BUF_OFFSET(25)(r1)
|
|
l.lwz r26,GPR_BUF_OFFSET(26)(r1)
|
|
l.lwz r27,GPR_BUF_OFFSET(27)(r1)
|
|
l.lwz r28,GPR_BUF_OFFSET(28)(r1)
|
|
l.lwz r29,GPR_BUF_OFFSET(29)(r1)
|
|
l.lwz r30,GPR_BUF_OFFSET(30)(r1)
|
|
l.lwz r31,GPR_BUF_OFFSET(31)(r1)
|
|
|
|
// Restore original stack
|
|
l.lwz r1,GPR_BUF_OFFSET(1)(r1)
|
|
|
|
l.rfe
|
|
l.nop
|
|
|
|
exception_exit:
|
|
/* Exception handler not set, exit */
|
|
OR1K_DELAYED(
|
|
OR1K_INST(l.or r3,r4,r4),
|
|
OR1K_INST(l.jal exit)
|
|
)
|