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