├── CommonDefs.h ├── LICENSE ├── README.md ├── main.cpp ├── ppcd.cpp ├── ppcd.h └── test.bin /CommonDefs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef WIN32 4 | #define WINDOWS 5 | #endif 6 | 7 | /* 8 | * General Data Types. 9 | */ 10 | 11 | typedef signed char s8; 12 | typedef signed short s16; 13 | typedef signed long s32; 14 | typedef unsigned char u8; 15 | typedef unsigned short u16; 16 | typedef unsigned long u32; 17 | typedef float f32; 18 | typedef double f64; 19 | 20 | #ifdef WINDOWS 21 | typedef unsigned __int64 u64; 22 | typedef signed __int64 s64; 23 | #else 24 | typedef unsigned long long u64; 25 | typedef signed long long s64; 26 | #endif 27 | 28 | #ifndef __cplusplus 29 | typedef enum { false = 0, true } bool; 30 | #endif 31 | 32 | #define FASTCALL __fastcall 33 | #define INLINE __inline 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PPCD is very accurate disassembler of PowerPC-based processors ISA. Current supported models are: 2 | 3 | * Generic POWERPC-32 4 | * Generic POWERPC-64 5 | * Gekko 6 | 7 | For each model standalone compiled executable is provided. To disassemble binary file, use: 8 | 9 | ppcd-**model** binary 10 | 11 | Output will go to stdout. 12 | 13 | Credits: This program has written by org between 2006-2007 for Gekko debugger. PPCD is free opensource. You can use it in your applications without mention. 14 | 15 | Let me know, if you made support for more processors. 16 | 17 | How to use sourcecode: 18 | 19 | You need to add ppcd.cpp/ppcd.h and Commondefs (data types) to your project. Call PPCDisasm and pass it PPCD\_CB structure with filled "pc" and "instr" parameters. At minimum you can use "mnemonic" and "operands" as output parameters, but if you need more detailed information about disassembled instruction, use "icalss", "immed", "target" and "r": 20 | 21 | * iclass: Combination of flags which specify instruction "class" or category. See ppcd.h for list of flags. Note, many flags can be combined, for example FPU + LDST. 22 | * immed: Immediate value for integer instructions or address displacement for load/store. 23 | * target: "Cooked" absolute branch address (calculated from input "pc" parameter) OR mask for rlwinm-like instructions. 24 | * r: Index list for register operands in appropriate order. 25 | 26 | As option there is PPCDisasmSimple call for quick use. Just call PPCDisasmSimple(pc, instr) and it will return formatted string. 27 | 28 | ppcd.cpp compilation tips: 29 | 30 | * If you need uppercase: define UPPERCASE 31 | * If you need another hexademical numbers representation: See HEX1 and HEX2 32 | * If you dont need spaces between commas: redefine COMMA as "," 33 | * If you dont need simplified mnemonics (highly not recommended :)): undefine SIMPLIFIED 34 | 35 | CHANGELOG: 36 | 37 | * 0.01 Initial release. Generic 32/64-bit ISA is implemented and extensively tested. 38 | * 0.02 Added support for Gekko. 39 | * 0.03 Fixed some typos. 40 | 41 | **This project is completed.** 42 | 43 | **If you're experience weird .cpp errors, use static type casting in problem places. Things may change in time in CPP world.** 44 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | // PowerPC disassembler. 2 | 3 | #include 4 | 5 | #include "Commondefs.h" 6 | #include "ppcd.h" 7 | 8 | #define MODULE_NAME "ppcd-generic32" 9 | #define MODULE_VER 0.03 10 | 11 | static void usage(void) 12 | { 13 | printf ("PPCD PowerPC Disassembler. Version %.2f\n", MODULE_VER); 14 | printf ("(c) 2007, org.\n\n"); 15 | printf ("Use: %s \n", MODULE_NAME); 16 | } 17 | 18 | static u32 FASTCALL Swap32(u32 data) 19 | { 20 | return ((data >> 24) ) | 21 | ((data >> 8) & 0x0000ff00) | 22 | ((data << 8) & 0x00ff0000) | 23 | ((data << 24) ); 24 | } 25 | 26 | int main (int argc, char **argv) 27 | { 28 | PPCD_CB disa; 29 | FILE *f; 30 | u32 pc = 0x80000000, instr; 31 | 32 | if (argc <= 1) 33 | { 34 | usage (); 35 | return (0); 36 | } 37 | 38 | f = fopen (argv[1], "rb"); 39 | if (f == NULL) return (0); 40 | 41 | while (!feof(f)) 42 | { 43 | fread (&instr, 1, 4, f); 44 | 45 | disa.pc = pc; 46 | disa.instr = Swap32 (instr); 47 | PPCDisasm (&disa); 48 | 49 | printf ("%08X %08X %-12s%-30s\n", pc, instr, disa.mnemonic, disa.operands); 50 | pc += 4; 51 | } 52 | 53 | fclose (f); 54 | return (1); 55 | } 56 | -------------------------------------------------------------------------------- /ppcd.cpp: -------------------------------------------------------------------------------- 1 | // Very accurate PowerPC Architecture disassembler (both 32 and 64-bit instructions are supported) 2 | 3 | // Branch Target in output parameters is NOT relative. Its already precalculated 4 | // from effective address of current instruction. 5 | 6 | // Note, that old mnemonics and operands will be overwritten, after next disasm 7 | // call. So dont forget to copy them away, if supposed to use them lately. 8 | 9 | // Instruction class can be combined from many flags. There can exist, for example, 10 | // "FPU" + "LDST" instruction, except "ILLEGAL", which cannot be combined. 11 | 12 | // RLWINM-like instructions mask is placed in output "target" parameter. 13 | 14 | #include 15 | #include 16 | 17 | #include "Commondefs.h" 18 | #include "ppcd.h" 19 | 20 | #define POWERPC_32 // Use generic 32-bit model 21 | //efine POWERPC_64 // Use generic 64-bit model 22 | //efine GEKKO // Use Gekko (32-bit ISA) 23 | //efine BROADWAY // Use Broadway (32-bit ISA) 24 | 25 | #define SIMPLIFIED // Allow simplified mnemonics 26 | //efine UPPERCASE // Use upper case strings in output 27 | #define COMMA ", " 28 | #define LPAREN " (" 29 | #define RPAREN ")" 30 | #define HEX1 "0x" // prefix 31 | #define HEX2 "" // suffix 32 | 33 | static int bigendian = -1; // Autodetect. 34 | 35 | // --------------------------------------------------------------------------- 36 | // Implementation. Look away, code is messed :) 37 | // Dont miss 'l' and '1'. 38 | 39 | static PPCD_CB *o; 40 | #define Instr (o->instr) 41 | #define DIS_PC (o->pc) 42 | 43 | // Simple decoder 44 | #define DIS_RD ((Instr >> 21) & 0x1f) 45 | #define DIS_RS DIS_RD 46 | #define DIS_RA ((Instr >> 16) & 0x1f) 47 | #define DIS_RB ((Instr >> 11) & 0x1f) 48 | #define DIS_RC ((Instr >> 6) & 0x1f) 49 | #define DIS_RE ((Instr >> 1) & 0x1f) 50 | #define DIS_MB DIS_RC 51 | #define DIS_ME DIS_RE 52 | #define DIS_OE (Instr & 0x400) 53 | #define DIS_SIMM ((s16)Instr) 54 | #define DIS_UIMM (Instr & 0xffff) 55 | #define DIS_CRM ((Instr >> 12) & 0xff) 56 | #define AA (Instr & 2) 57 | #define LK (Instr & 1) 58 | #define AALK (Instr & 3) 59 | #define Rc LK 60 | 61 | // GPRs. sp, sd1 and sd2 are named corresponding to PPC EABI. 62 | static char *regname[] = { 63 | #ifdef UPPERCASE 64 | "R0" , "R1" , "R2", "R3" , "R4" , "R5" , "R6" , "R7" , 65 | "R8" , "R9" , "R10", "R11", "R12", "R13", "R14", "R15", 66 | "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", 67 | "R24", "R25", "R26", "R27", "R28", "R29", "R30", "R31" 68 | #else 69 | "r0" , "r1" , "r2", "r3" , "r4" , "r5" , "r6" , "r7" , 70 | "r8" , "r9" , "r10", "r11", "r12", "r13", "r14", "r15", 71 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 72 | "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" 73 | #endif 74 | }; 75 | #define REGD (regname[DIS_RD]) 76 | #define REGS (regname[DIS_RS]) 77 | #define REGA (regname[DIS_RA]) 78 | #define REGB (regname[DIS_RB]) 79 | 80 | // Illegal instruction. 81 | static void ill(void) 82 | { 83 | #if 1 84 | o->mnemonic[0] = o->operands[0] = '\0'; 85 | #else 86 | strcpy(o->mnemonic, ".word"); 87 | sprintf(o->operands, HEX1 "%08X" HEX2, Instr); 88 | #endif 89 | o->iclass = PPC_DISA_ILLEGAL; 90 | } 91 | 92 | // Smart SIMM formatting (if hex=1, then force HEX; if s=1, use sign) 93 | static char * simm(int val, int hex, int s) 94 | { 95 | static char out[16]; 96 | if( ((val >= -256) && (val <= 256)) && !hex) sprintf(out, "%i", val); 97 | else 98 | { 99 | u16 hexval = (u16)val; 100 | if((hexval & 0x8000) && s) sprintf(out, "-" HEX1 "%04X" HEX2, ((~hexval) & 0xffff) + 1); 101 | else sprintf(out, HEX1 "%04X" HEX2, hexval); 102 | } 103 | return out; 104 | } 105 | 106 | // Simple instruction form + reserved bitmask. 107 | static void put(char * mnem, u32 mask, u32 chkval=0, int iclass=PPC_DISA_OTHER) 108 | { 109 | if( (Instr & mask) != chkval ) { ill(); return; } 110 | o->iclass |= iclass; 111 | strncpy(o->mnemonic, mnem, sizeof(o->mnemonic)); 112 | } 113 | 114 | // Simplified mnemonic trap conditions 115 | static char * t_cond[32] = { 116 | NULL, "lgt", "llt", NULL, "eq", "lge", "lle", NULL, 117 | "gt", NULL, NULL, NULL, "ge", NULL, NULL, NULL, 118 | "lt", NULL, NULL, NULL, "le", NULL, NULL, NULL, 119 | "ne", NULL, NULL, NULL, NULL, NULL, NULL, NULL, 120 | }; 121 | 122 | // Trap instructions. 123 | static void trap(int L, int imm) 124 | { 125 | static char t_mode[2] = { 'w', 'd' }; 126 | int rd = DIS_RD; // TO 127 | int s = (rd & 0x18) ? 1 : 0; 128 | #ifdef SIMPLIFIED 129 | if(t_cond[rd] != NULL) 130 | { 131 | sprintf(o->mnemonic, "t%c%s%c", t_mode[L & 1], t_cond[rd], imm ? 'i' : 0); 132 | if(imm) sprintf(o->operands, "%s" COMMA "%s", REGA, simm(DIS_SIMM, 0, s)); 133 | else sprintf(o->operands, "%s" COMMA "%s", REGA, REGB); 134 | o->iclass |= PPC_DISA_SIMPLIFIED; 135 | } 136 | else 137 | #endif 138 | { 139 | sprintf(o->mnemonic, "t%c%c", t_mode[L & 1], imm ? 'i' : 0); 140 | if(imm) sprintf(o->operands, "%i" COMMA "%s" COMMA "%s", rd, REGA, simm(DIS_SIMM, 0, s)); 141 | else sprintf(o->operands, "%i" COMMA "%s" COMMA "%s", rd, REGA, REGB); 142 | } 143 | if(L) o->iclass |= PPC_DISA_64; 144 | o->r[1] = DIS_RA; if(!imm) o->r[2] = DIS_RB; 145 | if(imm) 146 | { 147 | o->immed = Instr & 0xFFFF; 148 | if(o->immed & 0x8000) o->immed |= 0xFFFF0000; 149 | } 150 | } 151 | 152 | // DAB mask 153 | #define DAB_D 4 154 | #define DAB_A 2 155 | #define DAB_B 1 156 | 157 | // ASB mask 158 | #define ASB_A 4 159 | #define ASB_S 2 160 | #define ASB_B 1 161 | 162 | // cr%i 163 | #ifdef UPPERCASE 164 | static char crname[] = "CR"; 165 | #else 166 | static char crname[] = "cr"; 167 | #endif 168 | 169 | // fr%i 170 | #ifdef UPPERCASE 171 | static char fregname[] = "FR"; 172 | #else 173 | static char fregname[] = "fr"; 174 | #endif 175 | 176 | // Integer instructions 177 | // form: 'D' rD, rA, (s)IMM 178 | // 'S' rA, rS, (s)IMM 179 | // 'X' rD, rA, rB 180 | // 'Z' rA, rS, rB 181 | // 'F' frD, rA, rB 182 | // dab LSB bits : [D][A][B] (D should always present) 183 | // 'hex' for logic opcodes, 's' for alu opcodes, 'crfD' and 'L' for cmp opcodes 184 | // 'imm': 1 to show immediate operand 185 | static void integer(char *mnem, char form, int dab, int hex=0, int s=1, int crfD=0, int L=0, int imm=1) 186 | { 187 | char * ptr = o->operands; 188 | int rd = DIS_RD, ra = DIS_RA, rb = DIS_RB; 189 | strncpy(o->mnemonic, mnem, sizeof(o->mnemonic)); 190 | if(crfD) ptr += sprintf(ptr, "%s%i" COMMA, crname, rd >> 2); // CMP only 191 | if(L) ptr += sprintf(ptr, "%i" COMMA, rd & 1); // CMP only 192 | if(form == 'D') 193 | { 194 | if(dab & DAB_D) ptr += sprintf(ptr, "%s", REGD); 195 | if(dab & DAB_A) 196 | { 197 | if(dab & DAB_D) ptr += sprintf(ptr, "%s", COMMA); 198 | ptr += sprintf(ptr, "%s", REGA); 199 | } 200 | if(imm) ptr += sprintf(ptr, COMMA "%s", simm(s ? DIS_SIMM : DIS_UIMM, hex, s)); 201 | } 202 | else if(form == 'S') 203 | { 204 | if(dab & ASB_A) ptr += sprintf(ptr, "%s", REGA); 205 | if(dab & ASB_S) 206 | { 207 | if(dab & ASB_A) ptr += sprintf(ptr, "%s", COMMA); 208 | ptr += sprintf(ptr, "%s", REGS); 209 | } 210 | if(imm) ptr += sprintf(ptr, COMMA "%s", simm(s ? DIS_SIMM : DIS_UIMM, hex, s)); 211 | } 212 | else if(form == 'X') // DAB 213 | { 214 | if(dab & DAB_D) ptr += sprintf(ptr, "%s", REGD); 215 | if(dab & DAB_A) 216 | { 217 | if(dab & DAB_D) ptr += sprintf(ptr, "%s", COMMA); 218 | ptr += sprintf(ptr, "%s", REGA); 219 | } 220 | if(dab & DAB_B) 221 | { 222 | if(dab & (DAB_D|DAB_A)) ptr += sprintf(ptr, "%s", COMMA); 223 | ptr += sprintf(ptr, "%s", REGB); 224 | } 225 | } 226 | else if(form == 'F') // FPU DAB 227 | { 228 | if(dab & DAB_D) ptr += sprintf(ptr, "%s%i", fregname, rd); 229 | if(dab & DAB_A) 230 | { 231 | if(dab & DAB_D) ptr += sprintf(ptr, "%s", COMMA); 232 | ptr += sprintf(ptr, "%s", REGA); 233 | } 234 | if(dab & DAB_B) 235 | { 236 | if(dab & (DAB_D|DAB_A)) ptr += sprintf(ptr, "%s", COMMA); 237 | ptr += sprintf(ptr, "%s", REGB); 238 | } 239 | } 240 | else if(form == 'Z') // ASB 241 | { 242 | if(dab & ASB_A) ptr += sprintf(ptr, "%s", REGA); 243 | if(dab & ASB_S) 244 | { 245 | if(dab & ASB_A) ptr += sprintf(ptr, "%s", COMMA); 246 | ptr += sprintf(ptr, "%s", REGS); 247 | } 248 | if(dab & ASB_B) 249 | { 250 | if(dab & (ASB_A|ASB_S)) ptr += sprintf(ptr, "%s", COMMA); 251 | ptr += sprintf(ptr, "%s", REGB); 252 | } 253 | } 254 | else { ill(); return; } 255 | if(form == 'D' || form == 'X' || form == 'F') { o->r[0] = rd; o->r[1] = ra; } 256 | if(form == 'S' || form == 'Z') { o->r[0] = ra; o->r[1] = rd; } 257 | if(form == 'X' || form == 'Z' || form == 'F') o->r[2] = rb; 258 | if((form == 'D' || form == 'S') && imm) 259 | { 260 | o->immed = Instr & 0xFFFF; 261 | if(o->immed & 0x8000 && s) o->immed |= 0xFFFF0000; 262 | } 263 | o->iclass |= PPC_DISA_INTEGER; 264 | } 265 | 266 | // Compare instructions (wraps to integer call) 267 | static void cmp(char *l, char *i) 268 | { 269 | char mnem[sizeof(o->mnemonic)]; 270 | int rd = DIS_RD; 271 | 272 | if(rd & 2) { ill(); return; } // Reserved bit set 273 | if(rd & 1) 274 | { 275 | #ifndef POWERPC_64 276 | { ill(); return; } 277 | #endif 278 | o->iclass |= PPC_DISA_64; 279 | } 280 | 281 | #ifdef SIMPLIFIED 282 | sprintf(mnem, "cmp%s%c%s", l, (rd & 1) ? 'd' : 'w', i); 283 | integer(mnem, (*i == 'i') ? 'D' : 'X', DAB_A|DAB_B, 0, 1, (rd >> 2) ? 1 : 0, 0); 284 | o->iclass |= PPC_DISA_SIMPLIFIED; 285 | #else 286 | sprintf(mnem, "cmp%s%s", l, i); 287 | integer(mnem, (*i == 'i') ? 'D' : 'X', DAB_A|DAB_B, 0, 1, 1, 1); 288 | #endif 289 | } 290 | 291 | // Add immediate (wraps to integer call) 292 | static void addi(char *suffix) 293 | { 294 | char mnem[sizeof(o->mnemonic)]; 295 | 296 | #ifdef SIMPLIFIED 297 | if( (suffix[0] == '\0') && (DIS_RA == 0) ) // Load immediate 298 | { 299 | integer("li", 'D', DAB_D, 0, 1); 300 | o->iclass |= PPC_DISA_SIMPLIFIED; 301 | return; 302 | } 303 | if( (suffix[0] == 's') && (DIS_RA == 0) ) // Load address HI 304 | { 305 | integer("lis", 'D', DAB_D, 1, 0); 306 | o->iclass |= PPC_DISA_SIMPLIFIED; 307 | return; 308 | } 309 | if(DIS_UIMM & 0x8000) 310 | { 311 | sprintf(mnem, "subi%s", suffix); 312 | 313 | // Fix immediate field. 314 | u16 value = (u16)(~(DIS_UIMM) + 1); 315 | Instr = (Instr & ~0xFFFF) | value; 316 | 317 | integer(mnem, 'D', DAB_D|DAB_A, 0, 1); 318 | o->iclass |= PPC_DISA_SIMPLIFIED; 319 | } 320 | else 321 | { 322 | sprintf(mnem, "addi%s", suffix); 323 | integer(mnem, 'D', DAB_D|DAB_A, 0, 0); 324 | } 325 | #else 326 | sprintf(mnem, "addi%s", suffix); 327 | integer(mnem, 'D', DAB_D|DAB_A); 328 | #endif 329 | } 330 | 331 | // Branch suffix: AA || LK. 332 | static char *b_opt[4] = { "", "l", "a", "la" }; 333 | 334 | // Branch condition code: 4 * BO[1] + (BI & 3) 335 | static char * b_cond[8] = { 336 | "ge", "le", "ne", "ns", "lt", "gt", "eq", "so" 337 | }; 338 | 339 | // Branch on CTR code: BO[0..3] 340 | static char * b_ctr[16] = { 341 | "dnzf", "dzf", NULL, NULL, "dnzt", "dzt", NULL, NULL, 342 | "dnz", "dz", NULL, NULL, NULL, NULL, NULL, NULL 343 | }; 344 | 345 | // Place target address in operands. Helper for bcx/bx calls. 346 | static char *place_target(char *ptr, int comma) 347 | { 348 | char *old; 349 | u32 *t = (u32 *)&o->target; 350 | 351 | if(comma) ptr += sprintf(ptr, "%s", COMMA); 352 | old = ptr; 353 | #ifdef POWERPC_32 354 | ptr += sprintf(ptr, HEX1 "%08X" HEX2, (u32)o->target); 355 | #endif 356 | #ifdef POWERPC_64 357 | ptr = old; 358 | if(bigendian) ptr += sprintf(ptr, HEX1 "%08X_%08X" HEX2, t[0], t[1]); 359 | else ptr += sprintf(ptr, HEX1 "%08X_%08X" HEX2, t[1], t[0]); 360 | #endif 361 | return ptr; 362 | } 363 | 364 | // Branch conditional. 365 | // Disp:1 - branch with displacement.. 366 | // Disp:0 - branch by register (L:1 for LR, L:0 for CTR). 367 | static void bcx(int Disp, int L) 368 | { 369 | u64 bd = 0; 370 | int bo = DIS_RD, bi = DIS_RA; 371 | char *r = Disp ? "" : (L ? "lr" : "ctr"); 372 | char *ptr = o->operands; 373 | 374 | if( DIS_RB && !Disp ) { ill(); return; } 375 | 376 | o->operands[0] = '\0'; 377 | o->target = 0; 378 | o->iclass |= PPC_DISA_BRANCH; 379 | 380 | // Calculate displacement and target address 381 | if(Disp) 382 | { 383 | bd = DIS_UIMM & ~3; 384 | if(bd & 0x8000) bd |= 0xffffffffffff0000; 385 | o->target = (AA ? 0 : DIS_PC) + bd; 386 | } 387 | else o->target = 0; 388 | 389 | // Calculate branch prediction hint 390 | char y = (bo & 1) ^ ((((s64)bd < 0) && Disp) ? 1 : 0); 391 | y = y ? '+' : '-'; 392 | 393 | if(bo & 4) // No CTR decrement // BO[2] 394 | { 395 | if(bo & 16) // Branch always // BO[0] 396 | { 397 | #ifdef SIMPLIFIED 398 | sprintf(o->mnemonic, "b%s%s", r, b_opt[Disp ? AALK : LK]); 399 | if(Disp) ptr = place_target(ptr, 0); 400 | o->iclass |= PPC_DISA_SIMPLIFIED; 401 | return; 402 | #endif // SIMPLIFIED 403 | } 404 | else // Branch conditional 405 | { 406 | if(bo & 2) { ill(); return; } // BO[3] 407 | #ifdef SIMPLIFIED 408 | char *cond = b_cond[((bo & 8) >> 1) | (bi & 3)]; 409 | if(cond != NULL) // BO[1] 410 | { 411 | sprintf(o->mnemonic, "b%s%s%s%c", cond, r, b_opt[Disp ? AALK : LK], y); 412 | if(bi >= 4) ptr += sprintf(ptr, "%s%i", crname, bi >> 2); 413 | if(Disp) ptr = place_target(ptr, bi >= 4); 414 | o->iclass |= PPC_DISA_SIMPLIFIED; 415 | return; 416 | } 417 | #endif // SIMPLIFIED 418 | } 419 | } 420 | else // Decrement CTR 421 | { 422 | if(!L && !Disp) { ill(); return; } 423 | if(bo & 8) { ill(); return; } // BO[1] 424 | #ifdef SIMPLIFIED 425 | if(b_ctr[bo >> 1]) 426 | { 427 | sprintf(o->mnemonic, "b%s%s%s%c", b_ctr[bo >> 1], r, b_opt[Disp ? AALK : LK], y); 428 | if(!(bo & 16)) ptr += sprintf(ptr, "%i", bi); 429 | if(Disp) ptr = place_target(ptr, !(bo & 16)); 430 | o->iclass |= PPC_DISA_SIMPLIFIED; 431 | return; 432 | } 433 | #endif // SIMPLIFIED 434 | } 435 | 436 | // Not simplified standard form 437 | sprintf(o->mnemonic, "bc%s%s", r, b_opt[Disp ? AALK : LK]); 438 | ptr += sprintf(ptr, "%i" COMMA "%i", bo, bi); 439 | if(Disp) ptr = place_target(ptr, 1); 440 | } 441 | 442 | // Branch unconditional 443 | static void bx(void) 444 | { 445 | // Calculate displacement and target address 446 | u64 bd = Instr & 0x03fffffc; 447 | if(bd & 0x02000000) bd |= 0xfffffffffc000000; 448 | o->target = (AA ? 0 : DIS_PC) + bd; 449 | 450 | o->iclass |= PPC_DISA_BRANCH; 451 | sprintf(o->mnemonic, "b%s", b_opt[AALK]); 452 | place_target(o->operands, 0); 453 | } 454 | 455 | // Move CR field 456 | static void mcrf(void) 457 | { 458 | if(Instr & 0x63f801) { ill(); return; } 459 | strncpy(o->mnemonic, "mcrf", sizeof(o->mnemonic)); 460 | sprintf(o->operands, "%s%i" COMMA "%s%i", crname, DIS_RD >> 2, crname, DIS_RA >> 2); 461 | } 462 | 463 | // CR logic operations 464 | static void crop(char *name, char *simp="", int ddd=0, int daa=0) 465 | { 466 | if(Instr & 1) { ill(); return; } 467 | 468 | int crfD = DIS_RD, crfA = DIS_RA, crfB = DIS_RB; 469 | 470 | #ifdef SIMPLIFIED 471 | if( crfA == crfB ) 472 | { 473 | if( (crfD == crfA) && ddd ) 474 | { 475 | sprintf(o->mnemonic, "cr%s", simp); 476 | sprintf(o->operands, "%i", crfD); 477 | o->r[0] = crfD; 478 | o->iclass |= PPC_DISA_SIMPLIFIED; 479 | return; 480 | } 481 | if( daa ) 482 | { 483 | sprintf(o->mnemonic, "cr%s", simp); 484 | sprintf(o->operands, "%i" COMMA "%i", crfD, crfA); 485 | o->r[0] = crfD; o->r[1] = crfA; 486 | o->iclass |= PPC_DISA_SIMPLIFIED; 487 | return; 488 | } 489 | } 490 | #endif 491 | sprintf(o->mnemonic, "cr%s", name); 492 | sprintf(o->operands, "%i" COMMA "%i" COMMA "%i", crfD, crfA, crfB); 493 | o->r[0] = crfD; o->r[1] = crfA; o->r[2] = crfB; 494 | } 495 | 496 | #define MASK32(b, e) \ 497 | { \ 498 | u32 mask = ((u32)0xffffffff >> (b)) ^ (((e) >= 31) ? 0 : ((u32)0xffffffff) >> ((e) + 1)); \ 499 | o->target = ((b) > (e)) ? (~mask) : (mask); \ 500 | } 501 | 502 | #define MASK64(b, e) \ 503 | { \ 504 | u64 mask = ((u64)0xffffffffffffffff >> (b)) ^ (((e) >= 63) ? 0 : ((u64)0xffffffffffffffff) >> ((e) + 1)); \ 505 | o->target = ((b) > (e)) ? (~mask) : (mask); \ 506 | } 507 | 508 | // Rotate left word. 509 | static void rlw(char *name, int rb, int ins=0) 510 | { 511 | int mb = DIS_MB, me = DIS_ME; 512 | char * ptr = o->operands; 513 | sprintf(o->mnemonic, "rlw%s%c", name, Rc ? '.' : '\0'); 514 | ptr += sprintf(ptr, "%s" COMMA "%s" COMMA, REGA, REGS); 515 | if(rb) ptr += sprintf(ptr, "%s" COMMA, REGB); 516 | else ptr += sprintf(ptr, "%i" COMMA, DIS_RB); // sh 517 | ptr += sprintf(ptr, "%i" COMMA "%i", mb, me); 518 | 519 | // Put mask in target. 520 | MASK32(mb, me); 521 | #ifdef POWERPC_64 522 | MASK64(mb+32, me+32); 523 | #endif 524 | 525 | o->r[0] = DIS_RA; 526 | o->r[1] = DIS_RS; 527 | if(rb) o->r[2] = DIS_RB; 528 | o->iclass |= PPC_DISA_INTEGER; 529 | } 530 | 531 | // RLD mask 532 | #define RLDM_LEFT 0 // MASK(b, 63) 533 | #define RLDM_RIGHT 1 // MASK(0, e) 534 | #define RLDM_INS 2 // MASK(b, ~n) 535 | 536 | // Rotate left double-word. 537 | static void rld(char *name, int rb, int mtype) 538 | { 539 | #ifdef POWERPC_64 540 | int m = DIS_MB, n = DIS_RB; 541 | if(Instr & 0x20) m += 32; // b or e 542 | if(Instr & 0x02) n += 32; // sh 543 | 544 | char * ptr = o->operands; 545 | sprintf(o->mnemonic, "rld%s%c", name, Rc ? '.' : '\0'); 546 | ptr += sprintf(ptr, "%s" COMMA "%s" COMMA, REGA, REGS); 547 | if(rb) ptr += sprintf(ptr, "%s" COMMA, REGB); 548 | else ptr += sprintf(ptr, "%i" COMMA, n); 549 | ptr += sprintf(ptr, "%i", m); 550 | 551 | // Put mask in target. 552 | switch(mtype) 553 | { 554 | case RLDM_LEFT: MASK64(m, 63); break; 555 | case RLDM_RIGHT: MASK64(0, m); break; 556 | case RLDM_INS: MASK64(m, ~n); break; 557 | } 558 | 559 | o->r[0] = DIS_RA; 560 | o->r[1] = DIS_RS; 561 | if(rb) o->r[2] = DIS_RB; 562 | o->iclass |= PPC_DISA_64 | PPC_DISA_INTEGER; 563 | #endif 564 | } 565 | 566 | // Load/Store. 567 | static void ldst(char *name, int x/*indexed*/, int load=1, int L=0, int string=0, int fload=0) 568 | { 569 | if(x) integer(name, fload ? 'F' : 'X', DAB_D|DAB_A|DAB_B); 570 | else 571 | { 572 | int rd = DIS_RD, ra = DIS_RA; 573 | s16 imm = DIS_SIMM; 574 | strcpy (o->mnemonic, name); 575 | if(fload) sprintf (o->operands, "%s%i" COMMA "%s" LPAREN "%s" RPAREN, fregname, rd, simm(imm, 0, 1), regname[ra]); 576 | else sprintf (o->operands, "%s" COMMA "%s" LPAREN "%s" RPAREN, regname[rd], simm(imm, 0, 1), regname[ra]); 577 | o->r[0] = rd; 578 | o->r[1] = ra; 579 | o->immed = DIS_UIMM & 0x8000 ? DIS_UIMM | 0xFFFF0000 : DIS_UIMM; 580 | } 581 | 582 | o->iclass = PPC_DISA_LDST; 583 | if(L) o->iclass |= PPC_DISA_64; 584 | if(string) o->iclass |= PPC_DISA_STRING; 585 | if(fload) o->iclass |= PPC_DISA_FPU; 586 | } 587 | 588 | // Cache. 589 | static void cache(char *name, int flag=PPC_DISA_OTHER) 590 | { 591 | if (DIS_RD) { ill(); return; } 592 | else 593 | { 594 | integer(name, 'X', DAB_A|DAB_B); 595 | o->r[0] = o->r[1]; 596 | o->r[1] = o->r[2]; 597 | o->r[2] = 0; 598 | o->iclass &= ~PPC_DISA_INTEGER; 599 | o->iclass |= flag; 600 | } 601 | } 602 | 603 | static void movesr(char *name, int from, int L, int xform) 604 | { 605 | int reg = DIS_RD, sreg = DIS_RA & 0xF, regb = DIS_RB; 606 | 607 | strncpy(o->mnemonic, name, sizeof(o->mnemonic)); 608 | if(xform) 609 | { 610 | if(Instr & 0x001F0001) { ill(); return; } 611 | sprintf(o->operands, "%s" COMMA "%s", regname[reg], regname[regb]); 612 | o->r[0] = reg; 613 | o->r[1] = regb; 614 | } 615 | else 616 | { 617 | if(Instr & 0x0010F801) { ill(); return; } 618 | if(from) 619 | { 620 | sprintf(o->operands, "%s" COMMA "%i", regname[reg], sreg); 621 | o->r[0] = reg; 622 | o->r[1] = sreg; 623 | } 624 | else 625 | { 626 | sprintf(o->operands, "%i" COMMA "%s", sreg, regname[reg]); 627 | o->r[0] = sreg; 628 | o->r[1] = reg; 629 | } 630 | } 631 | 632 | if(L) o->iclass |= PPC_DISA_OEA | PPC_DISA_OPTIONAL | PPC_DISA_BRIDGE | PPC_DISA_64; 633 | else o->iclass |= PPC_DISA_OEA | PPC_DISA_BRIDGE; 634 | } 635 | 636 | static void mtcrf(void) 637 | { 638 | int rs = DIS_RS, crm = DIS_CRM; 639 | 640 | #ifdef SIMPLIFIED 641 | if(crm == 0xFF) 642 | { 643 | strncpy(o->mnemonic, "mtcr", sizeof(o->mnemonic)); 644 | sprintf(o->operands, "%s", regname[rs]); 645 | } 646 | else 647 | #endif 648 | { 649 | strncpy(o->mnemonic, "mtcrf", sizeof(o->mnemonic)); 650 | sprintf(o->operands, HEX1 "%02X" HEX2 COMMA "%s", crm, regname[rs]); 651 | } 652 | o->r[0] = rs; 653 | } 654 | 655 | static void mcrxr(void) 656 | { 657 | if (Instr & 0x007FF800) { ill(); return; } 658 | strcpy (o->mnemonic, "mcrxr"); 659 | sprintf (o->operands, "%s%i", crname, DIS_RD >> 2); 660 | o->r[0] = DIS_RD >> 2; 661 | } 662 | 663 | static char *spr_name(int n) 664 | { 665 | static char def[8]; 666 | 667 | switch(n) 668 | { 669 | // General architecture special-purpose registers. 670 | case 1: return "XER"; 671 | case 8: return "LR"; 672 | case 9: return "CTR"; 673 | case 18: return "DSISR"; 674 | case 19: return "DAR"; 675 | case 22: return "DEC"; 676 | case 25: return "SDR1"; 677 | case 26: return "SRR0"; 678 | case 27: return "SRR1"; 679 | case 272: return "SPRG0"; 680 | case 273: return "SPRG1"; 681 | case 274: return "SPRG2"; 682 | case 275: return "SPRG3"; 683 | #ifdef POWERPC_64 684 | case 280: return "ASR"; 685 | #endif 686 | case 284: return "TBL"; 687 | case 285: return "TBU"; 688 | case 287: return "PVR"; 689 | case 528: return "IBAT0U"; 690 | case 529: return "IBAT0L"; 691 | case 530: return "IBAT1U"; 692 | case 531: return "IBAT1L"; 693 | case 532: return "IBAT2U"; 694 | case 533: return "IBAT2L"; 695 | case 534: return "IBAT3U"; 696 | case 535: return "IBAT3L"; 697 | case 536: return "DBAT0U"; 698 | case 537: return "DBAT0L"; 699 | case 538: return "DBAT1U"; 700 | case 539: return "DBAT1L"; 701 | case 540: return "DBAT2U"; 702 | case 541: return "DBAT2L"; 703 | case 542: return "DBAT3U"; 704 | case 543: return "DBAT3L"; 705 | 706 | // Optional registers. 707 | #if !defined(GEKKO) && !defined(BROADWAY) 708 | case 282: return "EAR"; 709 | case 1013: return "DABR"; 710 | case 1022: return "FPECR"; 711 | case 1023: return "PIR"; 712 | #endif 713 | 714 | // Gekko-specific SPRs 715 | #ifdef GEKKO 716 | case 282: return "EAR"; 717 | case 912: return "GQR0"; 718 | case 913: return "GQR1"; 719 | case 914: return "GQR2"; 720 | case 915: return "GQR3"; 721 | case 916: return "GQR4"; 722 | case 917: return "GQR5"; 723 | case 918: return "GQR6"; 724 | case 919: return "GQR7"; 725 | case 920: return "HID2"; 726 | case 921: return "WPAR"; 727 | case 922: return "DMAU"; 728 | case 923: return "DMAL"; 729 | case 936: return "UMMCR0"; 730 | case 940: return "UMMCR1"; 731 | case 937: return "UPMC1"; 732 | case 938: return "UPMC2"; 733 | case 939: return "USIA"; 734 | case 941: return "UPMC3"; 735 | case 942: return "UPMC4"; 736 | case 943: return "USDA"; 737 | case 952: return "MMCR0"; 738 | case 953: return "PMC1"; 739 | case 954: return "PMC2"; 740 | case 955: return "SIA"; 741 | case 956: return "MMCR1"; 742 | case 957: return "PMC3"; 743 | case 958: return "PMC4"; 744 | case 959: return "SDA"; 745 | case 1008: return "HID0"; 746 | case 1009: return "HID1"; 747 | case 1010: return "IABR"; 748 | case 1013: return "DABR"; 749 | case 1017: return "L2CR"; 750 | case 1019: return "ICTC"; 751 | case 1020: return "THRM1"; 752 | case 1021: return "THRM2"; 753 | case 1022: return "THRM3"; 754 | #endif 755 | } 756 | 757 | sprintf(def, "%u", n); 758 | return def; 759 | } 760 | 761 | static char *tbr_name(int n) 762 | { 763 | static char def[8]; 764 | 765 | switch(n) 766 | { 767 | // General architecture time-base registers. 768 | case 268: return "TBL"; 769 | case 269: return "TBU"; 770 | } 771 | 772 | sprintf(def, "%u", n); 773 | return def; 774 | } 775 | 776 | static void movespr(int from) 777 | { 778 | int spr = (DIS_RB << 5) | DIS_RA, f = 1; 779 | char *fix; 780 | 781 | if( !((spr == 1) || (spr == 8) || (spr == 9)) ) o->iclass |= PPC_DISA_OEA; 782 | 783 | // Handle simplified mnemonic 784 | if (spr == 1) { fix = "xer"; o->iclass |= PPC_DISA_SIMPLIFIED; } 785 | else if (spr == 8) { fix = "lr"; o->iclass |= PPC_DISA_SIMPLIFIED; } 786 | else if (spr == 9) { fix = "ctr"; o->iclass |= PPC_DISA_SIMPLIFIED; } 787 | else { fix = "spr"; f = 0; } 788 | 789 | // Mnemonics and operands. 790 | sprintf (o->mnemonic, "m%c%s", from ? 'f' : 't', fix); 791 | if (f) 792 | { 793 | sprintf (o->operands, "%s", regname[DIS_RD]); 794 | o->r[0] = DIS_RD; 795 | } 796 | else 797 | { 798 | if (from) 799 | { 800 | sprintf (o->operands, "%s" COMMA "%s", regname[DIS_RD], spr_name(spr)); 801 | o->r[0] = DIS_RD; 802 | o->r[1] = spr; 803 | } 804 | else 805 | { 806 | sprintf (o->operands, "%s" COMMA "%s", spr_name(spr), regname[DIS_RD]); 807 | o->r[0] = spr; 808 | o->r[1] = DIS_RD; 809 | } 810 | } 811 | } 812 | 813 | static void movetbr(void) 814 | { 815 | int tbr = (DIS_RB << 5) | DIS_RA, f = 1; 816 | char *fix; 817 | 818 | // Handle simplified mnemonic 819 | if (tbr == 268) { fix = "tbl"; o->iclass |= PPC_DISA_SIMPLIFIED; } 820 | else if (tbr == 269) { fix = "tbu"; o->iclass |= PPC_DISA_SIMPLIFIED; } 821 | else { fix = "tb"; f = 0; } 822 | 823 | // Mnemonics and operands. 824 | sprintf (o->mnemonic, "mf%s", fix); 825 | if (f) 826 | { 827 | sprintf (o->operands, "%s", regname[DIS_RD]); 828 | o->r[0] = DIS_RD; 829 | } 830 | else 831 | { 832 | sprintf (o->operands, "%s" COMMA "%s", regname[DIS_RD], tbr_name(tbr)); 833 | o->r[0] = DIS_RD; 834 | o->r[1] = tbr; 835 | } 836 | } 837 | 838 | static void srawi(void) 839 | { 840 | int rs = DIS_RS, ra = DIS_RA, sh = DIS_RB; 841 | sprintf (o->mnemonic, "srawi%c", Rc ? '.' : 0); 842 | sprintf (o->operands, "%s" COMMA "%s" COMMA "%i", regname[ra], regname[rs], sh); 843 | o->r[0] = ra; 844 | o->r[1] = rs; 845 | o->r[2] = sh; 846 | o->iclass = PPC_DISA_INTEGER; 847 | } 848 | 849 | static void sradi(void) 850 | { 851 | int rs = DIS_RS, ra = DIS_RA, sh = (((Instr >> 1) & 1) << 5) | DIS_RB; 852 | sprintf (o->mnemonic, "sradi%c", Rc ? '.' : 0); 853 | sprintf (o->operands, "%s" COMMA "%s" COMMA "%i", regname[ra], regname[rs], sh); 854 | o->r[0] = ra; 855 | o->r[1] = rs; 856 | o->r[2] = sh; 857 | o->iclass = PPC_DISA_INTEGER | PPC_DISA_64; 858 | } 859 | 860 | static void lsswi(char *name) 861 | { 862 | int rd = DIS_RD, ra = DIS_RA, nb = DIS_RB; 863 | strcpy (o->mnemonic, name); 864 | sprintf (o->operands, "%s" COMMA "%s" COMMA "%i", regname[rd], regname[ra], nb); 865 | o->r[0] = rd; 866 | o->r[1] = ra; 867 | o->r[2] = nb; 868 | o->iclass = PPC_DISA_LDST | PPC_DISA_STRING; 869 | } 870 | 871 | #define FPU_DAB 1 872 | #define FPU_DB 2 873 | #define FPU_DAC 3 874 | #define FPU_DACB 4 875 | #define FPU_D 5 876 | 877 | static void fpu(char *name, u32 mask, int type, int flag=PPC_DISA_OTHER) 878 | { 879 | int d = DIS_RD, a = DIS_RA, c = DIS_RC, b = DIS_RB; 880 | 881 | if(Instr & mask) { ill(); return; } 882 | 883 | strcpy (o->mnemonic, name); 884 | 885 | switch (type) 886 | { 887 | case FPU_DAB: 888 | sprintf (o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, b); 889 | o->r[0] = d; o->r[1] = a; o->r[2] = b; 890 | break; 891 | case FPU_DB: 892 | sprintf (o->operands, "%s%i" COMMA "%s%i", fregname, d, fregname, b); 893 | o->r[0] = d; o->r[1] = b; 894 | break; 895 | case FPU_DAC: 896 | sprintf (o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, c); 897 | o->r[0] = d; o->r[1] = a; o->r[2] = c; 898 | break; 899 | case FPU_DACB: 900 | sprintf (o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, c, fregname, b); 901 | o->r[0] = d; o->r[1] = a; o->r[2] = c; o->r[3] = b; 902 | break; 903 | case FPU_D: 904 | sprintf (o->operands, "%s%i", fregname, d); 905 | o->r[0] = d; 906 | break; 907 | } 908 | 909 | o->iclass = PPC_DISA_FPU | flag; 910 | } 911 | 912 | static void fcmp(char *name) 913 | { 914 | int crfd = DIS_RD >> 2, ra = DIS_RA, rb = DIS_RB; 915 | 916 | if (Instr & 0x00600001) { ill(); return; } 917 | 918 | strcpy (o->mnemonic, name); 919 | sprintf (o->operands, "%i" COMMA "%s%i" COMMA "%s%i", crfd, fregname, ra, fregname, rb); 920 | o->r[0] = crfd; o->r[1] = ra; o->r[2] = rb; 921 | o->iclass = PPC_DISA_FPU; 922 | } 923 | 924 | static void mtfsf(void) 925 | { 926 | int fm = (Instr >> 17) & 0xFF, rb = DIS_RB; 927 | 928 | if(Instr & 0x02010000) { ill(); return; } 929 | 930 | sprintf (o->mnemonic, "mtfsf%c", Rc ? '.' : 0); 931 | sprintf (o->operands, HEX1 "%02X" HEX2 COMMA "%s%i", fm, fregname, rb); 932 | o->r[0] = fm; o->r[1] = rb; 933 | o->iclass = PPC_DISA_FPU; 934 | } 935 | 936 | static void mtfsb(char *name) 937 | { 938 | int crbd = DIS_RD; 939 | 940 | if (Instr & 0x001FF800) { ill(); return; } 941 | 942 | strcpy (o->mnemonic, name); 943 | sprintf (o->operands, "%i", crbd); 944 | o->r[0] = crbd; 945 | o->iclass = PPC_DISA_FPU; 946 | } 947 | 948 | static void mcrfs(void) 949 | { 950 | int crfD = DIS_RD >> 2, crfS = DIS_RA >> 2; 951 | 952 | if (Instr & 0x0063F801) { ill(); return; } 953 | 954 | strcpy (o->mnemonic, "mcrfs"); 955 | sprintf (o->operands, "%s%i" COMMA "%s%i", crname, crfD, crname, crfS); 956 | o->r[0] = crfD; o->r[1] = crfS; 957 | o->iclass = PPC_DISA_FPU; 958 | } 959 | 960 | static void mtfsfi(void) 961 | { 962 | int crfD = DIS_RD >> 2, imm = DIS_RB >> 1; 963 | 964 | if (Instr & 0x007F0800) { ill(); return; } 965 | 966 | sprintf (o->mnemonic, "mtfsfi%c", Rc ? '.' : 0); 967 | sprintf (o->operands, "%s%i" COMMA "%i", crname, crfD, imm); 968 | o->r[0] = crfD; o->r[1] = imm; 969 | o->iclass = PPC_DISA_FPU; 970 | } 971 | 972 | /* 973 | *********************************************************************************** 974 | * Architecture-specific extensions: 975 | * Processor model: GEKKO 976 | *********************************************************************************** 977 | */ 978 | 979 | #ifdef GEKKO 980 | 981 | static void ps_cmpx(int n) 982 | { 983 | static char *fix[] = { "u0", "o0", "u1", "o1" }; 984 | if(Instr & 0x00600001) { ill(); return; } 985 | sprintf(o->mnemonic, "ps_cmp%s", fix[n]); 986 | o->r[0] = DIS_RD>>2; o->r[1] = DIS_RA; o->r[2] = DIS_RB; 987 | sprintf(o->operands, "%s%d" COMMA "%s%d" COMMA "%s%d", crname, o->r[0], fregname, o->r[1], fregname, o->r[2]); 988 | o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC; 989 | } 990 | 991 | static char *ps_ldst_offs(unsigned long val) 992 | { 993 | static char buf[8]; 994 | 995 | if(val == 0) 996 | { 997 | return "0"; 998 | } 999 | else 1000 | { 1001 | if(val <= 128) 1002 | { 1003 | sprintf(buf, "%i", val); 1004 | return buf; 1005 | } 1006 | 1007 | if(val & 0x800) sprintf(buf, "-" HEX1 "%03X" HEX2, ((~val) & 0xfff) + 1); 1008 | else sprintf(buf, HEX1 "%03X" HEX2, val); 1009 | 1010 | return buf; 1011 | } 1012 | } 1013 | 1014 | static void ps_ldst(char *fix) 1015 | { 1016 | int s = DIS_RS, a = DIS_RA, d = (Instr & 0xfff); 1017 | sprintf(o->mnemonic, "psq_%s", fix); 1018 | sprintf( o->operands, "%s%i" COMMA "%s" LPAREN "%s" RPAREN COMMA "%i" COMMA "%i", 1019 | fregname, s, ps_ldst_offs(d), regname[a], (Instr >> 15) & 1, (Instr >> 12) & 7 ); 1020 | o->r[0] = s; o->r[1] = a; o->r[2] = DIS_RB >> 1; 1021 | o->immed = d & 0x800 ? d | 0xFFFFF000 : d; 1022 | o->iclass = PPC_DISA_FPU | PPC_DISA_LDST | PPC_DISA_SPECIFIC; 1023 | } 1024 | 1025 | static void ps_ldstx(char *fix) 1026 | { 1027 | int d = DIS_RD, a = DIS_RA, b = DIS_RB; 1028 | if(Instr & 1) { ill(); return; } 1029 | sprintf(o->mnemonic, "psq_%s", fix); 1030 | sprintf(o->operands, "%s%i" COMMA "%s" COMMA "%s" COMMA "%i" COMMA "%i", fregname, d, regname[a], regname[b], (Instr >> 10) & 1, (Instr >> 7) & 7); 1031 | o->r[0] = d; o->r[1] = a; o->r[2] = b; o->r[3] = DIS_RC >> 1; 1032 | o->iclass = PPC_DISA_FPU | PPC_DISA_LDST | PPC_DISA_SPECIFIC; 1033 | } 1034 | 1035 | static void ps_dacb(char *fix) 1036 | { 1037 | int a = DIS_RA, b = DIS_RB, c = DIS_RC, d = DIS_RD; 1038 | sprintf(o->mnemonic, "ps_%s%c", fix, Rc ? '.' : 0); 1039 | sprintf(o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, c, fregname, b); 1040 | o->r[0] = d; o->r[1] = a; o->r[2] = c; o->r[3] = b; 1041 | o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC; 1042 | } 1043 | 1044 | static void ps_dac(char *fix) 1045 | { 1046 | int a = DIS_RA, c = DIS_RC, d = DIS_RD; 1047 | if(Instr & 0x0000F800) { ill(); return; } 1048 | sprintf(o->mnemonic, "ps_%s%c", fix, Rc ? '.' : 0); 1049 | sprintf(o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, c); 1050 | o->r[0] = d; o->r[1] = a; o->r[2] = c; 1051 | o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC; 1052 | } 1053 | 1054 | static void ps_dab(char *fix, int unmask=0) 1055 | { 1056 | int d = DIS_RD, a = DIS_RA, b = DIS_RB; 1057 | if(Instr & 0x000007C0 && !unmask) { ill(); return; } 1058 | sprintf(o->mnemonic, "ps_%s%c", fix, Rc ? '.' : 0); 1059 | sprintf(o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, b); 1060 | o->r[0] = d; o->r[1] = a; o->r[2] = b; 1061 | o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC; 1062 | } 1063 | 1064 | static void ps_db(char *fix, int aonly=0) 1065 | { 1066 | int d = DIS_RD, b = DIS_RB; 1067 | if(aonly) { if(Instr & 0x001F0000) { ill(); return; } } 1068 | else { if(Instr & 0x001F07C0) { ill(); return; } } 1069 | sprintf(o->mnemonic, "ps_%s%c", fix, Rc ? '.' : 0); 1070 | sprintf(o->operands, "%s%i" COMMA "%s%i", fregname, d, fregname, b); 1071 | o->r[0] = d; o->r[1] = b; 1072 | o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC; 1073 | } 1074 | 1075 | #endif /* END OF GEKKO */ 1076 | 1077 | // --------------------------------------------------------------------------- 1078 | 1079 | void PPCDisasm(PPCD_CB *discb) 1080 | { 1081 | // Save parameters in local variables for static calls 1082 | o = discb; 1083 | if(o == NULL) return; 1084 | 1085 | // Detect endianness order. 1086 | if(bigendian == -1) 1087 | { 1088 | u8 test_value[2] = { 0xAA, 0xBB }; 1089 | u16 *value = (u16 *)test_value; 1090 | if(*value == 0xAABB) bigendian = 1; 1091 | else bigendian = 0; 1092 | } 1093 | 1094 | // Reset output parameters 1095 | o->iclass = PPC_DISA_OTHER; 1096 | o->r[0] = o->r[1] = o->r[2] = o->r[3] = 0; 1097 | o->immed = 0; 1098 | o->target = 0; 1099 | o->mnemonic[0] = o->operands[0] = '\0'; 1100 | 1101 | // Lets go! 1102 | 1103 | /* 1104 | * Main table 1105 | */ 1106 | 1107 | switch(Instr >> 26 /* Main opcode, base 8 */) { 1108 | #ifdef POWERPC_64 1109 | case 002: trap(1, 1); break; // tdi 1110 | #endif 1111 | case 003: trap(0, 1); break; // twi 1112 | case 007: integer("mulli", 'D', DAB_D|DAB_A); break; // mulli 1113 | case 010: integer("subfic", 'D', DAB_D|DAB_A); break; // subfic 1114 | case 012: cmp("l", "i"); break; // cmpli 1115 | case 013: cmp("", "i"); break; // cmpi 1116 | case 014: addi("c"); break; // addic 1117 | case 015: addi("c."); break; // addic. 1118 | case 016: addi(""); break; // addi 1119 | case 017: addi("s"); break; // addis 1120 | case 020: bcx(1, 0); break; // bcx 1121 | case 021: put("sc", 0x03ffffff, 2); break; // sc 1122 | case 022: bx(); break; // bx 1123 | case 024: rlw("imi", 0, 1); break; // rlwimix 1124 | case 025: rlw("inm", 0); break; // rlwinmx 1125 | case 027: rlw("nm", 1); break; // rlwnmx 1126 | case 030: // ori 1127 | #ifdef SIMPLIFIED 1128 | if(Instr == 0x60000000) put("nop", 0, 0, PPC_DISA_INTEGER | PPC_DISA_SIMPLIFIED); 1129 | else 1130 | #endif 1131 | integer("ori", 'S', ASB_A|ASB_S, 1, 0); break; 1132 | case 031: integer("oris", 'S', ASB_A|ASB_S, 1, 0); break; // oris 1133 | case 032: integer("xori", 'S', ASB_A|ASB_S, 1, 0); break; // xori 1134 | case 033: integer("xoris", 'S', ASB_A|ASB_S, 1, 0); break; // xoris 1135 | case 034: integer("andi.", 'S', ASB_A|ASB_S, 1, 0); break; // andi. 1136 | case 035: integer("andis.", 'S', ASB_A|ASB_S, 1, 0); break; // andis. 1137 | case 040: ldst("lwz", 0, 1); break; // lwz 1138 | case 041: ldst("lwzu", 0, 1); break; // lwzu 1139 | case 042: ldst("lbz", 0, 1); break; // lbz 1140 | case 043: ldst("lbzu", 0, 1); break; // lbzu 1141 | case 044: ldst("stw", 0, 0); break; // stw 1142 | case 045: ldst("stwu", 0, 0); break; // stwu 1143 | case 046: ldst("stb", 0, 0); break; // stb 1144 | case 047: ldst("stbu", 0, 0); break; // stbu 1145 | case 050: ldst("lhz", 0, 1); break; // lhz 1146 | case 051: ldst("lhzu", 0, 1); break; // lhzu 1147 | case 052: ldst("lha", 0, 1); break; // lha 1148 | case 053: ldst("lhau", 0, 1); break; // lhau 1149 | case 054: ldst("sth", 0, 0); break; // sth 1150 | case 055: ldst("sthu", 0, 0); break; // sthu 1151 | case 056: ldst("lmw", 0, 1, 0, 1); break; // lmw 1152 | case 057: ldst("stmw", 0, 0, 0, 1); break; // stmw 1153 | case 060: ldst("lfs", 0, 1, 0, 0, 1); break; // lfs 1154 | case 061: ldst("lfsu", 0, 1, 0, 0, 1); break; // lfsu 1155 | case 062: ldst("lfd", 0, 1, 0, 0, 1); break; // lfd 1156 | case 063: ldst("lfdu", 0, 1, 0, 0, 1); break; // lfdu 1157 | case 064: ldst("stfs", 0, 0, 0, 0, 1); break; // stfs 1158 | case 065: ldst("stfsu", 0, 0, 0, 0, 1); break; // stfsu 1159 | case 066: ldst("stfd", 0, 0, 0, 0, 1); break; // stfd 1160 | case 067: ldst("stfdu", 0, 0, 0, 0, 1); break; // stfdu 1161 | 1162 | /* 1163 | * Extention 1. 1164 | */ 1165 | 1166 | case 023: 1167 | switch((Instr >> 1) & 0x3ff /* Extended opcode 023, base 8 */) { 1168 | case 00020: bcx(0, 1); break; // bclrx 1169 | case 01020: bcx(0, 0); break; // bcctrx 1170 | case 00000: mcrf(); break; // mcrf 1171 | case 00401: crop("and"); break; // crand 1172 | case 00201: crop("andc"); break; // crandc 1173 | case 00441: crop("eqv", "set", 1); break; // creqv 1174 | case 00341: crop("nand"); break; // crnand 1175 | case 00041: crop("nor", "not", 0, 1); break; // crnor 1176 | case 00701: crop("or", "move", 0, 1); break; // cror 1177 | case 00641: crop("orc"); break; // crorc 1178 | case 00301: crop("xor", "clr", 1); break; // crxor 1179 | case 00226: put("isync", 0x3fff801); break; // isync 1180 | #ifdef POWERPC_32 1181 | case 00062: put("rfi", 0x3fff801, 0, PPC_DISA_OEA | PPC_DISA_BRIDGE ); break; // rfi 1182 | #endif 1183 | #ifdef POWERPC_64 1184 | case 00022: put("rfid", 0x3fff801, 0, PPC_DISA_OEA | PPC_DISA_64 ); break; // rfid 1185 | #endif 1186 | default: ill(); break; 1187 | } break; 1188 | 1189 | #ifdef POWERPC_64 1190 | case 036: 1191 | switch((Instr >> 1) & 0xf /* Rotate left double */) { 1192 | case 0x0: rld("icl", 0, RLDM_LEFT); break; // rldiclx 1193 | case 0x1: rld("icl", 0, RLDM_LEFT); break; 1194 | case 0x2: rld("icr", 0, RLDM_RIGHT); break; // rldicrx 1195 | case 0x3: rld("icr", 0, RLDM_RIGHT); break; 1196 | case 0x4: rld("ic", 0, RLDM_INS); break; // rldicx 1197 | case 0x5: rld("ic", 0, RLDM_INS); break; 1198 | case 0x6: rld("imi", 0, RLDM_INS); break; // rldimix 1199 | case 0x7: rld("imi", 0, RLDM_INS); break; 1200 | case 0x8: rld("cl", 1, RLDM_LEFT); break; // rldclx 1201 | case 0x9: rld("cr", 1, RLDM_RIGHT); break; // rldcrx 1202 | default: ill(); break; 1203 | } break; 1204 | #endif 1205 | 1206 | /* 1207 | * Extention 2. 1208 | */ 1209 | 1210 | #define OE 02000 1211 | case 037: 1212 | switch(Instr & 0x7ff /* Extended opcode 037, base 8 */) { 1213 | case 00000: cmp("", ""); break; // cmp 1214 | case 00010: // tw 1215 | #ifdef SIMPLIFIED 1216 | if(Instr == 0x7FE00008) put("trap", 0, 0, PPC_DISA_SIMPLIFIED); 1217 | else 1218 | #endif 1219 | trap(0, 0); break; 1220 | case 00020: integer("subfc", 'X', DAB_D|DAB_A|DAB_B); break; // subfcx 1221 | case 00020|OE: integer("subfco", 'X', DAB_D|DAB_A|DAB_B); break; 1222 | case 00021: integer("subfc.", 'X', DAB_D|DAB_A|DAB_B); break; 1223 | case 00021|OE: integer("subfco.", 'X', DAB_D|DAB_A|DAB_B); break; 1224 | case 00024: integer("addc", 'X', DAB_D|DAB_A|DAB_B); break; // addcx 1225 | case 00024|OE: integer("addco", 'X', DAB_D|DAB_A|DAB_B); break; 1226 | case 00025: integer("addc.", 'X', DAB_D|DAB_A|DAB_B); break; 1227 | case 00025|OE: integer("addco.", 'X', DAB_D|DAB_A|DAB_B); break; 1228 | case 00026: integer("mulhwu", 'X', DAB_D|DAB_A|DAB_B); break; // mulhwu 1229 | case 00027: integer("mulhwu.", 'X', DAB_D|DAB_A|DAB_B); break; 1230 | case 00046: if(DIS_RA | DIS_RB) ill(); // mfcr 1231 | else { integer("mfcr", 'D', DAB_D, 0,0,0,0,0); o->iclass = PPC_DISA_OTHER; } break; 1232 | case 00050: ldst("lwarx", 1); break; // lwarx 1233 | case 00056: ldst("lwzx", 1); break; // lwzx 1234 | case 00060: integer("slw", 'Z', ASB_A|ASB_S|ASB_B); break; // slwx 1235 | case 00061: integer("slw.", 'Z', ASB_A|ASB_S|ASB_B); break; 1236 | case 00064: if(DIS_RB) ill(); // cntlzwx 1237 | else integer("cntlzw", 'S', ASB_A|ASB_S, 0,0,0,0,0); break; 1238 | case 00065: if(DIS_RB) ill(); 1239 | else integer("cntlzw.", 'S', ASB_A|ASB_S, 0,0,0,0,0); break; 1240 | case 00070: integer("and", 'Z', ASB_A|ASB_S|ASB_B); break; // andx 1241 | case 00071: integer("and.", 'Z', ASB_A|ASB_S|ASB_B); break; 1242 | case 00100: cmp("l", ""); break; // cmpl 1243 | case 00120: integer("subf", 'X', DAB_D|DAB_A|DAB_B); break; // subfx 1244 | case 00120|OE: integer("subfo", 'X', DAB_D|DAB_A|DAB_B); break; 1245 | case 00121: integer("subf.", 'X', DAB_D|DAB_A|DAB_B); break; 1246 | case 00121|OE: integer("subfo.", 'X', DAB_D|DAB_A|DAB_B); break; 1247 | case 00154: cache("dcbst"); break; // dcbst 1248 | case 00156: ldst("lwzux", 1); break; // lwzux 1249 | case 00170: integer("andc", 'Z', ASB_A|ASB_S|ASB_B); break; // andcx 1250 | case 00171: integer("andc.", 'Z', ASB_A|ASB_S|ASB_B); break; 1251 | case 00226: integer("mulhw", 'X', DAB_D|DAB_A|DAB_B); break; // mulhw 1252 | case 00227: integer("mulhw.", 'X', DAB_D|DAB_A|DAB_B); break; 1253 | case 00246: if(DIS_RA || DIS_RB) ill(); // mfmsr 1254 | else { integer("mfmsr", 'X', DAB_D); o->iclass = PPC_DISA_OEA; } break; 1255 | case 00254: cache("dcbf"); break; // dcbf 1256 | case 00256: ldst("lbzx", 1, 1, 0); break; // lbzx 1257 | case 00320: if(DIS_RB) ill(); // negx 1258 | else integer("neg", 'X', DAB_D|DAB_A); break; 1259 | case 00321: if(DIS_RB) ill(); 1260 | else integer("neg.", 'X', DAB_D|DAB_A); break; 1261 | case 00320|OE: if(DIS_RB) ill(); 1262 | else integer("nego", 'X', DAB_D|DAB_A); break; 1263 | case 00321|OE: if(DIS_RB) ill(); 1264 | else integer("nego.", 'X', DAB_D|DAB_A); break; 1265 | case 00356: ldst("lbzux", 1, 1); break; // lbzux 1266 | case 00370: // norx 1267 | #ifdef SIMPLIFIED 1268 | if(DIS_RS == DIS_RB) { integer("not", 'Z', ASB_A|ASB_S); o->iclass |= PPC_DISA_SIMPLIFIED; } 1269 | else 1270 | #endif 1271 | integer("nor", 'Z', ASB_A|ASB_S|ASB_B); break; 1272 | case 00371: integer("nor.", 'Z', ASB_A|ASB_S|ASB_B); break; 1273 | case 00420: integer("subfe", 'X', DAB_D|DAB_A|DAB_B); break; // subfex 1274 | case 00420|OE: integer("subfeo", 'X', DAB_D|DAB_A|DAB_B); break; 1275 | case 00421: integer("subfe.", 'X', DAB_D|DAB_A|DAB_B); break; 1276 | case 00421|OE: integer("subfeo.", 'X', DAB_D|DAB_A|DAB_B); break; 1277 | case 00424: integer("adde", 'X', DAB_D|DAB_A|DAB_B); break; // addex 1278 | case 00424|OE: integer("addeo", 'X', DAB_D|DAB_A|DAB_B); break; 1279 | case 00425: integer("adde.", 'X', DAB_D|DAB_A|DAB_B); break; 1280 | case 00425|OE: integer("addeo.", 'X', DAB_D|DAB_A|DAB_B); break; 1281 | case 00440: mtcrf(); break; // mtcrf 1282 | #ifdef POWERPC_32 1283 | case 00444: if(DIS_RA || DIS_RB) ill(); // mtmsr 1284 | else { integer("mtmsr", 'X', DAB_D); o->iclass = PPC_DISA_OEA | PPC_DISA_BRIDGE; } break; 1285 | #endif 1286 | case 00455: ldst("stwcx.", 1, 0, 0); break; // stwcx. 1287 | case 00456: ldst("stwx", 1, 0, 0); break; // stwx 1288 | case 00556: ldst("stwux", 1, 0, 0); break; // stwux 1289 | case 00620: if(DIS_RB) ill(); // subfzex 1290 | else integer("subfze", 'X', DAB_D|DAB_A); break; 1291 | case 00620|OE: if(DIS_RB) ill(); 1292 | else integer("subfzeo", 'X', DAB_D|DAB_A); break; 1293 | case 00621: if(DIS_RB) ill(); 1294 | else integer("subfze.", 'X', DAB_D|DAB_A); break; 1295 | case 00621|OE: if(DIS_RB) ill(); 1296 | else integer("subfzeo.", 'X', DAB_D|DAB_A); break; 1297 | case 00624: if(DIS_RB) ill(); // addzex 1298 | else integer("addze", 'X', DAB_D|DAB_A); break; 1299 | case 00624|OE: if(DIS_RB) ill(); 1300 | else integer("addzeo", 'X', DAB_D|DAB_A); break; 1301 | case 00625: if(DIS_RB) ill(); 1302 | else integer("addze.", 'X', DAB_D|DAB_A); break; 1303 | case 00625|OE: if(DIS_RB) ill(); 1304 | else integer("addzeo.", 'X', DAB_D|DAB_A); break; 1305 | #ifdef POWERPC_32 1306 | case 00644: movesr("mtsr", 0, 0, 0); break; // mtsr 1307 | #endif 1308 | case 00656: ldst("stbx", 1, 0, 0); break; // stbx 1309 | case 00720: if(DIS_RB) ill(); // subfmex 1310 | else integer("subfme", 'X', DAB_D|DAB_A); break; 1311 | case 00720|OE: if(DIS_RB) ill(); 1312 | else integer("subfmeo", 'X', DAB_D|DAB_A); break; 1313 | case 00721: if(DIS_RB) ill(); 1314 | else integer("subfme.", 'X', DAB_D|DAB_A); break; 1315 | case 00721|OE: if(DIS_RB) ill(); 1316 | else integer("subfmeo.", 'X', DAB_D|DAB_A); break; 1317 | case 00724: if(DIS_RB) ill(); // addmex 1318 | else integer("addme", 'X', DAB_D|DAB_A); break; 1319 | case 00724|OE: if(DIS_RB) ill(); 1320 | else integer("addmeo", 'X', DAB_D|DAB_A); break; 1321 | case 00725: if(DIS_RB) ill(); 1322 | else integer("addme.", 'X', DAB_D|DAB_A); break; 1323 | case 00725|OE: if(DIS_RB) ill(); 1324 | else integer("addmeo.", 'X', DAB_D|DAB_A); break; 1325 | case 00726: integer("mullw", 'X', DAB_D|DAB_A|DAB_B); break; // mullwx 1326 | case 00726|OE: integer("mullwo", 'X', DAB_D|DAB_A|DAB_B); break; 1327 | case 00727: integer("mullw.", 'X', DAB_D|DAB_A|DAB_B); break; 1328 | case 00727|OE: integer("mullwo.", 'X', DAB_D|DAB_A|DAB_B); break; 1329 | #ifdef POWERPC_32 1330 | case 00744: movesr("mtsrin", 0, 0, 1); break; // mtsrin 1331 | #endif 1332 | case 00754: cache("dcbtst"); break; // dcbtst 1333 | case 00756: ldst("stbux", 1, 0, 0); break; // stbux 1334 | case 01024: integer("add", 'X', DAB_D|DAB_A|DAB_B); break; // addx 1335 | case 01024|OE: integer("addo", 'X', DAB_D|DAB_A|DAB_B); break; 1336 | case 01025: integer("add.", 'X', DAB_D|DAB_A|DAB_B); break; 1337 | case 01025|OE: integer("addo.", 'X', DAB_D|DAB_A|DAB_B); break; 1338 | case 01054: cache("dcbt"); break; // dcbt 1339 | case 01056: ldst("lhzx", 1); break; // lhzx 1340 | case 01070: integer("eqv", 'Z', ASB_A|ASB_S|ASB_B); break; // eqvx 1341 | case 01071: integer("eqv.", 'Z', ASB_A|ASB_S|ASB_B); break; 1342 | case 01144: if(DIS_RD || DIS_RA) ill(); // tlbie 1343 | else { integer("tlbie", 'X', DAB_B); o->iclass = PPC_DISA_OEA | PPC_DISA_OPTIONAL; o->r[0] = o->r[2]; o->r[2] = 0; } break; 1344 | case 01154: integer("eciwx", 'X', DAB_D|DAB_A|DAB_B); o->iclass = PPC_DISA_OPTIONAL; break; // eciwx 1345 | case 01156: ldst("lhzux", 1); break; // lhzux 1346 | case 01170: integer("xor", 'Z', ASB_A|ASB_S|ASB_B); break; // xorx 1347 | case 01171: integer("xor.", 'Z', ASB_A|ASB_S|ASB_B); break; 1348 | case 01246: movespr(1); break; // mfspr 1349 | case 01256: ldst("lhax", 1); break; // lhax 1350 | #if !defined(GEKKO) 1351 | case 01344: put("tlbia", 0x03FFF800, 0, PPC_DISA_OEA | PPC_DISA_OPTIONAL); break; // tlbia 1352 | #endif 1353 | case 01346: movetbr(); break; // mftb 1354 | case 01356: ldst("lhaux", 1); break; // lhaux 1355 | case 01456: ldst("sthx", 1, 0); break; // sthx 1356 | case 01470: integer("orc", 'Z', ASB_A|ASB_S|ASB_B); break; // orcx 1357 | case 01471: integer("orc.", 'Z', ASB_A|ASB_S|ASB_B); break; 1358 | case 01554: integer("ecowx", 'X', DAB_D|DAB_A|DAB_B); o->iclass = PPC_DISA_OPTIONAL; break; // ecowx 1359 | case 01556: ldst("sthux", 1, 0); break; // sthux 1360 | case 01570: integer("or", 'Z', ASB_A|ASB_S|ASB_B); break; // orx 1361 | case 01571: integer("or.", 'Z', ASB_A|ASB_S|ASB_B); break; 1362 | case 01626: integer("divwu", 'X', DAB_D|DAB_A|DAB_B); break; // divwux 1363 | case 01626|OE: integer("divwuo", 'X', DAB_D|DAB_A|DAB_B); break; 1364 | case 01627: integer("divwu.", 'X', DAB_D|DAB_A|DAB_B); break; 1365 | case 01627|OE: integer("divwuo.", 'X', DAB_D|DAB_A|DAB_B); break; 1366 | case 01646: movespr(0); break; // mtspr 1367 | case 01654: cache("dcbi", PPC_DISA_OEA); break; // dcbi 1368 | case 01670: integer("nand", 'Z', ASB_A|ASB_S|ASB_B); break; // nandx 1369 | case 01671: integer("nand.", 'Z', ASB_A|ASB_S|ASB_B); break; 1370 | case 01726: integer("divw", 'X', DAB_D|DAB_A|DAB_B); break; // divwx 1371 | case 01726|OE: integer("divwo", 'X', DAB_D|DAB_A|DAB_B); break; 1372 | case 01727: integer("divw.", 'X', DAB_D|DAB_A|DAB_B); break; 1373 | case 01727|OE: integer("divwo.", 'X', DAB_D|DAB_A|DAB_B); break; 1374 | case 02000: mcrxr(); break; // mcrxr 1375 | case 02052: ldst("lswx", 1, 1, 0, 1); break; // lswx 1376 | case 02054: ldst("lwbrx", 1); break; // lwbrx 1377 | case 02056: ldst("lfsx", 1, 1, 0, 0, 1); break; // lfsx 1378 | case 02060: integer("srw", 'Z', ASB_A|ASB_S|ASB_B); break; // srwx 1379 | case 02061: integer("srw.", 'Z', ASB_A|ASB_S|ASB_B); break; 1380 | case 02154: put("tlbsync", 0x03FFF800, 0, PPC_DISA_OEA | PPC_DISA_OPTIONAL); break; // tlbsync 1381 | case 02156: ldst("lfsux", 1, 1, 0, 0, 1); break; // lfsux 1382 | #ifdef POWERPC_32 1383 | case 02246: movesr("mfsr", 1, 0, 0); break; // mfsr 1384 | #endif 1385 | case 02252: lsswi("lswi"); break; // lswi 1386 | case 02254: put("sync", 0x03FFF800, 0); break; // sync 1387 | case 02256: ldst("lfdx", 1, 1, 0, 0, 1); break; // lfdx 1388 | case 02356: ldst("lfdux", 1, 1, 0, 0, 1); break; // lfdux 1389 | #ifdef POWERPC_32 1390 | case 02446: movesr("mfsrin", 1, 0, 1); break; // mfsrin 1391 | #endif 1392 | case 02452: ldst("stswx", 1, 1, 0, 1); break; // stswx 1393 | case 02454: ldst("stwbrx", 1, 0); break; // stwbrx 1394 | case 02456: ldst("stfsx", 1, 1, 0, 0, 1); break; // stfsx 1395 | case 02556: ldst("stfsux", 1, 1, 0, 0, 1); break; // stfsux 1396 | case 02652: lsswi("stswi"); break; // stswi 1397 | case 02656: ldst("stfdx", 1, 1, 0, 0, 1); break; // stfdx 1398 | #if !defined(GEKKO) 1399 | case 02754: cache("dcba", PPC_DISA_OPTIONAL); break; // dcba 1400 | #endif 1401 | case 02756: ldst("stfdux", 1, 1, 0, 0, 1); break; // stfdux 1402 | case 03054: ldst("lhbrx", 1); break; // lhbrx 1403 | case 03060: integer("sraw", 'Z', ASB_A|ASB_S|ASB_B); break; // srawx 1404 | case 03061: integer("sraw.", 'Z', ASB_A|ASB_S|ASB_B); break; 1405 | case 03160: srawi(); break; // srawi 1406 | case 03161: srawi(); break; 1407 | case 03254: put("eieio", 0x03FFF800, 0); break; // eieio 1408 | case 03454: ldst("sthbrx", 1, 0); break; // sthbrx 1409 | case 03464: if(DIS_RB) ill(); // extshx 1410 | else integer("extsh", 'S', ASB_A|ASB_S, 0,0,0,0,0); break; 1411 | case 03465: if(DIS_RB) ill(); 1412 | else integer("extsh.", 'S', ASB_A|ASB_S, 0,0,0,0,0); break; 1413 | case 03564: if(DIS_RB) ill(); // extsbx 1414 | else integer("extsb", 'S', ASB_A|ASB_S, 0,0,0,0,0); break; 1415 | case 03565: if(DIS_RB) ill(); 1416 | else integer("extsb.", 'S', ASB_A|ASB_S, 0,0,0,0,0); break; 1417 | case 03654: cache("icbi"); break; // icbi 1418 | case 03656: ldst("stfiwx", 1, 1, 0, 0, 1); o->iclass |= PPC_DISA_OPTIONAL; break; // stfiwx 1419 | case 03754: cache("dcbz"); break; // dcbz 1420 | #ifdef POWERPC_64 1421 | case 00022: integer("mulhdu", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // mulhdux 1422 | case 00023: integer("mulhdu.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; 1423 | case 00052: ldst("ldx", 1, 1, 1); break; // ldx 1424 | case 00066: integer("sld", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break; // sldx 1425 | case 00067: integer("sld.", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break; 1426 | case 00152: ldst("ldux", 1, 1, 1); break; // ldux 1427 | case 00164: if(DIS_RB) ill(); // cntlzdx 1428 | else integer("cntlzd", 'S', ASB_A|ASB_S, 0,0,0,0,0); o->iclass |= PPC_DISA_64; break; 1429 | case 00165: if(DIS_RB) ill(); 1430 | else integer("cntlzd.", 'S', ASB_A|ASB_S, 0,0,0,0,0); o->iclass |= PPC_DISA_64; break; 1431 | case 00210: trap(1, 0); break; 1432 | case 00222: integer("mulhd", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // mulhdx 1433 | case 00223: integer("mulhd.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; 1434 | case 00244: movesr("mtsrd", 0, 1, 0); break; // mtrsd 1435 | case 00250: ldst("ldarx", 1, 1, 1); break; // ldarx 1436 | case 00344: movesr("mtsrdin", 0, 1, 1); break; // mtrsdin 1437 | case 00452: ldst("stdx", 1, 0, 1); break; // stdx 1438 | case 00544: if(DIS_RA || DIS_RB) ill(); // mtmsrd 1439 | else { integer("mtmsrd", 'X', DAB_D); o->iclass = PPC_DISA_OEA | PPC_DISA_64; } break; 1440 | case 00552: ldst("stdux", 1, 0, 1); break; // stdux 1441 | case 00655: ldst("stdcx.", 1, 0, 1); break; // stdcx. 1442 | case 00722: integer("mulld", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // mulldx 1443 | case 00722|OE: integer("mulldo", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; 1444 | case 00723: integer("mulld.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; 1445 | case 00723|OE: integer("mulldo.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; 1446 | case 01252: ldst("lwax", 1, 1, 1); break; // lwax 1447 | case 01352: ldst("lwaux", 1, 1, 1); break; // lwaux 1448 | case 03164: sradi(); break; // sradi 1449 | case 03165: sradi(); break; 1450 | case 03166: sradi(); break; 1451 | case 03167: sradi(); break; 1452 | case 01544: if(DIS_RD || DIS_RA) ill(); // slbie 1453 | else { integer("slbie", 'X', DAB_B); o->iclass = PPC_DISA_64 | PPC_DISA_OEA | PPC_DISA_OPTIONAL; o->r[0] = o->r[2]; o->r[2] = 0; } break; 1454 | case 01622: integer("divdu", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // divdux 1455 | case 01622|OE: integer("divduo", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; 1456 | case 01623: integer("divdu.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; 1457 | case 01623|OE: integer("divduo.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; 1458 | case 01722: integer("divd", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // divdx 1459 | case 01722|OE: integer("divdo", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; 1460 | case 01723: integer("divd.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; 1461 | case 01723|OE: integer("divdo.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; 1462 | case 01744: put("slbia", 0x03FFF800, 0, PPC_DISA_64 | PPC_DISA_OEA | PPC_DISA_OPTIONAL); break; // slbia 1463 | case 02066: integer("srd", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break; // srdx 1464 | case 02067: integer("srd.", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break; 1465 | case 03064: integer("srad", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break; // sradx 1466 | case 03065: integer("srad.", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break; 1467 | case 03664: if(DIS_RB) ill(); // extswx 1468 | else { integer("extsw", 'S', ASB_A|ASB_S, 0,0,0,0,0); o->iclass |= PPC_DISA_64; } break; 1469 | case 03665: if(DIS_RB) ill(); 1470 | else { integer("extsw.", 'S', ASB_A|ASB_S, 0,0,0,0,0); o->iclass |= PPC_DISA_64; } break; 1471 | #endif 1472 | default: ill(); break; 1473 | } break; 1474 | 1475 | /* 1476 | * Extention 3. 1477 | */ 1478 | 1479 | #ifdef POWERPC_64 1480 | case 072: 1481 | switch(Instr & 3) { 1482 | case 0: Instr &= ~3; ldst("ld", 0, 1, 1); break; // ld 1483 | case 1: Instr &= ~3; ldst("ldu", 0, 1, 1); break; // ldu 1484 | case 2: Instr &= ~3; ldst("lwa", 0, 1, 1); break; // lwa 1485 | default: ill(); break; 1486 | } break; 1487 | #endif 1488 | 1489 | /* 1490 | * Extention 4. 1491 | */ 1492 | 1493 | #define MASK_D (0x1F << 21) 1494 | #define MASK_A (0x1F << 16) 1495 | #define MASK_B (0x1F << 11) 1496 | #define MASK_C (0x1F << 6) 1497 | case 073: 1498 | switch(Instr & 0x3F) { 1499 | case 044: fpu("fdivs", MASK_C, FPU_DAB); break; // fdivsx 1500 | case 045: fpu("fdivs.", MASK_C, FPU_DAB); break; 1501 | case 050: fpu("fsubs", MASK_C, FPU_DAB); break; // fsubsx 1502 | case 051: fpu("fsubs.", MASK_C, FPU_DAB); break; 1503 | case 052: fpu("fadds", MASK_C, FPU_DAB); break; // faddsx 1504 | case 053: fpu("fadds.", MASK_C, FPU_DAB); break; 1505 | #if !defined(GEKKO) 1506 | case 054: fpu("fsqrts", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; // fsqrtsx 1507 | case 055: fpu("fsqrts.", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; 1508 | #endif 1509 | case 060: fpu("fres", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; // fresx 1510 | case 061: fpu("fres.", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; 1511 | case 062: fpu("fmuls", MASK_B, FPU_DAC); break; // fmulsx 1512 | case 063: fpu("fmuls.", MASK_B, FPU_DAC); break; 1513 | case 070: fpu("fmsubs", 0, FPU_DACB); break; // fmsubsx 1514 | case 071: fpu("fmsubs.", 0, FPU_DACB); break; 1515 | case 072: fpu("fmadds", 0, FPU_DACB); break; // fmaddsx 1516 | case 073: fpu("fmadds.", 0, FPU_DACB); break; 1517 | case 074: fpu("fnmsubs", 0, FPU_DACB); break; // fnmsubsx 1518 | case 075: fpu("fnmsubs.", 0, FPU_DACB); break; 1519 | case 076: fpu("fnmadds", 0, FPU_DACB); break; // fnmaddsx 1520 | case 077: fpu("fnmadds.", 0, FPU_DACB); break; 1521 | default: ill(); break; 1522 | } break; 1523 | 1524 | /* 1525 | * Extention 5. 1526 | */ 1527 | 1528 | #ifdef POWERPC_64 1529 | case 076: 1530 | switch(Instr & 3) { 1531 | case 0: Instr &= ~3; ldst("std", 0, 0, 1); break; // std 1532 | case 1: Instr &= ~3; ldst("stdu", 0, 0, 1); break; // stdu 1533 | default: ill(); break; 1534 | } break; 1535 | #endif 1536 | 1537 | /* 1538 | * Extention 6. 1539 | */ 1540 | 1541 | case 077: 1542 | switch(Instr & 0x3F) { 1543 | case 000: 1544 | switch(DIS_RC) 1545 | { 1546 | case 0: fcmp("fcmpu"); break; // fcmpu 1547 | case 1: fcmp("fcmpo"); break; // fcmpo 1548 | case 2: mcrfs(); break; // mcrfs 1549 | default: ill(); break; 1550 | } 1551 | break; 1552 | case 014: 1553 | switch(DIS_RC) 1554 | { 1555 | case 1: mtfsb("mtfsb1"); break; // mtfsb1 1556 | case 2: mtfsb("mtfsb0"); break; // mtfsb0 1557 | case 4: mtfsfi(); break; // mtfsfi 1558 | default: ill(); break; 1559 | } 1560 | break; 1561 | case 015: 1562 | switch(DIS_RC) 1563 | { 1564 | case 1: mtfsb("mtfsb1."); break; // mtfsb1. 1565 | case 2: mtfsb("mtfsb0."); break; // mtfsb0. 1566 | case 4: mtfsfi(); break; // mtfsfi. 1567 | default: ill(); break; 1568 | } 1569 | break; 1570 | case 016: 1571 | switch(DIS_RC) 1572 | { 1573 | case 18: fpu("mffs", MASK_A|MASK_B, FPU_D); break; // mffs 1574 | case 22: mtfsf(); break; // mtfsf 1575 | default: ill(); break; 1576 | } 1577 | break; 1578 | case 017: 1579 | switch(DIS_RC) 1580 | { 1581 | case 18: fpu("mffs.", MASK_A|MASK_B, FPU_D); break; // mffs. 1582 | case 22: mtfsf(); break; // mtfsf. 1583 | default: ill(); break; 1584 | } 1585 | break; 1586 | case 020: 1587 | switch(DIS_RC) 1588 | { 1589 | case 1: fpu("fneg", MASK_A, FPU_DB); break; // fneg 1590 | case 2: fpu("fmr", MASK_A, FPU_DB); break; // fmr 1591 | case 4: fpu("fnabs", MASK_A, FPU_DB); break; // fnabs 1592 | case 8: fpu("fabs", MASK_A, FPU_DB); break; // fabs 1593 | default: ill(); break; 1594 | } 1595 | break; 1596 | case 021: 1597 | switch(DIS_RC) 1598 | { 1599 | case 1: fpu("fneg.", MASK_A, FPU_DB); break; // fneg 1600 | case 2: fpu("fmr.", MASK_A, FPU_DB); break; // fmr 1601 | case 4: fpu("fnabs.", MASK_A, FPU_DB); break; // fnabs 1602 | case 8: fpu("fabs.", MASK_A, FPU_DB); break; // fabs 1603 | default: ill(); break; 1604 | } 1605 | break; 1606 | case 030: 1607 | switch(DIS_RC) 1608 | { 1609 | case 0: fpu("frsp", MASK_A, FPU_DB); break; // frsp 1610 | default: ill(); break; 1611 | } 1612 | break; 1613 | case 031: 1614 | switch(DIS_RC) 1615 | { 1616 | case 0: fpu("frsp.", MASK_A, FPU_DB); break; // frsp. 1617 | default: ill(); break; 1618 | } 1619 | break; 1620 | case 034: 1621 | switch(DIS_RC) 1622 | { 1623 | case 0: fpu("fctiw", MASK_A, FPU_DB); break; // fctiw 1624 | #ifdef POWERPC_64 1625 | case 25: fpu("fctid", MASK_A, FPU_DB); break; // fctid 1626 | case 26: fpu("fcfid", MASK_A, FPU_DB); break; // fcfid 1627 | #endif 1628 | default: ill(); break; 1629 | } 1630 | break; 1631 | case 035: 1632 | switch(DIS_RC) 1633 | { 1634 | case 0: fpu("fctiw.", MASK_A, FPU_DB); break; // fctiw. 1635 | #ifdef POWERPC_64 1636 | case 25: fpu("fctid.", MASK_A, FPU_DB); break; // fctid. 1637 | case 26: fpu("fcfid.", MASK_A, FPU_DB); break; // fcfid. 1638 | #endif 1639 | default: ill(); break; 1640 | } 1641 | break; 1642 | case 036: 1643 | switch(DIS_RC) 1644 | { 1645 | case 0: fpu("fctiwz", MASK_A, FPU_DB); break; // fctiwz 1646 | #ifdef POWERPC_64 1647 | case 25: fpu("fctidz", MASK_A, FPU_DB); break; // fctidz 1648 | #endif 1649 | default: ill(); break; 1650 | } 1651 | break; 1652 | case 037: 1653 | switch(DIS_RC) 1654 | { 1655 | case 0: fpu("fctiwz.", MASK_A, FPU_DB); break; // fctiwz. 1656 | #ifdef POWERPC_64 1657 | case 25: fpu("fctidz.", MASK_A, FPU_DB); break; // fctidz. 1658 | #endif 1659 | default: ill(); break; 1660 | } 1661 | break; 1662 | case 044: fpu("fdiv", MASK_C, FPU_DAB); break; // fdivx 1663 | case 045: fpu("fdiv.", MASK_C, FPU_DAB); break; 1664 | case 050: fpu("fsub", MASK_C, FPU_DAB); break; // fsubx 1665 | case 051: fpu("fsub.", MASK_C, FPU_DAB); break; 1666 | case 052: fpu("fadd", MASK_C, FPU_DAB); break; // faddx 1667 | case 053: fpu("fadd.", MASK_C, FPU_DAB); break; 1668 | #if !defined(GEKKO) 1669 | case 054: fpu("fsqrt", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; // fsqrtx 1670 | case 055: fpu("fsqrt.", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; 1671 | #endif 1672 | case 056: fpu("fsel", 0, FPU_DACB, PPC_DISA_OPTIONAL); break; // fselx 1673 | case 057: fpu("fsel.", 0, FPU_DACB, PPC_DISA_OPTIONAL); break; 1674 | case 062: fpu("fmul", MASK_B, FPU_DAC); break; // fmulx 1675 | case 063: fpu("fmul.", MASK_B, FPU_DAC); break; 1676 | case 064: fpu("frsqrte", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; // frsqrtex 1677 | case 065: fpu("frsqrte.", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; 1678 | case 070: fpu("fmsub", 0, FPU_DACB); break; // fmsubx 1679 | case 071: fpu("fmsub.", 0, FPU_DACB); break; 1680 | case 072: fpu("fmadd", 0, FPU_DACB); break; // fmaddx 1681 | case 073: fpu("fmadd.", 0, FPU_DACB); break; 1682 | case 074: fpu("fnmsub", 0, FPU_DACB); break; // fnmsubx 1683 | case 075: fpu("fnmsub.", 0, FPU_DACB); break; 1684 | case 076: fpu("fnmadd", 0, FPU_DACB); break; // fnmaddx 1685 | case 077: fpu("fnmadd.", 0, FPU_DACB); break; 1686 | default: ill(); break; 1687 | } break; 1688 | 1689 | /* 1690 | *********************************************************************************** 1691 | * GEKKO Extention. 1692 | *********************************************************************************** 1693 | */ 1694 | 1695 | #ifdef GEKKO 1696 | case 004: 1697 | if(((Instr >> 1) & 0x3FF) == 1014) 1698 | { 1699 | cache("dcbz_l", PPC_DISA_SPECIFIC); // dcbz_l 1700 | } 1701 | else switch((Instr >> 1) & 0x1f) 1702 | { 1703 | case 0: ps_cmpx((Instr >> 6) & 3); break; // ps_cmpXX 1704 | case 6: if(Instr & 0x40) ps_ldstx("lux"); // ps_lux 1705 | else ps_ldstx("lx"); break; // ps_lx 1706 | case 7: if(Instr & 0x40) ps_ldstx("stux"); // ps_stux 1707 | else ps_ldstx("stx"); break; // ps_stx 1708 | case 8: 1709 | switch((Instr >> 6) & 0x1f) 1710 | { 1711 | case 1: ps_db("neg", 1); break; // ps_negx 1712 | case 2: ps_db("mr", 1); break; // ps_mrx 1713 | case 4: ps_db("nabs", 1); break; // ps_nabsx 1714 | case 8: ps_db("abs", 1); break; // ps_absx 1715 | default: ill(); break; 1716 | } break; 1717 | case 10: ps_dacb("sum0"); break; // ps_sum0x 1718 | case 11: ps_dacb("sum1"); break; // ps_sum1x 1719 | case 12: ps_dac("muls0"); break; // ps_muls0x 1720 | case 13: ps_dac("muls1"); break; // ps_muls1x 1721 | case 14: ps_dacb("madds0"); break; // ps_madds0x 1722 | case 15: ps_dacb("madds1"); break; // ps_madds1x 1723 | case 16: 1724 | switch((Instr >> 6) & 0x1f) 1725 | { 1726 | case 16: ps_dab("merge00", 1); break; // ps_merge00x 1727 | case 17: ps_dab("merge01", 1); break; // ps_merge11x 1728 | case 18: ps_dab("merge10", 1); break; // ps_merge10x 1729 | case 19: ps_dab("merge11", 1); break; // ps_merge11x 1730 | default: ill(); break; 1731 | } break; 1732 | case 18: ps_dab("div"); break; // ps_divx 1733 | case 20: ps_dab("sub"); break; // ps_subx 1734 | case 21: ps_dab("add"); break; // ps_addx 1735 | case 23: ps_dacb("sel"); break; // ps_selx 1736 | case 24: ps_db("res"); break; // ps_resx 1737 | case 25: ps_dac("mul"); break; // ps_mulx 1738 | case 26: ps_db("rsqrte"); break; // ps_rsqrtex 1739 | case 28: ps_dacb("msub"); break; // ps_msubx 1740 | case 29: ps_dacb("madd"); break; // ps_maddx 1741 | case 30: ps_dacb("nmsub"); break; // ps_nmsubx 1742 | case 31: ps_dacb("nmadd"); break; // ps_nmaddx 1743 | default: ill(); break; 1744 | } break; 1745 | 1746 | case 070: ps_ldst("l"); break; // psq_l 1747 | case 071: ps_ldst("lu"); break; // psq_lu 1748 | case 074: ps_ldst("st"); break; // psq_st 1749 | case 075: ps_ldst("stu"); break; // psq_stu 1750 | #endif /* GEKKO */ 1751 | 1752 | default: ill(); break; 1753 | } 1754 | 1755 | #ifdef UPPERCASE 1756 | strupr(o->mnemonic); 1757 | #endif 1758 | } 1759 | 1760 | char *PPCDisasmSimple(u64 pc, u32 instr) 1761 | { 1762 | PPCD_CB dis_out; 1763 | static char output[256]; 1764 | 1765 | dis_out.pc = pc; 1766 | dis_out.instr = instr; 1767 | 1768 | PPCDisasm(&dis_out); 1769 | sprintf(output, "%08X %08X %-10s %s", pc, instr, dis_out.mnemonic, dis_out.operands); 1770 | return output; 1771 | } 1772 | -------------------------------------------------------------------------------- /ppcd.h: -------------------------------------------------------------------------------- 1 | // See some documentation in CPP file. 2 | 3 | #pragma once 4 | 5 | // Instruction class 6 | #define PPC_DISA_OTHER 0x0000 // No additional information 7 | #define PPC_DISA_64 0x0001 // 64-bit architecture only 8 | #define PPC_DISA_INTEGER 0x0002 // Integer-type instruction 9 | #define PPC_DISA_BRANCH 0x0004 // Branch instruction 10 | #define PPC_DISA_LDST 0x0008 // Load-store instruction 11 | #define PPC_DISA_STRING 0x0010 // Load-store string/multiple 12 | #define PPC_DISA_FPU 0x0020 // Floating-point instruction 13 | #define PPC_DISA_OEA 0x0040 // Supervisor level 14 | #define PPC_DISA_OPTIONAL 0x0200 // Optional 15 | #define PPC_DISA_BRIDGE 0x0400 // Optional 64-bit bridge 16 | #define PPC_DISA_SPECIFIC 0x0800 // Implementation-specific 17 | #define PPC_DISA_ILLEGAL 0x1000 // Illegal 18 | #define PPC_DISA_SIMPLIFIED 0x8000 // Simplified mnemonic is used 19 | 20 | typedef struct PPCD_CB 21 | { 22 | u64 pc; // Program counter (input) 23 | u32 instr; // Instruction (input) 24 | char mnemonic[16]; // Instruction mnemonic. 25 | char operands[64]; // Instruction operands. 26 | u32 immed; // Immediate value (displacement for load/store, immediate operand for arithm./logic). 27 | int r[4]; // Index value for operand registers and immediates. 28 | u64 target; // Target address for branch instructions / Mask for RLWINM-like instructions 29 | int iclass; // One or combination of PPC_DISA_* flags. 30 | } PPCD_CB; 31 | 32 | void PPCDisasm(PPCD_CB *disa); 33 | char* PPCDisasmSimple(u64 pc, u32 instr); 34 | -------------------------------------------------------------------------------- /test.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ogamespec/ppcd/58f7e6df284fa4cd5a9a734b7a44d1851dcdaf16/test.bin --------------------------------------------------------------------------------