xref: /openbmc/qemu/target/mips/tcg/translate.h (revision a56ac09f5c37f57059c2a2c5ae6aeff7f7241a84)
1 /*
2  *  MIPS translation routines.
3  *
4  *  Copyright (c) 2004-2005 Jocelyn Mayer
5  *
6  * SPDX-License-Identifier: LGPL-2.1-or-later
7  */
8 #ifndef TARGET_MIPS_TRANSLATE_H
9 #define TARGET_MIPS_TRANSLATE_H
10 
11 #include "cpu.h"
12 #include "tcg/tcg-op.h"
13 #include "exec/translator.h"
14 #include "exec/helper-gen.h"
15 #include "qemu/log.h"
16 
17 #define MIPS_DEBUG_DISAS 0
18 
19 typedef struct DisasContext {
20     DisasContextBase base;
21     target_ulong saved_pc;
22     target_ulong page_start;
23     uint32_t opcode;
24     uint64_t insn_flags;
25     int32_t CP0_Config0;
26     int32_t CP0_Config1;
27     int32_t CP0_Config2;
28     int32_t CP0_Config3;
29     int32_t CP0_Config5;
30     /* Routine used to access memory */
31     int mem_idx;
32     MemOp default_tcg_memop_mask;
33     uint32_t hflags, saved_hflags;
34     target_ulong btarget;
35     bool ulri;
36     int kscrexist;
37     bool rxi;
38     int ie;
39     bool bi;
40     bool bp;
41     uint64_t PAMask;
42     bool mvh;
43     bool eva;
44     bool sc;
45     int CP0_LLAddr_shift;
46     bool ps;
47     bool vp;
48     bool cmgcr;
49     bool mrp;
50     bool nan2008;
51     bool abs2008;
52     bool mi;
53     int gi;
54     bool crcp;
55 } DisasContext;
56 
57 #define DISAS_STOP       DISAS_TARGET_0
58 #define DISAS_EXIT       DISAS_TARGET_1
59 #define DISAS_SEMIHOST   DISAS_TARGET_2
60 
61 /* MIPS major opcodes */
62 #define MASK_OP_MAJOR(op)   (op & (0x3F << 26))
63 
64 #define OPC_CP1 (0x11 << 26)
65 
66 /* Coprocessor 1 (rs field) */
67 #define MASK_CP1(op)                (MASK_OP_MAJOR(op) | (op & (0x1F << 21)))
68 
69 /* Values for the fmt field in FP instructions */
70 enum {
71     /* 0 - 15 are reserved */
72     FMT_S = 16,          /* single fp */
73     FMT_D = 17,          /* double fp */
74     FMT_E = 18,          /* extended fp */
75     FMT_Q = 19,          /* quad fp */
76     FMT_W = 20,          /* 32-bit fixed */
77     FMT_L = 21,          /* 64-bit fixed */
78     FMT_PS = 22,         /* paired single fp */
79     /* 23 - 31 are reserved */
80 };
81 
82 enum {
83     OPC_MFC1     = (0x00 << 21) | OPC_CP1,
84     OPC_DMFC1    = (0x01 << 21) | OPC_CP1,
85     OPC_CFC1     = (0x02 << 21) | OPC_CP1,
86     OPC_MFHC1    = (0x03 << 21) | OPC_CP1,
87     OPC_MTC1     = (0x04 << 21) | OPC_CP1,
88     OPC_DMTC1    = (0x05 << 21) | OPC_CP1,
89     OPC_CTC1     = (0x06 << 21) | OPC_CP1,
90     OPC_MTHC1    = (0x07 << 21) | OPC_CP1,
91     OPC_BC1      = (0x08 << 21) | OPC_CP1, /* bc */
92     OPC_BC1ANY2  = (0x09 << 21) | OPC_CP1,
93     OPC_BC1ANY4  = (0x0A << 21) | OPC_CP1,
94     OPC_S_FMT    = (FMT_S << 21) | OPC_CP1,
95     OPC_D_FMT    = (FMT_D << 21) | OPC_CP1,
96     OPC_E_FMT    = (FMT_E << 21) | OPC_CP1,
97     OPC_Q_FMT    = (FMT_Q << 21) | OPC_CP1,
98     OPC_W_FMT    = (FMT_W << 21) | OPC_CP1,
99     OPC_L_FMT    = (FMT_L << 21) | OPC_CP1,
100     OPC_PS_FMT   = (FMT_PS << 21) | OPC_CP1,
101     OPC_BC1EQZ   = (0x09 << 21) | OPC_CP1,
102     OPC_BC1NEZ   = (0x0D << 21) | OPC_CP1,
103 };
104 
105 #define MASK_CP1_FUNC(op)           (MASK_CP1(op) | (op & 0x3F))
106 #define MASK_BC1(op)                (MASK_CP1(op) | (op & (0x3 << 16)))
107 
108 enum {
109     OPC_BC1F     = (0x00 << 16) | OPC_BC1,
110     OPC_BC1T     = (0x01 << 16) | OPC_BC1,
111     OPC_BC1FL    = (0x02 << 16) | OPC_BC1,
112     OPC_BC1TL    = (0x03 << 16) | OPC_BC1,
113 };
114 
115 enum {
116     OPC_BC1FANY2     = (0x00 << 16) | OPC_BC1ANY2,
117     OPC_BC1TANY2     = (0x01 << 16) | OPC_BC1ANY2,
118 };
119 
120 enum {
121     OPC_BC1FANY4     = (0x00 << 16) | OPC_BC1ANY4,
122     OPC_BC1TANY4     = (0x01 << 16) | OPC_BC1ANY4,
123 };
124 
125 #define gen_helper_0e1i(name, arg1, arg2) do { \
126     gen_helper_##name(tcg_env, arg1, tcg_constant_i32(arg2)); \
127     } while (0)
128 
129 #define gen_helper_1e0i(name, ret, arg1) do { \
130     gen_helper_##name(ret, tcg_env, tcg_constant_i32(arg1)); \
131     } while (0)
132 
133 #define gen_helper_0e2i(name, arg1, arg2, arg3) do { \
134     gen_helper_##name(tcg_env, arg1, arg2, tcg_constant_i32(arg3));\
135     } while (0)
136 
137 void generate_exception(DisasContext *ctx, int excp);
138 void generate_exception_err(DisasContext *ctx, int excp, int err);
139 void generate_exception_end(DisasContext *ctx, int excp);
140 void generate_exception_break(DisasContext *ctx, int code);
141 void gen_reserved_instruction(DisasContext *ctx);
142 
143 void check_insn(DisasContext *ctx, uint64_t flags);
144 void check_mips_64(DisasContext *ctx);
145 /**
146  * check_cp0_enabled:
147  * Return %true if CP0 is enabled, otherwise return %false
148  * and emit a 'coprocessor unusable' exception.
149  */
150 bool check_cp0_enabled(DisasContext *ctx);
151 void check_cp1_enabled(DisasContext *ctx);
152 void check_cp1_64bitmode(DisasContext *ctx);
153 void check_cp1_registers(DisasContext *ctx, int regs);
154 void check_cop1x(DisasContext *ctx);
155 
156 void gen_base_offset_addr(DisasContext *ctx, TCGv addr, int base, int offset);
157 void gen_base_index_addr(DisasContext *ctx, TCGv addr, int base, int index);
158 void gen_move_low32(TCGv ret, TCGv_i64 arg);
159 void gen_move_high32(TCGv ret, TCGv_i64 arg);
160 void gen_load_gpr(TCGv t, int reg);
161 void gen_store_gpr(TCGv t, int reg);
162 #if defined(TARGET_MIPS64)
163 void gen_load_gpr_hi(TCGv_i64 t, int reg);
164 void gen_store_gpr_hi(TCGv_i64 t, int reg);
165 #endif /* TARGET_MIPS64 */
166 void gen_load_fpr32(DisasContext *ctx, TCGv_i32 t, int reg);
167 void gen_load_fpr64(DisasContext *ctx, TCGv_i64 t, int reg);
168 void gen_store_fpr32(DisasContext *ctx, TCGv_i32 t, int reg);
169 void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg);
170 int get_fp_bit(int cc);
171 
172 void gen_lx(DisasContext *ctx, int rd, int base, int index, MemOp mop);
173 void gen_ldxs(DisasContext *ctx, int base, int index, int rd);
174 void gen_align(DisasContext *ctx, int wordsz, int rd, int rs, int rt, int bp);
175 void gen_addiupc(DisasContext *ctx, int rx, int imm,
176                  int is_64_bit, int extended);
177 
178 /*
179  * Address Computation and Large Constant Instructions
180  */
181 void gen_op_addr_add(DisasContext *ctx, TCGv ret, TCGv arg0, TCGv arg1);
182 void gen_op_addr_addi(DisasContext *ctx, TCGv ret, TCGv base, target_long ofs);
183 bool gen_lsa(DisasContext *ctx, int rd, int rt, int rs, int sa);
184 bool gen_dlsa(DisasContext *ctx, int rd, int rt, int rs, int sa);
185 
186 void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel);
187 void gen_crc32(DisasContext *ctx, int rd, int rs, int rt, int sz, int crc32c);
188 
189 extern TCGv cpu_gpr[32], cpu_PC;
190 #if defined(TARGET_MIPS64)
191 extern TCGv_i64 cpu_gpr_hi[32];
192 #endif
193 extern TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC];
194 extern TCGv_i32 fpu_fcr0, fpu_fcr31;
195 extern TCGv_i64 fpu_f64[32];
196 extern TCGv bcond;
197 
198 #define LOG_DISAS(...)                                                        \
199     do {                                                                      \
200         if (MIPS_DEBUG_DISAS) {                                               \
201             qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__);                 \
202         }                                                                     \
203     } while (0)
204 
205 #define MIPS_INVAL(op)                                                        \
206     do {                                                                      \
207         if (MIPS_DEBUG_DISAS) {                                               \
208             qemu_log_mask(CPU_LOG_TB_IN_ASM,                                  \
209                           "%016" VADDR_PRIx                                   \
210                           ": %08x Invalid %s %03x %03x %03x\n",               \
211                           ctx->base.pc_next, ctx->opcode, op,                 \
212                           ctx->opcode >> 26, ctx->opcode & 0x3F,              \
213                           ((ctx->opcode >> 16) & 0x1F));                      \
214         }                                                                     \
215     } while (0)
216 
217 /* MSA */
218 void msa_translate_init(void);
219 
220 /* MXU */
221 void mxu_translate_init(void);
222 bool decode_ase_mxu(DisasContext *ctx, uint32_t insn);
223 
224 bool decode_64bit_enabled(DisasContext *ctx);
225 
226 /* decodetree generated */
227 bool decode_isa_rel6(DisasContext *ctx, uint32_t insn);
228 bool decode_ase_msa(DisasContext *ctx, uint32_t insn);
229 bool decode_ext_txx9(DisasContext *ctx, uint32_t insn);
230 bool decode_ext_loongson(DisasContext *ctx, uint32_t insn);
231 #if defined(TARGET_MIPS64)
232 bool decode_ase_lcsr(DisasContext *ctx, uint32_t insn);
233 bool decode_ext_tx79(DisasContext *ctx, uint32_t insn);
234 bool decode_ext_octeon(DisasContext *ctx, uint32_t insn);
235 #endif
236 bool decode_ext_vr54xx(DisasContext *ctx, uint32_t insn);
237 
disas_mt_available(DisasContext * ctx)238 static inline bool disas_mt_available(DisasContext *ctx)
239 {
240     return ctx->CP0_Config3 & (1 << CP0C3_MT);
241 }
242 
243 /*
244  * Helpers for implementing sets of trans_* functions.
245  * Defer the implementation of NAME to FUNC, with optional extra arguments.
246  */
247 #define TRANS(NAME, FUNC, ...) \
248     static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \
249     { return FUNC(ctx, a, __VA_ARGS__); }
250 
disas_is_bigendian(DisasContext * ctx)251 static inline bool disas_is_bigendian(DisasContext *ctx)
252 {
253     return extract32(ctx->CP0_Config0, CP0C0_BE, 1);
254 }
255 
mo_endian(DisasContext * dc)256 static inline MemOp mo_endian(DisasContext *dc)
257 {
258     return disas_is_bigendian(dc) ? MO_BE : MO_LE;
259 }
260 
mo_endian_rev(DisasContext * dc,bool reversed)261 static inline MemOp mo_endian_rev(DisasContext *dc, bool reversed)
262 {
263     return disas_is_bigendian(dc) ^ reversed ? MO_BE : MO_LE;
264 }
265 
266 #endif
267