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 bool decode_ext_loongson(DisasContext *ctx, uint32_t insn) 145 { 146 if (!decode_64bit_enabled(ctx)) { 147 return false; 148 } 149 if ((ctx->insn_flags & INSN_LOONGSON2E) && decode_godson2(ctx, ctx->opcode)) { 150 return true; 151 } 152 if ((ctx->insn_flags & ASE_LEXT) && decode_loong_ext(ctx, ctx->opcode)) { 153 return true; 154 } 155 return false; 156 } 157