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/**                                                                       */
15/** ThreadX Component                                                     */
16/**                                                                       */
17/**   Thread                                                              */
18/**                                                                       */
19/**************************************************************************/
20/**************************************************************************/
21
22#include "tx_port.h"
23
24    .section .text
25/**************************************************************************/
26/*                                                                        */
27/*  FUNCTION                                               RELEASE        */
28/*                                                                        */
29/*    _tx_thread_schedule                                RISC-V64/GNU     */
30/*                                                           6.2.1        */
31/*  AUTHOR                                                                */
32/*                                                                        */
33/*    Scott Larson, Microsoft Corporation                                 */
34/*                                                                        */
35/*  DESCRIPTION                                                           */
36/*                                                                        */
37/*    This function waits for a thread control block pointer to appear in */
38/*    the _tx_thread_execute_ptr variable.  Once a thread pointer appears */
39/*    in the variable, the corresponding thread is resumed.               */
40/*                                                                        */
41/*  INPUT                                                                 */
42/*                                                                        */
43/*    None                                                                */
44/*                                                                        */
45/*  OUTPUT                                                                */
46/*                                                                        */
47/*    None                                                                */
48/*                                                                        */
49/*  CALLS                                                                 */
50/*                                                                        */
51/*    None                                                                */
52/*                                                                        */
53/*  CALLED BY                                                             */
54/*                                                                        */
55/*    _tx_initialize_kernel_enter          ThreadX entry function         */
56/*    _tx_thread_system_return             Return to system from thread   */
57/*    _tx_thread_context_restore           Restore thread's context       */
58/*                                                                        */
59/*  RELEASE HISTORY                                                       */
60/*                                                                        */
61/*    DATE              NAME                      DESCRIPTION             */
62/*                                                                        */
63/*  03-08-2023      Scott Larson            Initial Version 6.2.1         */
64/*                                                                        */
65/**************************************************************************/
66/* VOID   _tx_thread_schedule(VOID)
67{  */
68    .global  _tx_thread_schedule
69_tx_thread_schedule:
70
71    /* Enable interrupts.  */
72    csrsi   mstatus, 0x08                               // Enable interrupts
73
74    /* Wait for a thread to execute.  */
75    /* do
76    {  */
77
78    la      t0, _tx_thread_execute_ptr                  // Pickup address of execute ptr
79_tx_thread_schedule_loop:
80    LOAD    t1, 0(t0)                                   // Pickup next thread to execute
81    beqz    t1, _tx_thread_schedule_loop                // If NULL, wait for thread to execute
82
83    /* }
84    while(_tx_thread_execute_ptr == TX_NULL);  */
85
86    /* Yes! We have a thread to execute.  Lockout interrupts and
87       transfer control to it.  */
88    csrci   mstatus, 0x08                               // Lockout interrupts
89
90    /* Setup the current thread pointer.  */
91    /* _tx_thread_current_ptr =  _tx_thread_execute_ptr;  */
92
93    la      t0, _tx_thread_current_ptr                  // Pickup current thread pointer address
94    STORE   t1, 0(t0)                                   // Set current thread pointer
95
96    /* Increment the run count for this thread.  */
97    /* _tx_thread_current_ptr -> tx_thread_run_count++;  */
98
99    LOAD    t2, 1*REGBYTES(t1)                          // Pickup run count
100    LOAD    t3, 6*REGBYTES(t1)                          // Pickup time slice value
101    addi    t2, t2, 1                                   // Increment run count
102    STORE   t2, 1*REGBYTES(t1)                          // Store new run count
103
104    /* Setup time-slice, if present.  */
105    /* _tx_timer_time_slice =  _tx_thread_current_ptr -> tx_thread_time_slice;  */
106
107    la      t2, _tx_timer_time_slice                    // Pickup time-slice variable address
108
109    /* Switch to the thread's stack.  */
110    /* SP =  _tx_thread_execute_ptr -> tx_thread_stack_ptr;  */
111
112    LOAD    sp, 2*REGBYTES(t1)                          // Switch to thread's stack
113    STORE   t3, 0(t2)                                   // Store new time-slice*/
114
115#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
116
117    call    _tx_execution_thread_enter                  // Call the thread execution enter function
118#endif
119
120    /* Determine if an interrupt frame or a synchronous task suspension frame
121       is present.  */
122
123    LOAD    t2, 0(sp)                                   // Pickup stack type
124    beqz    t2, _tx_thread_synch_return                 // If 0, solicited thread return
125
126    /* Determine if floating point registers need to be recovered.  */
127
128#if defined(__riscv_float_abi_single)
129    flw     f0, 31*REGBYTES(sp)                         // Recover ft0
130    flw     f1, 32*REGBYTES(sp)                         // Recover ft1
131    flw     f2, 33*REGBYTES(sp)                         // Recover ft2
132    flw     f3, 34*REGBYTES(sp)                         // Recover ft3
133    flw     f4, 35*REGBYTES(sp)                         // Recover ft4
134    flw     f5, 36*REGBYTES(sp)                         // Recover ft5
135    flw     f6, 37*REGBYTES(sp)                         // Recover ft6
136    flw     f7, 38*REGBYTES(sp)                         // Recover ft7
137    flw     f8, 39*REGBYTES(sp)                         // Recover fs0
138    flw     f9, 40*REGBYTES(sp)                         // Recover fs1
139    flw     f10,41*REGBYTES(sp)                         // Recover fa0
140    flw     f11,42*REGBYTES(sp)                         // Recover fa1
141    flw     f12,43*REGBYTES(sp)                         // Recover fa2
142    flw     f13,44*REGBYTES(sp)                         // Recover fa3
143    flw     f14,45*REGBYTES(sp)                         // Recover fa4
144    flw     f15,46*REGBYTES(sp)                         // Recover fa5
145    flw     f16,47*REGBYTES(sp)                         // Recover fa6
146    flw     f17,48*REGBYTES(sp)                         // Recover fa7
147    flw     f18,49*REGBYTES(sp)                         // Recover fs2
148    flw     f19,50*REGBYTES(sp)                         // Recover fs3
149    flw     f20,51*REGBYTES(sp)                         // Recover fs4
150    flw     f21,52*REGBYTES(sp)                         // Recover fs5
151    flw     f22,53*REGBYTES(sp)                         // Recover fs6
152    flw     f23,54*REGBYTES(sp)                         // Recover fs7
153    flw     f24,55*REGBYTES(sp)                         // Recover fs8
154    flw     f25,56*REGBYTES(sp)                         // Recover fs9
155    flw     f26,57*REGBYTES(sp)                         // Recover fs10
156    flw     f27,58*REGBYTES(sp)                         // Recover fs11
157    flw     f28,59*REGBYTES(sp)                         // Recover ft8
158    flw     f29,60*REGBYTES(sp)                         // Recover ft9
159    flw     f30,61*REGBYTES(sp)                         // Recover ft10
160    flw     f31,62*REGBYTES(sp)                         // Recover ft11
161    LOAD    t0, 63*REGBYTES(sp)                         // Recover fcsr
162    csrw    fcsr, t0                                    //
163#elif defined(__riscv_float_abi_double)
164    fld     f0, 31*REGBYTES(sp)                         // Recover ft0
165    fld     f1, 32*REGBYTES(sp)                         // Recover ft1
166    fld     f2, 33*REGBYTES(sp)                         // Recover ft2
167    fld     f3, 34*REGBYTES(sp)                         // Recover ft3
168    fld     f4, 35*REGBYTES(sp)                         // Recover ft4
169    fld     f5, 36*REGBYTES(sp)                         // Recover ft5
170    fld     f6, 37*REGBYTES(sp)                         // Recover ft6
171    fld     f7, 38*REGBYTES(sp)                         // Recover ft7
172    fld     f8, 39*REGBYTES(sp)                         // Recover fs0
173    fld     f9, 40*REGBYTES(sp)                         // Recover fs1
174    fld     f10,41*REGBYTES(sp)                         // Recover fa0
175    fld     f11,42*REGBYTES(sp)                         // Recover fa1
176    fld     f12,43*REGBYTES(sp)                         // Recover fa2
177    fld     f13,44*REGBYTES(sp)                         // Recover fa3
178    fld     f14,45*REGBYTES(sp)                         // Recover fa4
179    fld     f15,46*REGBYTES(sp)                         // Recover fa5
180    fld     f16,47*REGBYTES(sp)                         // Recover fa6
181    fld     f17,48*REGBYTES(sp)                         // Recover fa7
182    fld     f18,49*REGBYTES(sp)                         // Recover fs2
183    fld     f19,50*REGBYTES(sp)                         // Recover fs3
184    fld     f20,51*REGBYTES(sp)                         // Recover fs4
185    fld     f21,52*REGBYTES(sp)                         // Recover fs5
186    fld     f22,53*REGBYTES(sp)                         // Recover fs6
187    fld     f23,54*REGBYTES(sp)                         // Recover fs7
188    fld     f24,55*REGBYTES(sp)                         // Recover fs8
189    fld     f25,56*REGBYTES(sp)                         // Recover fs9
190    fld     f26,57*REGBYTES(sp)                         // Recover fs10
191    fld     f27,58*REGBYTES(sp)                         // Recover fs11
192    fld     f28,59*REGBYTES(sp)                         // Recover ft8
193    fld     f29,60*REGBYTES(sp)                         // Recover ft9
194    fld     f30,61*REGBYTES(sp)                         // Recover ft10
195    fld     f31,62*REGBYTES(sp)                         // Recover ft11
196    LOAD    t0, 63*REGBYTES(sp)                         // Recover fcsr
197#endif
198
199    /* Recover standard registers.  */
200
201    LOAD    t0, 30*REGBYTES(sp)                         // Recover mepc
202    csrw    mepc, t0                                    // Store mepc
203    li      t0, 0x1880                                  // Prepare MPIP
204    csrw    mstatus, t0                                 // Enable MPIP
205
206    LOAD    x1,  28*REGBYTES(sp)                        // Recover RA
207    LOAD    x5,  19*REGBYTES(sp)                        // Recover t0
208    LOAD    x6,  18*REGBYTES(sp)                        // Recover t1
209    LOAD    x7,  17*REGBYTES(sp)                        // Recover t2
210    LOAD    x8,  12*REGBYTES(sp)                        // Recover s0
211    LOAD    x9,  11*REGBYTES(sp)                        // Recover s1
212    LOAD    x10, 27*REGBYTES(sp)                        // Recover a0
213    LOAD    x11, 26*REGBYTES(sp)                        // Recover a1
214    LOAD    x12, 25*REGBYTES(sp)                        // Recover a2
215    LOAD    x13, 24*REGBYTES(sp)                        // Recover a3
216    LOAD    x14, 23*REGBYTES(sp)                        // Recover a4
217    LOAD    x15, 22*REGBYTES(sp)                        // Recover a5
218    LOAD    x16, 21*REGBYTES(sp)                        // Recover a6
219    LOAD    x17, 20*REGBYTES(sp)                        // Recover a7
220    LOAD    x18, 10*REGBYTES(sp)                        // Recover s2
221    LOAD    x19,  9*REGBYTES(sp)                        // Recover s3
222    LOAD    x20,  8*REGBYTES(sp)                        // Recover s4
223    LOAD    x21,  7*REGBYTES(sp)                        // Recover s5
224    LOAD    x22,  6*REGBYTES(sp)                        // Recover s6
225    LOAD    x23,  5*REGBYTES(sp)                        // Recover s7
226    LOAD    x24,  4*REGBYTES(sp)                        // Recover s8
227    LOAD    x25,  3*REGBYTES(sp)                        // Recover s9
228    LOAD    x26,  2*REGBYTES(sp)                        // Recover s10
229    LOAD    x27,  1*REGBYTES(sp)                        // Recover s11
230    LOAD    x28, 16*REGBYTES(sp)                        // Recover t3
231    LOAD    x29, 15*REGBYTES(sp)                        // Recover t4
232    LOAD    x30, 14*REGBYTES(sp)                        // Recover t5
233    LOAD    x31, 13*REGBYTES(sp)                        // Recover t6
234
235#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
236    addi    sp, sp, 65*REGBYTES                         // Recover stack frame - with floating point registers
237#else
238    addi    sp, sp, 32*REGBYTES                         // Recover stack frame - without floating point registers
239#endif
240    mret                                                // Return to point of interrupt
241
242_tx_thread_synch_return:
243
244#if defined(__riscv_float_abi_single)
245    flw     f8, 15*REGBYTES(sp)                         // Recover fs0
246    flw     f9, 16*REGBYTES(sp)                         // Recover fs1
247    flw     f18,17*REGBYTES(sp)                         // Recover fs2
248    flw     f19,18*REGBYTES(sp)                         // Recover fs3
249    flw     f20,19*REGBYTES(sp)                         // Recover fs4
250    flw     f21,20*REGBYTES(sp)                         // Recover fs5
251    flw     f22,21*REGBYTES(sp)                         // Recover fs6
252    flw     f23,22*REGBYTES(sp)                         // Recover fs7
253    flw     f24,23*REGBYTES(sp)                         // Recover fs8
254    flw     f25,24*REGBYTES(sp)                         // Recover fs9
255    flw     f26,25*REGBYTES(sp)                         // Recover fs10
256    flw     f27,26*REGBYTES(sp)                         // Recover fs11
257    LOAD    t0, 27*REGBYTES(sp)                         // Recover fcsr
258    csrw    fcsr, t0                                    //
259#elif defined(__riscv_float_abi_double)
260    fld     f8, 15*REGBYTES(sp)                         // Recover fs0
261    fld     f9, 16*REGBYTES(sp)                         // Recover fs1
262    fld     f18,17*REGBYTES(sp)                         // Recover fs2
263    fld     f19,18*REGBYTES(sp)                         // Recover fs3
264    fld     f20,19*REGBYTES(sp)                         // Recover fs4
265    fld     f21,20*REGBYTES(sp)                         // Recover fs5
266    fld     f22,21*REGBYTES(sp)                         // Recover fs6
267    fld     f23,22*REGBYTES(sp)                         // Recover fs7
268    fld     f24,23*REGBYTES(sp)                         // Recover fs8
269    fld     f25,24*REGBYTES(sp)                         // Recover fs9
270    fld     f26,25*REGBYTES(sp)                         // Recover fs10
271    fld     f27,26*REGBYTES(sp)                         // Recover fs11
272    LOAD    t0, 27*REGBYTES(sp)                         // Recover fcsr
273    csrw    fcsr, t0                                    //
274#endif
275
276    /* Recover standard preserved registers.  */
277    /* Recover standard registers.  */
278
279    LOAD    x1,  13*REGBYTES(sp)                        // Recover RA
280    LOAD    x8,  12*REGBYTES(sp)                        // Recover s0
281    LOAD    x9,  11*REGBYTES(sp)                        // Recover s1
282    LOAD    x18, 10*REGBYTES(sp)                        // Recover s2
283    LOAD    x19,  9*REGBYTES(sp)                        // Recover s3
284    LOAD    x20,  8*REGBYTES(sp)                        // Recover s4
285    LOAD    x21,  7*REGBYTES(sp)                        // Recover s5
286    LOAD    x22,  6*REGBYTES(sp)                        // Recover s6
287    LOAD    x23,  5*REGBYTES(sp)                        // Recover s7
288    LOAD    x24,  4*REGBYTES(sp)                        // Recover s8
289    LOAD    x25,  3*REGBYTES(sp)                        // Recover s9
290    LOAD    x26,  2*REGBYTES(sp)                        // Recover s10
291    LOAD    x27,  1*REGBYTES(sp)                        // Recover s11
292    LOAD    t0,  14*REGBYTES(sp)                        // Recover mstatus
293    csrw    mstatus, t0                                 // Store mstatus, enables interrupt
294#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
295    addi    sp, sp, 29*REGBYTES                         // Recover stack frame
296#else
297    addi    sp, sp, 16*REGBYTES                         // Recover stack frame
298#endif
299    ret                                                 // Return to thread
300
301/* }  */
302