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