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
|
/***************************************************************************
* Copyright (c) 2025 10xEngineers
*
* 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 */
/** */
/**************************************************************************/
/**************************************************************************/
.section .text
#include "tx_port.h"
.equ TX_TRAP_FRAME_SIZE, TX_RISCV_TRAP_FRAME_SIZE
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_stack_build RISC-V32/GNU */
/* 6.4.x */
/* AUTHOR */
/* */
/* Akif Ejaz, 10xEngineers */
/* */
/* DESCRIPTION */
/* */
/* This function builds a stack frame on the supplied thread's stack. */
/* The stack frame results in a fake interrupt return to the supplied */
/* function pointer. */
/* */
/* INPUT */
/* */
/* thread_ptr Pointer to thread control blk */
/* function_ptr Pointer to return function */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_thread_create Create thread service */
/* */
/**************************************************************************/
/* VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID))
{ */
.global _tx_thread_stack_build
_tx_thread_stack_build:
/* Build a fake interrupt frame. The form of the fake interrupt stack
on the RISC-V should look like the following after it is built:
Reg Index
Stack Top: 1 0 Interrupt stack frame type
x27 1 Initial s11
x26 2 Initial s10
x25 3 Initial s9
x24 4 Initial s8
x23 5 Initial s7
x22 6 Initial s6
x21 7 Initial s5
x20 8 Initial s4
x19 9 Initial s3
x18 10 Initial s2
x9 11 Initial s1
x8 12 Initial s0
x31 13 Initial t6
x30 14 Initial t5
x29 15 Initial t4
x28 16 Initial t3
x7 17 Initial t2
x6 18 Initial t1
x5 19 Initial t0
x17 20 Initial a7
x16 21 Initial a6
x15 22 Initial a5
x14 23 Initial a4
x13 24 Initial a3
x12 25 Initial a2
x11 26 Initial a1
x10 27 Initial a0
x1 28 Initial ra
mstatus 29 Initial mstatus seed
mepc 30 Initial mepc
-- 31 pad (0)
If floating point support (double ABI), byte offsets from
the frame base:
f0-f31 128 + i*8 Initial FP registers (all 0)
fcsr 384 Initial fcsr (0)
pad 388-399 (0)
Stack Bottom: (higher memory address) */
lw t0, 16(a0) // Pickup end of stack area
li t1, ~15 // Build 16-byte alignment mask
and t0, t0, t1 // Make sure 16-byte alignment
/* Actually build the stack frame. */
addi t0, t0, -TX_TRAP_FRAME_SIZE // Allocate space for the stack frame
li t1, 1 // Build stack type
sw t1, 0*4(t0) // Place stack type on the top
sw zero, 1*4(t0) // Initial s11
sw zero, 2*4(t0) // Initial s10
sw zero, 3*4(t0) // Initial s9
sw zero, 4*4(t0) // Initial s8
sw zero, 5*4(t0) // Initial s7
sw zero, 6*4(t0) // Initial s6
sw zero, 7*4(t0) // Initial s5
sw zero, 8*4(t0) // Initial s4
sw zero, 9*4(t0) // Initial s3
sw zero, 10*4(t0) // Initial s2
sw zero, 11*4(t0) // Initial s1
sw zero, 12*4(t0) // Initial s0
sw zero, 13*4(t0) // Initial t6
sw zero, 14*4(t0) // Initial t5
sw zero, 15*4(t0) // Initial t4
sw zero, 16*4(t0) // Initial t3
sw zero, 17*4(t0) // Initial t2
sw zero, 18*4(t0) // Initial t1
sw zero, 19*4(t0) // Initial t0
sw zero, 20*4(t0) // Initial a7
sw zero, 21*4(t0) // Initial a6
sw zero, 22*4(t0) // Initial a5
sw zero, 23*4(t0) // Initial a4
sw zero, 24*4(t0) // Initial a3
sw zero, 25*4(t0) // Initial a2
sw zero, 26*4(t0) // Initial a1
sw zero, 27*4(t0) // Initial a0
sw zero, 28*4(t0) // Initial ra
sw a1, 30*4(t0) // Initial mepc (thread entry point)
sw zero, 31*4(t0) // Pad word (0)
#if defined(__riscv_float_abi_double)
li t1, 0x6000 // mstatus seed: FS = Dirty (bits 14:13 = 11)
sw t1, 29*4(t0) // so the first dispatch restores the clean FP state
/* Zero the whole FP area: f0-f31 double slots (128-383), fcsr (384)
and the pad words up to the frame end. Threads start with clean
FP registers and fcsr = 0. */
addi t1, t0, 32*4 // First FP-area word (offset 128)
addi t2, t0, TX_TRAP_FRAME_SIZE // One past the frame end (offset 400)
_tx_thread_stack_build_fp_zero:
sw zero, 0(t1) // Clear FP-area word
addi t1, t1, 4
bne t1, t2, _tx_thread_stack_build_fp_zero
#else
sw zero, 29*4(t0) // Initial mstatus slot (0, no FP gate)
#endif
/* Setup stack pointer. */
/* thread_ptr -> tx_thread_stack_ptr = t0; */
sw t0, 8(a0) // Save stack pointer in thread's
ret // control block and return
/* } */
|