1;/*************************************************************************** 2; * Copyright (c) 2024 Microsoft Corporation 3; * 4; * This program and the accompanying materials are made available under the 5; * terms of the MIT License which is available at 6; * https://opensource.org/licenses/MIT. 7; * 8; * SPDX-License-Identifier: MIT 9; **************************************************************************/ 10 11;/**************************************************************************/ 12;/**************************************************************************/ 13;/** */ 14;/** ThreadX Component */ 15;/** */ 16;/** Thread */ 17;/** */ 18;/**************************************************************************/ 19;/**************************************************************************/ 20#ifdef TX_INCLUDE_USER_DEFINE_FILE 21#include "tx_user.h" 22#endif 23 24 .equ BTA, 0x412 25 .equ KSTACK_TOP, 0x264 26 .equ KSTACK_BASE, 0x265 27 .equ STATUS32_SC, 0x4000 28 29;/**************************************************************************/ 30;/* */ 31;/* FUNCTION RELEASE */ 32;/* */ 33;/* _tx_thread_context_restore ARCv2_EM/MetaWare */ 34;/* 6.2.1 */ 35;/* AUTHOR */ 36;/* */ 37;/* William E. Lamie, Microsoft Corporation */ 38;/* */ 39;/* DESCRIPTION */ 40;/* */ 41;/* This function restores the interrupt context if it is processing a */ 42;/* nested interrupt. If not, it returns to the interrupt thread if no */ 43;/* preemption is necessary. Otherwise, if preemption is necessary or */ 44;/* if no thread was running, the function returns to the scheduler. */ 45;/* */ 46;/* INPUT */ 47;/* */ 48;/* None */ 49;/* */ 50;/* OUTPUT */ 51;/* */ 52;/* None */ 53;/* */ 54;/* CALLS */ 55;/* */ 56;/* _tx_thread_schedule Thread scheduling routine */ 57;/* */ 58;/* CALLED BY */ 59;/* */ 60;/* ISRs Interrupt Service Routines */ 61;/* */ 62;/* RELEASE HISTORY */ 63;/* */ 64;/* DATE NAME DESCRIPTION */ 65;/* */ 66;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ 67;/* 04-02-2021 Andres Mlinar Modified comment(s), and */ 68;/* r25/r30 are caller saved, */ 69;/* resulting in version 6.1.6 */ 70;/* 10-15-2021 Andres Mlinar Modified comment(s), added */ 71;/* support for disabling the */ 72;/* loop control feature, */ 73;/* resulting in version 6.1.9 */ 74;/* 03-08-2023 Cindy Deng Modified comment(s), added */ 75;/* #include tx_user.h, */ 76;/* resulting in version 6.2.1 */ 77;/* */ 78;/**************************************************************************/ 79;VOID _tx_thread_context_restore(VOID) 80;{ 81 .global _tx_thread_context_restore 82 .type _tx_thread_context_restore, @function 83_tx_thread_context_restore: 84; 85; /* Note: it is assumed that the stack pointer is in the same position now as 86; it was after the last context save call. */ 87; 88; /* Lockout interrupts. */ 89; 90 clri ; Disable interrupts 91 nop ; Delay for interrupts to really be disabled 92 93 .ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY 94; 95; /* Call the ISR exit function to indicate an ISR is complete. */ 96; 97 bl.d _tx_execution_isr_exit ; Call the ISR exit function 98 sub sp, sp, 16 ; ..allocating some space on the stack 99 add sp, sp, 16 ; Recover the stack space 100 .endif 101; 102; /* Determine if interrupts are nested. */ 103; if (--_tx_thread_system_state) 104; { 105; 106 ld r0, [gp, _tx_thread_system_state@sda] ; Pickup system state contents 107 sub r0, r0, 1 ; Decrement the system state 108 st r0, [gp, _tx_thread_system_state@sda] ; Store the new system state 109 breq r0, 0, __tx_thread_not_nested_restore ; If zero, not a nested interrupt 110; 111; /* Interrupts are nested. */ 112; 113; /* Just recover the saved registers and return to the point of 114; interrupt. */ 115; 116 117__tx_thread_nested_restore: 118 119 .ifndef TX_DISABLE_LP 120 ld r0, [sp, 4] ; Recover LP_START 121 sr r0, [LP_START] ; Restore LP_START 122 ld r1, [sp, 8] ; Recover LP_END 123 sr r1, [LP_END] ; Restore LP_END 124 ld r2, [sp, 12] ; Recover LP_COUNT 125 mov LP_COUNT, r2 126 .endif 127 128 ld r2, [sp, 156] ; Pickup BTA 129 sr r2, [BTA] ; Recover BTA 130 .ifdef TX_ENABLE_ACC 131 ld r58, [sp, 140] ; Recover r58 132 ld r59, [sp, 144] ; Recover r59 133 .endif 134 ld blink, [sp, 16] ; Recover blink 135 ld r25, [sp, 32] ; Recover r25 136 ld r12, [sp, 84] ; Recover r12 137 ld r11, [sp, 88] ; Recover r11 138 ld r10, [sp, 92] ; Recover r10 139 ld r9, [sp, 96] ; Recover r9 140 ld r8, [sp, 100] ; Recover r8 141 ld r7, [sp, 104] ; Recover r7 142 ld r6, [sp, 108] ; Recover r6 143 ld r5, [sp, 112] ; Recover r5 144 ld r4, [sp, 116] ; Recover r4 145 ld r3, [sp, 120] ; Recover r3 146 ld r2, [sp, 124] ; Recover r2 147 ld r1, [sp, 128] ; Recover r1 148 ld r0, [sp, 132] ; Recover r0 149 ld r30, [sp, 136] ; Recover r30 150 add sp, sp, 160 ; Recover interrupt stack frame 151 rtie ; Return from interrupt 152; 153; 154; } 155__tx_thread_not_nested_restore: 156; 157; /* Determine if a thread was interrupted and no preemption is required. */ 158; else if (((_tx_thread_current_ptr) && (_tx_thread_current_ptr == _tx_thread_execute_ptr) 159; || (_tx_thread_preempt_disable)) 160; { 161; 162 ld r0, [gp, _tx_thread_current_ptr@sda] ; Pickup current thread pointer 163 ld r2, [gp, _tx_thread_preempt_disable@sda] ; Pickup preempt disable flag 164 sub.f 0, r0, 0 ; Set condition codes 165 beq.d __tx_thread_idle_system_restore ; If NULL, idle system was interrupted 166 lr r4, [AUX_IRQ_ACT] ; Pickup the interrupt active register 167 neg r5, r4 ; Negate 168 and r5, r4, r5 ; See if there are any other interrupts present 169 brne.d r4, r5, __tx_thread_no_preempt_restore ; If more interrupts, just return to the point of interrupt 170 ld r4, [gp, _tx_thread_execute_ptr@sda] ; Pickup next thread to execute 171 brne r2, 0, __tx_thread_no_preempt_restore ; If set, don't preempt executing thread 172 brne r0, r4, __tx_thread_preempt_restore ; Not equal, preempt executing thread 173; 174; 175__tx_thread_no_preempt_restore: 176; 177; /* Restore interrupted thread or ISR. */ 178; 179; /* Pickup the saved stack pointer. */ 180; sp = _tx_thread_current_ptr -> tx_thread_stack_ptr; 181; 182 183; /* Recover the saved context and return to the point of interrupt. */ 184; 185 186 .ifdef TX_ENABLE_HW_STACK_CHECKING 187 lr r2, [status32] ; Pickup current STATUS32 188 and r2, r2, ~STATUS32_SC ; Clear the hardware stack checking enable bit (SC) 189 kflag r2 ; Disable hardware stack checking 190 ld r3, [r0, 12] ; Pickup the top of the thread's stack (lowest address) 191 sr r3, [KSTACK_TOP] ; Setup KSTACK_TOP 192 ld r3, [r0, 16] ; Pickup the base of the thread's stack (highest address) 193 sr r3, [KSTACK_BASE] ; Setup KSTACK_BASE 194 .endif 195 196 ld sp, [r0, 8] ; Switch back to thread's stack 197 198 .ifdef TX_ENABLE_HW_STACK_CHECKING 199 or r2, r2, STATUS32_SC ; Or in hardware stack checking enable bit (SC) 200 kflag r2 ; Enable hardware stack checking 201 .endif 202 203 .ifndef TX_DISABLE_LP 204 ld r0, [sp, 4] ; Recover LP_START 205 sr r0, [LP_START] ; Restore LP_START 206 ld r1, [sp, 8] ; Recover LP_END 207 sr r1, [LP_END] ; Restore LP_END 208 ld r2, [sp, 12] ; Recover LP_COUNT 209 mov LP_COUNT, r2 210 .endif 211 212 ld r2, [sp, 156] ; Pickup BTA 213 sr r2, [BTA] ; Recover BTA 214 .ifdef TX_ENABLE_ACC 215 ld r58, [sp, 140] ; Recover r58 216 ld r59, [sp, 144] ; Recover r59 217 .endif 218 ld blink, [sp, 16] ; Recover blink 219 ld r25, [sp, 32] ; Recover r25 220 ld r12, [sp, 84] ; Recover r12 221 ld r11, [sp, 88] ; Recover r11 222 ld r10, [sp, 92] ; Recover r10 223 ld r9, [sp, 96] ; Recover r9 224 ld r8, [sp, 100] ; Recover r8 225 ld r7, [sp, 104] ; Recover r7 226 ld r6, [sp, 108] ; Recover r6 227 ld r5, [sp, 112] ; Recover r5 228 ld r4, [sp, 116] ; Recover r4 229 ld r3, [sp, 120] ; Recover r3 230 ld r2, [sp, 124] ; Recover r2 231 ld r1, [sp, 128] ; Recover r1 232 ld r0, [sp, 132] ; Recover r0 233 ld r30, [sp, 136] ; Recover r30 234 add sp, sp, 160 ; Recover interrupt stack frame 235 rtie ; Return from interrupt 236; 237; } 238; else 239; { 240__tx_thread_preempt_restore: 241; 242 ld r7, [r0, 8] ; Pickup stack pointer 243 mov r6, 1 ; Build interrupt stack type 244 st r6, [r7, 0] ; Setup interrupt stack type 245 st fp, [r7, 24] ; Save fp 246 st gp, [r7, 28] ; Save gp 247 st r24, [r7, 36] ; Save r24 248 st r23, [r7, 40] ; Save r23 249 st r22, [r7, 44] ; Save r22 250 st r21, [r7, 48] ; Save r21 251 st r20, [r7, 52] ; Save r20 252 st r19, [r7, 56] ; Save r19 253 st r18, [r7, 60] ; Save r18 254 st r17, [r7, 64] ; Save r17 255 st r16, [r7, 68] ; Save r16 256 st r15, [r7, 72] ; Save r15 257 st r14, [r7, 76] ; Save r14 258 st r13, [r7, 80] ; Save r13 259; 260; /* Save the remaining time-slice and disable it. */ 261; if (_tx_timer_time_slice) 262; { 263; 264 ld r2, [gp, _tx_timer_time_slice@sda] ; Pickup time-slice contents 265 mov r7, 0 ; Build clear/NULL value 266 breq r2, 0, __tx_thread_dont_save_ts ; No time-slice, don't need to save it 267; 268; _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice; 269; _tx_timer_time_slice = 0; 270; 271 st r2, [r0, 24] ; If set, save remaining time-slice 272 st r7, [gp, _tx_timer_time_slice@sda] ; If set, clear time slice 273; 274; } 275__tx_thread_dont_save_ts: 276; 277; 278; /* Clear the current thread pointer. */ 279; _tx_thread_current_ptr = TX_NULL; 280; 281 st r7, [gp, _tx_thread_current_ptr@sda] ; Set current thread ptr to NULL 282 283 sub sp, sp, 8 ; Allocate a small stack frame on the system stack 284 lr r0, [STATUS32] ; Pickup STATUS32 285 st r0, [sp, 4] ; Place on stack 286 mov r0, _tx_thread_schedule_reenter ; Build address of scheduler 287 st r0, [sp, 0] ; Write over the point of interrupt 288 rtie ; Return from interrupt to scheduler 289; 290; } 291; 292; /* Return to the scheduler. */ 293; _tx_thread_schedule(); 294; 295__tx_thread_idle_system_restore: 296 297 lr r4, [AUX_IRQ_ACT] ; Pickup the interrupt active register 298 neg r5, r4 ; Negate 299 and r5, r4, r5 ; See if there are any other interrupts present 300 sub.f 0, r4, r5 ; Set condition codes 301 bne __tx_thread_nested_restore ; If more interrupts, just return to the point of interrupt 302 303 lr r0, [STATUS32] ; Pickup STATUS32 304 st r0, [sp, 4] ; Place on stack 305 mov r0, _tx_thread_schedule ; Build address of scheduler 306 st r0, [sp, 0] ; Write over the point of interrupt 307 rtie ; Return from interrupt to scheduler 308; 309;} 310 .end 311 312