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/*   Copyright (c) Cadence Design Systems, Inc.                           */
13/*                                                                        */
14/* Permission is hereby granted, free of charge, to any person obtaining  */
15/* a copy of this software and associated documentation files (the        */
16/* "Software"), to deal in the Software without restriction, including    */
17/* without limitation the rights to use, copy, modify, merge, publish,    */
18/* distribute, sublicense, and/or sell copies of the Software, and to     */
19/* permit persons to whom the Software is furnished to do so, subject to  */
20/* the following conditions:                                              */
21/*                                                                        */
22/* The above copyright notice and this permission notice shall be         */
23/* included in all copies or substantial portions of the Software.        */
24/*                                                                        */
25/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
26/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
27/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
28/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
29/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
30/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
31/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
32/**************************************************************************/
33
34/**************************************************************************/
35/**************************************************************************/
36/**                                                                       */
37/** ThreadX Component                                                     */
38/**                                                                       */
39/**   Thread                                                              */
40/**                                                                       */
41/**************************************************************************/
42/**************************************************************************/
43
44
45#include "xtensa_rtos.h"
46#include "tx_api_asm.h"
47
48
49#if XCHAL_HAVE_XEA2
50
51    .text
52
53/**************************************************************************/
54/*                                                                        */
55/*  DESCRIPTION                                                           */
56/*                                                                        */
57/*    This function restores the interrupt context if it is processing a  */
58/*    nested interrupt. If not, it returns to the interrupt thread if no  */
59/*    preemption is necessary.  Otherwise, if preemption is necessary or  */
60/*    if no thread was running, the function returns to the scheduler.    */
61/*                                                                        */
62/*  RELEASE HISTORY                                                       */
63/*  12-31-2020      Cadence Design Systems  Initial Version 6.1.3         */
64/*  10-31-2022      Scott Larson            Updated EPK definitions,      */
65/*                                            resulting in version 6.2.0  */
66/*                                                                        */
67/**************************************************************************/
68
69//  VOID   _tx_thread_context_restore(VOID)
70//  {
71    .globl  _tx_thread_context_restore
72    .type   _tx_thread_context_restore,@function
73    .align  4
74_tx_thread_context_restore:
75
76    /*
77    Please note: Control flow might seem strange. This is because it has been
78    optimized to avoid taken branches in the longest normal path (the critical
79    one for worst-case latency), presumed to be a non-nested interrupt that
80    preempts) and to hide pipeline interlock cycles where possible.
81    */
82
83    /* Lockout interrupts.  */
84    XT_INTS_DISABLE(a0)
85
86    #if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
87    /* Call the ISR exit function to indicate an ISR is complete. */
88    #ifdef __XTENSA_CALL0_ABI__
89    call0   _tx_execution_isr_exit
90    #else
91    call8   _tx_execution_isr_exit
92    #endif
93    #endif
94
95    /* Determine if interrupts are nested.  */
96    //  if (--_tx_thread_system_state)
97    //  {
98
99    movi    a2, _tx_thread_system_state /* a2 = & interrupt nesting count */
100    l32i    a3, a2, 0                   /* decrement interrupt nesting count */
101    addi    a3, a3, -1
102    s32i    a3, a2, 0
103    bnez    a3, .L_tx_thread_nested_restore
104
105    //  }
106
107.Ln_tx_thread_not_nested_restore:
108
109    /* Determine if a thread was interrupted and no preemption is required.  */
110    //  else if (((_tx_thread_current_ptr)
111    //              && (_tx_thread_current_ptr == _tx_thread_execute_ptr))
112    //           || (_tx_thread_preempt_disable))
113    //  {
114
115    movi    a0, _tx_thread_current_ptr  /* a0 = &_tx_thread_current_ptr */
116    l32i    a2, a0, 0                   /* a2 =  _tx_thread_current_ptr (old) */
117    movi    a3, _tx_thread_execute_ptr
118    beqz    a2, .L_tx_thread_idle_system_restore
119
120    l32i    a3, a3, 0                   /* a3 = _tx_thread_execute_ptr (new) */
121    beq     a3, a2, .L_tx_thread_no_preempt_restore
122
123    movi    a3, _tx_thread_preempt_disable
124    l32i    a3, a3, 0                   /* a3 = _tx_thread_preempt_disable */
125
126    //      /* the no-preempt case has moved down so we fall-thru to preempt */
127    bgei    a3, 1, .L_tx_thread_no_preempt_restore
128
129    //  }
130    //  else
131    //  {
132
133.Ln_tx_thread_preempt_restore:
134
135    /* Save remaining context on the thread's stack.  */
136    l32i    a3, a2, tx_thread_stack_ptr /* a3 = thread's stack ptr */
137
138    /* Store standard preserved registers.  */
139    /*
140    Call0 ABI callee-saved regs a12-15 need to be saved before preemption.
141    However a12-13 were saved for scratch by _tx_thread_context_save().
142    */
143    #ifdef __XTENSA_CALL0_ABI__         /* Call0: now save callee-save regs  */
144    s32i    a14, a3, XT_STK_A14
145    s32i    a15, a3, XT_STK_A15
146    #endif
147
148    /* Save the remaining time-slice and disable it.  */
149    //      if (_tx_timer_time_slice)
150    //      {
151    movi    a3, _tx_timer_time_slice    /* a3 = &_tx_timer_time_slice */
152    l32i    a4, a3, 0                   /* a4 =  _tx_timer_time_slice */
153    beqz    a4, .L_tx_thread_dont_save_ts
154
155    //          _tx_thread_current_ptr -> tx_thread_time_slice
156    //              =  _tx_timer_time_slice;
157    //          _tx_timer_time_slice =  0;  */
158    s32i    a4, a2, tx_thread_time_slice
159    movi    a4, 0
160    s32i    a4, a3, 0
161
162    //      }
163
164.L_tx_thread_dont_save_ts:
165
166    /* Clear the current task pointer.  */
167    //      _tx_thread_current_ptr =  TX_NULL;
168    s32i    a4, a0, 0                   /* a4 == 0 == TX_NULL */
169
170    #if XCHAL_CP_NUM > 0
171    /* Save CPENABLE in thread's co-processor save area, and clear CPENABLE. */
172    rsr     a3, CPENABLE
173    s16i    a3, a2, tx_thread_cp_state + XT_CPENABLE
174    wsr     a4, CPENABLE                /* disable all co-processors */
175    #endif
176
177.L_tx_thread_idle_system_restore:
178
179    /*
180    Return via the scheduler.
181    Scheduler returns eventually to this function's caller as if called by it.
182    At this point we are still on the system stack.
183    */
184    //      _tx_thread_schedule();
185    call0   _tx_thread_schedule         /* never returns here */
186
187    //  }
188
189    /* Flow never falls through here. */
190
191.L_tx_thread_no_preempt_restore:
192
193    /* Restore interrupted thread.  */
194
195    /* Pickup the saved stack pointer.  */
196    //      SP =  _tx_thread_current_ptr -> tx_thread_stack_ptr;
197    l32i    sp, a2, tx_thread_stack_ptr
198
199.L_tx_thread_nested_restore:
200
201    /* Recover the saved context and return to the point of interrupt.  */
202
203    call0   _xt_context_restore
204
205    /*
206    Must return via the exit dispatcher corresponding to the entrypoint
207    from which this was called. Interruptee's A0, A1, PS, PC are restored
208    and the interrupt stack frame is deallocated in the exit dispatcher.
209    At this point we are on the thread's stack.
210    */
211    l32i    a0, sp, XT_STK_EXIT
212    ret
213
214//  }
215
216#endif /* XCHAL_HAVE_XEA2 */
217
218