qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

trans_rvm.c.inc (12483B)


      1 /*
      2  * RISC-V translation routines for the RV64M 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 
     21 #define REQUIRE_M_OR_ZMMUL(ctx) do {                      \
     22     if (!ctx->cfg_ptr->ext_zmmul && !has_ext(ctx, RVM)) { \
     23         return false;                                     \
     24     }                                                     \
     25 } while (0)
     26 
     27 static void gen_mulhu_i128(TCGv r2, TCGv r3, TCGv al, TCGv ah, TCGv bl, TCGv bh)
     28 {
     29     TCGv tmpl = tcg_temp_new();
     30     TCGv tmph = tcg_temp_new();
     31     TCGv r0 = tcg_temp_new();
     32     TCGv r1 = tcg_temp_new();
     33     TCGv zero = tcg_constant_tl(0);
     34 
     35     tcg_gen_mulu2_tl(r0, r1, al, bl);
     36 
     37     tcg_gen_mulu2_tl(tmpl, tmph, al, bh);
     38     tcg_gen_add2_tl(r1, r2, r1, zero, tmpl, tmph);
     39     tcg_gen_mulu2_tl(tmpl, tmph, ah, bl);
     40     tcg_gen_add2_tl(r1, tmph, r1, r2, tmpl, tmph);
     41     /* Overflow detection into r3 */
     42     tcg_gen_setcond_tl(TCG_COND_LTU, r3, tmph, r2);
     43 
     44     tcg_gen_mov_tl(r2, tmph);
     45 
     46     tcg_gen_mulu2_tl(tmpl, tmph, ah, bh);
     47     tcg_gen_add2_tl(r2, r3, r2, r3, tmpl, tmph);
     48 
     49     tcg_temp_free(tmpl);
     50     tcg_temp_free(tmph);
     51 }
     52 
     53 static void gen_mul_i128(TCGv rl, TCGv rh,
     54                          TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
     55 {
     56     TCGv tmpl = tcg_temp_new();
     57     TCGv tmph = tcg_temp_new();
     58     TCGv tmpx = tcg_temp_new();
     59     TCGv zero = tcg_constant_tl(0);
     60 
     61     tcg_gen_mulu2_tl(rl, rh, rs1l, rs2l);
     62     tcg_gen_mulu2_tl(tmpl, tmph, rs1l, rs2h);
     63     tcg_gen_add2_tl(rh, tmpx, rh, zero, tmpl, tmph);
     64     tcg_gen_mulu2_tl(tmpl, tmph, rs1h, rs2l);
     65     tcg_gen_add2_tl(rh, tmph, rh, tmpx, tmpl, tmph);
     66 
     67     tcg_temp_free(tmpl);
     68     tcg_temp_free(tmph);
     69     tcg_temp_free(tmpx);
     70 }
     71 
     72 static bool trans_mul(DisasContext *ctx, arg_mul *a)
     73 {
     74     REQUIRE_M_OR_ZMMUL(ctx);
     75     return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl, gen_mul_i128);
     76 }
     77 
     78 static void gen_mulh_i128(TCGv rl, TCGv rh,
     79                           TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
     80 {
     81     TCGv t0l = tcg_temp_new();
     82     TCGv t0h = tcg_temp_new();
     83     TCGv t1l = tcg_temp_new();
     84     TCGv t1h = tcg_temp_new();
     85 
     86     gen_mulhu_i128(rl, rh, rs1l, rs1h, rs2l, rs2h);
     87     tcg_gen_sari_tl(t0h, rs1h, 63);
     88     tcg_gen_and_tl(t0l, t0h, rs2l);
     89     tcg_gen_and_tl(t0h, t0h, rs2h);
     90     tcg_gen_sari_tl(t1h, rs2h, 63);
     91     tcg_gen_and_tl(t1l, t1h, rs1l);
     92     tcg_gen_and_tl(t1h, t1h, rs1h);
     93     tcg_gen_sub2_tl(t0l, t0h, rl, rh, t0l, t0h);
     94     tcg_gen_sub2_tl(rl, rh, t0l, t0h, t1l, t1h);
     95 
     96     tcg_temp_free(t0l);
     97     tcg_temp_free(t0h);
     98     tcg_temp_free(t1l);
     99     tcg_temp_free(t1h);
    100 }
    101 
    102 static void gen_mulh(TCGv ret, TCGv s1, TCGv s2)
    103 {
    104     TCGv discard = tcg_temp_new();
    105 
    106     tcg_gen_muls2_tl(discard, ret, s1, s2);
    107     tcg_temp_free(discard);
    108 }
    109 
    110 static void gen_mulh_w(TCGv ret, TCGv s1, TCGv s2)
    111 {
    112     tcg_gen_mul_tl(ret, s1, s2);
    113     tcg_gen_sari_tl(ret, ret, 32);
    114 }
    115 
    116 static bool trans_mulh(DisasContext *ctx, arg_mulh *a)
    117 {
    118     REQUIRE_M_OR_ZMMUL(ctx);
    119     return gen_arith_per_ol(ctx, a, EXT_SIGN, gen_mulh, gen_mulh_w,
    120                             gen_mulh_i128);
    121 }
    122 
    123 static void gen_mulhsu_i128(TCGv rl, TCGv rh,
    124                             TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
    125 {
    126 
    127     TCGv t0l = tcg_temp_new();
    128     TCGv t0h = tcg_temp_new();
    129 
    130     gen_mulhu_i128(rl, rh, rs1l, rs1h, rs2l, rs2h);
    131     tcg_gen_sari_tl(t0h, rs1h, 63);
    132     tcg_gen_and_tl(t0l, t0h, rs2l);
    133     tcg_gen_and_tl(t0h, t0h, rs2h);
    134     tcg_gen_sub2_tl(rl, rh, rl, rh, t0l, t0h);
    135 
    136     tcg_temp_free(t0l);
    137     tcg_temp_free(t0h);
    138 }
    139 
    140 static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2)
    141 {
    142     TCGv rl = tcg_temp_new();
    143     TCGv rh = tcg_temp_new();
    144 
    145     tcg_gen_mulu2_tl(rl, rh, arg1, arg2);
    146     /* fix up for one negative */
    147     tcg_gen_sari_tl(rl, arg1, TARGET_LONG_BITS - 1);
    148     tcg_gen_and_tl(rl, rl, arg2);
    149     tcg_gen_sub_tl(ret, rh, rl);
    150 
    151     tcg_temp_free(rl);
    152     tcg_temp_free(rh);
    153 }
    154 
    155 static void gen_mulhsu_w(TCGv ret, TCGv arg1, TCGv arg2)
    156 {
    157     TCGv t1 = tcg_temp_new();
    158     TCGv t2 = tcg_temp_new();
    159 
    160     tcg_gen_ext32s_tl(t1, arg1);
    161     tcg_gen_ext32u_tl(t2, arg2);
    162     tcg_gen_mul_tl(ret, t1, t2);
    163     tcg_temp_free(t1);
    164     tcg_temp_free(t2);
    165     tcg_gen_sari_tl(ret, ret, 32);
    166 }
    167 
    168 static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a)
    169 {
    170     REQUIRE_M_OR_ZMMUL(ctx);
    171     return gen_arith_per_ol(ctx, a, EXT_NONE, gen_mulhsu, gen_mulhsu_w,
    172                             gen_mulhsu_i128);
    173 }
    174 
    175 static void gen_mulhu(TCGv ret, TCGv s1, TCGv s2)
    176 {
    177     TCGv discard = tcg_temp_new();
    178 
    179     tcg_gen_mulu2_tl(discard, ret, s1, s2);
    180     tcg_temp_free(discard);
    181 }
    182 
    183 static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a)
    184 {
    185     REQUIRE_M_OR_ZMMUL(ctx);
    186     /* gen_mulh_w works for either sign as input. */
    187     return gen_arith_per_ol(ctx, a, EXT_ZERO, gen_mulhu, gen_mulh_w,
    188                             gen_mulhu_i128);
    189 }
    190 
    191 static void gen_div_i128(TCGv rdl, TCGv rdh,
    192                          TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
    193 {
    194     gen_helper_divs_i128(rdl, cpu_env, rs1l, rs1h, rs2l, rs2h);
    195     tcg_gen_ld_tl(rdh, cpu_env, offsetof(CPURISCVState, retxh));
    196 }
    197 
    198 static void gen_div(TCGv ret, TCGv source1, TCGv source2)
    199 {
    200     TCGv temp1, temp2, zero, one, mone, min;
    201 
    202     temp1 = tcg_temp_new();
    203     temp2 = tcg_temp_new();
    204     zero = tcg_constant_tl(0);
    205     one = tcg_constant_tl(1);
    206     mone = tcg_constant_tl(-1);
    207     min = tcg_constant_tl(1ull << (TARGET_LONG_BITS - 1));
    208 
    209     /*
    210      * If overflow, set temp2 to 1, else source2.
    211      * This produces the required result of min.
    212      */
    213     tcg_gen_setcond_tl(TCG_COND_EQ, temp1, source1, min);
    214     tcg_gen_setcond_tl(TCG_COND_EQ, temp2, source2, mone);
    215     tcg_gen_and_tl(temp1, temp1, temp2);
    216     tcg_gen_movcond_tl(TCG_COND_NE, temp2, temp1, zero, one, source2);
    217 
    218     /*
    219      * If div by zero, set temp1 to -1 and temp2 to 1 to
    220      * produce the required result of -1.
    221      */
    222     tcg_gen_movcond_tl(TCG_COND_EQ, temp1, source2, zero, mone, source1);
    223     tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, temp2);
    224 
    225     tcg_gen_div_tl(ret, temp1, temp2);
    226 
    227     tcg_temp_free(temp1);
    228     tcg_temp_free(temp2);
    229 }
    230 
    231 static bool trans_div(DisasContext *ctx, arg_div *a)
    232 {
    233     REQUIRE_EXT(ctx, RVM);
    234     return gen_arith(ctx, a, EXT_SIGN, gen_div, gen_div_i128);
    235 }
    236 
    237 static void gen_divu_i128(TCGv rdl, TCGv rdh,
    238                           TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
    239 {
    240     gen_helper_divu_i128(rdl, cpu_env, rs1l, rs1h, rs2l, rs2h);
    241     tcg_gen_ld_tl(rdh, cpu_env, offsetof(CPURISCVState, retxh));
    242 }
    243 
    244 static void gen_divu(TCGv ret, TCGv source1, TCGv source2)
    245 {
    246     TCGv temp1, temp2, zero, one, max;
    247 
    248     temp1 = tcg_temp_new();
    249     temp2 = tcg_temp_new();
    250     zero = tcg_constant_tl(0);
    251     one = tcg_constant_tl(1);
    252     max = tcg_constant_tl(~0);
    253 
    254     /*
    255      * If div by zero, set temp1 to max and temp2 to 1 to
    256      * produce the required result of max.
    257      */
    258     tcg_gen_movcond_tl(TCG_COND_EQ, temp1, source2, zero, max, source1);
    259     tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, source2);
    260     tcg_gen_divu_tl(ret, temp1, temp2);
    261 
    262     tcg_temp_free(temp1);
    263     tcg_temp_free(temp2);
    264 }
    265 
    266 static bool trans_divu(DisasContext *ctx, arg_divu *a)
    267 {
    268     REQUIRE_EXT(ctx, RVM);
    269     return gen_arith(ctx, a, EXT_ZERO, gen_divu, gen_divu_i128);
    270 }
    271 
    272 static void gen_rem_i128(TCGv rdl, TCGv rdh,
    273                          TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
    274 {
    275     gen_helper_rems_i128(rdl, cpu_env, rs1l, rs1h, rs2l, rs2h);
    276     tcg_gen_ld_tl(rdh, cpu_env, offsetof(CPURISCVState, retxh));
    277 }
    278 
    279 static void gen_rem(TCGv ret, TCGv source1, TCGv source2)
    280 {
    281     TCGv temp1, temp2, zero, one, mone, min;
    282 
    283     temp1 = tcg_temp_new();
    284     temp2 = tcg_temp_new();
    285     zero = tcg_constant_tl(0);
    286     one = tcg_constant_tl(1);
    287     mone = tcg_constant_tl(-1);
    288     min = tcg_constant_tl(1ull << (TARGET_LONG_BITS - 1));
    289 
    290     /*
    291      * If overflow, set temp1 to 0, else source1.
    292      * This avoids a possible host trap, and produces the required result of 0.
    293      */
    294     tcg_gen_setcond_tl(TCG_COND_EQ, temp1, source1, min);
    295     tcg_gen_setcond_tl(TCG_COND_EQ, temp2, source2, mone);
    296     tcg_gen_and_tl(temp1, temp1, temp2);
    297     tcg_gen_movcond_tl(TCG_COND_NE, temp1, temp1, zero, zero, source1);
    298 
    299     /*
    300      * If div by zero, set temp2 to 1, else source2.
    301      * This avoids a possible host trap, but produces an incorrect result.
    302      */
    303     tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, source2);
    304 
    305     tcg_gen_rem_tl(temp1, temp1, temp2);
    306 
    307     /* If div by zero, the required result is the original dividend. */
    308     tcg_gen_movcond_tl(TCG_COND_EQ, ret, source2, zero, source1, temp1);
    309 
    310     tcg_temp_free(temp1);
    311     tcg_temp_free(temp2);
    312 }
    313 
    314 static bool trans_rem(DisasContext *ctx, arg_rem *a)
    315 {
    316     REQUIRE_EXT(ctx, RVM);
    317     return gen_arith(ctx, a, EXT_SIGN, gen_rem, gen_rem_i128);
    318 }
    319 
    320 static void gen_remu_i128(TCGv rdl, TCGv rdh,
    321                           TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
    322 {
    323     gen_helper_remu_i128(rdl, cpu_env, rs1l, rs1h, rs2l, rs2h);
    324     tcg_gen_ld_tl(rdh, cpu_env, offsetof(CPURISCVState, retxh));
    325 }
    326 
    327 static void gen_remu(TCGv ret, TCGv source1, TCGv source2)
    328 {
    329     TCGv temp, zero, one;
    330 
    331     temp = tcg_temp_new();
    332     zero = tcg_constant_tl(0);
    333     one = tcg_constant_tl(1);
    334 
    335     /*
    336      * If div by zero, set temp to 1, else source2.
    337      * This avoids a possible host trap, but produces an incorrect result.
    338      */
    339     tcg_gen_movcond_tl(TCG_COND_EQ, temp, source2, zero, one, source2);
    340 
    341     tcg_gen_remu_tl(temp, source1, temp);
    342 
    343     /* If div by zero, the required result is the original dividend. */
    344     tcg_gen_movcond_tl(TCG_COND_EQ, ret, source2, zero, source1, temp);
    345 
    346     tcg_temp_free(temp);
    347 }
    348 
    349 static bool trans_remu(DisasContext *ctx, arg_remu *a)
    350 {
    351     REQUIRE_EXT(ctx, RVM);
    352     return gen_arith(ctx, a, EXT_ZERO, gen_remu, gen_remu_i128);
    353 }
    354 
    355 static bool trans_mulw(DisasContext *ctx, arg_mulw *a)
    356 {
    357     REQUIRE_64_OR_128BIT(ctx);
    358     REQUIRE_M_OR_ZMMUL(ctx);
    359     ctx->ol = MXL_RV32;
    360     return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl, NULL);
    361 }
    362 
    363 static bool trans_divw(DisasContext *ctx, arg_divw *a)
    364 {
    365     REQUIRE_64_OR_128BIT(ctx);
    366     REQUIRE_EXT(ctx, RVM);
    367     ctx->ol = MXL_RV32;
    368     return gen_arith(ctx, a, EXT_SIGN, gen_div, NULL);
    369 }
    370 
    371 static bool trans_divuw(DisasContext *ctx, arg_divuw *a)
    372 {
    373     REQUIRE_64_OR_128BIT(ctx);
    374     REQUIRE_EXT(ctx, RVM);
    375     ctx->ol = MXL_RV32;
    376     return gen_arith(ctx, a, EXT_ZERO, gen_divu, NULL);
    377 }
    378 
    379 static bool trans_remw(DisasContext *ctx, arg_remw *a)
    380 {
    381     REQUIRE_64_OR_128BIT(ctx);
    382     REQUIRE_EXT(ctx, RVM);
    383     ctx->ol = MXL_RV32;
    384     return gen_arith(ctx, a, EXT_SIGN, gen_rem, NULL);
    385 }
    386 
    387 static bool trans_remuw(DisasContext *ctx, arg_remuw *a)
    388 {
    389     REQUIRE_64_OR_128BIT(ctx);
    390     REQUIRE_EXT(ctx, RVM);
    391     ctx->ol = MXL_RV32;
    392     return gen_arith(ctx, a, EXT_ZERO, gen_remu, NULL);
    393 }
    394 
    395 static bool trans_muld(DisasContext *ctx, arg_muld *a)
    396 {
    397     REQUIRE_128BIT(ctx);
    398     REQUIRE_M_OR_ZMMUL(ctx);
    399     ctx->ol = MXL_RV64;
    400     return gen_arith(ctx, a, EXT_SIGN, tcg_gen_mul_tl, NULL);
    401 }
    402 
    403 static bool trans_divd(DisasContext *ctx, arg_divd *a)
    404 {
    405     REQUIRE_128BIT(ctx);
    406     REQUIRE_EXT(ctx, RVM);
    407     ctx->ol = MXL_RV64;
    408     return gen_arith(ctx, a, EXT_SIGN, gen_div, NULL);
    409 }
    410 
    411 static bool trans_divud(DisasContext *ctx, arg_divud *a)
    412 {
    413     REQUIRE_128BIT(ctx);
    414     REQUIRE_EXT(ctx, RVM);
    415     ctx->ol = MXL_RV64;
    416     return gen_arith(ctx, a, EXT_ZERO, gen_divu, NULL);
    417 }
    418 
    419 static bool trans_remd(DisasContext *ctx, arg_remd *a)
    420 {
    421     REQUIRE_128BIT(ctx);
    422     REQUIRE_EXT(ctx, RVM);
    423     ctx->ol = MXL_RV64;
    424     return gen_arith(ctx, a, EXT_SIGN, gen_rem, NULL);
    425 }
    426 
    427 static bool trans_remud(DisasContext *ctx, arg_remud *a)
    428 {
    429     REQUIRE_128BIT(ctx);
    430     REQUIRE_EXT(ctx, RVM);
    431     ctx->ol = MXL_RV64;
    432     return gen_arith(ctx, a, EXT_ZERO, gen_remu, NULL);
    433 }