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