/* * Copyright (c) 2018, Synopsys, Inc. * * SPDX-License-Identifier: Apache-2.0 */ #define __ASSEMBLY__ #include "inc/arc/arc.h" #include "inc/arc/arc_asm_common.h" .global rt_interrupt_enter; .type rt_interrupt_enter, %function .global rt_interrupt_leave; .type rt_interrupt_leave, %function .global context_switch_reqflg; .type context_switch_reqflg, %object .global rt_interrupt_from_thread; .type rt_interrupt_from_thread, %object .global rt_interrupt_to_thread; .type rt_interrupt_to_thread, %object .text .align 4 dispatcher: st sp, [r0] ld sp, [r1] pop r0 j [r0] /* return routine when task dispatch happened in task context */ dispatch_r: RESTORE_NONSCRATCH_REGS j [blink] /* * rt_base_t rt_hw_interrupt_disable(); */ .global rt_hw_interrupt_disable .type rt_hw_interrupt_disable, %function rt_hw_interrupt_disable: clri r0 j [blink] /* * void rt_hw_interrupt_enable(rt_base_t level); */ .global rt_hw_interrupt_enable .type rt_hw_interrupt_enable, %function rt_hw_interrupt_enable: seti r0 j [blink] .global rt_hw_context_switch_interrupt .type rt_hw_context_switch_interrupt, %function rt_hw_context_switch_interrupt: st r0, [rt_interrupt_from_thread] st r1, [rt_interrupt_to_thread] mov r0, 1 st r0, [context_switch_reqflg] j [blink] /* * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); * r0 --> from * r1 --> to */ .global rt_hw_context_switch .type rt_hw_context_switch, %function rt_hw_context_switch: SAVE_NONSCRATCH_REGS mov r2, dispatch_r push r2 b dispatcher /* * void rt_hw_context_switch_to(rt_uint32 to); * r0 --> to */ .global rt_hw_context_switch_to .type rt_hw_context_switch_to, %function rt_hw_context_switch_to: ld sp, [r0] pop r0 j [r0] .global start_r .type start_r, %function start_r: pop blink; pop r1 pop r2 pop r0 j_s.d [r1] kflag r2 /****** exceptions and interrupts handing ******/ /****** entry for exception handling ******/ .global exc_entry_cpu .align 4 exc_entry_cpu: EXCEPTION_PROLOGUE mov blink, sp mov r3, sp /* as exception handler's para(p_excinfo) */ ld r0, [exc_nest_count] add r1, r0, 1 st r1, [exc_nest_count] cmp r0, 0 bne exc_handler_1 /* change to exception stack if interrupt happened in task context */ mov sp, _e_stack exc_handler_1: PUSH blink lr r0, [AUX_ECR] lsr r0, r0, 16 mov r1, exc_int_handler_table ld.as r2, [r1, r0] mov r0, r3 jl [r2] /* interrupts are not allowed */ ret_exc: POP sp mov r1, exc_nest_count ld r0, [r1] sub r0, r0, 1 cmp r0, 0 bne.d ret_exc_1 st r0, [r1] ld r0, [context_switch_reqflg] cmp r0, 0 bne ret_exc_2 ret_exc_1: /* return from non-task context, interrupts or exceptions are nested */ EXCEPTION_EPILOGUE rtie /* there is a dispatch request */ ret_exc_2: /* clear dispatch request */ mov r0, 0 st r0, [context_switch_reqflg] SAVE_CALLEE_REGS /* save callee save registers */ /* clear exception bit to do exception exit by SW */ lr r0, [AUX_STATUS32] bclr r0, r0, AUX_STATUS_BIT_AE kflag r0 mov r1, ret_exc_r /* save return address */ PUSH r1 ld r0, [rt_interrupt_from_thread] ld r1, [rt_interrupt_to_thread] b dispatcher ret_exc_r: /* recover exception status */ lr r0, [AUX_STATUS32] bset r0, r0, AUX_STATUS_BIT_AE kflag r0 RESTORE_CALLEE_REGS EXCEPTION_EPILOGUE rtie /****** entry for normal interrupt exception handling ******/ .global exc_entry_int /* entry for interrupt handling */ .align 4 exc_entry_int: #if ARC_FEATURE_FIRQ == 1 /* check whether it is P0 interrupt */ #if ARC_FEATURE_RGF_NUM_BANKS > 1 lr r0, [AUX_IRQ_ACT] btst r0, 0 jnz exc_entry_firq #else PUSH r10 lr r10, [AUX_IRQ_ACT] btst r10, 0 POP r10 jnz exc_entry_firq #endif #endif INTERRUPT_PROLOGUE mov blink, sp clri /* disable interrupt */ ld r3, [exc_nest_count] add r2, r3, 1 st r2, [exc_nest_count] seti /* enable higher priority interrupt */ cmp r3, 0 bne irq_handler_1 /* change to exception stack if interrupt happened in task context */ mov sp, _e_stack irq_handler_1: PUSH blink jl rt_interrupt_enter lr r0, [AUX_IRQ_CAUSE] sr r0, [AUX_IRQ_SELECT] mov r1, exc_int_handler_table ld.as r2, [r1, r0] /* r2 = exc_int_handler_table + irqno *4 */ /* 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: lr r3, [AUX_IRQ_PRIORITY] PUSH r3 /* save irq priority */ jl [r2] /* jump to interrupt handler */ jl rt_interrupt_leave ret_int: clri /* disable interrupt */ POP r3 /* irq priority */ POP sp mov r1, exc_nest_count ld r0, [r1] sub r0, r0, 1 cmp r0, 0 bne.d ret_int_1 st r0, [r1] ld r0, [context_switch_reqflg] cmp r0, 0 bne ret_int_2 ret_int_1: /* return from non-task context */ INTERRUPT_EPILOGUE rtie /* there is a dispatch request */ ret_int_2: /* clear dispatch request */ mov r0, 0 st r0, [context_switch_reqflg] /* interrupt return by SW */ lr r10, [AUX_IRQ_ACT] PUSH r10 bclr r10, r10, r3 /* clear related bits in IRQ_ACT */ sr r10, [AUX_IRQ_ACT] SAVE_CALLEE_REGS /* save callee save registers */ mov r1, ret_int_r /* save return address */ PUSH r1 ld r0, [rt_interrupt_from_thread] ld r1, [rt_interrupt_to_thread] b dispatcher ret_int_r: RESTORE_CALLEE_REGS /* recover AUX_IRQ_ACT to restore the interrup status */ POPAX AUX_IRQ_ACT INTERRUPT_EPILOGUE rtie