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
|
/***************************************************************************
* 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
.text
.set noreorder
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_context_save MIPS32_interAptiv/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function saves the context of an executing thread in the */
/* beginning of interrupt processing. The function also ensures that */
/* the system stack is used upon return to the calling ISR. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* ISRs */
/* */
/**************************************************************************/
/* VOID _tx_thread_context_save(VOID)
{ */
.globl _tx_thread_context_save
_tx_thread_context_save:
/* Upon entry to this routine, it is assumed that interrupts are locked
out and the stack is exactly were it was when the interrupt occurred.
The return address is in $27 (k1). */
subu $29, $29, 392 # Allocate space for a full stack frame
/* # even though the whole thing might
# not be needed for awhile */
sw $25, 48($29) # Store t9
sw $24, 52($29) # Store t8
sw $8, 84($29) # Save t0
mfc0 $25, UserLocal # Pickup VPE ID
sll $24, $25, 2 # Build index based on VPE number
la $26, _tx_thread_system_state # Pickup address of system state
addu $26, $26, $24 # Index by VPE
lw $8, ($26) # Pickup system state
/* Check for a nested interrupt condition. */
/* if (_tx_thread_system_state[VPE]++)
{ */
beqz $8, _tx_thread_not_nested_save # If 0, first interrupt condition
addu $8, $8, 1 # Increment the nested interrupt counter
/* Nested interrupt condition. */
sw $8, ($26) # Store the interrupt counter
#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. */
bne $25, $0, _tx_skip_nest_int_save # If not VPE 0, skip FPU save
nop #
/* Save scratch floating point registers. */
cfc1 $8, $31 # Pickup floating point control reg
sdc1 $f19, 224($29) # Save f19
sdc1 $f18, 232($29) # Save f18
sdc1 $f17, 240($29) # Save f17
sdc1 $f16, 248($29) # Save f16
sdc1 $f15, 256($29) # Save f15
sdc1 $f14, 264($29) # Save f14
sdc1 $f13, 272($29) # Save f13
sdc1 $f12, 280($29) # Save f12
sdc1 $f11, 288($29) # Save f11
sdc1 $f10, 296($29) # Save f10
sdc1 $f9, 304($29) # Save f9
sdc1 $f8, 312($29) # Save f8
sdc1 $f7, 320($29) # Save f7
sdc1 $f6, 328($29) # Save f6
sdc1 $f5, 336($29) # Save f5
sdc1 $f4, 344($29) # Save f4
sdc1 $f3, 352($29) # Save f3
sdc1 $f2, 360($29) # Save f2
sdc1 $f1, 368($29) # Save f1
sdc1 $f0, 376($29) # Save f0
sw $8, 384($29) # Save fcr31
_tx_skip_nest_int_save:
#endif
/* Save the rest of the scratch registers on the stack and return to the
calling ISR. */
sw $16, 36($29) # Store s0
mfhi $8 # Pickup hi
mflo $26 # Pickup lo
sw $8, 40($29) # Store hi
sw $26, 44($29) # Store lo
sw $15, 56($29) # Store t7
sw $14, 60($29) # Store t6
sw $13, 64($29) # Store t5
sw $12, 68($29) # Store t4
sw $11, 72($29) # Store t3
sw $10, 76($29) # Store t2
sw $9, 80($29) # Store t1
sw $7, 88($29) # Store a3
sw $6, 92($29) # Store a2
sw $5, 96($29) # Store a1
sw $4, 100($29) # Store a0
sw $3, 104($29) # Store v1
sw $2, 108($29) # Store v0
.set noat
sw $1, 112($29) # Store at
.set at
sw $31, 116($29) # Store ra
mfc0 $8, $12 # Pickup SR
mfc0 $9, $14 # Pickup EPC
sw $8, 120($29) # Store SR
sw $9, 124($29) # Store EPC
/* Return to the ISR. */
j $27 # Return to ISR
nop #
_tx_thread_not_nested_save:
/* } */
/* Otherwise, not nested, check to see if a thread was running. */
/* else if (_tx_thread_current_ptr[VPE])
{ */
sw $8, ($26) # Store the interrupt counter
la $26, _tx_thread_current_ptr # Pickup address of current ptr
addu $26, $26, $24 # Build address of current pointer for this VPE
lw $8, ($26) # Pickup current thread pointer
beqz $8, _tx_thread_idle_system_save # If NULL, idle system was interrupted
sw $16, 36($29) # Store s0
/* Save minimal context of interrupted thread. */
#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 TC 0. */
bne $25, $0, _tx_skip_int_save # If not VPE 0, skip FPU save
nop # Delay
lw $26, 176($8) # Pickup FPU enable flag
beq $26, $0, _tx_skip_int_save # If FPU not enabled, skip FPU save
nop # Delay
/* Save scratch floating point registers. */
cfc1 $8, $31 # Pickup floating point control reg
sdc1 $f19, 224($29) # Save f19
sdc1 $f18, 232($29) # Save f18
sdc1 $f17, 240($29) # Save f17
sdc1 $f16, 248($29) # Save f16
sdc1 $f15, 256($29) # Save f15
sdc1 $f14, 264($29) # Save f14
sdc1 $f13, 272($29) # Save f13
sdc1 $f12, 280($29) # Save f12
sdc1 $f11, 288($29) # Save f11
sdc1 $f10, 296($29) # Save f10
sdc1 $f9, 304($29) # Save f9
sdc1 $f8, 312($29) # Save f8
sdc1 $f7, 320($29) # Save f7
sdc1 $f6, 328($29) # Save f6
sdc1 $f5, 336($29) # Save f5
sdc1 $f4, 344($29) # Save f4
sdc1 $f3, 352($29) # Save f3
sdc1 $f2, 360($29) # Save f2
sdc1 $f1, 368($29) # Save f1
sdc1 $f0, 376($29) # Save f0
sw $8, 384($29) # Save fcr31
_tx_skip_int_save:
#endif
/* Save the standard scratch registers. */
mfhi $8 # Pickup hi
mflo $26 # Pickup lo
sw $8, 40($29) # Store hi
sw $26, 44($29) # Store lo
sw $15, 56($29) # Store t7
sw $14, 60($29) # Store t6
sw $13, 64($29) # Store t5
sw $12, 68($29) # Store t4
sw $11, 72($29) # Store t3
sw $10, 76($29) # Store t2
sw $9, 80($29) # Store t1
sw $7, 88($29) # Store a3
sw $6, 92($29) # Store a2
sw $5, 96($29) # Store a1
sw $4, 100($29) # Store a0
sw $3, 104($29) # Store v1
sw $2, 108($29) # Store v0
.set noat
sw $1, 112($29) # Store at
.set at
sw $31, 116($29) # Store ra
mfc0 $8, $12 # Pickup SR
mfc0 $9, $14 # Pickup EPC
sw $8, 120($29) # Store SR
sw $9, 124($29) # Store EPC
li $8, 1 # Build stack type
sw $8, ($29) # Store stack type
/* Save the current stack pointer in the thread's control block. */
/* _tx_thread_current_ptr[VPE] -> tx_thread_stack_ptr = sp; */
/* Switch to the system stack. */
/* sp = _tx_thread_system_stack_ptr[VPE]; */
la $9, _tx_thread_current_ptr # Pickup address of current ptr
addu $9, $9, $24 # Build address of current pointer for this VPE
lw $11, ($9) # Pickup current thread pointer
la $10,_tx_thread_system_stack_ptr # Pickup the stack pointer address
sw $29, 8($11) # Save stack pointer
addu $10, $10, $24 # Build offset to system stack pointer
lw $29, ($10) # Switch to system stack
j $27 # Return to ISR
nop #
/* }
else
{ */
_tx_thread_idle_system_save:
/* Interrupt occurred in the scheduling loop. */
addu $29, $29, 392 # Recover the reserved stack space
j $27 # Return to ISR
nop #
/* }
} */
|