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 (rd == 0) { 35 /* Treat as NOP. */ 36 return true; 37 } 38 39 t0 = tcg_temp_new(); 40 t1 = tcg_temp_new(); 41 l1 = gen_new_label(); 42 l2 = gen_new_label(); 43 l3 = gen_new_label(); 44 45 gen_load_gpr(t0, rs); 46 gen_load_gpr(t1, rt); 47 48 if (!is_double) { 49 tcg_gen_ext32s_tl(t0, t0); 50 tcg_gen_ext32s_tl(t1, t1); 51 } 52 tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); 53 tcg_gen_movi_tl(cpu_gpr[rd], 0); 54 tcg_gen_br(l3); 55 gen_set_label(l1); 56 57 tcg_gen_brcondi_tl(TCG_COND_NE, t0, is_double ? LLONG_MIN : INT_MIN, l2); 58 tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2); 59 tcg_gen_mov_tl(cpu_gpr[rd], t0); 60 61 tcg_gen_br(l3); 62 gen_set_label(l2); 63 tcg_gen_div_tl(cpu_gpr[rd], t0, t1); 64 if (!is_double) { 65 tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); 66 } 67 gen_set_label(l3); 68 69 return true; 70 } 71 72 static bool trans_DIV_G(DisasContext *s, arg_muldiv *a) 73 { 74 return gen_lext_DIV_G(s, a->rd, a->rs, a->rt, false); 75 } 76 77 static bool trans_DDIV_G(DisasContext *s, arg_muldiv *a) 78 { 79 return gen_lext_DIV_G(s, a->rd, a->rs, a->rt, true); 80 } 81 82 static bool gen_lext_DIVU_G(DisasContext *s, int rd, int rs, int rt, 83 bool is_double) 84 { 85 TCGv t0, t1; 86 TCGLabel *l1, *l2; 87 88 if (rd == 0) { 89 /* Treat as NOP. */ 90 return true; 91 } 92 93 t0 = tcg_temp_new(); 94 t1 = tcg_temp_new(); 95 l1 = gen_new_label(); 96 l2 = gen_new_label(); 97 98 gen_load_gpr(t0, rs); 99 gen_load_gpr(t1, rt); 100 101 if (!is_double) { 102 tcg_gen_ext32u_tl(t0, t0); 103 tcg_gen_ext32u_tl(t1, t1); 104 } 105 tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); 106 tcg_gen_movi_tl(cpu_gpr[rd], 0); 107 108 tcg_gen_br(l2); 109 gen_set_label(l1); 110 tcg_gen_divu_tl(cpu_gpr[rd], t0, t1); 111 if (!is_double) { 112 tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); 113 } 114 gen_set_label(l2); 115 116 return true; 117 } 118 119 static bool trans_DIVU_G(DisasContext *s, arg_muldiv *a) 120 { 121 return gen_lext_DIVU_G(s, a->rd, a->rs, a->rt, false); 122 } 123 124 static bool trans_DDIVU_G(DisasContext *s, arg_muldiv *a) 125 { 126 return gen_lext_DIVU_G(s, a->rd, a->rs, a->rt, true); 127 } 128 129 static bool gen_lext_MOD_G(DisasContext *s, int rd, int rs, int rt, 130 bool is_double) 131 { 132 TCGv t0, t1; 133 TCGLabel *l1, *l2, *l3; 134 135 if (rd == 0) { 136 /* Treat as NOP. */ 137 return true; 138 } 139 140 t0 = tcg_temp_new(); 141 t1 = tcg_temp_new(); 142 l1 = gen_new_label(); 143 l2 = gen_new_label(); 144 l3 = gen_new_label(); 145 146 gen_load_gpr(t0, rs); 147 gen_load_gpr(t1, rt); 148 149 if (!is_double) { 150 tcg_gen_ext32u_tl(t0, t0); 151 tcg_gen_ext32u_tl(t1, t1); 152 } 153 tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); 154 tcg_gen_brcondi_tl(TCG_COND_NE, t0, is_double ? LLONG_MIN : INT_MIN, l2); 155 tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2); 156 gen_set_label(l1); 157 tcg_gen_movi_tl(cpu_gpr[rd], 0); 158 tcg_gen_br(l3); 159 gen_set_label(l2); 160 tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); 161 if (!is_double) { 162 tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); 163 } 164 gen_set_label(l3); 165 166 return true; 167 } 168 169 static bool trans_MOD_G(DisasContext *s, arg_muldiv *a) 170 { 171 return gen_lext_MOD_G(s, a->rd, a->rs, a->rt, false); 172 } 173 174 static bool trans_DMOD_G(DisasContext *s, arg_muldiv *a) 175 { 176 return gen_lext_MOD_G(s, a->rd, a->rs, a->rt, true); 177 } 178 179 static bool gen_lext_MODU_G(DisasContext *s, int rd, int rs, int rt, 180 bool is_double) 181 { 182 TCGv t0, t1; 183 TCGLabel *l1, *l2; 184 185 if (rd == 0) { 186 /* Treat as NOP. */ 187 return true; 188 } 189 190 t0 = tcg_temp_new(); 191 t1 = tcg_temp_new(); 192 l1 = gen_new_label(); 193 l2 = gen_new_label(); 194 195 gen_load_gpr(t0, rs); 196 gen_load_gpr(t1, rt); 197 198 if (!is_double) { 199 tcg_gen_ext32u_tl(t0, t0); 200 tcg_gen_ext32u_tl(t1, t1); 201 } 202 tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); 203 tcg_gen_movi_tl(cpu_gpr[rd], 0); 204 tcg_gen_br(l2); 205 gen_set_label(l1); 206 tcg_gen_remu_tl(cpu_gpr[rd], t0, t1); 207 if (!is_double) { 208 tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); 209 } 210 gen_set_label(l2); 211 212 return true; 213 } 214 215 static bool trans_MODU_G(DisasContext *s, arg_muldiv *a) 216 { 217 return gen_lext_MODU_G(s, a->rd, a->rs, a->rt, false); 218 } 219 220 static bool trans_DMODU_G(DisasContext *s, arg_muldiv *a) 221 { 222 return gen_lext_MODU_G(s, a->rd, a->rs, a->rt, true); 223 } 224 225 static bool gen_lext_MULT_G(DisasContext *s, int rd, int rs, int rt, 226 bool is_double) 227 { 228 TCGv t0, t1; 229 230 if (rd == 0) { 231 /* Treat as NOP. */ 232 return true; 233 } 234 235 t0 = tcg_temp_new(); 236 t1 = tcg_temp_new(); 237 238 gen_load_gpr(t0, rs); 239 gen_load_gpr(t1, rt); 240 241 tcg_gen_mul_tl(cpu_gpr[rd], t0, t1); 242 if (!is_double) { 243 tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); 244 } 245 246 return true; 247 } 248 249 static bool trans_MULTu_G(DisasContext *s, arg_muldiv *a) 250 { 251 return gen_lext_MULT_G(s, a->rd, a->rs, a->rt, false); 252 } 253 254 static bool trans_DMULTu_G(DisasContext *s, arg_muldiv *a) 255 { 256 return gen_lext_MULT_G(s, a->rd, a->rs, a->rt, true); 257 } 258 259 bool decode_ext_loongson(DisasContext *ctx, uint32_t insn) 260 { 261 if (!decode_64bit_enabled(ctx)) { 262 return false; 263 } 264 if ((ctx->insn_flags & INSN_LOONGSON2E) && decode_godson2(ctx, ctx->opcode)) { 265 return true; 266 } 267 if ((ctx->insn_flags & ASE_LEXT) && decode_loong_ext(ctx, ctx->opcode)) { 268 return true; 269 } 270 return false; 271 } 272