1/* 2 * RISC-V translation routines for the Zfa Standard Extension. 3 * 4 * Copyright (c) 2023 Christoph Müllner, christoph.muellner@vrull.eu 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2 or later, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License along with 16 * this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19#define REQUIRE_ZFA(ctx) do { \ 20 if (!ctx->cfg_ptr->ext_zfa) { \ 21 return false; \ 22 } \ 23} while (0) 24 25#define REQUIRE_ZFH(ctx) do { \ 26 if (!ctx->cfg_ptr->ext_zfh) { \ 27 return false; \ 28 } \ 29} while (0) 30 31static bool trans_fli_s(DisasContext *ctx, arg_fli_s *a) 32{ 33 REQUIRE_FPU; 34 REQUIRE_ZFA(ctx); 35 REQUIRE_EXT(ctx, RVF); 36 37 /* Values below are NaN-boxed to avoid a gen_nanbox_s(). */ 38 static const uint64_t fli_s_table[] = { 39 0xffffffffbf800000, /* -1.0 */ 40 0xffffffff00800000, /* minimum positive normal */ 41 0xffffffff37800000, /* 1.0 * 2^-16 */ 42 0xffffffff38000000, /* 1.0 * 2^-15 */ 43 0xffffffff3b800000, /* 1.0 * 2^-8 */ 44 0xffffffff3c000000, /* 1.0 * 2^-7 */ 45 0xffffffff3d800000, /* 1.0 * 2^-4 */ 46 0xffffffff3e000000, /* 1.0 * 2^-3 */ 47 0xffffffff3e800000, /* 0.25 */ 48 0xffffffff3ea00000, /* 0.3125 */ 49 0xffffffff3ec00000, /* 0.375 */ 50 0xffffffff3ee00000, /* 0.4375 */ 51 0xffffffff3f000000, /* 0.5 */ 52 0xffffffff3f200000, /* 0.625 */ 53 0xffffffff3f400000, /* 0.75 */ 54 0xffffffff3f600000, /* 0.875 */ 55 0xffffffff3f800000, /* 1.0 */ 56 0xffffffff3fa00000, /* 1.25 */ 57 0xffffffff3fc00000, /* 1.5 */ 58 0xffffffff3fe00000, /* 1.75 */ 59 0xffffffff40000000, /* 2.0 */ 60 0xffffffff40200000, /* 2.5 */ 61 0xffffffff40400000, /* 3 */ 62 0xffffffff40800000, /* 4 */ 63 0xffffffff41000000, /* 8 */ 64 0xffffffff41800000, /* 16 */ 65 0xffffffff43000000, /* 2^7 */ 66 0xffffffff43800000, /* 2^8 */ 67 0xffffffff47000000, /* 2^15 */ 68 0xffffffff47800000, /* 2^16 */ 69 0xffffffff7f800000, /* +inf */ 70 0xffffffff7fc00000, /* Canonical NaN */ 71 }; 72 73 TCGv_i64 dest = dest_fpr(ctx, a->rd); 74 tcg_gen_movi_i64(dest, fli_s_table[a->rs1]); 75 gen_set_fpr_hs(ctx, a->rd, dest); 76 77 mark_fs_dirty(ctx); 78 return true; 79} 80 81static bool trans_fli_d(DisasContext *ctx, arg_fli_d *a) 82{ 83 REQUIRE_FPU; 84 REQUIRE_ZFA(ctx); 85 REQUIRE_EXT(ctx, RVD); 86 87 static const uint64_t fli_d_table[] = { 88 0xbff0000000000000, /* -1.0 */ 89 0x0010000000000000, /* minimum positive normal */ 90 0x3ef0000000000000, /* 1.0 * 2^-16 */ 91 0x3f00000000000000, /* 1.0 * 2^-15 */ 92 0x3f70000000000000, /* 1.0 * 2^-8 */ 93 0x3f80000000000000, /* 1.0 * 2^-7 */ 94 0x3fb0000000000000, /* 1.0 * 2^-4 */ 95 0x3fc0000000000000, /* 1.0 * 2^-3 */ 96 0x3fd0000000000000, /* 0.25 */ 97 0x3fd4000000000000, /* 0.3125 */ 98 0x3fd8000000000000, /* 0.375 */ 99 0x3fdc000000000000, /* 0.4375 */ 100 0x3fe0000000000000, /* 0.5 */ 101 0x3fe4000000000000, /* 0.625 */ 102 0x3fe8000000000000, /* 0.75 */ 103 0x3fec000000000000, /* 0.875 */ 104 0x3ff0000000000000, /* 1.0 */ 105 0x3ff4000000000000, /* 1.25 */ 106 0x3ff8000000000000, /* 1.5 */ 107 0x3ffc000000000000, /* 1.75 */ 108 0x4000000000000000, /* 2.0 */ 109 0x4004000000000000, /* 2.5 */ 110 0x4008000000000000, /* 3 */ 111 0x4010000000000000, /* 4 */ 112 0x4020000000000000, /* 8 */ 113 0x4030000000000000, /* 16 */ 114 0x4060000000000000, /* 2^7 */ 115 0x4070000000000000, /* 2^8 */ 116 0x40e0000000000000, /* 2^15 */ 117 0x40f0000000000000, /* 2^16 */ 118 0x7ff0000000000000, /* +inf */ 119 0x7ff8000000000000, /* Canonical NaN */ 120 }; 121 122 TCGv_i64 dest = dest_fpr(ctx, a->rd); 123 tcg_gen_movi_i64(dest, fli_d_table[a->rs1]); 124 gen_set_fpr_d(ctx, a->rd, dest); 125 126 mark_fs_dirty(ctx); 127 return true; 128} 129 130static bool trans_fli_h(DisasContext *ctx, arg_fli_h *a) 131{ 132 REQUIRE_FPU; 133 REQUIRE_ZFA(ctx); 134 REQUIRE_ZFH(ctx); 135 136 /* Values below are NaN-boxed to avoid a gen_nanbox_h(). */ 137 static const uint64_t fli_h_table[] = { 138 0xffffffffffffbc00, /* -1.0 */ 139 0xffffffffffff0400, /* minimum positive normal */ 140 0xffffffffffff0100, /* 1.0 * 2^-16 */ 141 0xffffffffffff0200, /* 1.0 * 2^-15 */ 142 0xffffffffffff1c00, /* 1.0 * 2^-8 */ 143 0xffffffffffff2000, /* 1.0 * 2^-7 */ 144 0xffffffffffff2c00, /* 1.0 * 2^-4 */ 145 0xffffffffffff3000, /* 1.0 * 2^-3 */ 146 0xffffffffffff3400, /* 0.25 */ 147 0xffffffffffff3500, /* 0.3125 */ 148 0xffffffffffff3600, /* 0.375 */ 149 0xffffffffffff3700, /* 0.4375 */ 150 0xffffffffffff3800, /* 0.5 */ 151 0xffffffffffff3900, /* 0.625 */ 152 0xffffffffffff3a00, /* 0.75 */ 153 0xffffffffffff3b00, /* 0.875 */ 154 0xffffffffffff3c00, /* 1.0 */ 155 0xffffffffffff3d00, /* 1.25 */ 156 0xffffffffffff3e00, /* 1.5 */ 157 0xffffffffffff3f00, /* 1.75 */ 158 0xffffffffffff4000, /* 2.0 */ 159 0xffffffffffff4100, /* 2.5 */ 160 0xffffffffffff4200, /* 3 */ 161 0xffffffffffff4400, /* 4 */ 162 0xffffffffffff4800, /* 8 */ 163 0xffffffffffff4c00, /* 16 */ 164 0xffffffffffff5800, /* 2^7 */ 165 0xffffffffffff5c00, /* 2^8 */ 166 0xffffffffffff7800, /* 2^15 */ 167 0xffffffffffff7c00, /* 2^16 */ 168 0xffffffffffff7c00, /* +inf */ 169 0xffffffffffff7e00, /* Canonical NaN */ 170 }; 171 172 TCGv_i64 dest = dest_fpr(ctx, a->rd); 173 tcg_gen_movi_i64(dest, fli_h_table[a->rs1]); 174 gen_set_fpr_hs(ctx, a->rd, dest); 175 176 mark_fs_dirty(ctx); 177 return true; 178} 179 180static bool trans_fminm_s(DisasContext *ctx, arg_fminm_s *a) 181{ 182 REQUIRE_FPU; 183 REQUIRE_ZFA(ctx); 184 REQUIRE_EXT(ctx, RVF); 185 186 TCGv_i64 dest = dest_fpr(ctx, a->rd); 187 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 188 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 189 190 gen_helper_fminm_s(dest, cpu_env, src1, src2); 191 gen_set_fpr_hs(ctx, a->rd, dest); 192 193 mark_fs_dirty(ctx); 194 return true; 195} 196 197static bool trans_fmaxm_s(DisasContext *ctx, arg_fmaxm_s *a) 198{ 199 REQUIRE_FPU; 200 REQUIRE_ZFA(ctx); 201 REQUIRE_EXT(ctx, RVF); 202 203 TCGv_i64 dest = dest_fpr(ctx, a->rd); 204 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 205 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 206 207 gen_helper_fmaxm_s(dest, cpu_env, src1, src2); 208 gen_set_fpr_hs(ctx, a->rd, dest); 209 210 mark_fs_dirty(ctx); 211 return true; 212} 213 214static bool trans_fminm_d(DisasContext *ctx, arg_fminm_d *a) 215{ 216 REQUIRE_FPU; 217 REQUIRE_ZFA(ctx); 218 REQUIRE_EXT(ctx, RVD); 219 220 TCGv_i64 dest = dest_fpr(ctx, a->rd); 221 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 222 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 223 224 gen_helper_fminm_d(dest, cpu_env, src1, src2); 225 gen_set_fpr_d(ctx, a->rd, dest); 226 227 mark_fs_dirty(ctx); 228 return true; 229} 230 231static bool trans_fmaxm_d(DisasContext *ctx, arg_fmaxm_d *a) 232{ 233 REQUIRE_FPU; 234 REQUIRE_ZFA(ctx); 235 REQUIRE_EXT(ctx, RVD); 236 237 TCGv_i64 dest = dest_fpr(ctx, a->rd); 238 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 239 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 240 241 gen_helper_fmaxm_d(dest, cpu_env, src1, src2); 242 gen_set_fpr_d(ctx, a->rd, dest); 243 244 mark_fs_dirty(ctx); 245 return true; 246} 247 248static bool trans_fminm_h(DisasContext *ctx, arg_fminm_h *a) 249{ 250 REQUIRE_FPU; 251 REQUIRE_ZFA(ctx); 252 REQUIRE_ZFH(ctx); 253 254 TCGv_i64 dest = dest_fpr(ctx, a->rd); 255 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 256 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 257 258 gen_helper_fminm_h(dest, cpu_env, src1, src2); 259 gen_set_fpr_hs(ctx, a->rd, dest); 260 261 mark_fs_dirty(ctx); 262 return true; 263} 264 265static bool trans_fmaxm_h(DisasContext *ctx, arg_fmaxm_h *a) 266{ 267 REQUIRE_FPU; 268 REQUIRE_ZFA(ctx); 269 REQUIRE_ZFH(ctx); 270 271 TCGv_i64 dest = dest_fpr(ctx, a->rd); 272 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 273 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 274 275 gen_helper_fmaxm_h(dest, cpu_env, src1, src2); 276 gen_set_fpr_hs(ctx, a->rd, dest); 277 278 mark_fs_dirty(ctx); 279 return true; 280} 281 282static bool trans_fround_s(DisasContext *ctx, arg_fround_s *a) 283{ 284 REQUIRE_FPU; 285 REQUIRE_ZFA(ctx); 286 REQUIRE_EXT(ctx, RVF); 287 288 TCGv_i64 dest = dest_fpr(ctx, a->rd); 289 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 290 291 gen_set_rm(ctx, a->rm); 292 gen_helper_fround_s(dest, cpu_env, src1); 293 gen_set_fpr_hs(ctx, a->rd, dest); 294 295 mark_fs_dirty(ctx); 296 return true; 297} 298 299static bool trans_froundnx_s(DisasContext *ctx, arg_froundnx_s *a) 300{ 301 REQUIRE_FPU; 302 REQUIRE_ZFA(ctx); 303 REQUIRE_EXT(ctx, RVF); 304 305 TCGv_i64 dest = dest_fpr(ctx, a->rd); 306 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 307 308 gen_set_rm(ctx, a->rm); 309 gen_helper_froundnx_s(dest, cpu_env, src1); 310 gen_set_fpr_hs(ctx, a->rd, dest); 311 312 mark_fs_dirty(ctx); 313 return true; 314} 315 316static bool trans_fround_d(DisasContext *ctx, arg_fround_d *a) 317{ 318 REQUIRE_FPU; 319 REQUIRE_ZFA(ctx); 320 REQUIRE_EXT(ctx, RVD); 321 322 TCGv_i64 dest = dest_fpr(ctx, a->rd); 323 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 324 325 gen_set_rm(ctx, a->rm); 326 gen_helper_fround_d(dest, cpu_env, src1); 327 gen_set_fpr_hs(ctx, a->rd, dest); 328 329 mark_fs_dirty(ctx); 330 return true; 331} 332 333static bool trans_froundnx_d(DisasContext *ctx, arg_froundnx_d *a) 334{ 335 REQUIRE_FPU; 336 REQUIRE_ZFA(ctx); 337 REQUIRE_EXT(ctx, RVD); 338 339 TCGv_i64 dest = dest_fpr(ctx, a->rd); 340 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 341 342 gen_set_rm(ctx, a->rm); 343 gen_helper_froundnx_d(dest, cpu_env, src1); 344 gen_set_fpr_hs(ctx, a->rd, dest); 345 346 mark_fs_dirty(ctx); 347 return true; 348} 349 350static bool trans_fround_h(DisasContext *ctx, arg_fround_h *a) 351{ 352 REQUIRE_FPU; 353 REQUIRE_ZFA(ctx); 354 REQUIRE_ZFH(ctx); 355 356 TCGv_i64 dest = dest_fpr(ctx, a->rd); 357 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 358 359 gen_set_rm(ctx, a->rm); 360 gen_helper_fround_h(dest, cpu_env, src1); 361 gen_set_fpr_hs(ctx, a->rd, dest); 362 363 mark_fs_dirty(ctx); 364 return true; 365} 366 367static bool trans_froundnx_h(DisasContext *ctx, arg_froundnx_h *a) 368{ 369 REQUIRE_FPU; 370 REQUIRE_ZFA(ctx); 371 REQUIRE_ZFH(ctx); 372 373 TCGv_i64 dest = dest_fpr(ctx, a->rd); 374 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 375 376 gen_set_rm(ctx, a->rm); 377 gen_helper_froundnx_h(dest, cpu_env, src1); 378 gen_set_fpr_hs(ctx, a->rd, dest); 379 380 mark_fs_dirty(ctx); 381 return true; 382} 383 384bool trans_fcvtmod_w_d(DisasContext *ctx, arg_fcvtmod_w_d *a) 385{ 386 REQUIRE_FPU; 387 REQUIRE_ZFA(ctx); 388 REQUIRE_EXT(ctx, RVD); 389 390 TCGv dst = dest_gpr(ctx, a->rd); 391 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 392 TCGv_i64 t1 = tcg_temp_new_i64(); 393 394 /* Rounding mode is RTZ. */ 395 gen_set_rm(ctx, RISCV_FRM_RTZ); 396 gen_helper_fcvtmod_w_d(t1, cpu_env, src1); 397 tcg_gen_trunc_i64_tl(dst, t1); 398 gen_set_gpr(ctx, a->rd, dst); 399 400 return true; 401} 402 403bool trans_fmvh_x_d(DisasContext *ctx, arg_fmvh_x_d *a) 404{ 405 REQUIRE_FPU; 406 REQUIRE_ZFA(ctx); 407 REQUIRE_EXT(ctx, RVD); 408 REQUIRE_32BIT(ctx); 409 410 TCGv dst = dest_gpr(ctx, a->rd); 411 TCGv_i64 t1 = tcg_temp_new_i64(); 412 tcg_gen_sari_i64(t1, cpu_fpr[a->rs1], 32); 413 tcg_gen_trunc_i64_tl(dst, t1); 414 gen_set_gpr(ctx, a->rd, dst); 415 return true; 416} 417 418bool trans_fmvp_d_x(DisasContext *ctx, arg_fmvp_d_x *a) 419{ 420 REQUIRE_FPU; 421 REQUIRE_ZFA(ctx); 422 REQUIRE_EXT(ctx, RVD); 423 REQUIRE_32BIT(ctx); 424 425 TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); 426 TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); 427 tcg_gen_concat_tl_i64(cpu_fpr[a->rd], src1, src2); 428 429 mark_fs_dirty(ctx); 430 return true; 431} 432 433bool trans_fleq_s(DisasContext *ctx, arg_fleq_s *a) 434{ 435 REQUIRE_FPU; 436 REQUIRE_ZFA(ctx); 437 REQUIRE_EXT(ctx, RVF); 438 439 TCGv dest = dest_gpr(ctx, a->rd); 440 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 441 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 442 443 gen_helper_fleq_s(dest, cpu_env, src1, src2); 444 gen_set_gpr(ctx, a->rd, dest); 445 return true; 446} 447 448bool trans_fltq_s(DisasContext *ctx, arg_fltq_s *a) 449{ 450 REQUIRE_FPU; 451 REQUIRE_ZFA(ctx); 452 REQUIRE_EXT(ctx, RVF); 453 454 TCGv dest = dest_gpr(ctx, a->rd); 455 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 456 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 457 458 gen_helper_fltq_s(dest, cpu_env, src1, src2); 459 gen_set_gpr(ctx, a->rd, dest); 460 return true; 461} 462 463bool trans_fleq_d(DisasContext *ctx, arg_fleq_d *a) 464{ 465 REQUIRE_FPU; 466 REQUIRE_ZFA(ctx); 467 REQUIRE_EXT(ctx, RVD); 468 469 TCGv dest = dest_gpr(ctx, a->rd); 470 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 471 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 472 473 gen_helper_fltq_s(dest, cpu_env, src1, src2); 474 gen_set_gpr(ctx, a->rd, dest); 475 return true; 476} 477 478bool trans_fltq_d(DisasContext *ctx, arg_fltq_d *a) 479{ 480 REQUIRE_FPU; 481 REQUIRE_ZFA(ctx); 482 REQUIRE_EXT(ctx, RVD); 483 484 TCGv dest = dest_gpr(ctx, a->rd); 485 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 486 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 487 488 gen_helper_fltq_s(dest, cpu_env, src1, src2); 489 gen_set_gpr(ctx, a->rd, dest); 490 return true; 491} 492 493bool trans_fleq_h(DisasContext *ctx, arg_fleq_h *a) 494{ 495 REQUIRE_FPU; 496 REQUIRE_ZFA(ctx); 497 REQUIRE_ZFH(ctx); 498 499 TCGv dest = dest_gpr(ctx, a->rd); 500 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 501 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 502 503 gen_helper_fleq_h(dest, cpu_env, src1, src2); 504 gen_set_gpr(ctx, a->rd, dest); 505 return true; 506} 507 508bool trans_fltq_h(DisasContext *ctx, arg_fltq_h *a) 509{ 510 REQUIRE_FPU; 511 REQUIRE_ZFA(ctx); 512 REQUIRE_ZFH(ctx); 513 514 TCGv dest = dest_gpr(ctx, a->rd); 515 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 516 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 517 518 gen_helper_fltq_h(dest, cpu_env, src1, src2); 519 gen_set_gpr(ctx, a->rd, dest); 520 return true; 521} 522