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
21static bool trans_fld(DisasContext *ctx, arg_fld *a)
22{
23    TCGv addr;
24
25    REQUIRE_FPU;
26    REQUIRE_EXT(ctx, RVD);
27
28    addr = get_gpr(ctx, a->rs1, EXT_NONE);
29    if (a->imm) {
30        TCGv temp = temp_new(ctx);
31        tcg_gen_addi_tl(temp, addr, a->imm);
32        addr = temp;
33    }
34    addr = gen_pm_adjust_address(ctx, addr);
35
36    tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, MO_TEUQ);
37
38    mark_fs_dirty(ctx);
39    return true;
40}
41
42static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
43{
44    TCGv addr;
45
46    REQUIRE_FPU;
47    REQUIRE_EXT(ctx, RVD);
48
49    addr = get_gpr(ctx, a->rs1, EXT_NONE);
50    if (a->imm) {
51        TCGv temp = temp_new(ctx);
52        tcg_gen_addi_tl(temp, addr, a->imm);
53        addr = temp;
54    }
55    addr = gen_pm_adjust_address(ctx, addr);
56
57    tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUQ);
58
59    return true;
60}
61
62static bool trans_fmadd_d(DisasContext *ctx, arg_fmadd_d *a)
63{
64    REQUIRE_FPU;
65    REQUIRE_EXT(ctx, RVD);
66    gen_set_rm(ctx, a->rm);
67    gen_helper_fmadd_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
68                       cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
69    mark_fs_dirty(ctx);
70    return true;
71}
72
73static bool trans_fmsub_d(DisasContext *ctx, arg_fmsub_d *a)
74{
75    REQUIRE_FPU;
76    REQUIRE_EXT(ctx, RVD);
77    gen_set_rm(ctx, a->rm);
78    gen_helper_fmsub_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
79                       cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
80    mark_fs_dirty(ctx);
81    return true;
82}
83
84static bool trans_fnmsub_d(DisasContext *ctx, arg_fnmsub_d *a)
85{
86    REQUIRE_FPU;
87    REQUIRE_EXT(ctx, RVD);
88    gen_set_rm(ctx, a->rm);
89    gen_helper_fnmsub_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
90                        cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
91    mark_fs_dirty(ctx);
92    return true;
93}
94
95static bool trans_fnmadd_d(DisasContext *ctx, arg_fnmadd_d *a)
96{
97    REQUIRE_FPU;
98    REQUIRE_EXT(ctx, RVD);
99    gen_set_rm(ctx, a->rm);
100    gen_helper_fnmadd_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
101                        cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
102    mark_fs_dirty(ctx);
103    return true;
104}
105
106static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a)
107{
108    REQUIRE_FPU;
109    REQUIRE_EXT(ctx, RVD);
110
111    gen_set_rm(ctx, a->rm);
112    gen_helper_fadd_d(cpu_fpr[a->rd], cpu_env,
113                      cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
114
115    mark_fs_dirty(ctx);
116    return true;
117}
118
119static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a)
120{
121    REQUIRE_FPU;
122    REQUIRE_EXT(ctx, RVD);
123
124    gen_set_rm(ctx, a->rm);
125    gen_helper_fsub_d(cpu_fpr[a->rd], cpu_env,
126                      cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
127
128    mark_fs_dirty(ctx);
129    return true;
130}
131
132static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a)
133{
134    REQUIRE_FPU;
135    REQUIRE_EXT(ctx, RVD);
136
137    gen_set_rm(ctx, a->rm);
138    gen_helper_fmul_d(cpu_fpr[a->rd], cpu_env,
139                      cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
140
141    mark_fs_dirty(ctx);
142    return true;
143}
144
145static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a)
146{
147    REQUIRE_FPU;
148    REQUIRE_EXT(ctx, RVD);
149
150    gen_set_rm(ctx, a->rm);
151    gen_helper_fdiv_d(cpu_fpr[a->rd], cpu_env,
152                      cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
153
154    mark_fs_dirty(ctx);
155    return true;
156}
157
158static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a)
159{
160    REQUIRE_FPU;
161    REQUIRE_EXT(ctx, RVD);
162
163    gen_set_rm(ctx, a->rm);
164    gen_helper_fsqrt_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
165
166    mark_fs_dirty(ctx);
167    return true;
168}
169
170static bool trans_fsgnj_d(DisasContext *ctx, arg_fsgnj_d *a)
171{
172    if (a->rs1 == a->rs2) { /* FMOV */
173        tcg_gen_mov_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1]);
174    } else {
175        tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rs2],
176                            cpu_fpr[a->rs1], 0, 63);
177    }
178    mark_fs_dirty(ctx);
179    return true;
180}
181
182static bool trans_fsgnjn_d(DisasContext *ctx, arg_fsgnjn_d *a)
183{
184    REQUIRE_FPU;
185    REQUIRE_EXT(ctx, RVD);
186    if (a->rs1 == a->rs2) { /* FNEG */
187        tcg_gen_xori_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], INT64_MIN);
188    } else {
189        TCGv_i64 t0 = tcg_temp_new_i64();
190        tcg_gen_not_i64(t0, cpu_fpr[a->rs2]);
191        tcg_gen_deposit_i64(cpu_fpr[a->rd], t0, cpu_fpr[a->rs1], 0, 63);
192        tcg_temp_free_i64(t0);
193    }
194    mark_fs_dirty(ctx);
195    return true;
196}
197
198static bool trans_fsgnjx_d(DisasContext *ctx, arg_fsgnjx_d *a)
199{
200    REQUIRE_FPU;
201    REQUIRE_EXT(ctx, RVD);
202    if (a->rs1 == a->rs2) { /* FABS */
203        tcg_gen_andi_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], ~INT64_MIN);
204    } else {
205        TCGv_i64 t0 = tcg_temp_new_i64();
206        tcg_gen_andi_i64(t0, cpu_fpr[a->rs2], INT64_MIN);
207        tcg_gen_xor_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], t0);
208        tcg_temp_free_i64(t0);
209    }
210    mark_fs_dirty(ctx);
211    return true;
212}
213
214static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a)
215{
216    REQUIRE_FPU;
217    REQUIRE_EXT(ctx, RVD);
218
219    gen_helper_fmin_d(cpu_fpr[a->rd], cpu_env,
220                      cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
221
222    mark_fs_dirty(ctx);
223    return true;
224}
225
226static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a)
227{
228    REQUIRE_FPU;
229    REQUIRE_EXT(ctx, RVD);
230
231    gen_helper_fmax_d(cpu_fpr[a->rd], cpu_env,
232                      cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
233
234    mark_fs_dirty(ctx);
235    return true;
236}
237
238static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a)
239{
240    REQUIRE_FPU;
241    REQUIRE_EXT(ctx, RVD);
242
243    gen_set_rm(ctx, a->rm);
244    gen_helper_fcvt_s_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
245
246    mark_fs_dirty(ctx);
247    return true;
248}
249
250static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a)
251{
252    REQUIRE_FPU;
253    REQUIRE_EXT(ctx, RVD);
254
255    gen_set_rm(ctx, a->rm);
256    gen_helper_fcvt_d_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
257
258    mark_fs_dirty(ctx);
259    return true;
260}
261
262static bool trans_feq_d(DisasContext *ctx, arg_feq_d *a)
263{
264    REQUIRE_FPU;
265    REQUIRE_EXT(ctx, RVD);
266
267    TCGv dest = dest_gpr(ctx, a->rd);
268
269    gen_helper_feq_d(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
270    gen_set_gpr(ctx, a->rd, dest);
271    return true;
272}
273
274static bool trans_flt_d(DisasContext *ctx, arg_flt_d *a)
275{
276    REQUIRE_FPU;
277    REQUIRE_EXT(ctx, RVD);
278
279    TCGv dest = dest_gpr(ctx, a->rd);
280
281    gen_helper_flt_d(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
282    gen_set_gpr(ctx, a->rd, dest);
283    return true;
284}
285
286static bool trans_fle_d(DisasContext *ctx, arg_fle_d *a)
287{
288    REQUIRE_FPU;
289    REQUIRE_EXT(ctx, RVD);
290
291    TCGv dest = dest_gpr(ctx, a->rd);
292
293    gen_helper_fle_d(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
294    gen_set_gpr(ctx, a->rd, dest);
295    return true;
296}
297
298static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a)
299{
300    REQUIRE_FPU;
301    REQUIRE_EXT(ctx, RVD);
302
303    TCGv dest = dest_gpr(ctx, a->rd);
304
305    gen_helper_fclass_d(dest, cpu_fpr[a->rs1]);
306    gen_set_gpr(ctx, a->rd, dest);
307    return true;
308}
309
310static bool trans_fcvt_w_d(DisasContext *ctx, arg_fcvt_w_d *a)
311{
312    REQUIRE_FPU;
313    REQUIRE_EXT(ctx, RVD);
314
315    TCGv dest = dest_gpr(ctx, a->rd);
316
317    gen_set_rm(ctx, a->rm);
318    gen_helper_fcvt_w_d(dest, cpu_env, cpu_fpr[a->rs1]);
319    gen_set_gpr(ctx, a->rd, dest);
320    return true;
321}
322
323static bool trans_fcvt_wu_d(DisasContext *ctx, arg_fcvt_wu_d *a)
324{
325    REQUIRE_FPU;
326    REQUIRE_EXT(ctx, RVD);
327
328    TCGv dest = dest_gpr(ctx, a->rd);
329
330    gen_set_rm(ctx, a->rm);
331    gen_helper_fcvt_wu_d(dest, cpu_env, cpu_fpr[a->rs1]);
332    gen_set_gpr(ctx, a->rd, dest);
333    return true;
334}
335
336static bool trans_fcvt_d_w(DisasContext *ctx, arg_fcvt_d_w *a)
337{
338    REQUIRE_FPU;
339    REQUIRE_EXT(ctx, RVD);
340
341    TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
342
343    gen_set_rm(ctx, a->rm);
344    gen_helper_fcvt_d_w(cpu_fpr[a->rd], cpu_env, src);
345
346    mark_fs_dirty(ctx);
347    return true;
348}
349
350static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a)
351{
352    REQUIRE_FPU;
353    REQUIRE_EXT(ctx, RVD);
354
355    TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
356
357    gen_set_rm(ctx, a->rm);
358    gen_helper_fcvt_d_wu(cpu_fpr[a->rd], cpu_env, src);
359
360    mark_fs_dirty(ctx);
361    return true;
362}
363
364static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a)
365{
366    REQUIRE_64BIT(ctx);
367    REQUIRE_FPU;
368    REQUIRE_EXT(ctx, RVD);
369
370    TCGv dest = dest_gpr(ctx, a->rd);
371
372    gen_set_rm(ctx, a->rm);
373    gen_helper_fcvt_l_d(dest, cpu_env, cpu_fpr[a->rs1]);
374    gen_set_gpr(ctx, a->rd, dest);
375    return true;
376}
377
378static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a)
379{
380    REQUIRE_64BIT(ctx);
381    REQUIRE_FPU;
382    REQUIRE_EXT(ctx, RVD);
383
384    TCGv dest = dest_gpr(ctx, a->rd);
385
386    gen_set_rm(ctx, a->rm);
387    gen_helper_fcvt_lu_d(dest, cpu_env, cpu_fpr[a->rs1]);
388    gen_set_gpr(ctx, a->rd, dest);
389    return true;
390}
391
392static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a)
393{
394    REQUIRE_64BIT(ctx);
395    REQUIRE_FPU;
396    REQUIRE_EXT(ctx, RVD);
397
398#ifdef TARGET_RISCV64
399    gen_set_gpr(ctx, a->rd, cpu_fpr[a->rs1]);
400    return true;
401#else
402    qemu_build_not_reached();
403#endif
404}
405
406static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a)
407{
408    REQUIRE_64BIT(ctx);
409    REQUIRE_FPU;
410    REQUIRE_EXT(ctx, RVD);
411
412    TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
413
414    gen_set_rm(ctx, a->rm);
415    gen_helper_fcvt_d_l(cpu_fpr[a->rd], cpu_env, src);
416
417    mark_fs_dirty(ctx);
418    return true;
419}
420
421static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a)
422{
423    REQUIRE_64BIT(ctx);
424    REQUIRE_FPU;
425    REQUIRE_EXT(ctx, RVD);
426
427    TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
428
429    gen_set_rm(ctx, a->rm);
430    gen_helper_fcvt_d_lu(cpu_fpr[a->rd], cpu_env, src);
431
432    mark_fs_dirty(ctx);
433    return true;
434}
435
436static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a)
437{
438    REQUIRE_64BIT(ctx);
439    REQUIRE_FPU;
440    REQUIRE_EXT(ctx, RVD);
441
442#ifdef TARGET_RISCV64
443    tcg_gen_mov_tl(cpu_fpr[a->rd], get_gpr(ctx, a->rs1, EXT_NONE));
444    mark_fs_dirty(ctx);
445    return true;
446#else
447    qemu_build_not_reached();
448#endif
449}
450