qemu/target/riscv/insn_trans/trans_rvi.inc.c
<<
>>
Prefs
   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