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