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