| 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)) |