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