libretro: direct fb access requires duping support
[pcsx_rearmed.git] / deps / lightrec / disassembler.h
CommitLineData
98fa08a5 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
d16005f8 2/*
98fa08a5 3 * Copyright (C) 2014-2021 Paul Cercueil <paul@crapouillou.net>
d16005f8
PC
4 */
5
6#ifndef __DISASSEMBLER_H__
7#define __DISASSEMBLER_H__
8
9#include "debug.h"
10#include "lightrec.h"
03535202 11#include "lightrec-config.h"
d16005f8
PC
12
13#ifndef __packed
14#define __packed __attribute__((packed))
15#endif
16
98fa08a5
PC
17#define BIT(x) (1ULL << (x))
18
19/* Flags for all opcodes */
20#define LIGHTREC_NO_DS BIT(0)
03535202 21#define LIGHTREC_SYNC BIT(1)
98fa08a5 22
684432ad
PC
23/* Flags for LUI, ORI, ADDIU */
24#define LIGHTREC_MOVI BIT(2)
25
98fa08a5 26/* Flags for load/store opcodes */
03535202
PC
27#define LIGHTREC_SMC BIT(2)
28#define LIGHTREC_NO_INVALIDATE BIT(3)
29#define LIGHTREC_NO_MASK BIT(4)
cb72ea13 30#define LIGHTREC_LOAD_DELAY BIT(5)
22eee2ac
PC
31
32/* I/O mode for load/store opcodes */
cb72ea13 33#define LIGHTREC_IO_MODE_LSB 6
22eee2ac
PC
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
ba3814c1 41#define LIGHTREC_IO_DIRECT_HW 0x6
22eee2ac
PC
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)
98fa08a5
PC
45
46/* Flags for branches */
03535202
PC
47#define LIGHTREC_EMULATE_BRANCH BIT(2)
48#define LIGHTREC_LOCAL_BRANCH BIT(3)
98fa08a5
PC
49
50/* Flags for div/mult opcodes */
03535202
PC
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
d16005f8
PC
77
78struct block;
79
80enum 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
e26c79a8 114 OP_META = 0x3c,
ba3814c1
PC
115
116 OP_META_MULT2 = 0x19,
117 OP_META_MULTU2 = 0x1a,
5459088b
PC
118 OP_META_LWU = 0x1b,
119 OP_META_SWU = 0x1c,
d16005f8
PC
120};
121
122enum 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
153enum regimm_opcodes {
154 OP_REGIMM_BLTZ = 0x00,
155 OP_REGIMM_BGEZ = 0x01,
156 OP_REGIMM_BLTZAL = 0x10,
157 OP_REGIMM_BGEZAL = 0x11,
158};
159
160enum 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
168enum cp2_opcodes {
169 OP_CP2_BASIC = 0x00,
ba3814c1
PC
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,
d16005f8
PC
192};
193
194enum 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
cb72ea13
PC
201enum 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
d16005f8
PC
210struct 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
228struct 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
242struct 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
cb72ea13
PC
252struct 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
d16005f8
PC
270union 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;
cb72ea13 276 struct opcode_m m;
d16005f8
PC
277};
278
279struct 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;
cb72ea13 289 struct opcode_m m;
d16005f8 290 };
03535202 291 u32 flags;
d16005f8
PC
292};
293
ba3814c1
PC
294struct opcode_list {
295 u16 nb_ops;
296 struct opcode ops[];
297};
298
98fa08a5 299void lightrec_print_disassembly(const struct block *block, const u32 *code);
d16005f8 300
03535202
PC
301static inline _Bool op_flag_no_ds(u32 flags)
302{
303 return OPT_SWITCH_DELAY_SLOTS && (flags & LIGHTREC_NO_DS);
304}
305
306static inline _Bool op_flag_sync(u32 flags)
307{
308 return OPT_LOCAL_BRANCHES && (flags & LIGHTREC_SYNC);
309}
310
311static inline _Bool op_flag_smc(u32 flags)
312{
cb72ea13 313 return OPT_FLAG_IO && (flags & LIGHTREC_SMC);
03535202
PC
314}
315
316static inline _Bool op_flag_no_invalidate(u32 flags)
317{
cb72ea13 318 return OPT_FLAG_IO && (flags & LIGHTREC_NO_INVALIDATE);
03535202
PC
319}
320
321static inline _Bool op_flag_no_mask(u32 flags)
322{
323 return OPT_FLAG_IO && (flags & LIGHTREC_NO_MASK);
324}
325
cb72ea13
PC
326static inline _Bool op_flag_load_delay(u32 flags)
327{
328 return OPT_HANDLE_LOAD_DELAYS && (flags & LIGHTREC_LOAD_DELAY);
329}
330
03535202
PC
331static inline _Bool op_flag_emulate_branch(u32 flags)
332{
333 return OPT_DETECT_IMPOSSIBLE_BRANCHES &&
334 (flags & LIGHTREC_EMULATE_BRANCH);
335}
336
337static inline _Bool op_flag_local_branch(u32 flags)
338{
339 return OPT_LOCAL_BRANCHES && (flags & LIGHTREC_LOCAL_BRANCH);
340}
341
342static inline _Bool op_flag_no_lo(u32 flags)
343{
344 return OPT_FLAG_MULT_DIV && (flags & LIGHTREC_NO_LO);
345}
346
347static inline _Bool op_flag_no_hi(u32 flags)
348{
349 return OPT_FLAG_MULT_DIV && (flags & LIGHTREC_NO_HI);
350}
351
352static inline _Bool op_flag_no_div_check(u32 flags)
353{
354 return OPT_FLAG_MULT_DIV && (flags & LIGHTREC_NO_DIV_CHECK);
355}
356
d16005f8 357#endif /* __DISASSEMBLER_H__ */