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