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