1 /* 2 * MIPS Loongson 64-bit translation routines 3 * 4 * Copyright (c) 2004-2005 Jocelyn Mayer 5 * Copyright (c) 2006 Marius Groeger (FPU operations) 6 * Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support) 7 * Copyright (c) 2011 Richard Henderson <rth@twiddle.net> 8 * Copyright (c) 2021 Philippe Mathieu-Daudé 9 * 10 * This code is licensed under the GNU GPLv2 and later. 11 */ 12 13 #include "qemu/osdep.h" 14 #include "translate.h" 15 16 /* Include the auto-generated decoder. */ 17 #include "decode-godson2.c.inc" 18 #include "decode-loong-ext.c.inc" 19 20 /* 21 * Word or double-word Fixed-point instructions. 22 * --------------------------------------------- 23 * 24 * Fixed-point multiplies and divisions write only 25 * one result into general-purpose registers. 26 */ 27 28 static bool gen_lext_DIV_G(DisasContext *s, int rd, int rs, int rt, 29 bool is_double) 30 { 31 TCGv t0, t1; 32 TCGLabel *l1, *l2, *l3; 33 34 if (is_double) { 35 if (TARGET_LONG_BITS != 64) { 36 return false; 37 } 38 check_mips_64(s); 39 } 40 41 if (rd == 0) { 42 /* Treat as NOP. */ 43 return true; 44 } 45 46 t0 = tcg_temp_new(); 47 t1 = tcg_temp_new(); 48 l1 = gen_new_label(); 49 l2 = gen_new_label(); 50 l3 = gen_new_label(); 51 52 gen_load_gpr(t0, rs); 53 gen_load_gpr(t1, rt); 54 55 if (!is_double) { 56 tcg_gen_ext32s_tl(t0, t0); 57 tcg_gen_ext32s_tl(t1, t1); 58 } 59 tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); 60 tcg_gen_movi_tl(cpu_gpr[rd], 0); 61 tcg_gen_br(l3); 62 gen_set_label(l1); 63 64 tcg_gen_brcondi_tl(TCG_COND_NE, t0, is_double && TARGET_LONG_BITS == 64 65 ? LLONG_MIN : INT_MIN, l2); 66 tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2); 67 tcg_gen_mov_tl(cpu_gpr[rd], t0); 68 69 tcg_gen_br(l3); 70 gen_set_label(l2); 71 tcg_gen_div_tl(cpu_gpr[rd], t0, t1); 72 if (!is_double) { 73 tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); 74 } 75 gen_set_label(l3); 76 77 return true; 78 } 79 80 static bool trans_DIV_G(DisasContext *s, arg_muldiv *a) 81 { 82 return gen_lext_DIV_G(s, a->rd, a->rs, a->rt, false); 83 } 84 85 static bool trans_DDIV_G(DisasContext *s, arg_muldiv *a) 86 { 87 return gen_lext_DIV_G(s, a->rd, a->rs, a->rt, true); 88 } 89 90 static bool gen_lext_DIVU_G(DisasContext *s, int rd, int rs, int rt, 91 bool is_double) 92 { 93 TCGv t0, t1; 94 TCGLabel *l1, *l2; 95 96 if (is_double) { 97 if (TARGET_LONG_BITS != 64) { 98 return false; 99 } 100 check_mips_64(s); 101 } 102 103 if (rd == 0) { 104 /* Treat as NOP. */ 105 return true; 106 } 107 108 t0 = tcg_temp_new(); 109 t1 = tcg_temp_new(); 110 l1 = gen_new_label(); 111 l2 = gen_new_label(); 112 113 gen_load_gpr(t0, rs); 114 gen_load_gpr(t1, rt); 115 116 if (!is_double) { 117 tcg_gen_ext32u_tl(t0, t0); 118 tcg_gen_ext32u_tl(t1, t1); 119 } 120 tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); 121 tcg_gen_movi_tl(cpu_gpr[rd], 0); 122 123 tcg_gen_br(l2); 124 gen_set_label(l1); 125 tcg_gen_divu_tl(cpu_gpr[rd], t0, t1); 126 if (!is_double) { 127 tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); 128 } 129 gen_set_label(l2); 130 131 return true; 132 } 133 134 static bool trans_DIVU_G(DisasContext *s, arg_muldiv *a) 135 { 136 return gen_lext_DIVU_G(s, a->rd, a->rs, a->rt, false); 137 } 138 139 static bool trans_DDIVU_G(DisasContext *s, arg_muldiv *a) 140 { 141 return gen_lext_DIVU_G(s, a->rd, a->rs, a->rt, true); 142 } 143 144 static bool gen_lext_MOD_G(DisasContext *s, int rd, int rs, int rt, 145 bool is_double) 146 { 147 TCGv t0, t1; 148 TCGLabel *l1, *l2, *l3; 149 150 if (is_double) { 151 if (TARGET_LONG_BITS != 64) { 152 return false; 153 } 154 check_mips_64(s); 155 } 156 157 if (rd == 0) { 158 /* Treat as NOP. */ 159 return true; 160 } 161 162 t0 = tcg_temp_new(); 163 t1 = tcg_temp_new(); 164 l1 = gen_new_label(); 165 l2 = gen_new_label(); 166 l3 = gen_new_label(); 167 168 gen_load_gpr(t0, rs); 169 gen_load_gpr(t1, rt); 170 171 if (!is_double) { 172 tcg_gen_ext32u_tl(t0, t0); 173 tcg_gen_ext32u_tl(t1, t1); 174 } 175 tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); 176 tcg_gen_brcondi_tl(TCG_COND_NE, t0, is_double && TARGET_LONG_BITS == 64 177 ? LLONG_MIN : INT_MIN, l2); 178 tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2); 179 gen_set_label(l1); 180 tcg_gen_movi_tl(cpu_gpr[rd], 0); 181 tcg_gen_br(l3); 182 gen_set_label(l2); 183 tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); 184 if (!is_double) { 185 tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); 186 } 187 gen_set_label(l3); 188 189 return true; 190 } 191 192 static bool trans_MOD_G(DisasContext *s, arg_muldiv *a) 193 { 194 return gen_lext_MOD_G(s, a->rd, a->rs, a->rt, false); 195 } 196 197 static bool trans_DMOD_G(DisasContext *s, arg_muldiv *a) 198 { 199 return gen_lext_MOD_G(s, a->rd, a->rs, a->rt, true); 200 } 201 202 static bool gen_lext_MODU_G(DisasContext *s, int rd, int rs, int rt, 203 bool is_double) 204 { 205 TCGv t0, t1; 206 TCGLabel *l1, *l2; 207 208 if (is_double) { 209 if (TARGET_LONG_BITS != 64) { 210 return false; 211 } 212 check_mips_64(s); 213 } 214 215 if (rd == 0) { 216 /* Treat as NOP. */ 217 return true; 218 } 219 220 t0 = tcg_temp_new(); 221 t1 = tcg_temp_new(); 222 l1 = gen_new_label(); 223 l2 = gen_new_label(); 224 225 gen_load_gpr(t0, rs); 226 gen_load_gpr(t1, rt); 227 228 if (!is_double) { 229 tcg_gen_ext32u_tl(t0, t0); 230 tcg_gen_ext32u_tl(t1, t1); 231 } 232 tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); 233 tcg_gen_movi_tl(cpu_gpr[rd], 0); 234 tcg_gen_br(l2); 235 gen_set_label(l1); 236 tcg_gen_remu_tl(cpu_gpr[rd], t0, t1); 237 if (!is_double) { 238 tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); 239 } 240 gen_set_label(l2); 241 242 return true; 243 } 244 245 static bool trans_MODU_G(DisasContext *s, arg_muldiv *a) 246 { 247 return gen_lext_MODU_G(s, a->rd, a->rs, a->rt, false); 248 } 249 250 static bool trans_DMODU_G(DisasContext *s, arg_muldiv *a) 251 { 252 return gen_lext_MODU_G(s, a->rd, a->rs, a->rt, true); 253 } 254 255 bool decode_ext_loongson(DisasContext *ctx, uint32_t insn) 256 { 257 if (!decode_64bit_enabled(ctx)) { 258 return false; 259 } 260 if ((ctx->insn_flags & INSN_LOONGSON2E) && decode_godson2(ctx, ctx->opcode)) { 261 return true; 262 } 263 if ((ctx->insn_flags & ASE_LEXT) && decode_loong_ext(ctx, ctx->opcode)) { 264 return true; 265 } 266 return false; 267 } 268