libretro: adjust psxclock description
[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 LUI, ORI, ADDIU */
24 #define LIGHTREC_MOVI           BIT(2)
25
26 /* Flags for load/store opcodes */
27 #define LIGHTREC_SMC            BIT(2)
28 #define LIGHTREC_NO_INVALIDATE  BIT(3)
29 #define LIGHTREC_NO_MASK        BIT(4)
30 #define LIGHTREC_LOAD_DELAY     BIT(5)
31
32 /* I/O mode for load/store opcodes */
33 #define LIGHTREC_IO_MODE_LSB    6
34 #define LIGHTREC_IO_MODE(x)     ((x) << LIGHTREC_IO_MODE_LSB)
35 #define LIGHTREC_IO_UNKNOWN     0x0
36 #define LIGHTREC_IO_DIRECT      0x1
37 #define LIGHTREC_IO_HW          0x2
38 #define LIGHTREC_IO_RAM         0x3
39 #define LIGHTREC_IO_BIOS        0x4
40 #define LIGHTREC_IO_SCRATCH     0x5
41 #define LIGHTREC_IO_DIRECT_HW   0x6
42 #define LIGHTREC_IO_MASK        LIGHTREC_IO_MODE(0x7)
43 #define LIGHTREC_FLAGS_GET_IO_MODE(x) \
44         (((x) & LIGHTREC_IO_MASK) >> LIGHTREC_IO_MODE_LSB)
45
46 /* Flags for branches */
47 #define LIGHTREC_EMULATE_BRANCH BIT(2)
48 #define LIGHTREC_LOCAL_BRANCH   BIT(3)
49
50 /* Flags for div/mult opcodes */
51 #define LIGHTREC_NO_LO          BIT(2)
52 #define LIGHTREC_NO_HI          BIT(3)
53 #define LIGHTREC_NO_DIV_CHECK   BIT(4)
54
55 #define LIGHTREC_REG_RS_LSB     26
56 #define LIGHTREC_REG_RS(x)      ((x) << LIGHTREC_REG_RS_LSB)
57 #define LIGHTREC_REG_RS_MASK    LIGHTREC_REG_RS(0x3)
58 #define LIGHTREC_FLAGS_GET_RS(x) \
59         (((x) & LIGHTREC_REG_RS_MASK) >> LIGHTREC_REG_RS_LSB)
60
61 #define LIGHTREC_REG_RT_LSB     28
62 #define LIGHTREC_REG_RT(x)      ((x) << LIGHTREC_REG_RT_LSB)
63 #define LIGHTREC_REG_RT_MASK    LIGHTREC_REG_RT(0x3)
64 #define LIGHTREC_FLAGS_GET_RT(x) \
65         (((x) & LIGHTREC_REG_RT_MASK) >> LIGHTREC_REG_RT_LSB)
66
67 #define LIGHTREC_REG_RD_LSB     30
68 #define LIGHTREC_REG_RD(x)      ((x) << LIGHTREC_REG_RD_LSB)
69 #define LIGHTREC_REG_RD_MASK    LIGHTREC_REG_RD(0x3)
70 #define LIGHTREC_FLAGS_GET_RD(x) \
71         (((x) & LIGHTREC_REG_RD_MASK) >> LIGHTREC_REG_RD_LSB)
72
73 #define LIGHTREC_REG_NOOP       0x0
74 #define LIGHTREC_REG_UNLOAD     0x1
75 #define LIGHTREC_REG_DISCARD    0x2
76 #define LIGHTREC_REG_CLEAN      0x3
77
78 struct block;
79
80 enum standard_opcodes {
81         OP_SPECIAL              = 0x00,
82         OP_REGIMM               = 0x01,
83         OP_J                    = 0x02,
84         OP_JAL                  = 0x03,
85         OP_BEQ                  = 0x04,
86         OP_BNE                  = 0x05,
87         OP_BLEZ                 = 0x06,
88         OP_BGTZ                 = 0x07,
89         OP_ADDI                 = 0x08,
90         OP_ADDIU                = 0x09,
91         OP_SLTI                 = 0x0a,
92         OP_SLTIU                = 0x0b,
93         OP_ANDI                 = 0x0c,
94         OP_ORI                  = 0x0d,
95         OP_XORI                 = 0x0e,
96         OP_LUI                  = 0x0f,
97         OP_CP0                  = 0x10,
98         OP_CP2                  = 0x12,
99         OP_LB                   = 0x20,
100         OP_LH                   = 0x21,
101         OP_LWL                  = 0x22,
102         OP_LW                   = 0x23,
103         OP_LBU                  = 0x24,
104         OP_LHU                  = 0x25,
105         OP_LWR                  = 0x26,
106         OP_SB                   = 0x28,
107         OP_SH                   = 0x29,
108         OP_SWL                  = 0x2a,
109         OP_SW                   = 0x2b,
110         OP_SWR                  = 0x2e,
111         OP_LWC2                 = 0x32,
112         OP_SWC2                 = 0x3a,
113
114         OP_META                 = 0x3c,
115
116         OP_META_MULT2           = 0x19,
117         OP_META_MULTU2          = 0x1a,
118         OP_META_LWU             = 0x1b,
119         OP_META_SWU             = 0x1c,
120 };
121
122 enum special_opcodes {
123         OP_SPECIAL_SLL          = 0x00,
124         OP_SPECIAL_SRL          = 0x02,
125         OP_SPECIAL_SRA          = 0x03,
126         OP_SPECIAL_SLLV         = 0x04,
127         OP_SPECIAL_SRLV         = 0x06,
128         OP_SPECIAL_SRAV         = 0x07,
129         OP_SPECIAL_JR           = 0x08,
130         OP_SPECIAL_JALR         = 0x09,
131         OP_SPECIAL_SYSCALL      = 0x0c,
132         OP_SPECIAL_BREAK        = 0x0d,
133         OP_SPECIAL_MFHI         = 0x10,
134         OP_SPECIAL_MTHI         = 0x11,
135         OP_SPECIAL_MFLO         = 0x12,
136         OP_SPECIAL_MTLO         = 0x13,
137         OP_SPECIAL_MULT         = 0x18,
138         OP_SPECIAL_MULTU        = 0x19,
139         OP_SPECIAL_DIV          = 0x1a,
140         OP_SPECIAL_DIVU         = 0x1b,
141         OP_SPECIAL_ADD          = 0x20,
142         OP_SPECIAL_ADDU         = 0x21,
143         OP_SPECIAL_SUB          = 0x22,
144         OP_SPECIAL_SUBU         = 0x23,
145         OP_SPECIAL_AND          = 0x24,
146         OP_SPECIAL_OR           = 0x25,
147         OP_SPECIAL_XOR          = 0x26,
148         OP_SPECIAL_NOR          = 0x27,
149         OP_SPECIAL_SLT          = 0x2a,
150         OP_SPECIAL_SLTU         = 0x2b,
151 };
152
153 enum regimm_opcodes {
154         OP_REGIMM_BLTZ          = 0x00,
155         OP_REGIMM_BGEZ          = 0x01,
156         OP_REGIMM_BLTZAL        = 0x10,
157         OP_REGIMM_BGEZAL        = 0x11,
158 };
159
160 enum cp0_opcodes {
161         OP_CP0_MFC0             = 0x00,
162         OP_CP0_CFC0             = 0x02,
163         OP_CP0_MTC0             = 0x04,
164         OP_CP0_CTC0             = 0x06,
165         OP_CP0_RFE              = 0x10,
166 };
167
168 enum cp2_opcodes {
169         OP_CP2_BASIC            = 0x00,
170         OP_CP2_RTPS             = 0x01,
171         OP_CP2_NCLIP            = 0x06,
172         OP_CP2_OP               = 0x0c,
173         OP_CP2_DPCS             = 0x10,
174         OP_CP2_INTPL            = 0x11,
175         OP_CP2_MVMVA            = 0x12,
176         OP_CP2_NCDS             = 0x13,
177         OP_CP2_CDP              = 0x14,
178         OP_CP2_NCDT             = 0x16,
179         OP_CP2_NCCS             = 0x1b,
180         OP_CP2_CC               = 0x1c,
181         OP_CP2_NCS              = 0x1e,
182         OP_CP2_NCT              = 0x20,
183         OP_CP2_SQR              = 0x28,
184         OP_CP2_DCPL             = 0x29,
185         OP_CP2_DPCT             = 0x2a,
186         OP_CP2_AVSZ3            = 0x2d,
187         OP_CP2_AVSZ4            = 0x2e,
188         OP_CP2_RTPT             = 0x30,
189         OP_CP2_GPF              = 0x3d,
190         OP_CP2_GPL              = 0x3e,
191         OP_CP2_NCCT             = 0x3f,
192 };
193
194 enum cp2_basic_opcodes {
195         OP_CP2_BASIC_MFC2       = 0x00,
196         OP_CP2_BASIC_CFC2       = 0x02,
197         OP_CP2_BASIC_MTC2       = 0x04,
198         OP_CP2_BASIC_CTC2       = 0x06,
199 };
200
201 enum meta_opcodes {
202         OP_META_MOV             = 0x00,
203
204         OP_META_EXTC            = 0x01,
205         OP_META_EXTS            = 0x02,
206
207         OP_META_COM             = 0x03,
208 };
209
210 struct opcode_r {
211 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
212         u32 zero :6;
213         u32 rs   :5;
214         u32 rt   :5;
215         u32 rd   :5;
216         u32 imm  :5;
217         u32 op   :6;
218 #else
219         u32 op   :6;
220         u32 imm  :5;
221         u32 rd   :5;
222         u32 rt   :5;
223         u32 rs   :5;
224         u32 zero :6;
225 #endif
226 } __packed;
227
228 struct opcode_i {
229 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
230         u32 op  :6;
231         u32 rs  :5;
232         u32 rt  :5;
233         u32 imm :16;
234 #else
235         u32 imm :16;
236         u32 rt  :5;
237         u32 rs  :5;
238         u32 op  :6;
239 #endif
240 } __packed;
241
242 struct opcode_j {
243 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
244         u32 op  :6;
245         u32 imm :26;
246 #else
247         u32 imm :26;
248         u32 op  :6;
249 #endif
250 } __packed;
251
252 struct opcode_m {
253 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
254         u32 meta :6;
255         u32 rs   :5;
256         u32 rt   :5;
257         u32 rd   :5;
258         u32 imm  :6;
259         u32 op   :5;
260 #else
261         u32 op   :5;
262         u32 imm  :6;
263         u32 rd   :5;
264         u32 rt   :5;
265         u32 rs   :5;
266         u32 meta :6;
267 #endif
268 };
269
270 union code {
271         /* Keep in sync with struct opcode */
272         u32 opcode;
273         struct opcode_r r;
274         struct opcode_i i;
275         struct opcode_j j;
276         struct opcode_m m;
277 };
278
279 struct opcode {
280         /* Keep this union at the first position */
281         union {
282                 union code c;
283
284                 /* Keep in sync with union code */
285                 u32 opcode;
286                 struct opcode_r r;
287                 struct opcode_i i;
288                 struct opcode_j j;
289                 struct opcode_m m;
290         };
291         u32 flags;
292 };
293
294 struct opcode_list {
295         u16 nb_ops;
296         struct opcode ops[];
297 };
298
299 void lightrec_print_disassembly(const struct block *block, const u32 *code);
300
301 static inline _Bool op_flag_no_ds(u32 flags)
302 {
303         return OPT_SWITCH_DELAY_SLOTS && (flags & LIGHTREC_NO_DS);
304 }
305
306 static inline _Bool op_flag_sync(u32 flags)
307 {
308         return OPT_LOCAL_BRANCHES && (flags & LIGHTREC_SYNC);
309 }
310
311 static inline _Bool op_flag_smc(u32 flags)
312 {
313         return OPT_FLAG_IO && (flags & LIGHTREC_SMC);
314 }
315
316 static inline _Bool op_flag_no_invalidate(u32 flags)
317 {
318         return OPT_FLAG_IO && (flags & LIGHTREC_NO_INVALIDATE);
319 }
320
321 static inline _Bool op_flag_no_mask(u32 flags)
322 {
323         return OPT_FLAG_IO && (flags & LIGHTREC_NO_MASK);
324 }
325
326 static inline _Bool op_flag_load_delay(u32 flags)
327 {
328         return OPT_HANDLE_LOAD_DELAYS && (flags & LIGHTREC_LOAD_DELAY);
329 }
330
331 static inline _Bool op_flag_emulate_branch(u32 flags)
332 {
333         return OPT_DETECT_IMPOSSIBLE_BRANCHES &&
334                 (flags & LIGHTREC_EMULATE_BRANCH);
335 }
336
337 static inline _Bool op_flag_local_branch(u32 flags)
338 {
339         return OPT_LOCAL_BRANCHES && (flags & LIGHTREC_LOCAL_BRANCH);
340 }
341
342 static inline _Bool op_flag_no_lo(u32 flags)
343 {
344         return OPT_FLAG_MULT_DIV && (flags & LIGHTREC_NO_LO);
345 }
346
347 static inline _Bool op_flag_no_hi(u32 flags)
348 {
349         return OPT_FLAG_MULT_DIV && (flags & LIGHTREC_NO_HI);
350 }
351
352 static inline _Bool op_flag_no_div_check(u32 flags)
353 {
354         return OPT_FLAG_MULT_DIV && (flags & LIGHTREC_NO_DIV_CHECK);
355 }
356
357 #endif /* __DISASSEMBLER_H__ */