blob: 69c14f162d6c68053d00128edbe26011dfb9bbfe [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "inc/arc/arc.h"
#include "inc/arc/arc_asm_common.h"
.file "os_arc.s"
/*---------------------------------------------------------------
* Normal interrupt entry code.
*-------------------------------------------------------------*/
.global exc_entry_int
.align 4
exc_entry_int:
/* disable interrupts */
clri
#if ARC_FEATURE_FIRQ == 1
#if ARC_FEATURE_RGF_NUM_BANKS > 1
/* check whether it is P0 interrupt */
lr r0, [AUX_IRQ_ACT]
btst r0, 0
bnz exc_entry_firq
#else
PUSH r10
lr r10, [AUX_IRQ_ACT]
btst r10, 0
POP r10
bnz exc_entry_firq
#endif
#endif
/* Pushes r12, gp, fp, ilink, r30 and reserves one location */
INTERRUPT_PROLOGUE
/* Temporarily save current stack pointer */
mov blink, sp
/*
* Increment nested exception count. If within a nested exception the
* stack pointer is already set. If first exception, we use the exception
* stack going forward. The exception stack is a firmware created
* construct.
*/
ld r3, [exc_nest_count]
add r2, r3, 1
st r2, [exc_nest_count]
cmp r3, 0
bne irq_handler_1
mov sp, _e_stack
irq_handler_1:
/* Save old stack pointer */
PUSH blink
/* Get address of interrupt in r2 */
lr r0, [AUX_IRQ_CAUSE]
sr r0, [AUX_IRQ_SELECT]
mov r1, exc_int_handler_table
ld.as r2, [r1, r0]
/* handle software triggered interrupt */
lr r3, [AUX_IRQ_HINT]
cmp r3, r0
bne.d irq_hint_handled
xor r3, r3, r3
sr r3, [AUX_IRQ_HINT]
irq_hint_handled:
/*
* Enable interrupts to allow higher priority interrupts to preempt.
* Handle current interrupt
*/
seti
jl [r2]
/* Disable interrupts */
clri
/* Restore saved stack pointer */
POP blink
mov sp, blink
/*
* Decrement nested exception count. If nested, simply return.
* If not, check for context switch
*/
mov r1, exc_nest_count
ld r0, [r1]
sub r0, r0, 1
cmp r0, 0
bne.d ret_int
st r0, [r1]
/* Check if we should be running a different task */
mov r3, g_os_run_list
ld r2, [r3]
mov r3, g_current_task
ld r1, [r3]
cmp r1, r2
beq ret_int
/* Save remaining registers on current task stack */
SAVE_CALLEE_REGS
/*
* Current task is in r1 and task to run in r2. We need to:
* -> Save current stack pointer in cureren task.
* -> Set current task to new task to be run.
* -> Get stack pointer of new task.
*/
st sp, [r1]
st r2, [r3]
ld sp, [r2]
/* Restore registers of task that are not done by hw */
RESTORE_CALLEE_REGS
/* Return from the interrupt */
ret_int:
INTERRUPT_EPILOGUE
rtie
/*---------------------------------------------------------------
* Normal interrupt entry code.
*-------------------------------------------------------------*/
.global exc_entry_firq
.align 4
exc_entry_firq:
/* disable interrupt */
clri
SAVE_FIQ_EXC_REGS
/* Increment nested exceptopn count */
ld r0, [exc_nest_count]
add r0, r0, 1
st r0, [exc_nest_count]
/* r2 = _kernel_exc_tbl + irqno *4 */
lr r0, [AUX_IRQ_CAUSE]
mov r1, exc_int_handler_table
ld.as r2, [r1, r0]
/* for the case of software triggered interrupt */
lr r3, [AUX_IRQ_HINT]
cmp r3, r0
bne.d firq_hint_handled
xor r3, r3, r3
sr r3, [AUX_IRQ_HINT]
firq_hint_handled:
/* jump to interrupt handler */
jl [r2]
/* no interrupts are allowed from here */
firq_return:
/* exc_nest_count -1 */
ld r0, [exc_nest_count]
sub r0, r0, 1
st r0, [exc_nest_count]
RESTORE_FIQ_EXC_REGS
rtie
/*---------------------------------------------------------------
* Exception entry code.
*-------------------------------------------------------------*/
.global exc_entry_cpu
.align 4
exc_entry_cpu:
EXCEPTION_PROLOGUE
mov blink, sp
/*
* Increment nested exception count. If within a nested exception the
* stack pointer is already set. If first exception, we use the exception
* stack going forward. The exception stack is a firmware created
* construct.
*/
ld r0, [exc_nest_count]
add r1, r0, 1
st r1, [exc_nest_count]
cmp r0, 0
bne exc_handler_1
mov sp, _e_stack
exc_handler_1:
/* Save old stack pointer */
PUSH blink
/* Call exception handler */
lr r0, [AUX_ECR]
lsr r0, r0, 16
mov r1, exc_int_handler_table
ld.as r2, [r1, r0]
jl [r2]
ret_exc:
POP blink
mov sp, blink
mov r1, exc_nest_count
ld r0, [r1]
sub r0, r0, 1
cmp r0, 0
bne.d ret_exc_r_1
st r0, [r1]
/* Check if we should be running a different task */
mov r3, g_os_run_list
ld r2, [r3]
mov r3, g_current_task
ld r1, [r3]
cmp r1, r2
beq ret_exc_r_1
/* Save remaining registers on current task stack */
SAVE_CALLEE_REGS
/*
* Current task is in r1 and task to run in r2. We need to:
* -> Save current stack pointer in current task.
* -> Set current task to new task to be run.
* -> Get stack pointer of new task.
*/
st sp, [r1]
st r2, [r3]
ld sp, [r2]
/* Restore registers of task that are not done by hw */
RESTORE_CALLEE_REGS
ret_exc_r_1:
EXCEPTION_EPILOGUE
rtie