xref: /openbmc/qemu/target/mips/tcg/loong_translate.c (revision c112a5dd)
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