xref: /openbmc/qemu/target/mips/tcg/loong_translate.c (revision 297289dc)
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 bool decode_ext_loongson(DisasContext *ctx, uint32_t insn)
91 {
92     if (!decode_64bit_enabled(ctx)) {
93         return false;
94     }
95     if ((ctx->insn_flags & INSN_LOONGSON2E) && decode_godson2(ctx, ctx->opcode)) {
96         return true;
97     }
98     if ((ctx->insn_flags & ASE_LEXT) && decode_loong_ext(ctx, ctx->opcode)) {
99         return true;
100     }
101     return false;
102 }
103