1/*
2 * RISC-V translation routines for the RV64F Standard Extension.
3 *
4 * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
5 * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
6 * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2 or later, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#define REQUIRE_FPU do {\
22 if (ctx->mstatus_fs == 0) \
23 return false; \
24} while (0)
25
26static bool trans_flw(DisasContext *ctx, arg_flw *a)
27{
28 TCGv t0 = tcg_temp_new();
29 gen_get_gpr(t0, a->rs1);
30 REQUIRE_FPU;
31 REQUIRE_EXT(ctx, RVF);
32 tcg_gen_addi_tl(t0, t0, a->imm);
33
34 tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEUL);
35 /* RISC-V requires NaN-boxing of narrower width floating point values */
36 tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 0xffffffff00000000ULL);
37
38 tcg_temp_free(t0);
39 mark_fs_dirty(ctx);
40 return true;
41}
42
43static bool trans_fsw(DisasContext *ctx, arg_fsw *a)
44{
45 TCGv t0 = tcg_temp_new();
46 gen_get_gpr(t0, a->rs1);
47
48 REQUIRE_FPU;
49 REQUIRE_EXT(ctx, RVF);
50 tcg_gen_addi_tl(t0, t0, a->imm);
51
52 tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEUL);
53
54 tcg_temp_free(t0);
55 mark_fs_dirty(ctx);
56 return true;
57}
58
59static bool trans_fmadd_s(DisasContext *ctx, arg_fmadd_s *a)
60{
61 REQUIRE_FPU;
62 REQUIRE_EXT(ctx, RVF);
63 gen_set_rm(ctx, a->rm);
64 gen_helper_fmadd_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
65 cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
66 mark_fs_dirty(ctx);
67 return true;
68}
69
70static bool trans_fmsub_s(DisasContext *ctx, arg_fmsub_s *a)
71{
72 REQUIRE_FPU;
73 REQUIRE_EXT(ctx, RVF);
74 gen_set_rm(ctx, a->rm);
75 gen_helper_fmsub_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
76 cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
77 mark_fs_dirty(ctx);
78 return true;
79}
80
81static bool trans_fnmsub_s(DisasContext *ctx, arg_fnmsub_s *a)
82{
83 REQUIRE_FPU;
84 REQUIRE_EXT(ctx, RVF);
85 gen_set_rm(ctx, a->rm);
86 gen_helper_fnmsub_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
87 cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
88 mark_fs_dirty(ctx);
89 return true;
90}
91
92static bool trans_fnmadd_s(DisasContext *ctx, arg_fnmadd_s *a)
93{
94 REQUIRE_FPU;
95 REQUIRE_EXT(ctx, RVF);
96 gen_set_rm(ctx, a->rm);
97 gen_helper_fnmadd_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
98 cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
99 mark_fs_dirty(ctx);
100 return true;
101}
102
103static bool trans_fadd_s(DisasContext *ctx, arg_fadd_s *a)
104{
105 REQUIRE_FPU;
106 REQUIRE_EXT(ctx, RVF);
107
108 gen_set_rm(ctx, a->rm);
109 gen_helper_fadd_s(cpu_fpr[a->rd], cpu_env,
110 cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
111 mark_fs_dirty(ctx);
112 return true;
113}
114
115static bool trans_fsub_s(DisasContext *ctx, arg_fsub_s *a)
116{
117 REQUIRE_FPU;
118 REQUIRE_EXT(ctx, RVF);
119
120 gen_set_rm(ctx, a->rm);
121 gen_helper_fsub_s(cpu_fpr[a->rd], cpu_env,
122 cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
123 mark_fs_dirty(ctx);
124 return true;
125}
126
127static bool trans_fmul_s(DisasContext *ctx, arg_fmul_s *a)
128{
129 REQUIRE_FPU;
130 REQUIRE_EXT(ctx, RVF);
131
132 gen_set_rm(ctx, a->rm);
133 gen_helper_fmul_s(cpu_fpr[a->rd], cpu_env,
134 cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
135 mark_fs_dirty(ctx);
136 return true;
137}
138
139static bool trans_fdiv_s(DisasContext *ctx, arg_fdiv_s *a)
140{
141 REQUIRE_FPU;
142 REQUIRE_EXT(ctx, RVF);
143
144 gen_set_rm(ctx, a->rm);
145 gen_helper_fdiv_s(cpu_fpr[a->rd], cpu_env,
146 cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
147 mark_fs_dirty(ctx);
148 return true;
149}
150
151static bool trans_fsqrt_s(DisasContext *ctx, arg_fsqrt_s *a)
152{
153 REQUIRE_FPU;
154 REQUIRE_EXT(ctx, RVF);
155
156 gen_set_rm(ctx, a->rm);
157 gen_helper_fsqrt_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
158 mark_fs_dirty(ctx);
159 return true;
160}
161
162static bool trans_fsgnj_s(DisasContext *ctx, arg_fsgnj_s *a)
163{
164 REQUIRE_FPU;
165 REQUIRE_EXT(ctx, RVF);
166 if (a->rs1 == a->rs2) { /* FMOV */
167 tcg_gen_mov_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1]);
168 } else { /* FSGNJ */
169 tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rs2], cpu_fpr[a->rs1],
170 0, 31);
171 }
172 mark_fs_dirty(ctx);
173 return true;
174}
175
176static bool trans_fsgnjn_s(DisasContext *ctx, arg_fsgnjn_s *a)
177{
178 REQUIRE_FPU;
179 REQUIRE_EXT(ctx, RVF);
180 if (a->rs1 == a->rs2) { /* FNEG */
181 tcg_gen_xori_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], INT32_MIN);
182 } else {
183 TCGv_i64 t0 = tcg_temp_new_i64();
184 tcg_gen_not_i64(t0, cpu_fpr[a->rs2]);
185 tcg_gen_deposit_i64(cpu_fpr[a->rd], t0, cpu_fpr[a->rs1], 0, 31);
186 tcg_temp_free_i64(t0);
187 }
188 mark_fs_dirty(ctx);
189 return true;
190}
191
192static bool trans_fsgnjx_s(DisasContext *ctx, arg_fsgnjx_s *a)
193{
194 REQUIRE_FPU;
195 REQUIRE_EXT(ctx, RVF);
196 if (a->rs1 == a->rs2) { /* FABS */
197 tcg_gen_andi_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], ~INT32_MIN);
198 } else {
199 TCGv_i64 t0 = tcg_temp_new_i64();
200 tcg_gen_andi_i64(t0, cpu_fpr[a->rs2], INT32_MIN);
201 tcg_gen_xor_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], t0);
202 tcg_temp_free_i64(t0);
203 }
204 mark_fs_dirty(ctx);
205 return true;
206}
207
208static bool trans_fmin_s(DisasContext *ctx, arg_fmin_s *a)
209{
210 REQUIRE_FPU;
211 REQUIRE_EXT(ctx, RVF);
212
213 gen_helper_fmin_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
214 cpu_fpr[a->rs2]);
215 mark_fs_dirty(ctx);
216 return true;
217}
218
219static bool trans_fmax_s(DisasContext *ctx, arg_fmax_s *a)
220{
221 REQUIRE_FPU;
222 REQUIRE_EXT(ctx, RVF);
223
224 gen_helper_fmax_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
225 cpu_fpr[a->rs2]);
226 mark_fs_dirty(ctx);
227 return true;
228}
229
230static bool trans_fcvt_w_s(DisasContext *ctx, arg_fcvt_w_s *a)
231{
232 REQUIRE_FPU;
233 REQUIRE_EXT(ctx, RVF);
234
235 TCGv t0 = tcg_temp_new();
236 gen_set_rm(ctx, a->rm);
237 gen_helper_fcvt_w_s(t0, cpu_env, cpu_fpr[a->rs1]);
238 gen_set_gpr(a->rd, t0);
239 tcg_temp_free(t0);
240
241 return true;
242}
243
244static bool trans_fcvt_wu_s(DisasContext *ctx, arg_fcvt_wu_s *a)
245{
246 REQUIRE_FPU;
247 REQUIRE_EXT(ctx, RVF);
248
249 TCGv t0 = tcg_temp_new();
250 gen_set_rm(ctx, a->rm);
251 gen_helper_fcvt_wu_s(t0, cpu_env, cpu_fpr[a->rs1]);
252 gen_set_gpr(a->rd, t0);
253 tcg_temp_free(t0);
254
255 return true;
256}
257
258static bool trans_fmv_x_w(DisasContext *ctx, arg_fmv_x_w *a)
259{
260 /* NOTE: This was FMV.X.S in an earlier version of the ISA spec! */
261 REQUIRE_FPU;
262 REQUIRE_EXT(ctx, RVF);
263
264 TCGv t0 = tcg_temp_new();
265
266#if defined(TARGET_RISCV64)
267 tcg_gen_ext32s_tl(t0, cpu_fpr[a->rs1]);
268#else
269 tcg_gen_extrl_i64_i32(t0, cpu_fpr[a->rs1]);
270#endif
271
272 gen_set_gpr(a->rd, t0);
273 tcg_temp_free(t0);
274
275 return true;
276}
277
278static bool trans_feq_s(DisasContext *ctx, arg_feq_s *a)
279{
280 REQUIRE_FPU;
281 REQUIRE_EXT(ctx, RVF);
282 TCGv t0 = tcg_temp_new();
283 gen_helper_feq_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
284 gen_set_gpr(a->rd, t0);
285 tcg_temp_free(t0);
286 return true;
287}
288
289static bool trans_flt_s(DisasContext *ctx, arg_flt_s *a)
290{
291 REQUIRE_FPU;
292 REQUIRE_EXT(ctx, RVF);
293 TCGv t0 = tcg_temp_new();
294 gen_helper_flt_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
295 gen_set_gpr(a->rd, t0);
296 tcg_temp_free(t0);
297 return true;
298}
299
300static bool trans_fle_s(DisasContext *ctx, arg_fle_s *a)
301{
302 REQUIRE_FPU;
303 REQUIRE_EXT(ctx, RVF);
304 TCGv t0 = tcg_temp_new();
305 gen_helper_fle_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
306 gen_set_gpr(a->rd, t0);
307 tcg_temp_free(t0);
308 return true;
309}
310
311static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a)
312{
313 REQUIRE_FPU;
314 REQUIRE_EXT(ctx, RVF);
315
316 TCGv t0 = tcg_temp_new();
317
318 gen_helper_fclass_s(t0, cpu_fpr[a->rs1]);
319
320 gen_set_gpr(a->rd, t0);
321 tcg_temp_free(t0);
322
323 return true;
324}
325
326static bool trans_fcvt_s_w(DisasContext *ctx, arg_fcvt_s_w *a)
327{
328 REQUIRE_FPU;
329 REQUIRE_EXT(ctx, RVF);
330
331 TCGv t0 = tcg_temp_new();
332 gen_get_gpr(t0, a->rs1);
333
334 gen_set_rm(ctx, a->rm);
335 gen_helper_fcvt_s_w(cpu_fpr[a->rd], cpu_env, t0);
336
337 mark_fs_dirty(ctx);
338 tcg_temp_free(t0);
339
340 return true;
341}
342
343static bool trans_fcvt_s_wu(DisasContext *ctx, arg_fcvt_s_wu *a)
344{
345 REQUIRE_FPU;
346 REQUIRE_EXT(ctx, RVF);
347
348 TCGv t0 = tcg_temp_new();
349 gen_get_gpr(t0, a->rs1);
350
351 gen_set_rm(ctx, a->rm);
352 gen_helper_fcvt_s_wu(cpu_fpr[a->rd], cpu_env, t0);
353
354 mark_fs_dirty(ctx);
355 tcg_temp_free(t0);
356
357 return true;
358}
359
360static bool trans_fmv_w_x(DisasContext *ctx, arg_fmv_w_x *a)
361{
362 /* NOTE: This was FMV.S.X in an earlier version of the ISA spec! */
363 REQUIRE_FPU;
364 REQUIRE_EXT(ctx, RVF);
365
366 TCGv t0 = tcg_temp_new();
367 gen_get_gpr(t0, a->rs1);
368
369#if defined(TARGET_RISCV64)
370 tcg_gen_mov_i64(cpu_fpr[a->rd], t0);
371#else
372 tcg_gen_extu_i32_i64(cpu_fpr[a->rd], t0);
373#endif
374
375 mark_fs_dirty(ctx);
376 tcg_temp_free(t0);
377
378 return true;
379}
380
381#ifdef TARGET_RISCV64
382static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a)
383{
384 REQUIRE_FPU;
385 REQUIRE_EXT(ctx, RVF);
386
387 TCGv t0 = tcg_temp_new();
388 gen_set_rm(ctx, a->rm);
389 gen_helper_fcvt_l_s(t0, cpu_env, cpu_fpr[a->rs1]);
390 gen_set_gpr(a->rd, t0);
391 tcg_temp_free(t0);
392 return true;
393}
394
395static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a)
396{
397 REQUIRE_FPU;
398 REQUIRE_EXT(ctx, RVF);
399
400 TCGv t0 = tcg_temp_new();
401 gen_set_rm(ctx, a->rm);
402 gen_helper_fcvt_lu_s(t0, cpu_env, cpu_fpr[a->rs1]);
403 gen_set_gpr(a->rd, t0);
404 tcg_temp_free(t0);
405 return true;
406}
407
408static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a)
409{
410 REQUIRE_FPU;
411 REQUIRE_EXT(ctx, RVF);
412
413 TCGv t0 = tcg_temp_new();
414 gen_get_gpr(t0, a->rs1);
415
416 gen_set_rm(ctx, a->rm);
417 gen_helper_fcvt_s_l(cpu_fpr[a->rd], cpu_env, t0);
418
419 mark_fs_dirty(ctx);
420 tcg_temp_free(t0);
421 return true;
422}
423
424static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a)
425{
426 REQUIRE_FPU;
427 REQUIRE_EXT(ctx, RVF);
428
429 TCGv t0 = tcg_temp_new();
430 gen_get_gpr(t0, a->rs1);
431
432 gen_set_rm(ctx, a->rm);
433 gen_helper_fcvt_s_lu(cpu_fpr[a->rd], cpu_env, t0);
434
435 mark_fs_dirty(ctx);
436 tcg_temp_free(t0);
437 return true;
438}
439#endif
440