master
inc 615 lines 15.4 KB
Raw
1 /*
2 * RISC-V translation routines for the RV64D 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_ZDINX_OR_D(ctx) do { \
22 if (!ctx->cfg_ptr->ext_zdinx) { \
23 REQUIRE_EXT(ctx, RVD); \
24 } \
25 } while (0)
26
27 #define REQUIRE_EVEN(ctx, reg) do { \
28 if (ctx->cfg_ptr->ext_zdinx && (get_xl(ctx) == MXL_RV32) && \
29 ((reg) & 0x1)) { \
30 return false; \
31 } \
32 } while (0)
33
34 #define REQUIRE_ZCD_OR_DC(ctx) do { \
35 if (!ctx->cfg_ptr->ext_zcd) { \
36 if (!has_ext(ctx, RVD) || !has_ext(ctx, RVC)) { \
37 return false; \
38 } \
39 } \
40 } while (0)
41
42 static bool trans_fld(DisasContext *ctx, arg_fld *a)
43 {
44 TCGv addr;
45 MemOp memop = MO_UQ;
46
47 REQUIRE_FPU;
48 REQUIRE_EXT(ctx, RVD);
49
50 /*
51 * FLD and FSD are only guaranteed to execute atomically if the effective
52 * address is naturally aligned and XLEN≥64. Also, zama16b applies to
53 * loads and stores of no more than MXLEN bits defined in the F, D, and
54 * Q extensions.
55 */
56 if (get_xl_max(ctx) == MXL_RV32) {
57 memop |= MO_ATOM_NONE;
58 } else if (ctx->cfg_ptr->ext_zama16b) {
59 memop |= MO_ATOM_WITHIN16;
60 } else {
61 memop |= MO_ATOM_IFALIGN;
62 }
63 memop |= ctx->mo_endianness;
64 if (!ctx->cfg_ptr->ext_zicclsm) {
65 memop |= MO_ALIGN;
66 }
67
68 decode_save_opc(ctx, 0);
69 addr = get_address(ctx, a->rs1, a->imm);
70 tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, memop);
71
72 mark_fs_dirty(ctx);
73 return true;
74 }
75
76 static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
77 {
78 TCGv addr;
79 MemOp memop = MO_UQ;
80
81 REQUIRE_FPU;
82 REQUIRE_EXT(ctx, RVD);
83
84 if (get_xl_max(ctx) == MXL_RV32) {
85 memop |= MO_ATOM_NONE;
86 } else if (ctx->cfg_ptr->ext_zama16b) {
87 memop |= MO_ATOM_WITHIN16;
88 } else {
89 memop |= MO_ATOM_IFALIGN;
90 }
91 memop |= ctx->mo_endianness;
92 if (!ctx->cfg_ptr->ext_zicclsm) {
93 memop |= MO_ALIGN;
94 }
95
96 decode_save_opc(ctx, 0);
97 addr = get_address(ctx, a->rs1, a->imm);
98 tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, memop);
99 return true;
100 }
101
102 static bool trans_c_fld(DisasContext *ctx, arg_fld *a)
103 {
104 REQUIRE_ZCD_OR_DC(ctx);
105 return trans_fld(ctx, a);
106 }
107
108 static bool trans_c_fsd(DisasContext *ctx, arg_fsd *a)
109 {
110 REQUIRE_ZCD_OR_DC(ctx);
111 return trans_fsd(ctx, a);
112 }
113
114 static bool trans_fmadd_d(DisasContext *ctx, arg_fmadd_d *a)
115 {
116 REQUIRE_FPU;
117 REQUIRE_ZDINX_OR_D(ctx);
118 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2 | a->rs3);
119
120 TCGv_i64 dest = dest_fpr(ctx, a->rd);
121 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
122 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
123 TCGv_i64 src3 = get_fpr_d(ctx, a->rs3);
124
125 gen_set_rm(ctx, a->rm);
126 gen_helper_fmadd_d(dest, tcg_env, src1, src2, src3);
127 gen_set_fpr_d(ctx, a->rd, dest);
128 mark_fs_dirty(ctx);
129 return true;
130 }
131
132 static bool trans_fmsub_d(DisasContext *ctx, arg_fmsub_d *a)
133 {
134 REQUIRE_FPU;
135 REQUIRE_ZDINX_OR_D(ctx);
136 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2 | a->rs3);
137
138 TCGv_i64 dest = dest_fpr(ctx, a->rd);
139 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
140 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
141 TCGv_i64 src3 = get_fpr_d(ctx, a->rs3);
142
143 gen_set_rm(ctx, a->rm);
144 gen_helper_fmsub_d(dest, tcg_env, src1, src2, src3);
145 gen_set_fpr_d(ctx, a->rd, dest);
146 mark_fs_dirty(ctx);
147 return true;
148 }
149
150 static bool trans_fnmsub_d(DisasContext *ctx, arg_fnmsub_d *a)
151 {
152 REQUIRE_FPU;
153 REQUIRE_ZDINX_OR_D(ctx);
154 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2 | a->rs3);
155
156 TCGv_i64 dest = dest_fpr(ctx, a->rd);
157 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
158 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
159 TCGv_i64 src3 = get_fpr_d(ctx, a->rs3);
160
161 gen_set_rm(ctx, a->rm);
162 gen_helper_fnmsub_d(dest, tcg_env, src1, src2, src3);
163 gen_set_fpr_d(ctx, a->rd, dest);
164 mark_fs_dirty(ctx);
165 return true;
166 }
167
168 static bool trans_fnmadd_d(DisasContext *ctx, arg_fnmadd_d *a)
169 {
170 REQUIRE_FPU;
171 REQUIRE_ZDINX_OR_D(ctx);
172 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2 | a->rs3);
173
174 TCGv_i64 dest = dest_fpr(ctx, a->rd);
175 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
176 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
177 TCGv_i64 src3 = get_fpr_d(ctx, a->rs3);
178
179 gen_set_rm(ctx, a->rm);
180 gen_helper_fnmadd_d(dest, tcg_env, src1, src2, src3);
181 gen_set_fpr_d(ctx, a->rd, dest);
182 mark_fs_dirty(ctx);
183 return true;
184 }
185
186 static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a)
187 {
188 REQUIRE_FPU;
189 REQUIRE_ZDINX_OR_D(ctx);
190 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
191
192 TCGv_i64 dest = dest_fpr(ctx, a->rd);
193 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
194 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
195
196 gen_set_rm(ctx, a->rm);
197 gen_helper_fadd_d(dest, tcg_env, src1, src2);
198 gen_set_fpr_d(ctx, a->rd, dest);
199 mark_fs_dirty(ctx);
200 return true;
201 }
202
203 static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a)
204 {
205 REQUIRE_FPU;
206 REQUIRE_ZDINX_OR_D(ctx);
207 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
208
209 TCGv_i64 dest = dest_fpr(ctx, a->rd);
210 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
211 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
212
213 gen_set_rm(ctx, a->rm);
214 gen_helper_fsub_d(dest, tcg_env, src1, src2);
215 gen_set_fpr_d(ctx, a->rd, dest);
216 mark_fs_dirty(ctx);
217 return true;
218 }
219
220 static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a)
221 {
222 REQUIRE_FPU;
223 REQUIRE_ZDINX_OR_D(ctx);
224 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
225
226 TCGv_i64 dest = dest_fpr(ctx, a->rd);
227 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
228 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
229
230 gen_set_rm(ctx, a->rm);
231 gen_helper_fmul_d(dest, tcg_env, src1, src2);
232 gen_set_fpr_d(ctx, a->rd, dest);
233 mark_fs_dirty(ctx);
234 return true;
235 }
236
237 static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a)
238 {
239 REQUIRE_FPU;
240 REQUIRE_ZDINX_OR_D(ctx);
241 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
242
243 TCGv_i64 dest = dest_fpr(ctx, a->rd);
244 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
245 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
246
247 gen_set_rm(ctx, a->rm);
248 gen_helper_fdiv_d(dest, tcg_env, src1, src2);
249 gen_set_fpr_d(ctx, a->rd, dest);
250 mark_fs_dirty(ctx);
251 return true;
252 }
253
254 static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a)
255 {
256 REQUIRE_FPU;
257 REQUIRE_ZDINX_OR_D(ctx);
258 REQUIRE_EVEN(ctx, a->rd | a->rs1);
259
260 TCGv_i64 dest = dest_fpr(ctx, a->rd);
261 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
262
263 gen_set_rm(ctx, a->rm);
264 gen_helper_fsqrt_d(dest, tcg_env, src1);
265 gen_set_fpr_d(ctx, a->rd, dest);
266 mark_fs_dirty(ctx);
267 return true;
268 }
269
270 static bool trans_fsgnj_d(DisasContext *ctx, arg_fsgnj_d *a)
271 {
272 REQUIRE_FPU;
273 REQUIRE_ZDINX_OR_D(ctx);
274 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
275
276 TCGv_i64 dest = dest_fpr(ctx, a->rd);
277 if (a->rs1 == a->rs2) { /* FMOV */
278 dest = get_fpr_d(ctx, a->rs1);
279 } else {
280 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
281 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
282 tcg_gen_deposit_i64(dest, src2, src1, 0, 63);
283 }
284 gen_set_fpr_d(ctx, a->rd, dest);
285 mark_fs_dirty(ctx);
286 return true;
287 }
288
289 static bool trans_fsgnjn_d(DisasContext *ctx, arg_fsgnjn_d *a)
290 {
291 REQUIRE_FPU;
292 REQUIRE_ZDINX_OR_D(ctx);
293 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
294
295 TCGv_i64 dest = dest_fpr(ctx, a->rd);
296 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
297
298 if (a->rs1 == a->rs2) { /* FNEG */
299 tcg_gen_xori_i64(dest, src1, INT64_MIN);
300 } else {
301 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
302 TCGv_i64 t0 = tcg_temp_new_i64();
303 tcg_gen_not_i64(t0, src2);
304 tcg_gen_deposit_i64(dest, t0, src1, 0, 63);
305 }
306 gen_set_fpr_d(ctx, a->rd, dest);
307 mark_fs_dirty(ctx);
308 return true;
309 }
310
311 static bool trans_fsgnjx_d(DisasContext *ctx, arg_fsgnjx_d *a)
312 {
313 REQUIRE_FPU;
314 REQUIRE_ZDINX_OR_D(ctx);
315 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
316
317 TCGv_i64 dest = dest_fpr(ctx, a->rd);
318 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
319
320 if (a->rs1 == a->rs2) { /* FABS */
321 tcg_gen_andi_i64(dest, src1, ~INT64_MIN);
322 } else {
323 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
324 TCGv_i64 t0 = tcg_temp_new_i64();
325 tcg_gen_andi_i64(t0, src2, INT64_MIN);
326 tcg_gen_xor_i64(dest, src1, t0);
327 }
328 gen_set_fpr_d(ctx, a->rd, dest);
329 mark_fs_dirty(ctx);
330 return true;
331 }
332
333 static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a)
334 {
335 REQUIRE_FPU;
336 REQUIRE_ZDINX_OR_D(ctx);
337 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
338
339 TCGv_i64 dest = dest_fpr(ctx, a->rd);
340 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
341 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
342
343 gen_helper_fmin_d(dest, tcg_env, src1, src2);
344 gen_set_fpr_d(ctx, a->rd, dest);
345 mark_fs_dirty(ctx);
346 return true;
347 }
348
349 static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a)
350 {
351 REQUIRE_FPU;
352 REQUIRE_ZDINX_OR_D(ctx);
353 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
354
355 TCGv_i64 dest = dest_fpr(ctx, a->rd);
356 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
357 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
358
359 gen_helper_fmax_d(dest, tcg_env, src1, src2);
360 gen_set_fpr_d(ctx, a->rd, dest);
361 mark_fs_dirty(ctx);
362 return true;
363 }
364
365 static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a)
366 {
367 REQUIRE_FPU;
368 REQUIRE_ZDINX_OR_D(ctx);
369 REQUIRE_EVEN(ctx, a->rs1);
370
371 TCGv_i64 dest = dest_fpr(ctx, a->rd);
372 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
373
374 gen_set_rm(ctx, a->rm);
375 gen_helper_fcvt_s_d(dest, tcg_env, src1);
376 gen_set_fpr_hs(ctx, a->rd, dest);
377 mark_fs_dirty(ctx);
378 return true;
379 }
380
381 static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a)
382 {
383 REQUIRE_FPU;
384 REQUIRE_ZDINX_OR_D(ctx);
385 REQUIRE_EVEN(ctx, a->rd);
386
387 TCGv_i64 dest = dest_fpr(ctx, a->rd);
388 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1);
389
390 gen_set_rm(ctx, a->rm);
391 gen_helper_fcvt_d_s(dest, tcg_env, src1);
392 gen_set_fpr_d(ctx, a->rd, dest);
393 mark_fs_dirty(ctx);
394 return true;
395 }
396
397 static bool trans_feq_d(DisasContext *ctx, arg_feq_d *a)
398 {
399 REQUIRE_FPU;
400 REQUIRE_ZDINX_OR_D(ctx);
401 REQUIRE_EVEN(ctx, a->rs1 | a->rs2);
402
403 TCGv dest = dest_gpr(ctx, a->rd);
404 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
405 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
406
407 gen_helper_feq_d(dest, tcg_env, src1, src2);
408 gen_set_gpr(ctx, a->rd, dest);
409 return true;
410 }
411
412 static bool trans_flt_d(DisasContext *ctx, arg_flt_d *a)
413 {
414 REQUIRE_FPU;
415 REQUIRE_ZDINX_OR_D(ctx);
416 REQUIRE_EVEN(ctx, a->rs1 | a->rs2);
417
418 TCGv dest = dest_gpr(ctx, a->rd);
419 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
420 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
421
422 gen_helper_flt_d(dest, tcg_env, src1, src2);
423 gen_set_gpr(ctx, a->rd, dest);
424 return true;
425 }
426
427 static bool trans_fle_d(DisasContext *ctx, arg_fle_d *a)
428 {
429 REQUIRE_FPU;
430 REQUIRE_ZDINX_OR_D(ctx);
431 REQUIRE_EVEN(ctx, a->rs1 | a->rs2);
432
433 TCGv dest = dest_gpr(ctx, a->rd);
434 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
435 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
436
437 gen_helper_fle_d(dest, tcg_env, src1, src2);
438 gen_set_gpr(ctx, a->rd, dest);
439 return true;
440 }
441
442 static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a)
443 {
444 REQUIRE_FPU;
445 REQUIRE_ZDINX_OR_D(ctx);
446 REQUIRE_EVEN(ctx, a->rs1);
447
448 TCGv dest = dest_gpr(ctx, a->rd);
449 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
450
451 gen_helper_fclass_d(dest, src1);
452 gen_set_gpr(ctx, a->rd, dest);
453 return true;
454 }
455
456 static bool trans_fcvt_w_d(DisasContext *ctx, arg_fcvt_w_d *a)
457 {
458 REQUIRE_FPU;
459 REQUIRE_ZDINX_OR_D(ctx);
460 REQUIRE_EVEN(ctx, a->rs1);
461
462 TCGv dest = dest_gpr(ctx, a->rd);
463 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
464
465 gen_set_rm(ctx, a->rm);
466 gen_helper_fcvt_w_d(dest, tcg_env, src1);
467 gen_set_gpr(ctx, a->rd, dest);
468 return true;
469 }
470
471 static bool trans_fcvt_wu_d(DisasContext *ctx, arg_fcvt_wu_d *a)
472 {
473 REQUIRE_FPU;
474 REQUIRE_ZDINX_OR_D(ctx);
475 REQUIRE_EVEN(ctx, a->rs1);
476
477 TCGv dest = dest_gpr(ctx, a->rd);
478 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
479
480 gen_set_rm(ctx, a->rm);
481 gen_helper_fcvt_wu_d(dest, tcg_env, src1);
482 gen_set_gpr(ctx, a->rd, dest);
483 return true;
484 }
485
486 static bool trans_fcvt_d_w(DisasContext *ctx, arg_fcvt_d_w *a)
487 {
488 REQUIRE_FPU;
489 REQUIRE_ZDINX_OR_D(ctx);
490 REQUIRE_EVEN(ctx, a->rd);
491
492 TCGv_i64 dest = dest_fpr(ctx, a->rd);
493 TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
494
495 gen_set_rm(ctx, a->rm);
496 gen_helper_fcvt_d_w(dest, tcg_env, src);
497 gen_set_fpr_d(ctx, a->rd, dest);
498
499 mark_fs_dirty(ctx);
500 return true;
501 }
502
503 static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a)
504 {
505 REQUIRE_FPU;
506 REQUIRE_ZDINX_OR_D(ctx);
507 REQUIRE_EVEN(ctx, a->rd);
508
509 TCGv_i64 dest = dest_fpr(ctx, a->rd);
510 TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
511
512 gen_set_rm(ctx, a->rm);
513 gen_helper_fcvt_d_wu(dest, tcg_env, src);
514 gen_set_fpr_d(ctx, a->rd, dest);
515
516 mark_fs_dirty(ctx);
517 return true;
518 }
519
520 static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a)
521 {
522 REQUIRE_64BIT(ctx);
523 REQUIRE_FPU;
524 REQUIRE_ZDINX_OR_D(ctx);
525 REQUIRE_EVEN(ctx, a->rs1);
526
527 TCGv dest = dest_gpr(ctx, a->rd);
528 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
529
530 gen_set_rm(ctx, a->rm);
531 gen_helper_fcvt_l_d(dest, tcg_env, src1);
532 gen_set_gpr(ctx, a->rd, dest);
533 return true;
534 }
535
536 static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a)
537 {
538 REQUIRE_64BIT(ctx);
539 REQUIRE_FPU;
540 REQUIRE_ZDINX_OR_D(ctx);
541 REQUIRE_EVEN(ctx, a->rs1);
542
543 TCGv dest = dest_gpr(ctx, a->rd);
544 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
545
546 gen_set_rm(ctx, a->rm);
547 gen_helper_fcvt_lu_d(dest, tcg_env, src1);
548 gen_set_gpr(ctx, a->rd, dest);
549 return true;
550 }
551
552 static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a)
553 {
554 REQUIRE_64BIT(ctx);
555 REQUIRE_FPU;
556 REQUIRE_EXT(ctx, RVD);
557
558 #ifdef TARGET_RISCV64
559 gen_set_gpr(ctx, a->rd, cpu_fpr[a->rs1]);
560 return true;
561 #else
562 qemu_build_not_reached();
563 #endif
564 }
565
566 static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a)
567 {
568 REQUIRE_64BIT(ctx);
569 REQUIRE_FPU;
570 REQUIRE_ZDINX_OR_D(ctx);
571 REQUIRE_EVEN(ctx, a->rd);
572
573 TCGv_i64 dest = dest_fpr(ctx, a->rd);
574 TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
575
576 gen_set_rm(ctx, a->rm);
577 gen_helper_fcvt_d_l(dest, tcg_env, src);
578 gen_set_fpr_d(ctx, a->rd, dest);
579
580 mark_fs_dirty(ctx);
581 return true;
582 }
583
584 static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a)
585 {
586 REQUIRE_64BIT(ctx);
587 REQUIRE_FPU;
588 REQUIRE_ZDINX_OR_D(ctx);
589 REQUIRE_EVEN(ctx, a->rd);
590
591 TCGv_i64 dest = dest_fpr(ctx, a->rd);
592 TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
593
594 gen_set_rm(ctx, a->rm);
595 gen_helper_fcvt_d_lu(dest, tcg_env, src);
596 gen_set_fpr_d(ctx, a->rd, dest);
597
598 mark_fs_dirty(ctx);
599 return true;
600 }
601
602 static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a)
603 {
604 REQUIRE_64BIT(ctx);
605 REQUIRE_FPU;
606 REQUIRE_EXT(ctx, RVD);
607
608 #ifdef TARGET_RISCV64
609 tcg_gen_mov_tl(cpu_fpr[a->rd], get_gpr(ctx, a->rs1, EXT_NONE));
610 mark_fs_dirty(ctx);
611 return true;
612 #else
613 qemu_build_not_reached();
614 #endif
615 }