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/**                                                                       */
16/** ThreadX Component                                                     */
17/**                                                                       */
18/**   Thread                                                              */
19/**                                                                       */
20/**************************************************************************/
21/**************************************************************************/
22
23#include "tx_port.h"
24
25    .section .text
26/**************************************************************************/
27/*                                                                        */
28/*  FUNCTION                                               RELEASE        */
29/*                                                                        */
30/*    _tx_thread_context_save                            RISC-V64/GNU     */
31/*                                                           6.2.1        */
32/*  AUTHOR                                                                */
33/*                                                                        */
34/*    Scott Larson, Microsoft Corporation                                 */
35/*                                                                        */
36/*  DESCRIPTION                                                           */
37/*                                                                        */
38/*    This function saves the context of an executing thread in the       */
39/*    beginning of interrupt processing.  The function also ensures that  */
40/*    the system stack is used upon return to the calling ISR.            */
41/*                                                                        */
42/*  INPUT                                                                 */
43/*                                                                        */
44/*    None                                                                */
45/*                                                                        */
46/*  OUTPUT                                                                */
47/*                                                                        */
48/*    None                                                                */
49/*                                                                        */
50/*  CALLS                                                                 */
51/*                                                                        */
52/*    None                                                                */
53/*                                                                        */
54/*  CALLED BY                                                             */
55/*                                                                        */
56/*    ISRs                                                                */
57/*                                                                        */
58/*  RELEASE HISTORY                                                       */
59/*                                                                        */
60/*    DATE              NAME                      DESCRIPTION             */
61/*                                                                        */
62/*  03-08-2023      Scott Larson            Initial Version 6.2.1         */
63/*                                                                        */
64/**************************************************************************/
65/* VOID   _tx_thread_context_save(VOID)
66{  */
67    .global      _tx_thread_context_save
68_tx_thread_context_save:
69
70    /* Upon entry to this routine, it is assumed that interrupts are locked
71       out and the interrupt stack fame has been allocated and x1 (ra) has
72       been saved on the stack. */
73
74    STORE   x5, 19*REGBYTES(sp)                         // First store t0 and t1
75    STORE   x6, 18*REGBYTES(sp)
76
77    la      x5, _tx_thread_system_state                 // Pickup address of system state
78    LOAD    x6, 0(x5)                                   // Pickup system state
79
80    /* Check for a nested interrupt condition.  */
81    /* if (_tx_thread_system_state++)
82    {  */
83    beqz    x6, _tx_thread_not_nested_save              // If 0, first interrupt condition
84    addi    x6, x6, 1                                   // Increment the interrupt counter
85    STORE   x6, 0(x5)                                   // Store the interrupt counter
86
87    /* Nested interrupt condition.
88       Save the reset of the scratch registers on the stack and return to the
89       calling ISR.  */
90
91    STORE   x7,  17*REGBYTES(sp)                        // Store t2
92    STORE   x8,  12*REGBYTES(sp)                        // Store s0
93    STORE   x10, 27*REGBYTES(sp)                        // Store a0
94    STORE   x11, 26*REGBYTES(sp)                        // Store a1
95    STORE   x12, 25*REGBYTES(sp)                        // Store a2
96    STORE   x13, 24*REGBYTES(sp)                        // Store a3
97    STORE   x14, 23*REGBYTES(sp)                        // Store a4
98    STORE   x15, 22*REGBYTES(sp)                        // Store a5
99    STORE   x16, 21*REGBYTES(sp)                        // Store a6
100    STORE   x17, 20*REGBYTES(sp)                        // Store a7
101    STORE   x28, 16*REGBYTES(sp)                        // Store t3
102    STORE   x29, 15*REGBYTES(sp)                        // Store t4
103    STORE   x30, 14*REGBYTES(sp)                        // Store t5
104    STORE   x31, 13*REGBYTES(sp)                        // Store t6
105    csrr    t0, mepc                                    // Load exception program counter
106    STORE   t0, 30*REGBYTES(sp)                         // Save it on the stack
107
108    /* Save floating point scratch registers.  */
109#if defined(__riscv_float_abi_single)
110    fsw     f0, 31*REGBYTES(sp)                         // Store ft0
111    fsw     f1, 32*REGBYTES(sp)                         // Store ft1
112    fsw     f2, 33*REGBYTES(sp)                         // Store ft2
113    fsw     f3, 34*REGBYTES(sp)                         // Store ft3
114    fsw     f4, 35*REGBYTES(sp)                         // Store ft4
115    fsw     f5, 36*REGBYTES(sp)                         // Store ft5
116    fsw     f6, 37*REGBYTES(sp)                         // Store ft6
117    fsw     f7, 38*REGBYTES(sp)                         // Store ft7
118    fsw     f10,41*REGBYTES(sp)                         // Store fa0
119    fsw     f11,42*REGBYTES(sp)                         // Store fa1
120    fsw     f12,43*REGBYTES(sp)                         // Store fa2
121    fsw     f13,44*REGBYTES(sp)                         // Store fa3
122    fsw     f14,45*REGBYTES(sp)                         // Store fa4
123    fsw     f15,46*REGBYTES(sp)                         // Store fa5
124    fsw     f16,47*REGBYTES(sp)                         // Store fa6
125    fsw     f17,48*REGBYTES(sp)                         // Store fa7
126    fsw     f28,59*REGBYTES(sp)                         // Store ft8
127    fsw     f29,60*REGBYTES(sp)                         // Store ft9
128    fsw     f30,61*REGBYTES(sp)                         // Store ft10
129    fsw     f31,62*REGBYTES(sp)                         // Store ft11
130    csrr    t0, fcsr
131    STORE   t0, 63*REGBYTES(sp)                         // Store fcsr
132#elif defined(__riscv_float_abi_double)
133    fsd     f0, 31*REGBYTES(sp)                         // Store ft0
134    fsd     f1, 32*REGBYTES(sp)                         // Store ft1
135    fsd     f2, 33*REGBYTES(sp)                         // Store ft2
136    fsd     f3, 34*REGBYTES(sp)                         // Store ft3
137    fsd     f4, 35*REGBYTES(sp)                         // Store ft4
138    fsd     f5, 36*REGBYTES(sp)                         // Store ft5
139    fsd     f6, 37*REGBYTES(sp)                         // Store ft6
140    fsd     f7, 38*REGBYTES(sp)                         // Store ft7
141    fsd     f10,41*REGBYTES(sp)                         // Store fa0
142    fsd     f11,42*REGBYTES(sp)                         // Store fa1
143    fsd     f12,43*REGBYTES(sp)                         // Store fa2
144    fsd     f13,44*REGBYTES(sp)                         // Store fa3
145    fsd     f14,45*REGBYTES(sp)                         // Store fa4
146    fsd     f15,46*REGBYTES(sp)                         // Store fa5
147    fsd     f16,47*REGBYTES(sp)                         // Store fa6
148    fsd     f17,48*REGBYTES(sp)                         // Store fa7
149    fsd     f28,59*REGBYTES(sp)                         // Store ft8
150    fsd     f29,60*REGBYTES(sp)                         // Store ft9
151    fsd     f30,61*REGBYTES(sp)                         // Store ft10
152    fsd     f31,62*REGBYTES(sp)                         // Store ft11
153    csrr    t0, fcsr
154    STORE   t0, 63*REGBYTES(sp)                         // Store fcsr
155#endif
156
157#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
158    call    _tx_execution_isr_enter                     // Call the ISR execution enter function
159#endif
160
161    ret                                                 // Return to calling ISR
162
163_tx_thread_not_nested_save:
164    /* }  */
165
166    /* Otherwise, not nested, check to see if a thread was running.  */
167    /* else if (_tx_thread_current_ptr)
168    {  */
169    addi    x6, x6, 1                                   // Increment the interrupt counter
170    STORE   x6, 0(x5)                                   // Store the interrupt counter
171
172    /* Not nested: Find the user thread that was running and load our SP */
173
174    LOAD    x5, _tx_thread_current_ptr                  // Pickup current thread pointer
175    beqz    x5, _tx_thread_idle_system_save             // If NULL, idle system was interrupted
176
177    /* Save the standard scratch registers.  */
178
179    STORE   x7,  17*REGBYTES(sp)                        // Store t2
180    STORE   x8,  12*REGBYTES(sp)                        // Store s0
181    STORE   x10, 27*REGBYTES(sp)                        // Store a0
182    STORE   x11, 26*REGBYTES(sp)                        // Store a1
183    STORE   x12, 25*REGBYTES(sp)                        // Store a2
184    STORE   x13, 24*REGBYTES(sp)                        // Store a3
185    STORE   x14, 23*REGBYTES(sp)                        // Store a4
186    STORE   x15, 22*REGBYTES(sp)                        // Store a5
187    STORE   x16, 21*REGBYTES(sp)                        // Store a6
188    STORE   x17, 20*REGBYTES(sp)                        // Store a7
189    STORE   x28, 16*REGBYTES(sp)                        // Store t3
190    STORE   x29, 15*REGBYTES(sp)                        // Store t4
191    STORE   x30, 14*REGBYTES(sp)                        // Store t5
192    STORE   x31, 13*REGBYTES(sp)                        // Store t6
193
194    csrr    t0, mepc                                    // Load exception program counter
195    STORE   t0, 30*REGBYTES(sp)                         // Save it on the stack
196
197    /* Save floating point scratch registers.  */
198#if defined(__riscv_float_abi_single)
199    fsw     f0, 31*REGBYTES(sp)                         // Store ft0
200    fsw     f1, 32*REGBYTES(sp)                         // Store ft1
201    fsw     f2, 33*REGBYTES(sp)                         // Store ft2
202    fsw     f3, 34*REGBYTES(sp)                         // Store ft3
203    fsw     f4, 35*REGBYTES(sp)                         // Store ft4
204    fsw     f5, 36*REGBYTES(sp)                         // Store ft5
205    fsw     f6, 37*REGBYTES(sp)                         // Store ft6
206    fsw     f7, 38*REGBYTES(sp)                         // Store ft7
207    fsw     f10,41*REGBYTES(sp)                         // Store fa0
208    fsw     f11,42*REGBYTES(sp)                         // Store fa1
209    fsw     f12,43*REGBYTES(sp)                         // Store fa2
210    fsw     f13,44*REGBYTES(sp)                         // Store fa3
211    fsw     f14,45*REGBYTES(sp)                         // Store fa4
212    fsw     f15,46*REGBYTES(sp)                         // Store fa5
213    fsw     f16,47*REGBYTES(sp)                         // Store fa6
214    fsw     f17,48*REGBYTES(sp)                         // Store fa7
215    fsw     f28,59*REGBYTES(sp)                         // Store ft8
216    fsw     f29,60*REGBYTES(sp)                         // Store ft9
217    fsw     f30,61*REGBYTES(sp)                         // Store ft10
218    fsw     f31,62*REGBYTES(sp)                         // Store ft11
219    csrr    t0, fcsr
220    STORE   t0, 63*REGBYTES(sp)                         // Store fcsr
221#elif defined(__riscv_float_abi_double)
222    fsd     f0, 31*REGBYTES(sp)                         // Store ft0
223    fsd     f1, 32*REGBYTES(sp)                         // Store ft1
224    fsd     f2, 33*REGBYTES(sp)                         // Store ft2
225    fsd     f3, 34*REGBYTES(sp)                         // Store ft3
226    fsd     f4, 35*REGBYTES(sp)                         // Store ft4
227    fsd     f5, 36*REGBYTES(sp)                         // Store ft5
228    fsd     f6, 37*REGBYTES(sp)                         // Store ft6
229    fsd     f7, 38*REGBYTES(sp)                         // Store ft7
230    fsd     f10,41*REGBYTES(sp)                         // Store fa0
231    fsd     f11,42*REGBYTES(sp)                         // Store fa1
232    fsd     f12,43*REGBYTES(sp)                         // Store fa2
233    fsd     f13,44*REGBYTES(sp)                         // Store fa3
234    fsd     f14,45*REGBYTES(sp)                         // Store fa4
235    fsd     f15,46*REGBYTES(sp)                         // Store fa5
236    fsd     f16,47*REGBYTES(sp)                         // Store fa6
237    fsd     f17,48*REGBYTES(sp)                         // Store fa7
238    fsd     f28,59*REGBYTES(sp)                         // Store ft8
239    fsd     f29,60*REGBYTES(sp)                         // Store ft9
240    fsd     f30,61*REGBYTES(sp)                         // Store ft10
241    fsd     f31,62*REGBYTES(sp)                         // Store ft11
242    csrr    t0, fcsr
243    STORE   t0, 63*REGBYTES(sp)                         // Store fcsr
244#endif
245
246    /* Save the current stack pointer in the thread's control block.  */
247    /* _tx_thread_current_ptr -> tx_thread_stack_ptr =  sp;  */
248
249    /* Switch to the system stack.  */
250    /* sp =  _tx_thread_system_stack_ptr;  */
251
252    LOAD    t1, _tx_thread_current_ptr                  // Pickup current thread pointer
253    STORE   sp, 2*REGBYTES(t1)                          // Save stack pointer
254
255#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
256    /* _tx_execution_isr_enter is called with thread stack pointer */
257    call    _tx_execution_isr_enter                     // Call the ISR execution enter function
258#endif
259
260
261    LOAD    sp, _tx_thread_system_stack_ptr             // Switch to system stack
262    ret                                                 // Return to calling ISR
263
264    /* }
265    else
266    {  */
267
268_tx_thread_idle_system_save:
269
270
271#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
272    call    _tx_execution_isr_enter                     // Call the ISR execution enter function
273#endif
274
275    /* Interrupt occurred in the scheduling loop.  */
276
277    /* }
278}  */
279#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
280    addi    sp, sp, 65*REGBYTES                         // Recover stack frame - with floating point enabled
281#else
282    addi    sp, sp, 32*REGBYTES                         // Recover the reserved stack space
283#endif
284    ret                                                 // Return to calling ISR
285