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 22static bool trans_mul(DisasContext *ctx, arg_mul *a) 23{ 24 REQUIRE_EXT(ctx, RVM); 25 return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl); 26} 27 28static void gen_mulh(TCGv ret, TCGv s1, TCGv s2) 29{ 30 TCGv discard = tcg_temp_new(); 31 32 tcg_gen_muls2_tl(discard, ret, s1, s2); 33 tcg_temp_free(discard); 34} 35 36static bool trans_mulh(DisasContext *ctx, arg_mulh *a) 37{ 38 REQUIRE_EXT(ctx, RVM); 39 return gen_arith(ctx, a, EXT_NONE, gen_mulh); 40} 41 42static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2) 43{ 44 TCGv rl = tcg_temp_new(); 45 TCGv rh = tcg_temp_new(); 46 47 tcg_gen_mulu2_tl(rl, rh, arg1, arg2); 48 /* fix up for one negative */ 49 tcg_gen_sari_tl(rl, arg1, TARGET_LONG_BITS - 1); 50 tcg_gen_and_tl(rl, rl, arg2); 51 tcg_gen_sub_tl(ret, rh, rl); 52 53 tcg_temp_free(rl); 54 tcg_temp_free(rh); 55} 56 57static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a) 58{ 59 REQUIRE_EXT(ctx, RVM); 60 return gen_arith(ctx, a, EXT_NONE, gen_mulhsu); 61} 62 63static void gen_mulhu(TCGv ret, TCGv s1, TCGv s2) 64{ 65 TCGv discard = tcg_temp_new(); 66 67 tcg_gen_mulu2_tl(discard, ret, s1, s2); 68 tcg_temp_free(discard); 69} 70 71static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a) 72{ 73 REQUIRE_EXT(ctx, RVM); 74 return gen_arith(ctx, a, EXT_NONE, gen_mulhu); 75} 76 77static void gen_div(TCGv ret, TCGv source1, TCGv source2) 78{ 79 TCGv temp1, temp2, zero, one, mone, min; 80 81 temp1 = tcg_temp_new(); 82 temp2 = tcg_temp_new(); 83 zero = tcg_constant_tl(0); 84 one = tcg_constant_tl(1); 85 mone = tcg_constant_tl(-1); 86 min = tcg_constant_tl(1ull << (TARGET_LONG_BITS - 1)); 87 88 /* 89 * If overflow, set temp2 to 1, else source2. 90 * This produces the required result of min. 91 */ 92 tcg_gen_setcond_tl(TCG_COND_EQ, temp1, source1, min); 93 tcg_gen_setcond_tl(TCG_COND_EQ, temp2, source2, mone); 94 tcg_gen_and_tl(temp1, temp1, temp2); 95 tcg_gen_movcond_tl(TCG_COND_NE, temp2, temp1, zero, one, source2); 96 97 /* 98 * If div by zero, set temp1 to -1 and temp2 to 1 to 99 * produce the required result of -1. 100 */ 101 tcg_gen_movcond_tl(TCG_COND_EQ, temp1, source2, zero, mone, source1); 102 tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, temp2); 103 104 tcg_gen_div_tl(ret, temp1, temp2); 105 106 tcg_temp_free(temp1); 107 tcg_temp_free(temp2); 108} 109 110static bool trans_div(DisasContext *ctx, arg_div *a) 111{ 112 REQUIRE_EXT(ctx, RVM); 113 return gen_arith(ctx, a, EXT_SIGN, gen_div); 114} 115 116static void gen_divu(TCGv ret, TCGv source1, TCGv source2) 117{ 118 TCGv temp1, temp2, zero, one, max; 119 120 temp1 = tcg_temp_new(); 121 temp2 = tcg_temp_new(); 122 zero = tcg_constant_tl(0); 123 one = tcg_constant_tl(1); 124 max = tcg_constant_tl(~0); 125 126 /* 127 * If div by zero, set temp1 to max and temp2 to 1 to 128 * produce the required result of max. 129 */ 130 tcg_gen_movcond_tl(TCG_COND_EQ, temp1, source2, zero, max, source1); 131 tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, source2); 132 tcg_gen_divu_tl(ret, temp1, temp2); 133 134 tcg_temp_free(temp1); 135 tcg_temp_free(temp2); 136} 137 138static bool trans_divu(DisasContext *ctx, arg_divu *a) 139{ 140 REQUIRE_EXT(ctx, RVM); 141 return gen_arith(ctx, a, EXT_ZERO, gen_divu); 142} 143 144static void gen_rem(TCGv ret, TCGv source1, TCGv source2) 145{ 146 TCGv temp1, temp2, zero, one, mone, min; 147 148 temp1 = tcg_temp_new(); 149 temp2 = tcg_temp_new(); 150 zero = tcg_constant_tl(0); 151 one = tcg_constant_tl(1); 152 mone = tcg_constant_tl(-1); 153 min = tcg_constant_tl(1ull << (TARGET_LONG_BITS - 1)); 154 155 /* 156 * If overflow, set temp1 to 0, else source1. 157 * This avoids a possible host trap, and produces the required result of 0. 158 */ 159 tcg_gen_setcond_tl(TCG_COND_EQ, temp1, source1, min); 160 tcg_gen_setcond_tl(TCG_COND_EQ, temp2, source2, mone); 161 tcg_gen_and_tl(temp1, temp1, temp2); 162 tcg_gen_movcond_tl(TCG_COND_NE, temp1, temp1, zero, zero, source1); 163 164 /* 165 * If div by zero, set temp2 to 1, else source2. 166 * This avoids a possible host trap, but produces an incorrect result. 167 */ 168 tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, source2); 169 170 tcg_gen_rem_tl(temp1, temp1, temp2); 171 172 /* If div by zero, the required result is the original dividend. */ 173 tcg_gen_movcond_tl(TCG_COND_EQ, ret, source2, zero, source1, temp1); 174 175 tcg_temp_free(temp1); 176 tcg_temp_free(temp2); 177} 178 179static bool trans_rem(DisasContext *ctx, arg_rem *a) 180{ 181 REQUIRE_EXT(ctx, RVM); 182 return gen_arith(ctx, a, EXT_SIGN, gen_rem); 183} 184 185static void gen_remu(TCGv ret, TCGv source1, TCGv source2) 186{ 187 TCGv temp, zero, one; 188 189 temp = tcg_temp_new(); 190 zero = tcg_constant_tl(0); 191 one = tcg_constant_tl(1); 192 193 /* 194 * If div by zero, set temp to 1, else source2. 195 * This avoids a possible host trap, but produces an incorrect result. 196 */ 197 tcg_gen_movcond_tl(TCG_COND_EQ, temp, source2, zero, one, source2); 198 199 tcg_gen_remu_tl(temp, source1, temp); 200 201 /* If div by zero, the required result is the original dividend. */ 202 tcg_gen_movcond_tl(TCG_COND_EQ, ret, source2, zero, source1, temp); 203 204 tcg_temp_free(temp); 205} 206 207static bool trans_remu(DisasContext *ctx, arg_remu *a) 208{ 209 REQUIRE_EXT(ctx, RVM); 210 return gen_arith(ctx, a, EXT_ZERO, gen_remu); 211} 212 213static bool trans_mulw(DisasContext *ctx, arg_mulw *a) 214{ 215 REQUIRE_64BIT(ctx); 216 REQUIRE_EXT(ctx, RVM); 217 ctx->ol = MXL_RV32; 218 return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl); 219} 220 221static bool trans_divw(DisasContext *ctx, arg_divw *a) 222{ 223 REQUIRE_64BIT(ctx); 224 REQUIRE_EXT(ctx, RVM); 225 ctx->ol = MXL_RV32; 226 return gen_arith(ctx, a, EXT_SIGN, gen_div); 227} 228 229static bool trans_divuw(DisasContext *ctx, arg_divuw *a) 230{ 231 REQUIRE_64BIT(ctx); 232 REQUIRE_EXT(ctx, RVM); 233 ctx->ol = MXL_RV32; 234 return gen_arith(ctx, a, EXT_ZERO, gen_divu); 235} 236 237static bool trans_remw(DisasContext *ctx, arg_remw *a) 238{ 239 REQUIRE_64BIT(ctx); 240 REQUIRE_EXT(ctx, RVM); 241 ctx->ol = MXL_RV32; 242 return gen_arith(ctx, a, EXT_SIGN, gen_rem); 243} 244 245static bool trans_remuw(DisasContext *ctx, arg_remuw *a) 246{ 247 REQUIRE_64BIT(ctx); 248 REQUIRE_EXT(ctx, RVM); 249 ctx->ol = MXL_RV32; 250 return gen_arith(ctx, a, EXT_ZERO, gen_remu); 251} 252