/*
* 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.org/license/LICENSE.
*/
#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