;/*************************************************************************** ; * Copyright (c) 2024 Microsoft Corporation ; * ; * This program and the accompanying materials are made available under the ; * terms of the MIT License which is available at ; * https://opensource.org/licenses/MIT. ; * ; * SPDX-License-Identifier: MIT ; **************************************************************************/ ; ; ;/**************************************************************************/ ;/**************************************************************************/ ;/** */ ;/** ThreadX Component */ ;/** */ ;/** Thread */ ;/** */ ;/**************************************************************************/ ;/**************************************************************************/ #ifdef TX_INCLUDE_USER_DEFINE_FILE #include "tx_user.h" #endif .equ BTA, 0x412 ;/**************************************************************************/ ;/* */ ;/* FUNCTION RELEASE */ ;/* */ ;/* _tx_thread_context_fast_restore ARC_HS/MetaWare */ ;/* 6.2.1 */ ;/* AUTHOR */ ;/* */ ;/* William E. Lamie, Microsoft Corporation */ ;/* */ ;/* DESCRIPTION */ ;/* */ ;/* This function restores the fast interrupt context, which can be a */ ;/* nesting condition on a non-fast ISR, an idle system restore, a */ ;/* restore of an interrupted thread, and a preemption of an interrupted*/ ;/* thread. */ ;/* */ ;/* INPUT */ ;/* */ ;/* None */ ;/* */ ;/* OUTPUT */ ;/* */ ;/* None */ ;/* */ ;/* CALLS */ ;/* */ ;/* _tx_thread_schedule Thread scheduling routine */ ;/* */ ;/* CALLED BY */ ;/* */ ;/* ISRs Interrupt Service Routines */ ;/* */ ;/**************************************************************************/ ;VOID _tx_thread_context_fast_restore(VOID) ;{ .global _tx_thread_context_fast_restore .type _tx_thread_context_fast_restore, @function _tx_thread_context_fast_restore: ; ; /* Note: it is assumed that the stack pointer is in the same position now as ; it was after the last context fast save call. */ ; .ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY ; ; /* Call the ISR exit function to indicate an ISR is complete. */ ; bl.d _tx_execution_isr_exit ; Call the ISR exit function sub sp, sp, 16 ; ..allocating some space on the stack add sp, sp, 16 ; Recover the stack space .endif ; ; /* Determine if interrupts are nested. */ ; if (--_tx_thread_system_state) ; { ; ld r0, [gp, _tx_thread_system_state@sda] ; Pickup system state contents sub r0, r0, 1 ; Decrement the system state st r0, [gp, _tx_thread_system_state@sda] ; Store the new system state breq r0, 0, __tx_thread_not_nested_restore ; If zero, not a nested interrupt ; ; /* Interrupts are nested. */ ; ; /* Just recover the saved registers and return to the point of ; interrupt. */ ; __tx_thread_nested_restore: rtie ; Return from interrupt ; ; ; } __tx_thread_not_nested_restore: ; ; /* Determine if a thread was interrupted and no preemption is required. */ ; else if (((_tx_thread_current_ptr) && (_tx_thread_current_ptr == _tx_thread_execute_ptr)) ; || (_tx_thread_preempt_disable)) ; { ; ld r0, [gp, _tx_thread_current_ptr@sda] ; Pickup current thread pointer ld r2, [gp, _tx_thread_preempt_disable@sda] ; Pickup preempt disable flag sub.f 0, r0, 0 ; Set condition codes beq.d __tx_thread_idle_system_restore ; If NULL, idle system was interrupted lr r4, [AUX_IRQ_ACT] ; Pickup the interrupt active register neg r5, r4 ; Negate and r5, r4, r5 ; See if there are any other interrupts present brne.d r4, r5, __tx_thread_no_preempt_restore ; If more interrupts, just return to the point of interrupt ld r4, [gp, _tx_thread_execute_ptr@sda] ; Pickup next thread to execute brne r2, 0, __tx_thread_no_preempt_restore ; If set, don't preempt executing thread brne r0, r4, __tx_thread_preempt_restore ; Not equal, preempt executing thread ; ; __tx_thread_no_preempt_restore: ; ; /* Restore interrupted thread or ISR. */ ; ; /* Pickup the saved stack pointer. */ ; sp = _tx_thread_current_ptr -> tx_thread_stack_ptr; ; ; /* Return to the point of interrupt. */ ; rtie ; Return from interrupt ; ; } ; else ; { __tx_thread_preempt_restore: ; lr r3, [status32_p0] ; Pickup the interrupted status32.p0 register lsr r4, r3, 16 ; Move the register bank bits down and r4, r4, 7 ; Isolate the register bank breq r4, 0, __tx_software_interrupt_context ; If register bank 0, software interrupt context is present st ilink, [sp, 0] ; Save ilink (point of interrupt) st r3, [sp, 4] ; Save actual status32.p0 bclr r4, r3, 16 ; Build register bank 0 value bclr r4, r4, 17 ; bclr r4, r4, 18 ; sr r4, [status32_p0] ; Setup status32.p0 to return to bank 0 when fast ISR is finishe mov ilink, sp ; Pass the information back to the other register bank via ilink bclr r3, r3, 31 ; Make sure interrupts are not enabled kflag r3 ; Switch back to the interrupted thread's hardware register bank sub sp, sp, 168 ; Allocate an hardware interrupt stack frame st r0, [sp, 132] ; Temporarily save r0 mov r0, 3 ; Build hardware interrupt stack type st r0, [sp, 0] ; Setup interrupt stack type .ifndef TX_DISABLE_LP lr r0, [LP_START] ; Pickup LP_START st r0, [sp, 4] ; Save LP_START lr r0, [LP_END] ; Pickup LP_END st r0, [sp, 8] ; Save LP_END st LP_COUNT, [sp, 12] ; Save LP_COUNT .endif lr r0, [BTA] ; Pickup BTA st r0, [sp, 156] ; Save BTA ld r0, [ilink, 0] ; Pickup the point of interrupt st r0, [sp, 160] ; Setup the point of interrupt st r0, [sp, 20] ; Save ilink ld r0, [ilink, 4] ; Pickup the status32 st r0, [sp, 164] ; Setup the status32 ld r0, [gp, _tx_thread_current_ptr@sda] ; Pickup current thread pointer st sp, [r0, 8] ; Save stack pointer in thread control block ld r0, [sp, 132] ; Restore r0 lr ilink, [status32] ; Pickup status32 register bset ilink, ilink, 16 ; Build register bank 1 value bclr ilink, ilink, 17 ; bclr ilink, ilink, 18 ; kflag ilink ; Move back to register bank 0 b __tx_preempt_save_done ; Done, finished with preemption save __tx_software_interrupt_context: st ilink, [sp, 0] ; Save ilink (point of interrupt) st r3, [sp, 4] ; Save status32 mov ilink, sp ; Pass the information back to the other register bank via ilink bclr r3, r3, 31 ; Make sure interrupts are not enabled kflag r3 ; Switch back to the interrupted thread's hardware register bank sub sp, sp, 168 ; Allocate an hardware interrupt stack frame st blink, [sp, 16] ; Save blink st fp, [sp, 24] ; Save fp st gp, [sp, 28] ; Save gp st r25, [sp, 32] ; Save r25 st r24, [sp, 36] ; Save r24 st r23, [sp, 40] ; Save r23 st r22, [sp, 44] ; Save r22 st r21, [sp, 48] ; Save r21 st r20, [sp, 52] ; Save r20 st r19, [sp, 56] ; Save r19 st r18, [sp, 60] ; Save r18 st r17, [sp, 64] ; Save r17 st r16, [sp, 68] ; Save r16 st r15, [sp, 72] ; Save r15 st r14, [sp, 76] ; Save r14 st r13, [sp, 80] ; Save r13 st r12, [sp, 84] ; Save r12 st r11, [sp, 88] ; Save r11 st r10, [sp, 92] ; Save r10 st r9, [sp, 96] ; Save r9 st r8, [sp, 100] ; Save r8 st r7, [sp, 104] ; Save r7 st r6, [sp, 108] ; Save r6 st r5, [sp, 112] ; Save r5 st r4, [sp, 116] ; Save r6 st r3, [sp, 120] ; Save r3 st r2, [sp, 124] ; Save r2 st r1, [sp, 128] ; Save r1 st r0, [sp, 132] ; Save r0 st r30, [sp, 136] ; Save r30 .ifndef TX_DISABLE_LP lr r10, [LP_START] ; Pickup LP_START lr r9, [LP_END] ; Pickup LP_END st LP_COUNT, [sp, 12] ; Save LP_COUNT st r10, [sp, 4] ; Save LP_START st r9, [sp, 8] ; Save LP_END .endif lr r0, [BTA] ; Pickup BTA st r0, [sp, 156] ; Save BTA mov r6, 1 ; Build interrupt stack type st r6, [sp, 0] ; Setup interrupt stack type ld r0, [ilink, 0] ; Pickup the point of interrupt st r0, [sp, 160] ; Setup the point of interrupt st r0, [sp, 20] ; Save ilink ld r0, [ilink, 4] ; Pickup the status32 st r0, [sp, 164] ; Setup the status32 ld r0, [gp, _tx_thread_current_ptr@sda] ; Pickup current thread pointer st sp, [r0, 8] ; Save stack pointer in thread control block lr ilink, [status32] ; Pickup status32 register bset ilink, ilink, 16 ; Build register bank 1 value bclr ilink, ilink, 17 ; bclr ilink, ilink, 18 ; kflag ilink ; Move back to register bank 1 __tx_preempt_save_done: ; ld r0, [gp, _tx_thread_current_ptr@sda] ; Pickup current thread ptr ; ; /* Save the remaining time-slice and disable it. */ ; if (_tx_timer_time_slice) ; { ; ld r2, [gp, _tx_timer_time_slice@sda] ; Pickup time-slice contents mov r7, 0 ; Build clear/NULL value breq r2, 0, __tx_thread_dont_save_ts ; No time-slice, don't need to save it ; ; _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice; ; _tx_timer_time_slice = 0; ; st r2, [r0, 24] ; If set, save remaining time-slice st r7, [gp, _tx_timer_time_slice@sda] ; If set, clear time slice ; ; } __tx_thread_dont_save_ts: ; ; ; /* Clear the current thread pointer. */ ; _tx_thread_current_ptr = TX_NULL; ; st r7, [gp, _tx_thread_current_ptr@sda] ; Set current thread ptr to NULL mov ilink, _tx_thread_schedule ; Build address of scheduler rtie ; Return from interrupt to scheduler ; ; } ; ; /* Return to the scheduler. */ ; _tx_thread_schedule(); ; __tx_thread_idle_system_restore: lr r4, [AUX_IRQ_ACT] ; Pickup the interrupt active register neg r5, r4 ; Negate and r5, r4, r5 ; See if there are any other interrupts present sub.f 0, r4, r5 ; Set condition codes bne __tx_thread_nested_restore ; If more interrupts, just return to the point of interrupt mov ilink, _tx_thread_schedule ; Build address of scheduler rtie ; Return from interrupt to scheduler ; ;} .end