1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
|
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
* Copyright (c) 2026-present Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* SPDX-License-Identifier: MIT
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
#define UserLocal $4,2
#define C0_TCBind $2,2
#define C0_TCContext $2,5
#define C0_TCHalt $2,4
#ifdef TX_THREAD_SMP_WAKEUP_LOGIC
.globl TX_MIPS32_1004K_VPE_YIELD
#endif
.text
.set noreorder
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_schedule MIPS32_interAptiv/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function waits for a thread control block pointer to appear in */
/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */
/* in the variable, the corresponding thread is resumed. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_initialize_kernel_enter ThreadX entry function */
/* _tx_thread_system_return Return to system from thread */
/* _tx_thread_context_restore Restore thread's context */
/* */
/**************************************************************************/
/* VOID _tx_thread_schedule(VOID)
{ */
.globl _tx_thread_schedule_idle_system
_tx_thread_schedule_idle_system:
#ifndef TX_THREAD_SMP_WAKEUP_LOGIC
ei # Enable interrupts
ehb #
li $11,-1 #
yield $11, $11 # Yield so this VPE does not consume all the cycles
lw $8, ($9) # Pickup next thread to execute
beq $8, $0, _tx_thread_schedule_idle_system # If not-NULL, check the thread's ready bit
nop # Delay slot
#else
la $8, TX_MIPS32_1004K_VPE_YIELD # Get call-out address
jalr $8 # Make the call
or $4, $0, $9 # Pass the properly indexed _tx_thread_execute_ptr[x]
#endif
.globl _tx_thread_schedule
_tx_thread_schedule:
/* Enable interrupts. */
ei # Enable interrupts
ehb #
/* Disable interrupts. */
di # Disable interrupts
ehb #
/* Pickup the executing VPE number. */
mfc0 $25, UserLocal # Pickup VPE ID
sll $25, $25, 2 # Build index based on VPE number
/* Calculate the execute pointer for this VPE. */
la $9, _tx_thread_execute_ptr # Pickup starting address of execute list
addu $9, $9, $25 # Build address of execute pointer for this TC
/* Wait for a thread to execute. */
/* do
{ */
_tx_thread_schedule_loop:
lw $8, ($9) # Pickup next thread to execute
beq $8, $0, _tx_thread_schedule_idle_system # If not-NULL, check the thread's ready bit
nop # Delay slot
_tx_thread_check_ready_bit:
lw $9, 152($8) # Pickup the thread's VPE control register
andi $10, $9, 0x8000 # Pickup ready bit (bit 15)
bne $10, $0, _tx_thread_is_ready # If ready bit is set, actually schedule the thread
andi $9, $9, 0x7FFF # Clear the ready bit (bit 15)
b _tx_thread_schedule # Resume at the top of the scheduling loop
nop
_tx_thread_is_ready:
sw $9, 152($8) # Store the cleared ready bit to prevent any other VPE from scheduling this thread
sync
/* }
while(_tx_thread_execute_ptr[VPE] == TX_NULL); */
_tx_thread_schedule_thread:
/* Yes! We have a thread to execute. Interrupts and multithreading are locked out.
Pickup the thread's register context, enable multithreading, and transfer control to
the thread. */
/* Save this thread in the context register of the TC. */
mtc0 $8, C0_TCContext # Set TCContext to current thread
ehb #
#ifdef TX_ENABLE_EVENT_LOGGING
or $16, $8, $0 # Save thread pointer into non-volatile
or $4, $8, $0 # Move thread pointer into input register
la $9, _tx_el_thread_running # Build address of thread running event routine
jal $9 # Call event logging routine
nop # Delay slot
or $8, $16, $0 # Recover thread pointer
#endif
/* Setup the current thread pointer. */
/* _tx_thread_current_ptr[VPE] = _tx_thread_execute_ptr[VPE]; */
la $9, _tx_thread_current_ptr # Pickup current thread pointer address
addu $9, $9, $25 # Offset to VPE specific entry
sw $8, ($9) # Set current thread pointer
/* Increment the run count for this thread. */
/* _tx_thread_current_ptr[VPE] -> tx_thread_run_count++; */
lw $10, 4($8) # Pickup run count
lw $11, 24($8) # Pickup time slice value
addu $10, $10, 1 # Increment run count
sw $10, 4($8) # Store new run count
/* Setup time-slice, if present. */
/* _tx_timer_time_slice[VPE] = _tx_thread_current_ptr[VPE] -> tx_thread_time_slice; */
la $10, _tx_timer_time_slice # Pickup time-slice variable address
addu $10, $10, $25 # Offset to VPE specific time-slice
/* Switch to the thread's stack. */
/* SP = _tx_thread_current_ptr[VPE] -> tx_thread_stack_ptr; */
lw $29, 8($8) # Switch to thread's stack
lw $15, 176($8) # Pickup FPU enable flag in TX_THREAD structure
sw $11, ($10) # Store new time-slice
/* Determine if an interrupt frame or a synchronous task suspension frame
is present. */
lw $10, ($29) # Pickup stack type
beqz $10, _tx_thread_synch_return # If 0, solicited thread return
nop # Delay slot
#ifdef TX_ENABLE_64BIT_FPU_SUPPORT
/* Check if FPU is enabled for this thread. Note that threads with FPU enabled will only be
scheduled in VPE 0. */
lw $9,120($29) # Recover SR
li $10,0xDFFFFFFF # Mask for FPU enable bit
mfc0 $8, UserLocal # Pickup VPE ID
and $9, $9, $10 # Build SR with FPU enable bit masked
bne $8, $0, _tx_skip_fpu_int_restore # If not VPE 0, skip FPU restore
li $10, 0x20000000 # Build FPU enable bit
or $9, $9, $10 # Build SR with FPU enable
beq $15, $0, _tx_skip_fpu_int_restore # If FPU not enabled, skip FPU restore
nop
lw $8, 384($29) # Recover fcr31
ctc1 $8, $31 # Setup fcr31
ldc1 $f31, 128($29) # Recover f31
ldc1 $f30, 136($29) # Recover f30
ldc1 $f29, 144($29) # Recover f29
ldc1 $f28, 152($29) # Recover f28
ldc1 $f27, 160($29) # Recover f27
ldc1 $f26, 168($29) # Recover f26
ldc1 $f25, 176($29) # Recover f25
ldc1 $f24, 184($29) # Recover f24
ldc1 $f23, 192($29) # Recover f23
ldc1 $f22, 200($29) # Recover f22
ldc1 $f21, 208($29) # Recover f21
ldc1 $f20, 216($29) # Recover f20
ldc1 $f19, 224($29) # Recover f19
ldc1 $f18, 232($29) # Recover f18
ldc1 $f17, 240($29) # Recover f17
ldc1 $f16, 248($29) # Recover f16
ldc1 $f15, 256($29) # Recover f15
ldc1 $f14, 264($29) # Recover f14
ldc1 $f13, 272($29) # Recover f13
ldc1 $f12, 280($29) # Recover f12
ldc1 $f11, 288($29) # Recover f11
ldc1 $f10, 296($29) # Recover f10
ldc1 $f9, 304($29) # Recover f9
ldc1 $f8, 312($29) # Recover f8
ldc1 $f7, 320($29) # Recover f7
ldc1 $f6, 328($29) # Recover f6
ldc1 $f5, 336($29) # Recover f5
ldc1 $f4, 344($29) # Recover f4
ldc1 $f3, 352($29) # Recover f3
ldc1 $f2, 360($29) # Recover f2
ldc1 $f1, 368($29) # Recover f1
ldc1 $f0, 376($29) # Recover f0
_tx_skip_fpu_int_restore:
sw $9,120($29) # Store new SR
#endif
/* Recover standard registers. */
lw $8,124($29) # Recover EPC
lw $9,120($29) # Recover SR
mtc0 $8, $14 # Setup EPC
ehb #
lw $30, 4($29) # Recover s8
mtc0 $9, $12 # Restore SR
ehb # Clear hazards
lw $23, 8($29) # Recover s7
lw $22, 12($29) # Recover s6
lw $21, 16($29) # Recover s5
lw $20, 20($29) # Recover s4
lw $19, 24($29) # Recover s3
lw $18, 28($29) # Recover s2
lw $17, 32($29) # Recover s1
lw $16, 36($29) # Recover s0
lw $8, 40($29) # Recover hi
lw $9, 44($29) # Recover low
mthi $8 # Setup hi
mtlo $9 # Setup lo
lw $25, 48($29) # Recover t9
lw $24, 52($29) # Recover t8
lw $15, 56($29) # Recover t7
lw $14, 60($29) # Recover t6
lw $13, 64($29) # Recover t5
lw $12, 68($29) # Recover t4
lw $11, 72($29) # Recover t3
lw $10, 76($29) # Recover t2
lw $9, 80($29) # Recover t1
lw $8, 84($29) # Recover t0
lw $7, 88($29) # Recover a3
lw $6, 92($29) # Recover a2
lw $5, 96($29) # Recover a1
lw $4, 100($29) # Recover a0
lw $3, 104($29) # Recover v1
lw $2, 108($29) # Recover v0
.set noat
lw $1, 112($29) # Recover at
.set at
lw $31,116($29) # Recover ra
addu $29, $29, 392 # Recover stack frame
emt # Enable multithreading again
eret # Return to point of interrupt
_tx_thread_synch_return:
#ifdef TX_ENABLE_64BIT_FPU_SUPPORT
/* Check if FPU is enabled for this thread. Note that threads with FPU enabled will only be
scheduled in VPE 0. */
lw $9,52($29) # Recover SR
li $10,0xDFFFFFFF # Mask for FPU enable bit
mfc0 $8, UserLocal # Pickup VPE ID
and $9, $9, $10 # Build SR with FPU enable bit masked
bne $8, $0, _tx_skip_fpu_sync_restore # If not TC 0, skip FPU restore
li $10, 0x20000000 # Build FPU enable bit
or $9, $9, $10 # Build SR with FPU enable
beq $15, $0, _tx_skip_fpu_sync_restore # If FPU not enabled, skip FPU restore
nop
lw $8, 152($29) # Recover fcr31
ctc1 $8, $31 # Setup fcr31
ldc1 $f31, 56($29) # Recover f31
ldc1 $f30, 64($29) # Recover f30
ldc1 $f29, 72($29) # Recover f29
ldc1 $f28, 80($29) # Recover f28
ldc1 $f27, 88($29) # Recover f27
ldc1 $f26, 96($29) # Recover f26
ldc1 $f25, 104($29) # Recover f25
ldc1 $f24, 112($29) # Recover f24
ldc1 $f23, 120($29) # Recover f23
ldc1 $f22, 128($29) # Recover f22
ldc1 $f21, 136($29) # Recover f21
ldc1 $f20, 144($29) # Recover f20
_tx_skip_fpu_sync_restore:
sw $9,52($29) # Store new SR
#endif
/* Recover standard preserved registers. */
lw $30, 4($29) # Recover s8
lw $23, 8($29) # Recover s7
lw $22, 12($29) # Recover s6
lw $21, 16($29) # Recover s5
lw $20, 20($29) # Recover s4
lw $19, 24($29) # Recover s3
lw $18, 28($29) # Recover s2
lw $17, 32($29) # Recover s1
lw $16, 36($29) # Recover s0
lw $8, 40($29) # Recover hi
lw $9, 44($29) # Recover low
mthi $8 # Setup hi
mtlo $9 # Setup lo
lw $8, 52($29) # Recover SR
lw $31, 48($29) # Recover ra
addu $29, $29, 160 # Recover stack space
mtc0 $8, $12 # Restore SR
ehb # Clear hazards
emt # Enable multithreading
jr.hb $31 # Return to thread
nop #
/* } */
|