Update lightrec 20220716 (#672)
[pcsx_rearmed.git] / deps / lightrec / disassembler.h
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /*
3  * Copyright (C) 2014-2021 Paul Cercueil <paul@crapouillou.net>
4  */
5
6 #ifndef __DISASSEMBLER_H__
7 #define __DISASSEMBLER_H__
8
9 #include "debug.h"
10 #include "lightrec.h"
11 #include "lightrec-config.h"
12
13 #ifndef __packed
14 #define __packed __attribute__((packed))
15 #endif
16
17 #define BIT(x) (1ULL << (x))
18
19 /* Flags for all opcodes */
20 #define LIGHTREC_NO_DS          BIT(0)
21 #define LIGHTREC_SYNC           BIT(1)
22
23 /* Flags for load/store opcodes */
24 #define LIGHTREC_SMC            BIT(2)
25 #define LIGHTREC_NO_INVALIDATE  BIT(3)
26 #define LIGHTREC_NO_MASK        BIT(4)
27
28 /* I/O mode for load/store opcodes */
29 #define LIGHTREC_IO_MODE_LSB    5
30 #define LIGHTREC_IO_MODE(x)     ((x) << LIGHTREC_IO_MODE_LSB)
31 #define LIGHTREC_IO_UNKNOWN     0x0
32 #define LIGHTREC_IO_DIRECT      0x1
33 #define LIGHTREC_IO_HW          0x2
34 #define LIGHTREC_IO_RAM         0x3
35 #define LIGHTREC_IO_BIOS        0x4
36 #define LIGHTREC_IO_SCRATCH     0x5
37 #define LIGHTREC_IO_MASK        LIGHTREC_IO_MODE(0x7)
38 #define LIGHTREC_FLAGS_GET_IO_MODE(x) \
39         (((x) & LIGHTREC_IO_MASK) >> LIGHTREC_IO_MODE_LSB)
40
41 /* Flags for branches */
42 #define LIGHTREC_EMULATE_BRANCH BIT(2)
43 #define LIGHTREC_LOCAL_BRANCH   BIT(3)
44
45 /* Flags for div/mult opcodes */
46 #define LIGHTREC_NO_LO          BIT(2)
47 #define LIGHTREC_NO_HI          BIT(3)
48 #define LIGHTREC_NO_DIV_CHECK   BIT(4)
49
50 #define LIGHTREC_REG_RS_LSB     26
51 #define LIGHTREC_REG_RS(x)      ((x) << LIGHTREC_REG_RS_LSB)
52 #define LIGHTREC_REG_RS_MASK    LIGHTREC_REG_RS(0x3)
53 #define LIGHTREC_FLAGS_GET_RS(x) \
54         (((x) & LIGHTREC_REG_RS_MASK) >> LIGHTREC_REG_RS_LSB)
55
56 #define LIGHTREC_REG_RT_LSB     28
57 #define LIGHTREC_REG_RT(x)      ((x) << LIGHTREC_REG_RT_LSB)
58 #define LIGHTREC_REG_RT_MASK    LIGHTREC_REG_RT(0x3)
59 #define LIGHTREC_FLAGS_GET_RT(x) \
60         (((x) & LIGHTREC_REG_RT_MASK) >> LIGHTREC_REG_RT_LSB)
61
62 #define LIGHTREC_REG_RD_LSB     30
63 #define LIGHTREC_REG_RD(x)      ((x) << LIGHTREC_REG_RD_LSB)
64 #define LIGHTREC_REG_RD_MASK    LIGHTREC_REG_RD(0x3)
65 #define LIGHTREC_FLAGS_GET_RD(x) \
66         (((x) & LIGHTREC_REG_RD_MASK) >> LIGHTREC_REG_RD_LSB)
67
68 #define LIGHTREC_REG_NOOP       0x0
69 #define LIGHTREC_REG_UNLOAD     0x1
70 #define LIGHTREC_REG_DISCARD    0x2
71 #define LIGHTREC_REG_CLEAN      0x3
72
73 struct block;
74
75 enum standard_opcodes {
76         OP_SPECIAL              = 0x00,
77         OP_REGIMM               = 0x01,
78         OP_J                    = 0x02,
79         OP_JAL                  = 0x03,
80         OP_BEQ                  = 0x04,
81         OP_BNE                  = 0x05,
82         OP_BLEZ                 = 0x06,
83         OP_BGTZ                 = 0x07,
84         OP_ADDI                 = 0x08,
85         OP_ADDIU                = 0x09,
86         OP_SLTI                 = 0x0a,
87         OP_SLTIU                = 0x0b,
88         OP_ANDI                 = 0x0c,
89         OP_ORI                  = 0x0d,
90         OP_XORI                 = 0x0e,
91         OP_LUI                  = 0x0f,
92         OP_CP0                  = 0x10,
93         OP_CP2                  = 0x12,
94         OP_LB                   = 0x20,
95         OP_LH                   = 0x21,
96         OP_LWL                  = 0x22,
97         OP_LW                   = 0x23,
98         OP_LBU                  = 0x24,
99         OP_LHU                  = 0x25,
100         OP_LWR                  = 0x26,
101         OP_SB                   = 0x28,
102         OP_SH                   = 0x29,
103         OP_SWL                  = 0x2a,
104         OP_SW                   = 0x2b,
105         OP_SWR                  = 0x2e,
106         OP_LWC2                 = 0x32,
107         OP_SWC2                 = 0x3a,
108
109         OP_META_MOV             = 0x16,
110
111         OP_META_EXTC            = 0x17,
112         OP_META_EXTS            = 0x18,
113 };
114
115 enum special_opcodes {
116         OP_SPECIAL_SLL          = 0x00,
117         OP_SPECIAL_SRL          = 0x02,
118         OP_SPECIAL_SRA          = 0x03,
119         OP_SPECIAL_SLLV         = 0x04,
120         OP_SPECIAL_SRLV         = 0x06,
121         OP_SPECIAL_SRAV         = 0x07,
122         OP_SPECIAL_JR           = 0x08,
123         OP_SPECIAL_JALR         = 0x09,
124         OP_SPECIAL_SYSCALL      = 0x0c,
125         OP_SPECIAL_BREAK        = 0x0d,
126         OP_SPECIAL_MFHI         = 0x10,
127         OP_SPECIAL_MTHI         = 0x11,
128         OP_SPECIAL_MFLO         = 0x12,
129         OP_SPECIAL_MTLO         = 0x13,
130         OP_SPECIAL_MULT         = 0x18,
131         OP_SPECIAL_MULTU        = 0x19,
132         OP_SPECIAL_DIV          = 0x1a,
133         OP_SPECIAL_DIVU         = 0x1b,
134         OP_SPECIAL_ADD          = 0x20,
135         OP_SPECIAL_ADDU         = 0x21,
136         OP_SPECIAL_SUB          = 0x22,
137         OP_SPECIAL_SUBU         = 0x23,
138         OP_SPECIAL_AND          = 0x24,
139         OP_SPECIAL_OR           = 0x25,
140         OP_SPECIAL_XOR          = 0x26,
141         OP_SPECIAL_NOR          = 0x27,
142         OP_SPECIAL_SLT          = 0x2a,
143         OP_SPECIAL_SLTU         = 0x2b,
144 };
145
146 enum regimm_opcodes {
147         OP_REGIMM_BLTZ          = 0x00,
148         OP_REGIMM_BGEZ          = 0x01,
149         OP_REGIMM_BLTZAL        = 0x10,
150         OP_REGIMM_BGEZAL        = 0x11,
151 };
152
153 enum cp0_opcodes {
154         OP_CP0_MFC0             = 0x00,
155         OP_CP0_CFC0             = 0x02,
156         OP_CP0_MTC0             = 0x04,
157         OP_CP0_CTC0             = 0x06,
158         OP_CP0_RFE              = 0x10,
159 };
160
161 enum cp2_opcodes {
162         OP_CP2_BASIC            = 0x00,
163 };
164
165 enum cp2_basic_opcodes {
166         OP_CP2_BASIC_MFC2       = 0x00,
167         OP_CP2_BASIC_CFC2       = 0x02,
168         OP_CP2_BASIC_MTC2       = 0x04,
169         OP_CP2_BASIC_CTC2       = 0x06,
170 };
171
172 struct opcode_r {
173 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
174         u32 zero :6;
175         u32 rs   :5;
176         u32 rt   :5;
177         u32 rd   :5;
178         u32 imm  :5;
179         u32 op   :6;
180 #else
181         u32 op   :6;
182         u32 imm  :5;
183         u32 rd   :5;
184         u32 rt   :5;
185         u32 rs   :5;
186         u32 zero :6;
187 #endif
188 } __packed;
189
190 struct opcode_i {
191 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
192         u32 op  :6;
193         u32 rs  :5;
194         u32 rt  :5;
195         u32 imm :16;
196 #else
197         u32 imm :16;
198         u32 rt  :5;
199         u32 rs  :5;
200         u32 op  :6;
201 #endif
202 } __packed;
203
204 struct opcode_j {
205 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
206         u32 op  :6;
207         u32 imm :26;
208 #else
209         u32 imm :26;
210         u32 op  :6;
211 #endif
212 } __packed;
213
214 union code {
215         /* Keep in sync with struct opcode */
216         u32 opcode;
217         struct opcode_r r;
218         struct opcode_i i;
219         struct opcode_j j;
220 };
221
222 struct opcode {
223         /* Keep this union at the first position */
224         union {
225                 union code c;
226
227                 /* Keep in sync with union code */
228                 u32 opcode;
229                 struct opcode_r r;
230                 struct opcode_i i;
231                 struct opcode_j j;
232         };
233         u32 flags;
234 };
235
236 void lightrec_print_disassembly(const struct block *block, const u32 *code);
237
238 static inline _Bool op_flag_no_ds(u32 flags)
239 {
240         return OPT_SWITCH_DELAY_SLOTS && (flags & LIGHTREC_NO_DS);
241 }
242
243 static inline _Bool op_flag_sync(u32 flags)
244 {
245         return OPT_LOCAL_BRANCHES && (flags & LIGHTREC_SYNC);
246 }
247
248 static inline _Bool op_flag_smc(u32 flags)
249 {
250         return OPT_FLAG_STORES && (flags & LIGHTREC_SMC);
251 }
252
253 static inline _Bool op_flag_no_invalidate(u32 flags)
254 {
255         return (OPT_FLAG_IO || OPT_FLAG_STORES) &&
256                 (flags & LIGHTREC_NO_INVALIDATE);
257 }
258
259 static inline _Bool op_flag_no_mask(u32 flags)
260 {
261         return OPT_FLAG_IO && (flags & LIGHTREC_NO_MASK);
262 }
263
264 static inline _Bool op_flag_emulate_branch(u32 flags)
265 {
266         return OPT_DETECT_IMPOSSIBLE_BRANCHES &&
267                 (flags & LIGHTREC_EMULATE_BRANCH);
268 }
269
270 static inline _Bool op_flag_local_branch(u32 flags)
271 {
272         return OPT_LOCAL_BRANCHES && (flags & LIGHTREC_LOCAL_BRANCH);
273 }
274
275 static inline _Bool op_flag_no_lo(u32 flags)
276 {
277         return OPT_FLAG_MULT_DIV && (flags & LIGHTREC_NO_LO);
278 }
279
280 static inline _Bool op_flag_no_hi(u32 flags)
281 {
282         return OPT_FLAG_MULT_DIV && (flags & LIGHTREC_NO_HI);
283 }
284
285 static inline _Bool op_flag_no_div_check(u32 flags)
286 {
287         return OPT_FLAG_MULT_DIV && (flags & LIGHTREC_NO_DIV_CHECK);
288 }
289
290 #endif /* __DISASSEMBLER_H__ */