diff options
Diffstat (limited to '')
-rw-r--r-- | cpukit/score/cpu/nios2/nios2-eic-rsie-low-level.S | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/cpukit/score/cpu/nios2/nios2-eic-rsie-low-level.S b/cpukit/score/cpu/nios2/nios2-eic-rsie-low-level.S new file mode 100644 index 0000000000..efb71ebd0c --- /dev/null +++ b/cpukit/score/cpu/nios2/nios2-eic-rsie-low-level.S @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2011 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#include <rtems/score/percpu.h> + +#define FRAME_OFFSET_AT 0 +#define FRAME_OFFSET_R2 4 +#define FRAME_OFFSET_R3 8 +#define FRAME_OFFSET_R4 12 +#define FRAME_OFFSET_R5 16 +#define FRAME_OFFSET_R6 20 +#define FRAME_OFFSET_R7 24 +#define FRAME_OFFSET_R8 28 +#define FRAME_OFFSET_R9 32 +#define FRAME_OFFSET_R10 36 +#define FRAME_OFFSET_R11 40 +#define FRAME_OFFSET_R12 44 +#define FRAME_OFFSET_R13 48 +#define FRAME_OFFSET_R14 52 +#define FRAME_OFFSET_R15 56 +#define FRAME_OFFSET_RA 60 +#define FRAME_OFFSET_EA 64 +#define FRAME_OFFSET_ESTATUS 68 +#define FRAME_OFFSET_R16 72 + +#define FRAME_SIZE (FRAME_OFFSET_R16 + 4) + + .set noat + .section .text + + .extern _Per_CPU_Information + .extern _Thread_Dispatch_disable_level + + .globl _Nios2_ISR_Dispatch_with_shadow_preemptive + +_Nios2_ISR_Dispatch_with_shadow_preemptive: + + /* Obtain stack frame */ + subi sp, sp, FRAME_SIZE + + /* Save volatile registers */ + stw at, FRAME_OFFSET_AT(sp) + stw r2, FRAME_OFFSET_R2(sp) + stw r3, FRAME_OFFSET_R3(sp) + stw r4, FRAME_OFFSET_R4(sp) + stw r5, FRAME_OFFSET_R5(sp) + stw r6, FRAME_OFFSET_R6(sp) + stw r7, FRAME_OFFSET_R7(sp) + stw r8, FRAME_OFFSET_R8(sp) + stw r9, FRAME_OFFSET_R9(sp) + stw r10, FRAME_OFFSET_R10(sp) + stw r11, FRAME_OFFSET_R11(sp) + stw r12, FRAME_OFFSET_R12(sp) + stw r13, FRAME_OFFSET_R13(sp) + stw r14, FRAME_OFFSET_R14(sp) + stw r15, FRAME_OFFSET_R15(sp) + + /* Save context */ + rdctl r2, estatus + subi ea, ea, 4 + stw ra, FRAME_OFFSET_RA(sp) + stw ea, FRAME_OFFSET_EA(sp) + stw r2, FRAME_OFFSET_ESTATUS(sp) + + /* Save one non-volatile register for further usage */ + stw r16, FRAME_OFFSET_R16(sp) + + /* Save stack pointer */ + mov r16, sp + + /* Increment ISR nest level and thread dispatch disable level */ + ldw r9, %gprel(_Per_CPU_Information + PER_CPU_ISR_NEST_LEVEL)(gp) + ldw r10, %gprel(_Thread_Dispatch_disable_level)(gp) + addi r11, r9, 1 + addi r10, r10, 1 + stw r11, %gprel(_Per_CPU_Information + PER_CPU_ISR_NEST_LEVEL)(gp) + stw r10, %gprel(_Thread_Dispatch_disable_level)(gp) + + /* Switch to interrupt stack if necessary */ + bne r9, zero, switch_to_interrupt_stack_done + ldw sp, %gprel(_Per_CPU_Information + PER_CPU_INTERRUPT_STACK_HIGH)(gp) + +switch_to_interrupt_stack_done: + + /* Load high level handler address and argument */ + ldw r12, 4(et) + ldw r4, 8(et) + + /* Enable interrupts */ + rdctl r13, status + orhi r13, r13, 0x0080 + wrctl status, r13 + + /* Call high level handler with argument */ + callr r12 + + /* Disable interrupts */ + rdctl r12, status + movhi r13, 0xff80 + subi r13, r13, 1 + and r12, r12, r13 + wrctl status, r12 + + /* Decrement ISR nest level and thread dispatch disable level */ + ldw r9, %gprel(_Per_CPU_Information + PER_CPU_ISR_NEST_LEVEL)(gp) + ldw r10, %gprel(_Thread_Dispatch_disable_level)(gp) + subi r9, r9, 1 + subi r10, r10, 1 + stw r9, %gprel(_Per_CPU_Information + PER_CPU_ISR_NEST_LEVEL)(gp) + stw r10, %gprel(_Thread_Dispatch_disable_level)(gp) + + /* + * Restore stack pointer. If the ISR nest level is greater than one, + * then this is a nop, else we switch back to the thread stack. + */ + mov sp, r16 + + /* Thread dispatch */ + bne r10, zero, thread_dispatch_done + call _Thread_Dispatch + +thread_dispatch_done: + + /* Restore volatile registers */ + ldw at, FRAME_OFFSET_AT(sp) + ldw r2, FRAME_OFFSET_R2(sp) + ldw r3, FRAME_OFFSET_R3(sp) + ldw r4, FRAME_OFFSET_R4(sp) + ldw r5, FRAME_OFFSET_R5(sp) + ldw r6, FRAME_OFFSET_R6(sp) + ldw r7, FRAME_OFFSET_R7(sp) + ldw r8, FRAME_OFFSET_R8(sp) + ldw r9, FRAME_OFFSET_R9(sp) + ldw r10, FRAME_OFFSET_R10(sp) + ldw r11, FRAME_OFFSET_R11(sp) + ldw r12, FRAME_OFFSET_R12(sp) + ldw r13, FRAME_OFFSET_R13(sp) + ldw r14, FRAME_OFFSET_R14(sp) + ldw r15, FRAME_OFFSET_R15(sp) + + /* Restore context */ + ldw ra, FRAME_OFFSET_RA(sp) + ldw ea, FRAME_OFFSET_EA(sp) + ldw et, FRAME_OFFSET_ESTATUS(sp) + + /* Restore the non-volatile register */ + ldw r16, FRAME_OFFSET_R16(sp) + + /* Release stack frame */ + addi sp, sp, FRAME_SIZE + + /* Restore context */ + wrctl estatus, et + + /* Return */ + eret |