| 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 | extern TCGv_i64 oct_mpl[OCTEON_MULTIPLIER_REGS]; |
| 193 | extern TCGv_i64 oct_p[OCTEON_MULTIPLIER_REGS]; |
| 194 | #endif |
| 195 | extern TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC]; |
| 196 | extern TCGv_i32 fpu_fcr0, fpu_fcr31; |
| 197 | extern TCGv_i64 fpu_f64[32]; |
| 198 | extern TCGv bcond; |
| 199 | |
| 200 | #define LOG_DISAS(...) \ |
| 201 | do { \ |
| 202 | if (MIPS_DEBUG_DISAS) { \ |
| 203 | qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__); \ |
| 204 | } \ |
| 205 | } while (0) |
| 206 | |
| 207 | #define MIPS_INVAL(op) \ |
| 208 | do { \ |
| 209 | if (MIPS_DEBUG_DISAS) { \ |
| 210 | qemu_log_mask(CPU_LOG_TB_IN_ASM, \ |
| 211 | "%016" VADDR_PRIx \ |
| 212 | ": %08x Invalid %s %03x %03x %03x\n", \ |
| 213 | ctx->base.pc_next, ctx->opcode, op, \ |
| 214 | ctx->opcode >> 26, ctx->opcode & 0x3F, \ |
| 215 | ((ctx->opcode >> 16) & 0x1F)); \ |
| 216 | } \ |
| 217 | } while (0) |
| 218 | |
| 219 | /* MSA */ |
| 220 | void msa_translate_init(void); |
| 221 | |
| 222 | /* MXU */ |
| 223 | void mxu_translate_init(void); |
| 224 | bool decode_ase_mxu(DisasContext *ctx, uint32_t insn); |
| 225 | |
| 226 | bool decode_64bit_enabled(DisasContext *ctx); |
| 227 | |
| 228 | /* decodetree generated */ |
| 229 | bool decode_isa_rel6(DisasContext *ctx, uint32_t insn); |
| 230 | bool decode_ase_msa(DisasContext *ctx, uint32_t insn); |
| 231 | bool decode_ext_txx9(DisasContext *ctx, uint32_t insn); |
| 232 | bool decode_ext_loongson(DisasContext *ctx, uint32_t insn); |
| 233 | #if defined(TARGET_MIPS64) |
| 234 | bool decode_ase_lcsr(DisasContext *ctx, uint32_t insn); |
| 235 | bool decode_ext_tx79(DisasContext *ctx, uint32_t insn); |
| 236 | bool decode_ext_octeon(DisasContext *ctx, uint32_t insn); |
| 237 | #endif |
| 238 | bool decode_ext_vr54xx(DisasContext *ctx, uint32_t insn); |
| 239 | |
| 240 | static inline bool disas_mt_available(DisasContext *ctx) |
| 241 | { |
| 242 | return ctx->CP0_Config3 & (1 << CP0C3_MT); |
| 243 | } |
| 244 | |
| 245 | /* |
| 246 | * Helpers for implementing sets of trans_* functions. |
| 247 | * Defer the implementation of NAME to FUNC, with optional extra arguments. |
| 248 | */ |
| 249 | #define TRANS(NAME, FUNC, ...) \ |
| 250 | static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ |
| 251 | { return FUNC(ctx, a, __VA_ARGS__); } |
| 252 | |
| 253 | static inline bool disas_is_bigendian(DisasContext *ctx) |
| 254 | { |
| 255 | return extract32(ctx->CP0_Config0, CP0C0_BE, 1); |
| 256 | } |
| 257 | |
| 258 | static inline MemOp mo_endian(DisasContext *dc) |
| 259 | { |
| 260 | return disas_is_bigendian(dc) ? MO_BE : MO_LE; |
| 261 | } |
| 262 | |
| 263 | static inline MemOp mo_endian_rev(DisasContext *dc, bool reversed) |
| 264 | { |
| 265 | return disas_is_bigendian(dc) ^ reversed ? MO_BE : MO_LE; |
| 266 | } |
| 267 | |
| 268 | #endif |