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