1 /*
2  * Octeon-specific instructions translation routines
3  *
4  *  Copyright (c) 2022 Pavel Dovgalyuk
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8 
9 #include "qemu/osdep.h"
10 #include "tcg/tcg-op.h"
11 #include "tcg/tcg-op-gvec.h"
12 #include "exec/helper-gen.h"
13 #include "translate.h"
14 
15 /* Include the auto-generated decoder.  */
16 #include "decode-octeon.c.inc"
17 
18 static bool trans_BBIT(DisasContext *ctx, arg_BBIT *a)
19 {
20     TCGv p;
21 
22     if (ctx->hflags & MIPS_HFLAG_BMASK) {
23         LOG_DISAS("Branch in delay / forbidden slot at PC 0x"
24                   TARGET_FMT_lx "\n", ctx->base.pc_next);
25         generate_exception_end(ctx, EXCP_RI);
26         return true;
27     }
28 
29     /* Load needed operands */
30     TCGv t0 = tcg_temp_new();
31     gen_load_gpr(t0, a->rs);
32 
33     p = tcg_constant_tl(1ULL << a->p);
34     if (a->set) {
35         tcg_gen_and_tl(bcond, p, t0);
36     } else {
37         tcg_gen_andc_tl(bcond, p, t0);
38     }
39 
40     ctx->hflags |= MIPS_HFLAG_BC;
41     ctx->btarget = ctx->base.pc_next + 4 + a->offset * 4;
42     ctx->hflags |= MIPS_HFLAG_BDS32;
43 
44     tcg_temp_free(t0);
45     return true;
46 }
47 
48 static bool trans_BADDU(DisasContext *ctx, arg_BADDU *a)
49 {
50     TCGv t0, t1;
51 
52     if (a->rt == 0) {
53         /* nop */
54         return true;
55     }
56 
57     t0 = tcg_temp_new();
58     t1 = tcg_temp_new();
59     gen_load_gpr(t0, a->rs);
60     gen_load_gpr(t1, a->rt);
61 
62     tcg_gen_add_tl(t0, t0, t1);
63     tcg_gen_andi_i64(cpu_gpr[a->rd], t0, 0xff);
64 
65     tcg_temp_free(t0);
66     tcg_temp_free(t1);
67 
68     return true;
69 }
70 
71 static bool trans_DMUL(DisasContext *ctx, arg_DMUL *a)
72 {
73     TCGv t0, t1;
74 
75     if (a->rt == 0) {
76         /* nop */
77         return true;
78     }
79 
80     t0 = tcg_temp_new();
81     t1 = tcg_temp_new();
82     gen_load_gpr(t0, a->rs);
83     gen_load_gpr(t1, a->rt);
84 
85     tcg_gen_mul_i64(cpu_gpr[a->rd], t0, t1);
86 
87     tcg_temp_free(t0);
88     tcg_temp_free(t1);
89 
90     return true;
91 }
92 
93 static bool trans_EXTS(DisasContext *ctx, arg_EXTS *a)
94 {
95     TCGv t0;
96 
97     if (a->rt == 0) {
98         /* nop */
99         return true;
100     }
101 
102     t0 = tcg_temp_new();
103     gen_load_gpr(t0, a->rs);
104     tcg_gen_sextract_tl(t0, t0, a->p, a->lenm1 + 1);
105     gen_store_gpr(t0, a->rt);
106     tcg_temp_free(t0);
107 
108     return true;
109 }
110 
111 static bool trans_CINS(DisasContext *ctx, arg_CINS *a)
112 {
113     TCGv t0;
114 
115     if (a->rt == 0) {
116         /* nop */
117         return true;
118     }
119 
120     t0 = tcg_temp_new();
121     gen_load_gpr(t0, a->rs);
122     tcg_gen_deposit_z_tl(t0, t0, a->p, a->lenm1 + 1);
123     gen_store_gpr(t0, a->rt);
124     tcg_temp_free(t0);
125 
126     return true;
127 }
128 
129 static bool trans_POP(DisasContext *ctx, arg_POP *a)
130 {
131     TCGv t0;
132 
133     if (a->rd == 0) {
134         /* nop */
135         return true;
136     }
137 
138     t0 = tcg_temp_new();
139     gen_load_gpr(t0, a->rs);
140     if (!a->dw) {
141         tcg_gen_andi_i64(t0, t0, 0xffffffff);
142     }
143     tcg_gen_ctpop_tl(t0, t0);
144     gen_store_gpr(t0, a->rd);
145     tcg_temp_free(t0);
146 
147     return true;
148 }
149 
150 static bool trans_SEQNE(DisasContext *ctx, arg_SEQNE *a)
151 {
152     TCGv t0, t1;
153 
154     if (a->rd == 0) {
155         /* nop */
156         return true;
157     }
158 
159     t0 = tcg_temp_new();
160     t1 = tcg_temp_new();
161 
162     gen_load_gpr(t0, a->rs);
163     gen_load_gpr(t1, a->rt);
164 
165     if (a->ne) {
166         tcg_gen_setcond_tl(TCG_COND_NE, cpu_gpr[a->rd], t1, t0);
167     } else {
168         tcg_gen_setcond_tl(TCG_COND_EQ, cpu_gpr[a->rd], t1, t0);
169     }
170 
171     tcg_temp_free(t0);
172     tcg_temp_free(t1);
173 
174     return true;
175 }
176 
177 static bool trans_SEQNEI(DisasContext *ctx, arg_SEQNEI *a)
178 {
179     TCGv t0;
180 
181     if (a->rt == 0) {
182         /* nop */
183         return true;
184     }
185 
186     t0 = tcg_temp_new();
187 
188     gen_load_gpr(t0, a->rs);
189 
190     /* Sign-extend to 64 bit value */
191     target_ulong imm = a->imm;
192     if (a->ne) {
193         tcg_gen_setcondi_tl(TCG_COND_NE, cpu_gpr[a->rt], t0, imm);
194     } else {
195         tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_gpr[a->rt], t0, imm);
196     }
197 
198     tcg_temp_free(t0);
199 
200     return true;
201 }
202