1/* 2 * RISC-V translation routines for the RVXI Base Integer Instruction Set. 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_illegal(DisasContext *ctx, arg_empty *a) 22{ 23 gen_exception_illegal(ctx); 24 return true; 25} 26 27static bool trans_lui(DisasContext *ctx, arg_lui *a) 28{ 29 if (a->rd != 0) { 30 tcg_gen_movi_tl(cpu_gpr[a->rd], a->imm); 31 } 32 return true; 33} 34 35static bool trans_auipc(DisasContext *ctx, arg_auipc *a) 36{ 37 if (a->rd != 0) { 38 tcg_gen_movi_tl(cpu_gpr[a->rd], a->imm + ctx->base.pc_next); 39 } 40 return true; 41} 42 43static bool trans_jal(DisasContext *ctx, arg_jal *a) 44{ 45 gen_jal(ctx, a->rd, a->imm); 46 return true; 47} 48 49static bool trans_jalr(DisasContext *ctx, arg_jalr *a) 50{ 51 /* no chaining with JALR */ 52 TCGLabel *misaligned = NULL; 53 TCGv t0 = tcg_temp_new(); 54 55 56 gen_get_gpr(cpu_pc, a->rs1); 57 tcg_gen_addi_tl(cpu_pc, cpu_pc, a->imm); 58 tcg_gen_andi_tl(cpu_pc, cpu_pc, (target_ulong)-2); 59 60 if (!has_ext(ctx, RVC)) { 61 misaligned = gen_new_label(); 62 tcg_gen_andi_tl(t0, cpu_pc, 0x2); 63 tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x0, misaligned); 64 } 65 66 if (a->rd != 0) { 67 tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->pc_succ_insn); 68 } 69 lookup_and_goto_ptr(ctx); 70 71 if (misaligned) { 72 gen_set_label(misaligned); 73 gen_exception_inst_addr_mis(ctx); 74 } 75 ctx->base.is_jmp = DISAS_NORETURN; 76 77 tcg_temp_free(t0); 78 return true; 79} 80 81static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond) 82{ 83 TCGLabel *l = gen_new_label(); 84 TCGv source1, source2; 85 source1 = tcg_temp_new(); 86 source2 = tcg_temp_new(); 87 gen_get_gpr(source1, a->rs1); 88 gen_get_gpr(source2, a->rs2); 89 90 tcg_gen_brcond_tl(cond, source1, source2, l); 91 gen_goto_tb(ctx, 1, ctx->pc_succ_insn); 92 gen_set_label(l); /* branch taken */ 93 94 if (!has_ext(ctx, RVC) && ((ctx->base.pc_next + a->imm) & 0x3)) { 95 /* misaligned */ 96 gen_exception_inst_addr_mis(ctx); 97 } else { 98 gen_goto_tb(ctx, 0, ctx->base.pc_next + a->imm); 99 } 100 ctx->base.is_jmp = DISAS_NORETURN; 101 102 tcg_temp_free(source1); 103 tcg_temp_free(source2); 104 105 return true; 106} 107 108static bool trans_beq(DisasContext *ctx, arg_beq *a) 109{ 110 return gen_branch(ctx, a, TCG_COND_EQ); 111} 112 113static bool trans_bne(DisasContext *ctx, arg_bne *a) 114{ 115 return gen_branch(ctx, a, TCG_COND_NE); 116} 117 118static bool trans_blt(DisasContext *ctx, arg_blt *a) 119{ 120 return gen_branch(ctx, a, TCG_COND_LT); 121} 122 123static bool trans_bge(DisasContext *ctx, arg_bge *a) 124{ 125 return gen_branch(ctx, a, TCG_COND_GE); 126} 127 128static bool trans_bltu(DisasContext *ctx, arg_bltu *a) 129{ 130 return gen_branch(ctx, a, TCG_COND_LTU); 131} 132 133static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a) 134{ 135 return gen_branch(ctx, a, TCG_COND_GEU); 136} 137 138static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop) 139{ 140 TCGv t0 = tcg_temp_new(); 141 TCGv t1 = tcg_temp_new(); 142 gen_get_gpr(t0, a->rs1); 143 tcg_gen_addi_tl(t0, t0, a->imm); 144 145 tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, memop); 146 gen_set_gpr(a->rd, t1); 147 tcg_temp_free(t0); 148 tcg_temp_free(t1); 149 return true; 150} 151 152static bool trans_lb(DisasContext *ctx, arg_lb *a) 153{ 154 return gen_load(ctx, a, MO_SB); 155} 156 157static bool trans_lh(DisasContext *ctx, arg_lh *a) 158{ 159 return gen_load(ctx, a, MO_TESW); 160} 161 162static bool trans_lw(DisasContext *ctx, arg_lw *a) 163{ 164 return gen_load(ctx, a, MO_TESL); 165} 166 167static bool trans_lbu(DisasContext *ctx, arg_lbu *a) 168{ 169 return gen_load(ctx, a, MO_UB); 170} 171 172static bool trans_lhu(DisasContext *ctx, arg_lhu *a) 173{ 174 return gen_load(ctx, a, MO_TEUW); 175} 176 177static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop) 178{ 179 TCGv t0 = tcg_temp_new(); 180 TCGv dat = tcg_temp_new(); 181 gen_get_gpr(t0, a->rs1); 182 tcg_gen_addi_tl(t0, t0, a->imm); 183 gen_get_gpr(dat, a->rs2); 184 185 tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx, memop); 186 tcg_temp_free(t0); 187 tcg_temp_free(dat); 188 return true; 189} 190 191 192static bool trans_sb(DisasContext *ctx, arg_sb *a) 193{ 194 return gen_store(ctx, a, MO_SB); 195} 196 197static bool trans_sh(DisasContext *ctx, arg_sh *a) 198{ 199 return gen_store(ctx, a, MO_TESW); 200} 201 202static bool trans_sw(DisasContext *ctx, arg_sw *a) 203{ 204 return gen_store(ctx, a, MO_TESL); 205} 206 207#ifdef TARGET_RISCV64 208static bool trans_lwu(DisasContext *ctx, arg_lwu *a) 209{ 210 return gen_load(ctx, a, MO_TEUL); 211} 212 213static bool trans_ld(DisasContext *ctx, arg_ld *a) 214{ 215 return gen_load(ctx, a, MO_TEQ); 216} 217 218static bool trans_sd(DisasContext *ctx, arg_sd *a) 219{ 220 return gen_store(ctx, a, MO_TEQ); 221} 222#endif 223 224static bool trans_addi(DisasContext *ctx, arg_addi *a) 225{ 226 return gen_arith_imm_fn(ctx, a, &tcg_gen_addi_tl); 227} 228 229static void gen_slt(TCGv ret, TCGv s1, TCGv s2) 230{ 231 tcg_gen_setcond_tl(TCG_COND_LT, ret, s1, s2); 232} 233 234static void gen_sltu(TCGv ret, TCGv s1, TCGv s2) 235{ 236 tcg_gen_setcond_tl(TCG_COND_LTU, ret, s1, s2); 237} 238 239 240static bool trans_slti(DisasContext *ctx, arg_slti *a) 241{ 242 return gen_arith_imm_tl(ctx, a, &gen_slt); 243} 244 245static bool trans_sltiu(DisasContext *ctx, arg_sltiu *a) 246{ 247 return gen_arith_imm_tl(ctx, a, &gen_sltu); 248} 249 250static bool trans_xori(DisasContext *ctx, arg_xori *a) 251{ 252 return gen_arith_imm_fn(ctx, a, &tcg_gen_xori_tl); 253} 254static bool trans_ori(DisasContext *ctx, arg_ori *a) 255{ 256 return gen_arith_imm_fn(ctx, a, &tcg_gen_ori_tl); 257} 258static bool trans_andi(DisasContext *ctx, arg_andi *a) 259{ 260 return gen_arith_imm_fn(ctx, a, &tcg_gen_andi_tl); 261} 262static bool trans_slli(DisasContext *ctx, arg_slli *a) 263{ 264 if (a->shamt >= TARGET_LONG_BITS) { 265 return false; 266 } 267 268 if (a->rd != 0) { 269 TCGv t = tcg_temp_new(); 270 gen_get_gpr(t, a->rs1); 271 272 tcg_gen_shli_tl(t, t, a->shamt); 273 274 gen_set_gpr(a->rd, t); 275 tcg_temp_free(t); 276 } /* NOP otherwise */ 277 return true; 278} 279 280static bool trans_srli(DisasContext *ctx, arg_srli *a) 281{ 282 if (a->shamt >= TARGET_LONG_BITS) { 283 return false; 284 } 285 286 if (a->rd != 0) { 287 TCGv t = tcg_temp_new(); 288 gen_get_gpr(t, a->rs1); 289 290 tcg_gen_shri_tl(t, t, a->shamt); 291 gen_set_gpr(a->rd, t); 292 tcg_temp_free(t); 293 } /* NOP otherwise */ 294 return true; 295} 296 297static bool trans_srai(DisasContext *ctx, arg_srai *a) 298{ 299 if (a->shamt >= TARGET_LONG_BITS) { 300 return false; 301 } 302 303 if (a->rd != 0) { 304 TCGv t = tcg_temp_new(); 305 gen_get_gpr(t, a->rs1); 306 307 tcg_gen_sari_tl(t, t, a->shamt); 308 gen_set_gpr(a->rd, t); 309 tcg_temp_free(t); 310 } /* NOP otherwise */ 311 return true; 312} 313 314static bool trans_add(DisasContext *ctx, arg_add *a) 315{ 316 return gen_arith(ctx, a, &tcg_gen_add_tl); 317} 318 319static bool trans_sub(DisasContext *ctx, arg_sub *a) 320{ 321 return gen_arith(ctx, a, &tcg_gen_sub_tl); 322} 323 324static bool trans_sll(DisasContext *ctx, arg_sll *a) 325{ 326 return gen_shift(ctx, a, &tcg_gen_shl_tl); 327} 328 329static bool trans_slt(DisasContext *ctx, arg_slt *a) 330{ 331 return gen_arith(ctx, a, &gen_slt); 332} 333 334static bool trans_sltu(DisasContext *ctx, arg_sltu *a) 335{ 336 return gen_arith(ctx, a, &gen_sltu); 337} 338 339static bool trans_xor(DisasContext *ctx, arg_xor *a) 340{ 341 return gen_arith(ctx, a, &tcg_gen_xor_tl); 342} 343 344static bool trans_srl(DisasContext *ctx, arg_srl *a) 345{ 346 return gen_shift(ctx, a, &tcg_gen_shr_tl); 347} 348 349static bool trans_sra(DisasContext *ctx, arg_sra *a) 350{ 351 return gen_shift(ctx, a, &tcg_gen_sar_tl); 352} 353 354static bool trans_or(DisasContext *ctx, arg_or *a) 355{ 356 return gen_arith(ctx, a, &tcg_gen_or_tl); 357} 358 359static bool trans_and(DisasContext *ctx, arg_and *a) 360{ 361 return gen_arith(ctx, a, &tcg_gen_and_tl); 362} 363 364#ifdef TARGET_RISCV64 365static bool trans_addiw(DisasContext *ctx, arg_addiw *a) 366{ 367 return gen_arith_imm_tl(ctx, a, &gen_addw); 368} 369 370static bool trans_slliw(DisasContext *ctx, arg_slliw *a) 371{ 372 TCGv source1; 373 source1 = tcg_temp_new(); 374 gen_get_gpr(source1, a->rs1); 375 376 tcg_gen_shli_tl(source1, source1, a->shamt); 377 tcg_gen_ext32s_tl(source1, source1); 378 gen_set_gpr(a->rd, source1); 379 380 tcg_temp_free(source1); 381 return true; 382} 383 384static bool trans_srliw(DisasContext *ctx, arg_srliw *a) 385{ 386 TCGv t = tcg_temp_new(); 387 gen_get_gpr(t, a->rs1); 388 tcg_gen_extract_tl(t, t, a->shamt, 32 - a->shamt); 389 /* sign-extend for W instructions */ 390 tcg_gen_ext32s_tl(t, t); 391 gen_set_gpr(a->rd, t); 392 tcg_temp_free(t); 393 return true; 394} 395 396static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a) 397{ 398 TCGv t = tcg_temp_new(); 399 gen_get_gpr(t, a->rs1); 400 tcg_gen_sextract_tl(t, t, a->shamt, 32 - a->shamt); 401 gen_set_gpr(a->rd, t); 402 tcg_temp_free(t); 403 return true; 404} 405 406static bool trans_addw(DisasContext *ctx, arg_addw *a) 407{ 408 return gen_arith(ctx, a, &gen_addw); 409} 410 411static bool trans_subw(DisasContext *ctx, arg_subw *a) 412{ 413 return gen_arith(ctx, a, &gen_subw); 414} 415 416static bool trans_sllw(DisasContext *ctx, arg_sllw *a) 417{ 418 TCGv source1 = tcg_temp_new(); 419 TCGv source2 = tcg_temp_new(); 420 421 gen_get_gpr(source1, a->rs1); 422 gen_get_gpr(source2, a->rs2); 423 424 tcg_gen_andi_tl(source2, source2, 0x1F); 425 tcg_gen_shl_tl(source1, source1, source2); 426 427 tcg_gen_ext32s_tl(source1, source1); 428 gen_set_gpr(a->rd, source1); 429 tcg_temp_free(source1); 430 tcg_temp_free(source2); 431 return true; 432} 433 434static bool trans_srlw(DisasContext *ctx, arg_srlw *a) 435{ 436 TCGv source1 = tcg_temp_new(); 437 TCGv source2 = tcg_temp_new(); 438 439 gen_get_gpr(source1, a->rs1); 440 gen_get_gpr(source2, a->rs2); 441 442 /* clear upper 32 */ 443 tcg_gen_ext32u_tl(source1, source1); 444 tcg_gen_andi_tl(source2, source2, 0x1F); 445 tcg_gen_shr_tl(source1, source1, source2); 446 447 tcg_gen_ext32s_tl(source1, source1); 448 gen_set_gpr(a->rd, source1); 449 tcg_temp_free(source1); 450 tcg_temp_free(source2); 451 return true; 452} 453 454static bool trans_sraw(DisasContext *ctx, arg_sraw *a) 455{ 456 TCGv source1 = tcg_temp_new(); 457 TCGv source2 = tcg_temp_new(); 458 459 gen_get_gpr(source1, a->rs1); 460 gen_get_gpr(source2, a->rs2); 461 462 /* 463 * first, trick to get it to act like working on 32 bits (get rid of 464 * upper 32, sign extend to fill space) 465 */ 466 tcg_gen_ext32s_tl(source1, source1); 467 tcg_gen_andi_tl(source2, source2, 0x1F); 468 tcg_gen_sar_tl(source1, source1, source2); 469 470 gen_set_gpr(a->rd, source1); 471 tcg_temp_free(source1); 472 tcg_temp_free(source2); 473 474 return true; 475} 476#endif 477 478static bool trans_fence(DisasContext *ctx, arg_fence *a) 479{ 480 /* FENCE is a full memory barrier. */ 481 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); 482 return true; 483} 484 485static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a) 486{ 487 if (!ctx->ext_ifencei) { 488 return false; 489 } 490 491 /* 492 * FENCE_I is a no-op in QEMU, 493 * however we need to end the translation block 494 */ 495 tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); 496 exit_tb(ctx); 497 ctx->base.is_jmp = DISAS_NORETURN; 498 return true; 499} 500 501#define RISCV_OP_CSR_PRE do {\ 502 source1 = tcg_temp_new(); \ 503 csr_store = tcg_temp_new(); \ 504 dest = tcg_temp_new(); \ 505 rs1_pass = tcg_temp_new(); \ 506 gen_get_gpr(source1, a->rs1); \ 507 tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); \ 508 tcg_gen_movi_tl(rs1_pass, a->rs1); \ 509 tcg_gen_movi_tl(csr_store, a->csr); \ 510 gen_io_start();\ 511} while (0) 512 513#define RISCV_OP_CSR_POST do {\ 514 gen_set_gpr(a->rd, dest); \ 515 tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); \ 516 exit_tb(ctx); \ 517 ctx->base.is_jmp = DISAS_NORETURN; \ 518 tcg_temp_free(source1); \ 519 tcg_temp_free(csr_store); \ 520 tcg_temp_free(dest); \ 521 tcg_temp_free(rs1_pass); \ 522} while (0) 523 524 525static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a) 526{ 527 TCGv source1, csr_store, dest, rs1_pass; 528 RISCV_OP_CSR_PRE; 529 gen_helper_csrrw(dest, cpu_env, source1, csr_store); 530 RISCV_OP_CSR_POST; 531 return true; 532} 533 534static bool trans_csrrs(DisasContext *ctx, arg_csrrs *a) 535{ 536 TCGv source1, csr_store, dest, rs1_pass; 537 RISCV_OP_CSR_PRE; 538 gen_helper_csrrs(dest, cpu_env, source1, csr_store, rs1_pass); 539 RISCV_OP_CSR_POST; 540 return true; 541} 542 543static bool trans_csrrc(DisasContext *ctx, arg_csrrc *a) 544{ 545 TCGv source1, csr_store, dest, rs1_pass; 546 RISCV_OP_CSR_PRE; 547 gen_helper_csrrc(dest, cpu_env, source1, csr_store, rs1_pass); 548 RISCV_OP_CSR_POST; 549 return true; 550} 551 552static bool trans_csrrwi(DisasContext *ctx, arg_csrrwi *a) 553{ 554 TCGv source1, csr_store, dest, rs1_pass; 555 RISCV_OP_CSR_PRE; 556 gen_helper_csrrw(dest, cpu_env, rs1_pass, csr_store); 557 RISCV_OP_CSR_POST; 558 return true; 559} 560 561static bool trans_csrrsi(DisasContext *ctx, arg_csrrsi *a) 562{ 563 TCGv source1, csr_store, dest, rs1_pass; 564 RISCV_OP_CSR_PRE; 565 gen_helper_csrrs(dest, cpu_env, rs1_pass, csr_store, rs1_pass); 566 RISCV_OP_CSR_POST; 567 return true; 568} 569 570static bool trans_csrrci(DisasContext *ctx, arg_csrrci *a) 571{ 572 TCGv source1, csr_store, dest, rs1_pass; 573 RISCV_OP_CSR_PRE; 574 gen_helper_csrrc(dest, cpu_env, rs1_pass, csr_store, rs1_pass); 575 RISCV_OP_CSR_POST; 576 return true; 577} 578