/* This file is in the public domain. */ #include #include #include #include #include "fnprintf.h" #include "machine.h" #define CF_BASEFORM (CF_MSPEC+0) #define CF_JUMPTABLE (CF_MSPEC+1) #define CF_JUMPFIRST (CF_MSPEC+2) #define OPCODE_WIDTH 12 #define ASZ(array) (sizeof(array)/sizeof(array[0])) typedef struct instr INSTR; typedef struct spr SPR; struct spr { unsigned int which; #define SPR_MFSPR 0x00000001 #define SPR_MFTB 0x00000002 #define SPR_MTSPR 0x00000004 unsigned int v; const char *name; } ; struct instr { unsigned int mask; unsigned int value; const char *fmt; } ; #define BITSAT(n,at) ((~((~0UL)<<(n))) << (at)) #define NINE(nine) 0xfc0003fe, (((31<<26)|((nine)<<1))) #define SIX(six) 0xfc000000, ((six)<<26) #define TEN(six,ten) 0xfc0007fe, ((((six)<<26)|((ten)<<1))) #define FLOAT(five) 0xec00003e, (((59<<26)|((five)<<1))) #define FIVE(six,five) 0xfc00003e, ((((six)<<26)|((five)<<1))) static INSTR instrs[] = { { NINE(266), "add~o~ ~r0,~r1,~r2" }, { NINE( 10), "addc~o~ ~r0,~r1,~r2" }, { NINE(138), "adde~o~ ~r0,~r1,~r2" }, { SIX(14), "addi~ ~r0,~rz,~is" }, { SIX(12), "addic~ ~r0,~r1,~is" }, { SIX(13), "addic.~ ~r0,~r1,~is" }, { SIX(15), "addis~ ~r0,~rz,~is" }, { NINE(234), "addme~o~ ~r0,~r1~R2" }, { NINE(202), "addze~o~ ~r0,~r1~R2" }, { TEN(31, 28), "and~.~ ~r1,~r0,~r2" }, { TEN(31, 60), "andc~.~ ~r1,~r0,~r2" }, { SIX(28), "andi.~ ~r1,~r0,~iu" }, { SIX(29), "andis.~ ~r1,~r0,~iu" }, { SIX(18), "~K" }, { SIX(16), "~K" }, { TEN(19, 528), "~K" }, { TEN(19, 16), "~K" }, { TEN(31, 0), "cmpw~ ~ci0,~r1,~r2~Ra" }, { SIX(11), "cmpwi~ ~ci0,~r1,~is" }, { TEN(31, 32), "cmplw~ ~ci0,~r1,~r2~Ra" }, { SIX(10), "cmplwi~ ~ci0,~r1,~iu" }, { TEN(31, 26), "cntlzw~.~ ~r1,~r0,~R2" }, { TEN(19, 257), "crand~ ~Ci0,~Ci1,~Ci2~Ra" }, { TEN(19, 129), "crandc~ ~Cii0,~Ci1,~Ci2~Ra" }, { TEN(19, 289), "creqv~ ~Ci0,~Ci1,~Ci2~Ra" }, { TEN(19, 225), "crnand~ ~Ci0,~Ci1,~Ci2~Ra" }, { TEN(19, 33), "crnor~ ~Ci0,~Ci1,~Ci2~Ra" }, { TEN(19, 449), "cror~ ~Ci0,~Ci1,~Ci2~Ra" }, { TEN(19, 417), "crorc~ ~Ci0,~Ci1,~Ci2~Ra" }, { TEN(19, 193), "crxor~ ~Ci0,~Ci1,~Ci2~Ra" }, { TEN(31, 758), "dcba~ ~r1,~r2~R0~Ra" }, { TEN(31, 86), "dcbf~ ~r1,~r2~R0~Ra" }, { TEN(31, 470), "dcbi~ ~r1,~r2~R0~Ra" }, { TEN(31, 54), "dcbst~ ~r1,~r2~R0~Ra" }, { TEN(31, 278), "dcbt~ ~r1,~r2~R0~Ra" }, { TEN(31, 246), "dcbtst~ ~r1,~r2~R0~Ra" }, { TEN(31,1014), "dcbz~ ~r1,~r2~R0~Ra" }, { NINE(491), "divw~o~ ~r0,~r1,~r2" }, { NINE(459), "divwu~o~ ~r0,~r1,~r2" }, { TEN(31, 310), "eciwx~ ~r0,~rz,~r2~Ra" }, { TEN(31, 438), "ecowx~ ~r0,~rz,~r2~Ra" }, { TEN(31, 854), "eieio~R0~R1~R2~Ra" }, { TEN(31, 284), "eqv~.~ ~r1,~r0,~r2" }, { TEN(31, 954), "extsb~.~ ~r1,~r0~R2" }, { TEN(31, 922), "extsh~.~ ~r1,~r0~R2" }, { TEN(63, 264), "fabs~.~ ~f0,~f2~R1" }, { FLOAT(21), "fadd~s~.~ ~f0,~f1,~f2~R3" }, { TEN(63, 32), "fcmpo~ ~cf0,~f1,~f2~Ra" }, { TEN(63, 0), "fcmpu~ ~cf0,~f1,~f2~Ra" }, { TEN(63, 14), "fctiw~.~ ~f0,~f2~R1" }, { TEN(63, 15), "fctiwz~.~ ~f0,~f2~R1" }, { FLOAT(18), "fdiv~s~.~ ~f0,~f1,~f2~R3" }, { FLOAT(29), "fmadd~s~.~ ~f0,~f1,~f3,~f2" }, { TEN(63, 72), "fmr~.~ ~f0,~f2~R1" }, { FLOAT(28), "fmsub~s~.~ ~f0,~f1,~f3,~f2" }, { FLOAT(25), "fmul~s~.~ ~f0,~f1,~f3~R2" }, { TEN(63, 136), "fnabs~.~ ~f0,~f2~R1" }, { TEN(63, 40), "fneg~.~ ~f0,~f2~R1" }, { FLOAT(31), "fnmadd~s~.~ ~f0,~f1,~f3,~f2" }, { FLOAT(30), "fnmsub~s~.~ ~f0,~f1,~f3,~f2" }, { FIVE(59,24), "fres~.~ ~f0,~f2~R1~R3" }, { TEN(63, 12), "frsp~.~ ~f0,~f2~R1" }, { FIVE(63,26), "frsqrte~.~ ~f0,~f2~R1~R3" }, { FIVE(63,23), "fsel~.~ ~f0,~f1,~f3,~f2" }, { FLOAT(22), "fsqrt~s~.~ ~f0,~f2~R1~R3" }, { FLOAT(20), "fsub~s~.~ ~f0,~f1,~f2~R3" }, { TEN(31, 982), "icbi~ ~r1,~r2~R0~Ra" }, { TEN(19, 150), "isync~R0~R1~R2~Ra" }, { SIX(34), "lbz~ ~r0,~is(~rz)" }, { SIX(35), "lbzu~ ~r0,~is(~r1)~ID" }, { TEN(31, 119), "lbzux~ ~r0,~r1,~r2~Ra~ID" }, { TEN(31, 87), "lbzx~ ~r0,~rz,~r2~Ra" }, { SIX(50), "lfd~ ~f0,~is(~rz)" }, { SIX(51), "lfdu~ ~f0,~is(~r1)~I0" }, { TEN(31, 631), "lfdux~ ~f0,~r1,~r2~Ra" }, { TEN(31, 599), "lfdx~ ~f0,~rz,~r2~Ra" }, { SIX(48), "lfs~ ~f0,~is(~rz)" }, { SIX(49), "lfsu~ ~f0,~is(~r1)~I0" }, { TEN(31, 567), "lfsux~ ~f0,~r1,~r2~Ra~I0" }, { TEN(31, 535), "lfsx~ ~f0,~rz,~r2~Ra" }, { SIX(42), "lha~ ~r0,~is(~r1)" }, { SIX(43), "lhau~ ~r0,~is(~r1)~ID" }, { TEN(31, 375), "lhaux~ ~r0,~r1,~r2~Ra~ID" }, { TEN(31, 343), "lhax~ ~r0,~rz,~r2~Ra" }, { TEN(31, 790), "lhbrx~ ~r0,~rz,~r2~Ra" }, { SIX(40), "lhz~ ~r0,~is(~rz)" }, { SIX(41), "lhzu~ ~r0,~is(~r1)~ID" }, { TEN(31, 311), "lhzux~ ~r0,~r1,~r2~Ra~ID" }, { TEN(31, 279), "lhzx~ ~r0,~rz,~r2~Ra" }, { SIX(46), "lmw~ ~r0,~is(~rz)" }, { TEN(31, 597), "lswi~ ~r0,~rz,~d+~Ra" }, { TEN(31, 533), "lswx~ ~r0,~rz,~r2~Ra" }, { TEN(31, 20), "lwarx~ ~r0,~rz,~r2~Ra" }, { TEN(31, 534), "lwbrx~ ~r0,~rz,~r2~Ra" }, { SIX(32), "lwz~ ~r0,~is(~rz)" }, { SIX(33), "lwzu~ ~r0,~is(~r1)~ID" }, { TEN(31, 55), "lwzux~ ~r1,~r2,~r3~Ra" }, { TEN(31, 23), "lwzx~ ~r0,~rz,~r2~Ra" }, { TEN(19, 0), "mcrf~ ~cf0,~cf1~R2~Ra" }, { TEN(63, 64), "mcrfs~ ~cf0,~cf1~R2~Ra" }, { TEN(31, 512), "mcrxr~ ~cf0~R1~R2~Ra" }, { TEN(31, 19), "mfcr~ ~r0~R1~R2~Ra" }, { TEN(63, 583), "mffs~.~ ~f0~R1~R2" }, { TEN(31, 83), "mfmsr~ ~r0~R1~R2~Ra" }, { TEN(31, 339), "mfspr~ ~r0,~Na~Ra" }, { TEN(31, 595), "mfsr~ ~r0,~d(4@16)~R(20)~R2~Ra" }, { TEN(31, 659), "mfsrin~ ~r0,~r2~R1~Ra" }, { TEN(31, 371), "mftb~ ~r0~Nb~Ra" }, { TEN(31, 144), "mtcrf~ ~d(8@12),~r0~R(20)~R(11)~Ra" }, { TEN(63, 70), "mtfsb0~.~ ~Ci0~R1~R2" }, { TEN(63, 38), "mtfsb1~.~ ~Ci0~R1~R2" }, { TEN(63, 711), "mtfsf~.~ ~d(8@17)~f2~R(25)~R(16)" }, { TEN(63, 134), "mtfsfi~.~ ~cf0,~d(4@12)~R1~R(11)~Ra" }, { TEN(31, 146), "mtmsr~ ~r0~R1~R2~Ra" }, { TEN(31, 467), "mtspr~ ~Nc,~r0~Ra" }, { TEN(31, 210), "mtsr~ ~d(4@16),~r0~R(20)~Ra" }, { TEN(31, 242), "mtsrin~ ~r0,~r2~R1~Ra" }, { NINE( 75), "mulhw~.~ ~r0,~r1,~r2~R(10)" }, { NINE( 11), "mulhwu~.~ ~r0,~r1,~r2~R(10)" }, { SIX( 7), "mulli~ ~r0,~r1,~is" }, { NINE(235), "mullw~o~ ~r0,~r1,~r2" }, { TEN(31, 476), "nand~.~ ~r1,~r0,~r2" }, { NINE(104), "neg~o~ ~r0,~r1~R2" }, { TEN(31, 124), "nor~.~ ~r1,~r0,~r2" }, { TEN(31, 444), "or~.~ ~r1,~r0,~r2" }, { TEN(31, 412), "or~.~ ~r1,~r0,~r2" }, { SIX(24), "ori~ ~r1,~r0,~iu" }, { SIX(25), "oris~ ~r1,~r0,~iu" }, { TEN(19, 50), "rfi~R0~R1~R2~Ra" }, { SIX(20), "~K" }, { SIX(21), "~K" }, { SIX(23), "~K" }, { 0xfc000002, 0x18000002, "sc~R0~R1~R2~R3~R(5)~R(4)~R(3)~R(2)~Ra" }, { TEN(31, 24), "slw~.~ ~r1,~r0,~r2" }, { TEN(31, 792), "sraw~.~ ~r1,~r0,~r2" }, { TEN(31, 824), "srawi~.~ ~r1,~r0,~d2" }, { TEN(31, 536), "srw~.~ ~r1,~r0,~r2" }, { SIX(38), "stb~ ~r0,~is(~rz)" }, { SIX(39), "stbu~ ~r0,~is(~r1)~I0" }, { TEN(31, 247), "stbux~ ~r0,~r1,~r2~Ra" }, { TEN(31, 215), "stbx~ ~r0,~rz,~r2~Ra" }, { SIX(54), "stfd~ ~f0,~is(~rz)" }, { SIX(55), "stfdu~ ~f0,~is(~rz)" }, { TEN(31, 759), "stfdux~ ~f0,~f1,~f2~Ra" }, { TEN(31, 727), "stfdx~ ~f0,~rz,~r2~Ra" }, { TEN(31, 983), "stfiwx~ ~f0,~rz,~r2~Ra" }, { SIX(52), "stfs~ ~f0,~is(~rz)" }, { SIX(53), "stfsu~ ~f0,~is(~r1)" }, { TEN(31, 695), "stfsux~ ~f0,~r1,~r2~Ra" }, { TEN(31, 663), "stfsx~ ~f0,~rz,~r2~Ra" }, { SIX(44), "sth~ ~r0,~is(~rz)" }, { TEN(31, 918), "sthbrx~ ~r0,~rz,~r2~Ra" }, { SIX(45), "sthu~ ~r0,~is(~r1)~I0" }, { TEN(31, 439), "sthux~ ~r0,~r1,~r2~Ra" }, { TEN(31, 407), "sthx~ ~r0,~rz,~r2~Ra" }, { SIX(47), "stmw~ ~r0,~is(~rz)" }, { TEN(31, 725), "stswi~ ~r0,~rz,~d2~Ra" }, { TEN(31, 661), "stswx~ ~r0,~rz,~r2~Ra" }, { SIX(36), "stw~ ~r0,~is(~rz)" }, { TEN(31, 662), "stwbrx~ ~r0,~rz,~r2~Ra" }, { 0xfc0007ff, 0x7c00012d, "stwcx.~ ~r0,~rz,~r2" }, /* TEN(31,150)+1 */ { SIX(37), "stwu~ ~r0,~is(~r1)" }, { TEN(31, 183), "stwux~ ~r0,~r1,~r2~Ra~I0" }, { TEN(31, 151), "stwx~ ~r0,~rz,~r2~Ra" }, { NINE( 40), "sub~o~ ~r0,~r2,~r1" }, { NINE( 8), "subc~o~ ~r0,~r2,~r1" }, { NINE(136), "subfe~o~ ~r0,~r1,~r2" }, { SIX( 8), "subfic~ ~r0,~r1,~is" }, { NINE(232), "subfme~o~ ~r0,~r1~R2" }, { NINE(200), "subfze~o~ ~r0,~r1~R2" }, { TEN(31, 598), "sync~R0~R1~R2~Ra" }, { TEN(31, 370), "tlbia~R0~R1~R2~Ra" }, { TEN(31, 306), "tlbie~ ~r2~R0~R1~Ra" }, { TEN(31, 566), "tblsync~R0~R1~R2~Ra" }, { TEN(31, 4), "~K" }, { SIX( 3), "~K" }, { TEN(31, 316), "xor~.~ ~r1,~r0,~r2" }, { SIX(26), "xori~ ~r1,~r0,~iu" }, { SIX(27), "xoris~ ~r1,~r0,~iu" } }; static unsigned int searchmask; static SPR sprs[] = { /* In 6xx_pem.pdf (IBM techlib) */ { SPR_MFSPR|SPR_MTSPR, 1, "XER" }, { SPR_MFSPR|SPR_MTSPR, 8, "LR" }, { SPR_MFSPR|SPR_MTSPR, 9, "CTR" }, { SPR_MFSPR|SPR_MTSPR, 18, "DSISR" }, { SPR_MFSPR|SPR_MTSPR, 19, "DAR" }, { SPR_MFSPR|SPR_MTSPR, 22, "DEC" }, { SPR_MFSPR|SPR_MTSPR, 25, "SDR1" }, { SPR_MFSPR|SPR_MTSPR, 26, "SRR0" }, { SPR_MFSPR|SPR_MTSPR, 27, "SRR1" }, { SPR_MFTB, 268, "TBL" }, { SPR_MFTB, 269, "TBH" }, { SPR_MFSPR|SPR_MTSPR, 272, "SPRG0" }, { SPR_MFSPR|SPR_MTSPR, 273, "SPRG1" }, { SPR_MFSPR|SPR_MTSPR, 274, "SPRG2" }, { SPR_MFSPR|SPR_MTSPR, 275, "SPRG3" }, { SPR_MFSPR|SPR_MTSPR, 282, "EAR" }, { SPR_MTSPR, 284, "TBL" }, { SPR_MTSPR, 285, "TBH" }, { SPR_MFSPR, 287, "PVR" }, { SPR_MFSPR|SPR_MTSPR, 528, "IBAT0U" }, { SPR_MFSPR|SPR_MTSPR, 529, "IBAT0L" }, { SPR_MFSPR|SPR_MTSPR, 530, "IBAT1U" }, { SPR_MFSPR|SPR_MTSPR, 531, "IBAT1L" }, { SPR_MFSPR|SPR_MTSPR, 532, "IBAT2U" }, { SPR_MFSPR|SPR_MTSPR, 533, "IBAT2L" }, { SPR_MFSPR|SPR_MTSPR, 534, "IBAT3U" }, { SPR_MFSPR|SPR_MTSPR, 535, "IBAT3L" }, { SPR_MFSPR|SPR_MTSPR, 536, "DBAT0U" }, { SPR_MFSPR|SPR_MTSPR, 537, "DBAT0L" }, { SPR_MFSPR|SPR_MTSPR, 538, "DBAT1U" }, { SPR_MFSPR|SPR_MTSPR, 539, "DBAT1L" }, { SPR_MFSPR|SPR_MTSPR, 540, "DBAT2U" }, { SPR_MFSPR|SPR_MTSPR, 541, "DBAT2L" }, { SPR_MFSPR|SPR_MTSPR, 542, "DBAT3U" }, { SPR_MFSPR|SPR_MTSPR, 543, "DBAT3L" }, { SPR_MFSPR|SPR_MTSPR, 1013, "DABR" }, /* Extracted from gdb - for 860 */ { SPR_MFSPR|SPR_MTSPR, 144, "CMPA" }, { SPR_MFSPR|SPR_MTSPR, 145, "CMPB" }, { SPR_MFSPR|SPR_MTSPR, 146, "CMPC" }, { SPR_MFSPR|SPR_MTSPR, 147, "CMPD" }, { SPR_MFSPR|SPR_MTSPR, 148, "ICR" }, { SPR_MFSPR|SPR_MTSPR, 149, "DER" }, { SPR_MFSPR|SPR_MTSPR, 150, "COUNTA" }, { SPR_MFSPR|SPR_MTSPR, 151, "COUNTB" }, { SPR_MFSPR|SPR_MTSPR, 152, "CMPE" }, { SPR_MFSPR|SPR_MTSPR, 153, "CMPF" }, { SPR_MFSPR|SPR_MTSPR, 154, "CMPG" }, { SPR_MFSPR|SPR_MTSPR, 155, "CMPH" }, { SPR_MFSPR|SPR_MTSPR, 156, "LCTRL1" }, { SPR_MFSPR|SPR_MTSPR, 157, "LCTRL2" }, { SPR_MFSPR|SPR_MTSPR, 158, "ICTRL" }, { SPR_MFSPR|SPR_MTSPR, 159, "BAR" }, { SPR_MFSPR, 560, "IC_CST" }, { SPR_MFSPR, 561, "IC_ADR" }, { SPR_MFSPR, 562, "IC_DAT" }, { SPR_MFSPR, 568, "DC_CST" }, { SPR_MFSPR, 569, "DC_ADR" }, { SPR_MFSPR, 570, "DC_DAT" }, { SPR_MFSPR, 630, "DPDR" }, { SPR_MFSPR, 631, "DPIR" }, { SPR_MFSPR, 638, "IMMR" }, { SPR_MFSPR, 784, "MI_CTR" }, { SPR_MFSPR, 786, "MI_AP" }, { SPR_MFSPR, 787, "MI_EPN" }, { SPR_MFSPR, 789, "MI_TWC" }, { SPR_MFSPR, 790, "MI_RPN" }, { SPR_MFSPR, 792, "MD_CTR" }, { SPR_MFSPR, 793, "M_CASID" }, { SPR_MFSPR, 794, "MD_AP" }, { SPR_MFSPR, 795, "MD_EPN" }, { SPR_MFSPR, 796, "MD_TWB" }, { SPR_MFSPR, 797, "MD_TWC" }, { SPR_MFSPR, 798, "MD_RPN" }, { SPR_MFSPR, 799, "M_TW" }, { SPR_MFSPR, 816, "MI_DBCAM" }, { SPR_MFSPR, 817, "MI_DBRAM0" }, { SPR_MFSPR, 818, "MI_DBRAM1" }, { SPR_MFSPR, 824, "MD_DBCAM" }, { SPR_MFSPR, 825, "MD_DBRAM0" }, { SPR_MFSPR, 826, "MD_DBRAM1" }, /* Assumed based on the above and existing code */ { SPR_MTSPR, 560, "(IC_CST)" }, { SPR_MTSPR, 561, "(IC_ADR)" }, { SPR_MTSPR, 568, "(DC_CST)" }, { SPR_MTSPR, 569, "(DC_ADR)" }, { SPR_MTSPR, 638, "(IMMR)" }, { SPR_MTSPR, 784, "(MI_CTR)" }, { SPR_MTSPR, 786, "(MI_AP)" }, { SPR_MTSPR, 787, "(MI_EPN)" }, { SPR_MTSPR, 789, "(MI_TWC)" }, { SPR_MTSPR, 790, "(MI_RPN)" }, { SPR_MTSPR, 792, "(MD_CTR)" }, { SPR_MTSPR, 793, "(M_CASID)" }, { SPR_MTSPR, 794, "(MD_AP)" }, { SPR_MTSPR, 795, "(MD_EPN)" }, { SPR_MTSPR, 796, "(MD_TWB)" }, { SPR_MTSPR, 797, "(MD_TWC)" }, { SPR_MTSPR, 798, "(MD_RPN)" }, { SPR_MTSPR, 799, "(M_TW)" }, { SPR_MTSPR, 816, "(MI_DBCAM)" }, { SPR_MTSPR, 824, "(MD_DBCAM)" }, /* That's it */ }; static signed long int signextend(unsigned long int ul, int nbits) { return( (ul&(1UL<<(nbits-1))) ? -(signed long int)((((1UL<>2); switch (cb & 3) { default: abort(); break; case 0: fnprintf(fn,"lt"); break; case 1: fnprintf(fn,"gt"); break; case 2: fnprintf(fn,"eq"); break; case 3: if (fp) fnprintf(fn,"un"); else fnprintf(fn,"so"); break; } } static int do_dis_inst(ADDR addr, void (*argfn)(char), CFLAG flg, int forcebase) { __label__ out; unsigned int opc; unsigned long int used; unsigned long int resv; int i; int j; int k; int n; const char *fp; char *ep; char termc; void fn(char c) { if (argfn) (*argfn)(c); n ++; } void opcode_pad(void) { while (n < OPCODE_WIDTH) fn(' '); } void use(int n, int at) { unsigned long int m; if ((n < 1) || (at < 0) || (n > 31) || (at > 31) || (n+at > 32)) abort(); m = BITSAT(n,at); if (used & m) { fnprintf(&fn,"[USED %08lx %d %d]",used,n,at); goto out; } used |= m; } addr -= corebase; if (addr+4 > coresize) return(-1); opc = corefetchu(addr,4); i = -1; j = ASZ(instrs); while (j-i > 1) { k = (i + j) >> 1; if ((opc & searchmask) < (instrs[k].value & searchmask)) j = k; else i = k; } n = j; i = -1; while (j-i > 1) { k = (i + j) >> 1; if ((opc & searchmask) > (instrs[k].value & searchmask)) i = k; else j = k; } k = -1; for (i=j;i (fp=instrs[k].fmt;*fp;fp++) { if (*fp != '~') { fn(*fp); continue; } fp ++; switch (*fp) { case ' ': opcode_pad(); break; case 'o': use(1,10); if (opc & (1<<10)) fn('o'); /* fall through */ case '.': use(1,0); if (opc & 1) fn('.'); break; case 's': use(1,28); if (opc & (1<<28)) fn('s'); break; case 'R': fp ++; switch (*fp) { default: abort(); break; case 'a': i = 1; j = 0; break; case '0': i = 5; j = 21; break; case '1': i = 5; j = 16; break; case '2': i = 5; j = 11; break; case '3': i = 5; j = 6; break; case '(': j = strtol(fp+1,&ep,10); if (*ep != ')') abort(); fp = ep; i = 1; break; } resv |= BITSAT(i,j); break; case 'I': fp ++; switch (*fp) { default: abort(); break; case '0': if (((opc >> 16) & 31) == 0) { fnprintf(&fn," **INVALID r0"); } break; case 'D': if (((opc >> 16) & 31) == 0) { fnprintf(&fn," **INVALID r0"); } else if ( ((opc >> 16) & 31) == ((opc >> 21) & 31) ) { fnprintf(&fn," **INVALID r%u",(opc>>16)&31); } break; } break; case 'r': fp ++; switch (*fp) { default: abort(); break; case '0': i = 21; if (0) { case '1': i = 16; } if (0) { case '2': i = 11; } if (0) { break; case '3': i = 6; } use(5,i); fnprintf(&fn,"r%u",(opc>>i)&31); break; case 'z': use(5,16); i = (opc >> 16) & 31; if (i) fnprintf(&fn,"r%d",i); else fnprintf(&fn,"#0"); break; } break; case 'f': fp ++; switch (*fp) { default: abort(); break; case '0': i = 21; break; case '1': i = 16; break; case '2': i = 11; break; case '3': i = 6; break; } use(5,i); fnprintf(&fn,"f%u",(opc>>i)&31); break; case 'i': fp ++; use(16,0); switch (*fp) { default: abort(); break; case 's': i = signextend(opc&0xffff,16); break; case 'u': i = opc & 0xffff; break; } fnprintf(&fn,"%d",i); break; case 'd': fp ++; switch (*fp) { default: abort(); break; case '0': i = 21; if (0) { case '1': i = 16; } if (0) { case '2': i = 11; } if (0) { case '3': i = 6; } if (0) { case '4': i = 1; } use(5,i); fnprintf(&fn,"%u",(opc>>i)&31); break; case '+': use(5,11); i = (opc >> 11) & 31; if (! i) i = 32; fnprintf(&fn,"%u",(opc>>i)&31); break; case '(': if (sscanf(fp,"(%d@%d%c",&i,&j,&termc) != 3) abort(); if (termc != ')') abort(); while (*fp != ')') fp ++; use(i,j); fnprintf(&fn,"%lu",(opc>>j)&BITSAT(i,0)); break; } break; case 'c': fp ++; switch (*fp) { default: abort(); break; case 'i': fp ++; if (*fp != '0') abort(); i = 21; break; case 'f': fp ++; switch (*fp) { default: abort(); break; case '0': i = 21; break; case '1': i = 16; break; } break; } use(3,i+2); resv |= 3 << i; fnprintf(&fn,"cr%u",(opc>>(i+2))&7); break; case 'C': fp ++; switch (*fp) { default: abort(); break; case 'i': case 'f': fp ++; switch (*fp) { default: abort(); break; case '0': i = 21; break; case '1': i = 16; break; case '2': i = 11; break; } break; } use(5,i); print_crbit(&fn,(opc>>i)&31,fp[-1]=='f'); break; case 'N': fp ++; use(10,11); i = ((opc >> 6) & (31 << 5)) | ((opc >> 16) & 31); switch (*fp) { default: abort(); break; case 'a': j = SPR_MFSPR; break; case 'b': j = SPR_MFTB; break; case 'c': j = SPR_MTSPR; break; } for (k=ASZ(sprs)-1;k>=0;k--) { if ((sprs[k].v == i) && (sprs[k].which & j)) { fnprintf(&fn,"%s",sprs[k].name); continue <"fmt">; } } fnprintf(&fn,"?%d",i); break; case 'K': switch ((opc >> 26) & 63) { const char *txt; unsigned int code; int sh; int mb; int me; int bo; int bi; void rlopcode(const char *s) { fnprintf(&fn,"%s",s); use(1,0); if (opc & 1) fn('.'); opcode_pad(); use(5,16); use(5,21); fnprintf(&fn,"r%d,r%d,",(opc>>16)&31,(opc>>21)&31); } void cbcommon(void) { use(5,21); bo = (opc >> 21) & 31; use(5,16); bi = (opc >> 16) & 31; if ((bo & 0x18) == 0x18) { resv |= 0x08 << 16; used &= ~(0x08 << 16); bo &= ~0x08; } if ((bo & 0x06) == 0x06) { resv |= 0x02 << 16; used &= ~(0x02 << 16); bo &= ~0x02; } if ((bo & 0x14) == 0x14) { resv |= 0x0b << 16; used &= ~(0x0b << 16); bo = 0x14; } if (bo & 0x10) bi = 0; fn('b'); switch (bo & 6) { case 0: fnprintf(&fn,"dnz"); break; case 2: fnprintf(&fn,"dz"); break; } switch (bo & 0x18) { case 0x00: fn('f'); break; case 0x08: fn('t'); break; } } int bo_uses_crbit(void) { return(!(bo&0x10)); } case 18: /* bX */ fn('j'); use(1,0); if (opc & 1) fn('l'); use(1,1); if (opc & 2) { fn('a'); opcode_pad(); use(24,2); print_symbol_or_hex(&fn,signextend(opc&0x03fffffc,26)); } else { opcode_pad(); use(24,2); print_symbol_or_hex(&fn,corebase+addr+signextend(opc&0x03fffffc,26)); } break; case 16: /* bcX */ cbcommon(); use(1,0); if (opc & 1) fn('l'); use(1,1); if (opc & 2) fn('a'); opcode_pad(); if (bo_uses_crbit()) { print_crbit(&fn,bi,0); fn(','); } if (opc & 2) { use(14,2); print_symbol_or_hex(&fn,signextend(opc&0x0000fffc,16)); } else { use(14,2); print_symbol_or_hex(&fn,corebase+addr+signextend(opc&0x0000fffc,16)); } break; case 19: /* bcctrX and bclrX */ cbcommon(); if (opc & 1024) fnprintf(&fn,"ctr"); else fnprintf(&fn,"lr"); use(1,0); if (opc & 1) fn('l'); if (bo_uses_crbit()) { opcode_pad(); print_crbit(&fn,bi,0); } resv |= 31 << 11; if ((opc & 1024) && !(bo & 4)) fnprintf(&fn," **INVALID ctr use"); break; case 20: /* rlwimiX */ use(5,11); use(5,6); use(5,1); sh = (opc >> 11) & 31; mb = (opc >> 6) & 31; me = (opc >> 1) & 31; if (!forcebase && (sh+me == 31) && (me-mb >= 0)) { rlopcode("insrwi"); fnprintf(&fn,"%d,%d",me+1-mb,mb); } else if (!forcebase && (sh+mb == 32) && (me-mb >= 0)) { rlopcode("inslwi"); fnprintf(&fn,"%d,%d",me+1-mb,mb); } else { rlopcode("rlwimi"); fnprintf(&fn,"%d,%d,%d",sh,mb,me); } break; case 21: /* rlwinmX */ use(5,11); use(5,6); use(5,1); sh = (opc >> 11) & 31; mb = (opc >> 6) & 31; me = (opc >> 1) & 31; if (!forcebase && (sh == 0) && (mb == 0)) { rlopcode("clrrwi"); fnprintf(&fn,"%d",31-me); } else if (!forcebase && (sh == 0) && (me == 31)) { rlopcode("clrlwi"); fnprintf(&fn,"%d",mb); } else if (!forcebase && (mb == 0) && (me == 31)) { rlopcode("rotrwi"); fnprintf(&fn,"%d",32-sh); } else if (!forcebase && (me == 31) && (sh == 32-mb)) { rlopcode("srwi"); fnprintf(&fn,"%d",mb); } else if (!forcebase && (me == 31) && (sh >= 32-mb)) { rlopcode("extrwi"); fnprintf(&fn,"%d,%d",32-mb,sh-(32-mb)); } else if (!forcebase && (mb == 0) && (me+sh == 31)) { rlopcode("slwi"); fnprintf(&fn,"%d",sh); } else if (!forcebase && (mb == 0)) { rlopcode("extlwi"); fnprintf(&fn,"%d,%d",me+1,sh); } else if (!forcebase && (mb == 0) && (me == 31)) { rlopcode("rotlwi"); fnprintf(&fn,"%d",sh); } else if (!forcebase && (mb == 0) && (me == 31-sh)) { rlopcode("slwi"); fnprintf(&fn,"%d",sh); } else if (!forcebase && (me == 31-sh) && (mb-sh >= sh)) { rlopcode("clrlslwi"); fnprintf(&fn,"%d,%d",mb-sh,sh); } else { rlopcode("rlwinm"); fnprintf(&fn,"%d,%d,%d",sh,mb,me); } break; case 23: /* rlwnmX */ use(5,6); use(5,1); mb = (opc >> 6) & 31; me = (opc >> 1) & 31; if (!forcebase && (mb == 0) && (me == 31)) { rlopcode("rotlw"); use(5,11); fnprintf(&fn,"r%d",(opc>>11)&31); } else { rlopcode("rlwnm"); use(5,11); fnprintf(&fn,"r%d,%d,%d",(opc>>11)&31,mb,me); } break; case 31: /* tw */ if (forcebase) { fnprintf(&fn,"tw"); opcode_pad(); fnprintf(&fn,"%d,",code); fnprintf(&fn,"r%u,r%u",(opc>>16)&31,(opc>>11)&31); } else if (opc == 0x7fe00008) { fnprintf(&fn,"trap"); } else { code = (opc >> 21) & 31; txt = traptext(code); if (txt) { fnprintf(&fn,"tw%s",txt); opcode_pad(); } else { fnprintf(&fn,"tw"); opcode_pad(); fnprintf(&fn,"%d,",code); } fnprintf(&fn,"r%u,r%u",(opc>>16)&31,(opc>>11)&31); } break; case 3: /* twi */ use(5,21); code = (opc >> 21) & 31; txt = forcebase ? 0 : traptext(code); if (txt) { fnprintf(&fn,"tw%si",txt); opcode_pad(); } else { fnprintf(&fn,"twi"); opcode_pad(); fnprintf(&fn,"%d,",code); } use(5,16); use(16,0); fnprintf(&fn,"r%u,%ld",(opc>>16)&31,signextend(opc&0xffff,16)); break; } break; } } if (((opc >> 26) == 14) && (addr >= 4)) { /* it's an addi with a previous instr */ unsigned int prevopc; prevopc = corefetchu(addr-4,4); if ( ((prevopc >> 26) == 15) && (((prevopc >> 16) & 31) == 0) && (((prevopc >> 21) & 31) == ((opc >> 16) & 31)) ) { /* is "addis rN,#0,valh ; addi rM,rN,vall" sequence; annotate */ unsigned int val; val = ((prevopc & 0xffff) << 16) + signextend(opc&0xffff,16); fnprintf(&fn," ! "); print_symbol_or_hex(&fn,val); } } else if (((opc >> 26) == 24) && (addr >= 4)) { /* it's an ori with a previous instr */ unsigned int prevopc; prevopc = corefetchu(addr-4,4); if ( ((prevopc >> 26) == 15) && (((prevopc >> 16) & 31) == 0) && (((prevopc >> 21) & 31) == ((opc >> 16) & 31)) ) { /* is "addis rN,#0,valh ; ori rM,rN,vall" sequence; annotate */ unsigned int val; val = ((prevopc & 0xffff) << 16) | (opc&0xffff); fnprintf(&fn," ! "); print_symbol_or_hex(&fn,val); } } if (used & resv) { fnprintf(&fn," [used resv %08lx]",used&resv); } if ((used|resv) != 0xffffffff) { fnprintf(&fn," [used %08lx]",used); } if (opc & resv) { fnprintf(&fn," [resv %08lx]",opc&resv); } out:; if (addr & 3) { fnprintf(fn," {unaligned}"); return(1); } if (flg & CFF_INST_PARALLEL) { fnprintf(fn," {parallel}"); return(1); } flags[addr+1] = CF_PREV; flags[addr+2] = CF_PREV; flags[addr+3] = CF_PREV; return(4); } static int do_dis_jump(ADDR addr, void (*fn)(char)) { static ADDR next = 0; static ADDR base = 0; if (!( (addr == next) && (base < coresize) && (flags[base] == CF_JUMPFIRST) )) { if (addr < corebase) abort(); base = addr - corebase; if (base >= coresize) abort(); while (1) { if (flags[base] == CF_JUMPFIRST) break; if ((base < 4) || (flags[base] != CF_JUMPTABLE)) { flags[addr-corebase] = CF_LONG; return(0); } base -= 4; } } switch (flags[addr-corebase]) { default: abort(); break; case CF_JUMPFIRST: fnprintf(fn,"%-*s",OPCODE_WIDTH,".jtable"); break; case CF_JUMPTABLE: fnprintf(fn,"%-*s",OPCODE_WIDTH,".jump"); break; } print_symbol_or_hex(fn,corebase+base+corefetchu(addr-corebase,4)); next = addr + 4; return(4); } #define HL(x) (((x)<<1)+1) #define HR(x) (((x)+1)<<1) #define HU(x) (((x)-1)>>1) static void ppc_init(void) { unsigned int sv[ASZ(instrs)]; int isort[ASZ(instrs)]; int i; INSTR sorted[ASZ(instrs)]; #define V(x) sv[isort[(x)]] void dn(int x, int top) { int l; int r; int s; int t; while (1) { l = HL(x); r = HR(x); if ((r < top) && (V(r) > V(x))) { if (V(l) > V(x)) { s = (V(l) > V(r)) ? l : r; } else { s = r; } } else { if ((l < top) && (V(l) > V(x))) { s = l; } else { return; } } t = isort[x]; isort[x] = isort[s]; isort[s] = t; x = s; } } searchmask = ~0U; for (i=ASZ(instrs)-1;i>=0;i--) { isort[i] = i; searchmask &= instrs[i].mask; } for (i=ASZ(instrs)-1;i>=0;i--) sv[i] = instrs[i].value & searchmask; for (i=HU(ASZ(instrs)-1);i>=0;i--) dn(i,ASZ(instrs)); for (i=ASZ(instrs)-1;i>0;i--) { sorted[i] = instrs[isort[0]]; isort[0] = isort[i]; dn(0,i); } sorted[0] = instrs[isort[0]]; for (i=ASZ(instrs)-1;i>0;i--) { if ((sorted[i].value & searchmask) < (sorted[i-1].value & searchmask)) { abort(); } } bcopy(&sorted[0],&instrs[0],sizeof(instrs)); #undef V } #undef HL #undef HR #undef HU static void underscore_command(void) { if (changecur(1)) return; flags[loc.u.on.aoff] = CF_BASEFORM; } static void J_command(void) { ADDR a; if (checkchange(1)) return; if ( (flags[loc.u.on.aoff] != CF_LONG) || ( (loc.u.on.aoff >= 4) && (flags[loc.u.on.aoff-4] == CF_LONG) ) ) { disas_beep(); return; } flags[loc.u.on.aoff] = CF_JUMPFIRST; for (a=loc.u.on.aoff+4;(a",(unsigned long int)flags[addr-corebase]); rv = 1; } break; case CF_BASEFORM: rv = do_dis_inst(addr,fn,flags[addr-corebase],1); break; case CF_JUMPFIRST: case CF_JUMPTABLE: rv = do_dis_jump(addr,fn); break; } return(rv); } static unsigned long int ppceb_fetch(const void *base, int size) #define bp(n) ((unsigned long int)(((const unsigned char *)base)[(n)])) { switch (size) { case 1: return(bp(0)); break; case 2: return((bp(0)<<8)|bp(1)); break; case 4: return((bp(0)<<24)|(bp(1)<<16)|(bp(2)<<8)|bp(3)); break; } abort(); } #undef bp static unsigned long int ppcel_fetch(const void *base, int size) #define bp(n) ((unsigned long int)(((const unsigned char *)base)[(n)])) { switch (size) { case 1: return(bp(0)); break; case 2: return((bp(1)<<8)|bp(0)); break; case 4: return((bp(3)<<24)|(bp(2)<<16)|(bp(1)<<8)|bp(0)); break; } abort(); } #undef bp static const char *ppceb_names[] = { "PPCEB", "ppceb", "PPC", "ppc", 0 }; MACHINE machine_ppceb = { &ppceb_names[0], 4, &ppc_init, &ppc_cmd, &ppc_dis, &ppceb_fetch, 0 }; static const char *ppcel_names[] = { "PPCEL", "ppcel", 0 }; MACHINE machine_ppcel = { &ppcel_names[0], 4, &ppc_init, &ppc_cmd, &ppc_dis, &ppcel_fetch, 0 };