1 /**
2  * @file
3  * @brief RISCV GCC specific floating point register macros
4  */
5 
6 /*
7  * Copyright (c) 2019, Huang Qi <757509347@qq.com>.
8  *
9  * SPDX-License-Identifier: Apache-2.0
10  */
11 
12 #ifndef _FLOAT_REGS_RISCV_GCC_H
13 #define _FLOAT_REGS_RISCV_GCC_H
14 
15 #if !defined(__GNUC__) || !defined(CONFIG_RISCV)
16 #error __FILE__ goes only with RISCV GCC
17 #endif
18 
19 #include <zephyr/toolchain.h>
20 #include "float_context.h"
21 
22 #ifdef CONFIG_CPU_HAS_FPU_DOUBLE_PRECISION
23 #define RV_FPREG_WIDTH 8
24 #define RV_FPREG_SAVE "fsd "
25 #define RV_FPREG_LOAD "fld "
26 #else
27 #define RV_FPREG_WIDTH 4
28 #define RV_FPREG_SAVE "fsw "
29 #define RV_FPREG_LOAD "flw "
30 #endif
31 
32 /**
33  *
34  * @brief Load all floating point registers
35  *
36  * This function loads ALL floating point registers pointed to by @a regs.
37  * It is expected that a subsequent call to _store_all_float_registers()
38  * will be issued to dump the floating point registers to memory.
39  *
40  * The format/organization of 'struct fp_register_set'; the generic C test
41  * code (main.c) merely treat the register set as an array of bytes.
42  *
43  * The only requirement is that the arch specific implementations of
44  * _load_all_float_registers() and _store_all_float_registers() agree
45  * on the format.
46  *
47  */
_load_all_float_registers(struct fp_register_set * regs)48 static inline void _load_all_float_registers(struct fp_register_set *regs)
49 {
50 	__asm__(
51 		"mv  t0, %0\n"
52 		"mv  t1, %1\n"
53 		RV_FPREG_LOAD "f0, 0(t0)\n"
54 		"add t0, t0, t1\n"
55 		RV_FPREG_LOAD "f1, 0(t0)\n"
56 		"add t0, t0, t1\n"
57 		RV_FPREG_LOAD "f2, 0(t0)\n"
58 		"add t0, t0, t1\n"
59 		RV_FPREG_LOAD "f3, 0(t0)\n"
60 		"add t0, t0, t1\n"
61 		RV_FPREG_LOAD "f4, 0(t0)\n"
62 		"add t0, t0, t1\n"
63 		RV_FPREG_LOAD "f5, 0(t0)\n"
64 		"add t0, t0, t1\n"
65 		RV_FPREG_LOAD "f6, 0(t0)\n"
66 		"add t0, t0, t1\n"
67 		RV_FPREG_LOAD "f7, 0(t0)\n"
68 		"add t0, t0, t1\n"
69 		RV_FPREG_LOAD "f8, 0(t0)\n"
70 		"add t0, t0, t1\n"
71 		RV_FPREG_LOAD "f9, 0(t0)\n"
72 		"add t0, t0, t1\n"
73 		RV_FPREG_LOAD "f10, 0(t0)\n"
74 		"add t0, t0, t1\n"
75 		RV_FPREG_LOAD "f11, 0(t0)\n"
76 		"add t0, t0, t1\n"
77 		RV_FPREG_LOAD "f12, 0(t0)\n"
78 		"add t0, t0, t1\n"
79 		RV_FPREG_LOAD "f13, 0(t0)\n"
80 		"add t0, t0, t1\n"
81 		RV_FPREG_LOAD "f14, 0(t0)\n"
82 		"add t0, t0, t1\n"
83 		RV_FPREG_LOAD "f15, 0(t0)\n"
84 		"add t0, t0, t1\n"
85 		RV_FPREG_LOAD "f16, 0(t0)\n"
86 		"add t0, t0, t1\n"
87 		RV_FPREG_LOAD "f17, 0(t0)\n"
88 		"add t0, t0, t1\n"
89 		RV_FPREG_LOAD "f18, 0(t0)\n"
90 		"add t0, t0, t1\n"
91 		RV_FPREG_LOAD "f19, 0(t0)\n"
92 		"add t0, t0, t1\n"
93 		RV_FPREG_LOAD "f20, 0(t0)\n"
94 		"add t0, t0, t1\n"
95 		RV_FPREG_LOAD "f21, 0(t0)\n"
96 		"add t0, t0, t1\n"
97 		RV_FPREG_LOAD "f22, 0(t0)\n"
98 		"add t0, t0, t1\n"
99 		RV_FPREG_LOAD "f23, 0(t0)\n"
100 		"add t0, t0, t1\n"
101 		RV_FPREG_LOAD "f24, 0(t0)\n"
102 		"add t0, t0, t1\n"
103 		RV_FPREG_LOAD "f25, 0(t0)\n"
104 		"add t0, t0, t1\n"
105 		RV_FPREG_LOAD "f26, 0(t0)\n"
106 		"add t0, t0, t1\n"
107 		RV_FPREG_LOAD "f27, 0(t0)\n"
108 		"add t0, t0, t1\n"
109 		RV_FPREG_LOAD "f28, 0(t0)\n"
110 		"add t0, t0, t1\n"
111 		RV_FPREG_LOAD "f29, 0(t0)\n"
112 		"add t0, t0, t1\n"
113 		RV_FPREG_LOAD "f30, 0(t0)\n"
114 		"add t0, t0, t1\n"
115 		RV_FPREG_LOAD "f31, 0(t0)\n"
116 		:
117 		: "r"(regs), "r"(RV_FPREG_WIDTH)
118 		: "t0", "t1"
119 	);
120 }
121 
122 /**
123  *
124  * @brief Dump all floating point registers to memory
125  *
126  * This function stores ALL floating point registers to the memory buffer
127  * specified by @a regs. It is expected that a previous invocation of
128  * _load_all_float_registers() occurred to load all the floating point
129  * registers from a memory buffer.
130  *
131  */
132 
_store_all_float_registers(struct fp_register_set * regs)133 static inline void _store_all_float_registers(struct fp_register_set *regs)
134 {
135 	__asm__ volatile(
136 		"mv t0, %0\n\t"
137 		"mv t1, %1\n\t"
138 		RV_FPREG_SAVE "f0, 0(t0)\n"
139 		"add t0, t0, t1\n"
140 		RV_FPREG_SAVE "f1, 0(t0)\n"
141 		"add t0, t0, t1\n"
142 		RV_FPREG_SAVE "f2, 0(t0)\n"
143 		"add t0, t0, t1\n"
144 		RV_FPREG_SAVE "f3, 0(t0)\n"
145 		"add t0, t0, t1\n"
146 		RV_FPREG_SAVE "f4, 0(t0)\n"
147 		"add t0, t0, t1\n"
148 		RV_FPREG_SAVE "f5, 0(t0)\n"
149 		"add t0, t0, t1\n"
150 		RV_FPREG_SAVE "f6, 0(t0)\n"
151 		"add t0, t0, t1\n"
152 		RV_FPREG_SAVE "f7, 0(t0)\n"
153 		"add t0, t0, t1\n"
154 		RV_FPREG_SAVE "f8, 0(t0)\n"
155 		"add t0, t0, t1\n"
156 		RV_FPREG_SAVE "f9, 0(t0)\n"
157 		"add t0, t0, t1\n"
158 		RV_FPREG_SAVE "f10, 0(t0)\n"
159 		"add t0, t0, t1\n"
160 		RV_FPREG_SAVE "f11, 0(t0)\n"
161 		"add t0, t0, t1\n"
162 		RV_FPREG_SAVE "f12, 0(t0)\n"
163 		"add t0, t0, t1\n"
164 		RV_FPREG_SAVE "f13, 0(t0)\n"
165 		"add t0, t0, t1\n"
166 		RV_FPREG_SAVE "f14, 0(t0)\n"
167 		"add t0, t0, t1\n"
168 		RV_FPREG_SAVE "f15, 0(t0)\n"
169 		"add t0, t0, t1\n"
170 		RV_FPREG_SAVE "f16, 0(t0)\n"
171 		"add t0, t0, t1\n"
172 		RV_FPREG_SAVE "f17, 0(t0)\n"
173 		"add t0, t0, t1\n"
174 		RV_FPREG_SAVE "f18, 0(t0)\n"
175 		"add t0, t0, t1\n"
176 		RV_FPREG_SAVE "f19, 0(t0)\n"
177 		"add t0, t0, t1\n"
178 		RV_FPREG_SAVE "f20, 0(t0)\n"
179 		"add t0, t0, t1\n"
180 		RV_FPREG_SAVE "f21, 0(t0)\n"
181 		"add t0, t0, t1\n"
182 		RV_FPREG_SAVE "f22, 0(t0)\n"
183 		"add t0, t0, t1\n"
184 		RV_FPREG_SAVE "f23, 0(t0)\n"
185 		"add t0, t0, t1\n"
186 		RV_FPREG_SAVE "f24, 0(t0)\n"
187 		"add t0, t0, t1\n"
188 		RV_FPREG_SAVE "f25, 0(t0)\n"
189 		"add t0, t0, t1\n"
190 		RV_FPREG_SAVE "f26, 0(t0)\n"
191 		"add t0, t0, t1\n"
192 		RV_FPREG_SAVE "f27, 0(t0)\n"
193 		"add t0, t0, t1\n"
194 		RV_FPREG_SAVE "f28, 0(t0)\n"
195 		"add t0, t0, t1\n"
196 		RV_FPREG_SAVE "f29, 0(t0)\n"
197 		"add t0, t0, t1\n"
198 		RV_FPREG_SAVE "f30, 0(t0)\n"
199 		"add t0, t0, t1\n"
200 		RV_FPREG_SAVE "f31, 0(t0)\n"
201 		:
202 		: "r"(regs), "r"(RV_FPREG_WIDTH)
203 		: "t0", "t1", "memory"
204 	);
205 }
206 
207 /**
208  *
209  * @brief Load then dump all float registers to memory
210  *
211  * This function loads ALL floating point registers from the memory buffer
212  * specified by @a regs, and then stores them back to that buffer.
213  *
214  * This routine is called by a high priority thread prior to calling a primitive
215  * that pends and triggers a co-operative context switch to a low priority
216  * thread.
217  *
218  */
219 
_load_then_store_all_float_registers(struct fp_register_set * regs)220 static inline void _load_then_store_all_float_registers(struct fp_register_set
221 							*regs)
222 {
223 	_load_all_float_registers(regs);
224 	_store_all_float_registers(regs);
225 }
226 #endif /* _FLOAT_REGS_ARC_GCC_H */
227