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