Commit | Line | Data |
---|---|---|
ef79bbde P |
1 | /*************************************************************************** |
2 | * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * | |
3 | * * | |
4 | * This program is free software; you can redistribute it and/or modify * | |
5 | * it under the terms of the GNU General Public License as published by * | |
6 | * the Free Software Foundation; either version 2 of the License, or * | |
7 | * (at your option) any later version. * | |
8 | * * | |
9 | * This program is distributed in the hope that it will be useful, * | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
12 | * GNU General Public License for more details. * | |
13 | * * | |
14 | * You should have received a copy of the GNU General Public License * | |
15 | * along with this program; if not, write to the * | |
16 | * Free Software Foundation, Inc., * | |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. * | |
18 | ***************************************************************************/ | |
19 | ||
20 | /* | |
21 | * R3000A disassembler. | |
22 | */ | |
23 | ||
24 | #include "psxcommon.h" | |
25 | ||
5b568098 | 26 | // XXX: don't care but maybe fix it someday |
27 | #if defined(__GNUC__) && __GNUC__ >= 7 | |
28 | #pragma GCC diagnostic ignored "-Wrestrict" | |
29 | #endif | |
30 | ||
ef79bbde P |
31 | char ostr[256]; |
32 | ||
33 | // Names of registers | |
34 | static char *disRNameGPR[] = { | |
35 | "r0", "at", "v0", "v1", "a0", "a1","a2", "a3", | |
36 | "t0", "t1", "t2", "t3", "t4", "t5","t6", "t7", | |
37 | "s0", "s1", "s2", "s3", "s4", "s5","s6", "s7", | |
38 | "t8", "t9", "k0", "k1", "gp", "sp","fp", "ra"}; | |
39 | ||
40 | char *disRNameCP0[] = { | |
41 | "Index" , "Random" , "EntryLo0", "EntryLo1", "Context" , "PageMask" , "Wired" , "*Check me*", | |
42 | "BadVAddr" , "Count" , "EntryHi" , "Compare" , "Status" , "Cause" , "ExceptPC" , "PRevID" , | |
43 | "Config" , "LLAddr" , "WatchLo" , "WatchHi" , "XContext", "*RES*" , "*RES*" , "*RES*" , | |
44 | "*RES*" , "*RES* " , "PErr" , "CacheErr", "TagLo" , "TagHi" , "ErrorEPC" , "*RES*" }; | |
45 | ||
46 | ||
47 | // Type deffinition of our functions | |
48 | ||
49 | typedef char* (*TdisR3000AF)(u32 code, u32 pc); | |
50 | ||
51 | // These macros are used to assemble the disassembler functions | |
52 | #define MakeDisFg(fn, b) char* fn(u32 code, u32 pc) { b; return ostr; } | |
53 | #define MakeDisF(fn, b) \ | |
54 | static char* fn(u32 code, u32 pc) { \ | |
55 | sprintf (ostr, "%8.8x %8.8x:", pc, code); \ | |
56 | b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \ | |
57 | } | |
58 | ||
59 | ||
60 | #include "r3000a.h" | |
61 | ||
62 | #undef _Funct_ | |
63 | #undef _Rd_ | |
64 | #undef _Rt_ | |
65 | #undef _Rs_ | |
66 | #undef _Sa_ | |
67 | #undef _Im_ | |
68 | #undef _Target_ | |
69 | ||
70 | #define _Funct_ ((code ) & 0x3F) // The funct part of the instruction register | |
71 | #define _Rd_ ((code >> 11) & 0x1F) // The rd part of the instruction register | |
72 | #define _Rt_ ((code >> 16) & 0x1F) // The rt part of the instruction register | |
73 | #define _Rs_ ((code >> 21) & 0x1F) // The rs part of the instruction register | |
74 | #define _Sa_ ((code >> 6) & 0x1F) // The sa part of the instruction register | |
75 | #define _Im_ ( code & 0xFFFF) // The immediate part of the instruction register | |
76 | ||
77 | #define _Target_ ((pc & 0xf0000000) + ((code & 0x03ffffff) * 4)) | |
78 | #define _Branch_ (pc + 4 + ((short)_Im_ * 4)) | |
79 | #define _OfB_ _Im_, _nRs_ | |
80 | ||
9361a5aa EC |
81 | #define dName(i) snprintf(ostr, sizeof(ostr), "%s %-7s,", ostr, i) |
82 | #define dGPR(i) snprintf(ostr, sizeof(ostr), "%s %8.8x (%s),", ostr, psxRegs.GPR.r[i], disRNameGPR[i]) | |
83 | #define dCP0(i) snprintf(ostr, sizeof(ostr), "%s %8.8x (%s),", ostr, psxRegs.CP0.r[i], disRNameCP0[i]) | |
84 | #define dHI() snprintf(ostr, sizeof(ostr), "%s %8.8x (%s),", ostr, psxRegs.GPR.n.hi, "hi") | |
85 | #define dLO() snprintf(ostr, sizeof(ostr), "%s %8.8x (%s),", ostr, psxRegs.GPR.n.lo, "lo") | |
86 | #define dImm() snprintf(ostr, sizeof(ostr), "%s %4.4x (%d),", ostr, _Im_, _Im_) | |
87 | #define dTarget() snprintf(ostr, sizeof(ostr), "%s %8.8x,", ostr, _Target_) | |
88 | #define dSa() snprintf(ostr, sizeof(ostr), "%s %2.2x (%d),", ostr, _Sa_, _Sa_) | |
89 | #define dOfB() snprintf(ostr, sizeof(ostr), "%s %4.4x (%8.8x (%s)),", ostr, _Im_, psxRegs.GPR.r[_Rs_], disRNameGPR[_Rs_]) | |
90 | #define dOffset() snprintf(ostr, sizeof(ostr), "%s %8.8x,", ostr, _Branch_) | |
91 | #define dCode() snprintf(ostr, sizeof(ostr), "%s %8.8x,", ostr, (code >> 6) & 0xffffff) | |
ef79bbde P |
92 | |
93 | /********************************************************* | |
94 | * Arithmetic with immediate operand * | |
95 | * Format: OP rt, rs, immediate * | |
96 | *********************************************************/ | |
97 | MakeDisF(disADDI, dName("ADDI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) | |
98 | MakeDisF(disADDIU, dName("ADDIU"); dGPR(_Rt_); dGPR(_Rs_); dImm();) | |
99 | MakeDisF(disANDI, dName("ANDI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) | |
100 | MakeDisF(disORI, dName("ORI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) | |
101 | MakeDisF(disSLTI, dName("SLTI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) | |
102 | MakeDisF(disSLTIU, dName("SLTIU"); dGPR(_Rt_); dGPR(_Rs_); dImm();) | |
103 | MakeDisF(disXORI, dName("XORI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) | |
104 | ||
105 | /********************************************************* | |
106 | * Register arithmetic * | |
107 | * Format: OP rd, rs, rt * | |
108 | *********************************************************/ | |
109 | MakeDisF(disADD, dName("ADD"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) | |
110 | MakeDisF(disADDU, dName("ADDU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) | |
111 | MakeDisF(disAND, dName("AND"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) | |
112 | MakeDisF(disNOR, dName("NOR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) | |
113 | MakeDisF(disOR, dName("OR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) | |
114 | MakeDisF(disSLT, dName("SLT"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) | |
115 | MakeDisF(disSLTU, dName("SLTU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) | |
116 | MakeDisF(disSUB, dName("SUB"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) | |
117 | MakeDisF(disSUBU, dName("SUBU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) | |
118 | MakeDisF(disXOR, dName("XOR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) | |
119 | ||
120 | /********************************************************* | |
121 | * Register arithmetic & Register trap logic * | |
122 | * Format: OP rs, rt * | |
123 | *********************************************************/ | |
124 | MakeDisF(disDIV, dName("DIV"); dGPR(_Rs_); dGPR(_Rt_);) | |
125 | MakeDisF(disDIVU, dName("DIVU"); dGPR(_Rs_); dGPR(_Rt_);) | |
126 | MakeDisF(disMULT, dName("MULT"); dGPR(_Rs_); dGPR(_Rt_);) | |
127 | MakeDisF(disMULTU, dName("MULTU"); dGPR(_Rs_); dGPR(_Rt_);) | |
128 | ||
129 | /********************************************************* | |
130 | * Register branch logic * | |
131 | * Format: OP rs, offset * | |
132 | *********************************************************/ | |
133 | MakeDisF(disBGEZ, dName("BGEZ"); dGPR(_Rs_); dOffset();) | |
134 | MakeDisF(disBGEZAL, dName("BGEZAL"); dGPR(_Rs_); dOffset();) | |
135 | MakeDisF(disBGTZ, dName("BGTZ"); dGPR(_Rs_); dOffset();) | |
136 | MakeDisF(disBLEZ, dName("BLEZ"); dGPR(_Rs_); dOffset();) | |
137 | MakeDisF(disBLTZ, dName("BLTZ"); dGPR(_Rs_); dOffset();) | |
138 | MakeDisF(disBLTZAL, dName("BLTZAL"); dGPR(_Rs_); dOffset();) | |
139 | ||
140 | /********************************************************* | |
141 | * Shift arithmetic with constant shift * | |
142 | * Format: OP rd, rt, sa * | |
143 | *********************************************************/ | |
144 | MakeDisF(disSLL, if (code) { dName("SLL"); dGPR(_Rd_); dGPR(_Rt_); dSa(); } else { dName("NOP"); }) | |
145 | MakeDisF(disSRA, dName("SRA"); dGPR(_Rd_); dGPR(_Rt_); dSa();) | |
146 | MakeDisF(disSRL, dName("SRL"); dGPR(_Rd_); dGPR(_Rt_); dSa();) | |
147 | ||
148 | /********************************************************* | |
149 | * Shift arithmetic with variant register shift * | |
150 | * Format: OP rd, rt, rs * | |
151 | *********************************************************/ | |
152 | MakeDisF(disSLLV, dName("SLLV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) | |
153 | MakeDisF(disSRAV, dName("SRAV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) | |
154 | MakeDisF(disSRLV, dName("SRLV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) | |
155 | ||
156 | /********************************************************* | |
157 | * Load higher 16 bits of the first word in GPR with imm * | |
158 | * Format: OP rt, immediate * | |
159 | *********************************************************/ | |
160 | MakeDisF(disLUI, dName("LUI"); dGPR(_Rt_); dImm();) | |
161 | ||
162 | /********************************************************* | |
163 | * Move from HI/LO to GPR * | |
164 | * Format: OP rd * | |
165 | *********************************************************/ | |
166 | MakeDisF(disMFHI, dName("MFHI"); dGPR(_Rd_); dHI();) | |
167 | MakeDisF(disMFLO, dName("MFLO"); dGPR(_Rd_); dLO();) | |
168 | ||
169 | /********************************************************* | |
170 | * Move from GPR to HI/LO * | |
171 | * Format: OP rd * | |
172 | *********************************************************/ | |
173 | MakeDisF(disMTHI, dName("MTHI"); dHI(); dGPR(_Rs_);) | |
174 | MakeDisF(disMTLO, dName("MTLO"); dLO(); dGPR(_Rs_);) | |
175 | ||
176 | /********************************************************* | |
177 | * Special purpose instructions * | |
178 | * Format: OP * | |
179 | *********************************************************/ | |
180 | MakeDisF(disBREAK, dName("BREAK")) | |
181 | MakeDisF(disRFE, dName("RFE")) | |
182 | MakeDisF(disSYSCALL, dName("SYSCALL")) | |
183 | MakeDisF(disHLE, dName("HLE")) | |
184 | ||
185 | ||
186 | MakeDisF(disRTPS, dName("RTPS")) | |
187 | MakeDisF(disOP , dName("OP")) | |
188 | MakeDisF(disNCLIP, dName("NCLIP")) | |
189 | MakeDisF(disDPCS, dName("DPCS")) | |
190 | MakeDisF(disINTPL, dName("INTPL")) | |
191 | MakeDisF(disMVMVA, dName("MVMVA")) | |
192 | MakeDisF(disNCDS , dName("NCDS")) | |
193 | MakeDisF(disCDP , dName("CDP")) | |
194 | MakeDisF(disNCDT , dName("NCDT")) | |
195 | MakeDisF(disNCCS , dName("NCCS")) | |
196 | MakeDisF(disCC , dName("CC")) | |
197 | MakeDisF(disNCS , dName("NCS")) | |
198 | MakeDisF(disNCT , dName("NCT")) | |
199 | MakeDisF(disSQR , dName("SQR")) | |
200 | MakeDisF(disDCPL , dName("DCPL")) | |
201 | MakeDisF(disDPCT , dName("DPCT")) | |
202 | MakeDisF(disAVSZ3, dName("AVSZ3")) | |
203 | MakeDisF(disAVSZ4, dName("AVSZ4")) | |
204 | MakeDisF(disRTPT , dName("RTPT")) | |
205 | MakeDisF(disGPF , dName("GPF")) | |
206 | MakeDisF(disGPL , dName("GPL")) | |
207 | MakeDisF(disNCCT , dName("NCCT")) | |
208 | ||
209 | MakeDisF(disMFC2, dName("MFC2"); dGPR(_Rt_);) | |
210 | MakeDisF(disCFC2, dName("CFC2"); dGPR(_Rt_);) | |
211 | MakeDisF(disMTC2, dName("MTC2"); dGPR(_Rt_);) | |
212 | MakeDisF(disCTC2, dName("CTC2"); dGPR(_Rt_);) | |
213 | ||
214 | /********************************************************* | |
215 | * Register branch logic * | |
216 | * Format: OP rs, rt, offset * | |
217 | *********************************************************/ | |
218 | MakeDisF(disBEQ, dName("BEQ"); dGPR(_Rs_); dGPR(_Rt_); dOffset();) | |
219 | MakeDisF(disBNE, dName("BNE"); dGPR(_Rs_); dGPR(_Rt_); dOffset();) | |
220 | ||
221 | /********************************************************* | |
222 | * Jump to target * | |
223 | * Format: OP target * | |
224 | *********************************************************/ | |
225 | MakeDisF(disJ, dName("J"); dTarget();) | |
226 | MakeDisF(disJAL, dName("JAL"); dTarget(); dGPR(31);) | |
227 | ||
228 | /********************************************************* | |
229 | * Register jump * | |
230 | * Format: OP rs, rd * | |
231 | *********************************************************/ | |
232 | MakeDisF(disJR, dName("JR"); dGPR(_Rs_);) | |
233 | MakeDisF(disJALR, dName("JALR"); dGPR(_Rs_); dGPR(_Rd_)) | |
234 | ||
235 | /********************************************************* | |
236 | * Load and store for GPR * | |
237 | * Format: OP rt, offset(base) * | |
238 | *********************************************************/ | |
239 | MakeDisF(disLB, dName("LB"); dGPR(_Rt_); dOfB();) | |
240 | MakeDisF(disLBU, dName("LBU"); dGPR(_Rt_); dOfB();) | |
241 | MakeDisF(disLH, dName("LH"); dGPR(_Rt_); dOfB();) | |
242 | MakeDisF(disLHU, dName("LHU"); dGPR(_Rt_); dOfB();) | |
243 | MakeDisF(disLW, dName("LW"); dGPR(_Rt_); dOfB();) | |
244 | MakeDisF(disLWL, dName("LWL"); dGPR(_Rt_); dOfB();) | |
245 | MakeDisF(disLWR, dName("LWR"); dGPR(_Rt_); dOfB();) | |
246 | MakeDisF(disLWC2, dName("LWC2"); dGPR(_Rt_); dOfB();) | |
247 | MakeDisF(disSB, dName("SB"); dGPR(_Rt_); dOfB();) | |
248 | MakeDisF(disSH, dName("SH"); dGPR(_Rt_); dOfB();) | |
249 | MakeDisF(disSW, dName("SW"); dGPR(_Rt_); dOfB();) | |
250 | MakeDisF(disSWL, dName("SWL"); dGPR(_Rt_); dOfB();) | |
251 | MakeDisF(disSWR, dName("SWR"); dGPR(_Rt_); dOfB();) | |
252 | MakeDisF(disSWC2, dName("SWC2"); dGPR(_Rt_); dOfB();) | |
253 | ||
254 | /********************************************************* | |
255 | * Moves between GPR and COPx * | |
256 | * Format: OP rt, fs * | |
257 | *********************************************************/ | |
258 | MakeDisF(disMFC0, dName("MFC0"); dGPR(_Rt_); dCP0(_Rd_);) | |
259 | MakeDisF(disMTC0, dName("MTC0"); dCP0(_Rd_); dGPR(_Rt_);) | |
260 | MakeDisF(disCFC0, dName("CFC0"); dGPR(_Rt_); dCP0(_Rd_);) | |
261 | MakeDisF(disCTC0, dName("CTC0"); dCP0(_Rd_); dGPR(_Rt_);) | |
262 | ||
263 | /********************************************************* | |
264 | * Unknow instruction (would generate an exception) * | |
265 | * Format: ? * | |
266 | *********************************************************/ | |
267 | MakeDisF(disNULL, dName("*** Bad OP ***");) | |
268 | ||
269 | ||
270 | TdisR3000AF disR3000A_SPECIAL[] = { // Subset of disSPECIAL | |
271 | disSLL , disNULL , disSRL , disSRA , disSLLV , disNULL , disSRLV , disSRAV , | |
272 | disJR , disJALR , disNULL, disNULL, disSYSCALL, disBREAK , disNULL , disNULL , | |
273 | disMFHI, disMTHI , disMFLO, disMTLO, disNULL , disNULL , disNULL , disNULL , | |
274 | disMULT, disMULTU, disDIV , disDIVU, disNULL , disNULL , disNULL , disNULL , | |
275 | disADD , disADDU , disSUB , disSUBU, disAND , disOR , disXOR , disNOR , | |
276 | disNULL, disNULL , disSLT , disSLTU, disNULL , disNULL , disNULL , disNULL , | |
277 | disNULL, disNULL , disNULL, disNULL, disNULL , disNULL , disNULL , disNULL , | |
278 | disNULL, disNULL , disNULL, disNULL, disNULL , disNULL , disNULL , disNULL}; | |
279 | ||
280 | MakeDisF(disSPECIAL, disR3000A_SPECIAL[_Funct_](code, pc)) | |
281 | ||
282 | TdisR3000AF disR3000A_BCOND[] = { // Subset of disBCOND | |
283 | disBLTZ , disBGEZ , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, | |
284 | disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, | |
285 | disBLTZAL, disBGEZAL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, | |
286 | disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; | |
287 | ||
288 | MakeDisF(disBCOND, disR3000A_BCOND[_Rt_](code, pc)) | |
289 | ||
290 | TdisR3000AF disR3000A_COP0[] = { // Subset of disCOP0 | |
291 | disMFC0, disNULL, disCFC0, disNULL, disMTC0, disNULL, disCTC0, disNULL, | |
292 | disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, | |
293 | disRFE , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, | |
294 | disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; | |
295 | ||
296 | MakeDisF(disCOP0, disR3000A_COP0[_Rs_](code, pc)) | |
297 | ||
298 | TdisR3000AF disR3000A_BASIC[] = { // Subset of disBASIC (based on rs) | |
299 | disMFC2, disNULL, disCFC2, disNULL, disMTC2, disNULL, disCTC2, disNULL, | |
300 | disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, | |
301 | disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, | |
302 | disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; | |
303 | ||
304 | MakeDisF(disBASIC, disR3000A_BASIC[_Rs_](code, pc)) | |
305 | ||
306 | TdisR3000AF disR3000A_COP2[] = { // Subset of disR3000F_COP2 (based on funct) | |
307 | disBASIC, disRTPS , disNULL , disNULL , disNULL, disNULL , disNCLIP, disNULL, | |
308 | disNULL , disNULL , disNULL , disNULL , disOP , disNULL , disNULL , disNULL, | |
309 | disDPCS , disINTPL, disMVMVA, disNCDS , disCDP , disNULL , disNCDT , disNULL, | |
310 | disNULL , disNULL , disNULL , disNCCS , disCC , disNULL , disNCS , disNULL, | |
311 | disNCT , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL , disNULL, | |
312 | disSQR , disDCPL , disDPCT , disNULL , disNULL, disAVSZ3, disAVSZ4, disNULL, | |
313 | disRTPT , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL , disNULL, | |
314 | disNULL , disNULL , disNULL , disNULL , disNULL, disGPF , disGPL , disNCCT }; | |
315 | ||
316 | MakeDisF(disCOP2, disR3000A_COP2[_Funct_](code, pc)) | |
317 | ||
318 | TdisR3000AF disR3000A[] = { | |
319 | disSPECIAL , disBCOND , disJ , disJAL , disBEQ , disBNE , disBLEZ , disBGTZ , | |
320 | disADDI , disADDIU , disSLTI , disSLTIU, disANDI, disORI , disXORI , disLUI , | |
321 | disCOP0 , disNULL , disCOP2 , disNULL , disNULL, disNULL, disNULL , disNULL , | |
322 | disNULL , disNULL , disNULL , disNULL , disNULL, disNULL, disNULL , disNULL , | |
323 | disLB , disLH , disLWL , disLW , disLBU , disLHU , disLWR , disNULL , | |
324 | disSB , disSH , disSWL , disSW , disNULL, disNULL, disSWR , disNULL , | |
325 | disNULL , disNULL , disLWC2 , disNULL , disNULL, disNULL, disNULL , disNULL , | |
326 | disNULL , disNULL , disSWC2 , disHLE , disNULL, disNULL, disNULL , disNULL }; | |
327 | ||
328 | MakeDisFg(disR3000AF, disR3000A[code >> 26](code, pc)) |