Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/riscv/kernel/fpu.S
26451 views
1
/* SPDX-License-Identifier: GPL-2.0 */
2
/*
3
* Copyright (C) 2012 Regents of the University of California
4
* Copyright (C) 2017 SiFive
5
*
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* as published by the Free Software Foundation, version 2.
9
*
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
14
*/
15
16
#include <linux/linkage.h>
17
18
#include <asm/asm.h>
19
#include <asm/csr.h>
20
#include <asm/asm-offsets.h>
21
22
SYM_FUNC_START(__fstate_save)
23
li a2, TASK_THREAD_F0
24
add a0, a0, a2
25
li t1, SR_FS
26
csrs CSR_STATUS, t1
27
frcsr t0
28
fsd f0, TASK_THREAD_F0_F0(a0)
29
fsd f1, TASK_THREAD_F1_F0(a0)
30
fsd f2, TASK_THREAD_F2_F0(a0)
31
fsd f3, TASK_THREAD_F3_F0(a0)
32
fsd f4, TASK_THREAD_F4_F0(a0)
33
fsd f5, TASK_THREAD_F5_F0(a0)
34
fsd f6, TASK_THREAD_F6_F0(a0)
35
fsd f7, TASK_THREAD_F7_F0(a0)
36
fsd f8, TASK_THREAD_F8_F0(a0)
37
fsd f9, TASK_THREAD_F9_F0(a0)
38
fsd f10, TASK_THREAD_F10_F0(a0)
39
fsd f11, TASK_THREAD_F11_F0(a0)
40
fsd f12, TASK_THREAD_F12_F0(a0)
41
fsd f13, TASK_THREAD_F13_F0(a0)
42
fsd f14, TASK_THREAD_F14_F0(a0)
43
fsd f15, TASK_THREAD_F15_F0(a0)
44
fsd f16, TASK_THREAD_F16_F0(a0)
45
fsd f17, TASK_THREAD_F17_F0(a0)
46
fsd f18, TASK_THREAD_F18_F0(a0)
47
fsd f19, TASK_THREAD_F19_F0(a0)
48
fsd f20, TASK_THREAD_F20_F0(a0)
49
fsd f21, TASK_THREAD_F21_F0(a0)
50
fsd f22, TASK_THREAD_F22_F0(a0)
51
fsd f23, TASK_THREAD_F23_F0(a0)
52
fsd f24, TASK_THREAD_F24_F0(a0)
53
fsd f25, TASK_THREAD_F25_F0(a0)
54
fsd f26, TASK_THREAD_F26_F0(a0)
55
fsd f27, TASK_THREAD_F27_F0(a0)
56
fsd f28, TASK_THREAD_F28_F0(a0)
57
fsd f29, TASK_THREAD_F29_F0(a0)
58
fsd f30, TASK_THREAD_F30_F0(a0)
59
fsd f31, TASK_THREAD_F31_F0(a0)
60
sw t0, TASK_THREAD_FCSR_F0(a0)
61
csrc CSR_STATUS, t1
62
ret
63
SYM_FUNC_END(__fstate_save)
64
65
SYM_FUNC_START(__fstate_restore)
66
li a2, TASK_THREAD_F0
67
add a0, a0, a2
68
li t1, SR_FS
69
lw t0, TASK_THREAD_FCSR_F0(a0)
70
csrs CSR_STATUS, t1
71
fld f0, TASK_THREAD_F0_F0(a0)
72
fld f1, TASK_THREAD_F1_F0(a0)
73
fld f2, TASK_THREAD_F2_F0(a0)
74
fld f3, TASK_THREAD_F3_F0(a0)
75
fld f4, TASK_THREAD_F4_F0(a0)
76
fld f5, TASK_THREAD_F5_F0(a0)
77
fld f6, TASK_THREAD_F6_F0(a0)
78
fld f7, TASK_THREAD_F7_F0(a0)
79
fld f8, TASK_THREAD_F8_F0(a0)
80
fld f9, TASK_THREAD_F9_F0(a0)
81
fld f10, TASK_THREAD_F10_F0(a0)
82
fld f11, TASK_THREAD_F11_F0(a0)
83
fld f12, TASK_THREAD_F12_F0(a0)
84
fld f13, TASK_THREAD_F13_F0(a0)
85
fld f14, TASK_THREAD_F14_F0(a0)
86
fld f15, TASK_THREAD_F15_F0(a0)
87
fld f16, TASK_THREAD_F16_F0(a0)
88
fld f17, TASK_THREAD_F17_F0(a0)
89
fld f18, TASK_THREAD_F18_F0(a0)
90
fld f19, TASK_THREAD_F19_F0(a0)
91
fld f20, TASK_THREAD_F20_F0(a0)
92
fld f21, TASK_THREAD_F21_F0(a0)
93
fld f22, TASK_THREAD_F22_F0(a0)
94
fld f23, TASK_THREAD_F23_F0(a0)
95
fld f24, TASK_THREAD_F24_F0(a0)
96
fld f25, TASK_THREAD_F25_F0(a0)
97
fld f26, TASK_THREAD_F26_F0(a0)
98
fld f27, TASK_THREAD_F27_F0(a0)
99
fld f28, TASK_THREAD_F28_F0(a0)
100
fld f29, TASK_THREAD_F29_F0(a0)
101
fld f30, TASK_THREAD_F30_F0(a0)
102
fld f31, TASK_THREAD_F31_F0(a0)
103
fscsr t0
104
csrc CSR_STATUS, t1
105
ret
106
SYM_FUNC_END(__fstate_restore)
107
108
#define get_f32(which) fmv.x.s a0, which; j 2f
109
#define put_f32(which) fmv.s.x which, a1; j 2f
110
#if __riscv_xlen == 64
111
# define get_f64(which) fmv.x.d a0, which; j 2f
112
# define put_f64(which) fmv.d.x which, a1; j 2f
113
#else
114
# define get_f64(which) fsd which, 0(a1); j 2f
115
# define put_f64(which) fld which, 0(a1); j 2f
116
#endif
117
118
.macro fp_access_prologue
119
/*
120
* Compute jump offset to store the correct FP register since we don't
121
* have indirect FP register access
122
*/
123
sll t0, a0, 3
124
la t2, 1f
125
add t0, t0, t2
126
li t1, SR_FS
127
csrs CSR_STATUS, t1
128
jr t0
129
1:
130
.endm
131
132
.macro fp_access_epilogue
133
2:
134
csrc CSR_STATUS, t1
135
ret
136
.endm
137
138
#define fp_access_body(__access_func) \
139
__access_func(f0); \
140
__access_func(f1); \
141
__access_func(f2); \
142
__access_func(f3); \
143
__access_func(f4); \
144
__access_func(f5); \
145
__access_func(f6); \
146
__access_func(f7); \
147
__access_func(f8); \
148
__access_func(f9); \
149
__access_func(f10); \
150
__access_func(f11); \
151
__access_func(f12); \
152
__access_func(f13); \
153
__access_func(f14); \
154
__access_func(f15); \
155
__access_func(f16); \
156
__access_func(f17); \
157
__access_func(f18); \
158
__access_func(f19); \
159
__access_func(f20); \
160
__access_func(f21); \
161
__access_func(f22); \
162
__access_func(f23); \
163
__access_func(f24); \
164
__access_func(f25); \
165
__access_func(f26); \
166
__access_func(f27); \
167
__access_func(f28); \
168
__access_func(f29); \
169
__access_func(f30); \
170
__access_func(f31)
171
172
173
#ifdef CONFIG_RISCV_SCALAR_MISALIGNED
174
175
/*
176
* Disable compressed instructions set to keep a constant offset between FP
177
* load/store/move instructions
178
*/
179
.option norvc
180
/*
181
* put_f32_reg - Set a FP register from a register containing the value
182
* a0 = FP register index to be set
183
* a1 = value to be loaded in the FP register
184
*/
185
SYM_FUNC_START(put_f32_reg)
186
fp_access_prologue
187
fp_access_body(put_f32)
188
fp_access_epilogue
189
SYM_FUNC_END(put_f32_reg)
190
191
/*
192
* get_f32_reg - Get a FP register value and return it
193
* a0 = FP register index to be retrieved
194
*/
195
SYM_FUNC_START(get_f32_reg)
196
fp_access_prologue
197
fp_access_body(get_f32)
198
fp_access_epilogue
199
SYM_FUNC_END(get_f32_reg)
200
201
/*
202
* put_f64_reg - Set a 64 bits FP register from a value or a pointer.
203
* a0 = FP register index to be set
204
* a1 = value/pointer to be loaded in the FP register (when xlen == 32 bits, we
205
* load the value to a pointer).
206
*/
207
SYM_FUNC_START(put_f64_reg)
208
fp_access_prologue
209
fp_access_body(put_f64)
210
fp_access_epilogue
211
SYM_FUNC_END(put_f64_reg)
212
213
/*
214
* get_f64_reg - Get a 64 bits FP register value and returned it or store it to
215
* a pointer.
216
* a0 = FP register index to be retrieved
217
* a1 = If xlen == 32, pointer which should be loaded with the FP register value
218
* or unused if xlen == 64. In which case the FP register value is returned
219
* through a0
220
*/
221
SYM_FUNC_START(get_f64_reg)
222
fp_access_prologue
223
fp_access_body(get_f64)
224
fp_access_epilogue
225
SYM_FUNC_END(get_f64_reg)
226
227
#endif /* CONFIG_RISCV_SCALAR_MISALIGNED */
228
229