xref: /openbmc/qemu/target/mips/tcg/translate.h (revision 67194c7018b8b06a1c149757f596bb919c683725)
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  
disas_mt_available(DisasContext * ctx)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  
disas_is_bigendian(DisasContext * ctx)247  static inline bool disas_is_bigendian(DisasContext *ctx)
248  {
249      return extract32(ctx->CP0_Config0, CP0C0_BE, 1);
250  }
251  
mo_endian(DisasContext * dc)252  static inline MemOp mo_endian(DisasContext *dc)
253  {
254      return disas_is_bigendian(dc) ? MO_BE : MO_LE;
255  }
256  
mo_endian_rev(DisasContext * dc,bool reversed)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