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