dolphin/Externals/Bochs_disasm/PowerPCDisasm.cpp
Soren Jorvang 30e437f9e3 Fix some cases of variables being used uninitialized. Also some unused
variables, writeable strings and dangerously shadowed variables.

index(), gamma(), exp() and y0() are POSIX functions and using those
names can cause namespace confusion.

A number of C files were missing the final newline required by ANSI C
and some versions of GCC are pedantic enough to complain about this.

These changes simply the scons build, allowing us to get rid of
filterWarnings which is simply more trouble than it's worth.


git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5574 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-06-02 20:35:12 +00:00

2284 lines
44 KiB
C++

/* $VER: ppc_disasm.c V1.1 (19.02.2000)
*
* Disassembler module for the PowerPC microprocessor family
* Copyright (c) 1998-2000 Frank Wille
*
* ppc_disasm.c is freeware and may be freely redistributed as long as
* no modifications are made and nothing is charged for it.
* Non-commercial usage is allowed without any restrictions.
* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
*
*
* v1.2 (31.07.2003) org
* modified for IBM PowerPC Gekko.
* v1.1 (19.02.2000) phx
* fabs wasn't recognized.
* v1.0 (30.01.2000) phx
* stfsx, stfdx, lfsx, lfdx, stfsux, stfdux, lfsux, lfdux, etc.
* printed "rd,ra,rb" as operands instead "fd,ra,rb".
* v0.4 (01.06.1999) phx
* 'stwm' shoud have been 'stmw'.
* v0.3 (17.11.1998) phx
* The OE-types (e.g. addo, subfeo, etc.) didn't work for all
* instructions.
* AA-form branches have an absolute destination.
* addze and subfze must not have a third operand.
* sc was not recognized.
* v0.2 (29.05.1998) phx
* Sign error. SUBI got negative immediate values.
* v0.1 (23.05.1998) phx
* First version, which implements all PowerPC instructions.
* v0.0 (09.05.1998) phx
* File created.
*/
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "PowerPCDisasm.h"
namespace PPCDisasm
{
/* version/revision */
#define PPCDISASM_VER 1
#define PPCDISASM_REV 1
/* typedefs */
typedef unsigned int ppc_word;
#undef BIGENDIAN
#undef LITTTLEENDIAN
/* endianess */
#define LITTLEENDIAN 0
/* general defines */
#define PPCIDXMASK 0xfc000000
#define PPCIDX2MASK 0x000007fe
#define PPCDMASK 0x03e00000
#define PPCAMASK 0x001f0000
#define PPCBMASK 0x0000f800
#define PPCCMASK 0x000007c0
#define PPCMMASK 0x0000003e
#define PPCCRDMASK 0x03800000
#define PPCCRAMASK 0x001c0000
#define PPCLMASK 0x00600000
#define PPCOE 0x00000400
#define PPCIDXSH 26
#define PPCDSH 21
#define PPCASH 16
#define PPCBSH 11
#define PPCCSH 6
#define PPCMSH 1
#define PPCCRDSH 23
#define PPCCRASH 18
#define PPCLSH 21
#define PPCIDX2SH 1
#define PPCGETIDX(x) (((x)&PPCIDXMASK)>>PPCIDXSH)
#define PPCGETD(x) (((x)&PPCDMASK)>>PPCDSH)
#define PPCGETA(x) (((x)&PPCAMASK)>>PPCASH)
#define PPCGETB(x) (((x)&PPCBMASK)>>PPCBSH)
#define PPCGETC(x) (((x)&PPCCMASK)>>PPCCSH)
#define PPCGETM(x) (((x)&PPCMMASK)>>PPCMSH)
#define PPCGETCRD(x) (((x)&PPCCRDMASK)>>PPCCRDSH)
#define PPCGETCRA(x) (((x)&PPCCRAMASK)>>PPCCRASH)
#define PPCGETL(x) (((x)&PPCLMASK)>>PPCLSH)
#define PPCGETIDX2(x) (((x)&PPCIDX2MASK)>>PPCIDX2SH)
/* Disassembler structure, the interface to the application */
struct DisasmPara_PPC {
ppc_word *instr; /* pointer to instruction to disassemble */
ppc_word *iaddr; /* instr.addr., usually the same as instr */
char *opcode; /* buffer for opcode, min. 10 chars. */
char *operands; /* operand buffer, min. 24 chars. */
/* changed by disassembler: */
unsigned char type; /* type of instruction, see below */
unsigned char flags; /* additional flags */
unsigned short sreg; /* register in load/store instructions */
ppc_word displacement; /* branch- or load/store displacement */
};
#define PPCINSTR_OTHER 0 /* no additional info for other instr. */
#define PPCINSTR_BRANCH 1 /* branch dest. = PC+displacement */
#define PPCINSTR_LDST 2 /* load/store instruction: displ(sreg) */
#define PPCINSTR_IMM 3 /* 16-bit immediate val. in displacement */
#define PPCF_ILLEGAL (1<<0) /* illegal PowerPC instruction */
#define PPCF_UNSIGNED (1<<1) /* unsigned immediate instruction */
#define PPCF_SUPER (1<<2) /* supervisor level instruction */
#define PPCF_64 (1<<3) /* 64-bit only instruction */
/* ppc_disasm.o prototypes */
#ifndef PPC_DISASM_C
extern ppc_word *PPC_Disassemble(struct DisasmPara_PPC *);
#endif
static const char *trap_condition[32] = {
NULL,"lgt","llt",NULL,"eq","lge","lle",NULL,
"gt",NULL,NULL,NULL,"ge",NULL,NULL,NULL,
"lt",NULL,NULL,NULL,"le",NULL,NULL,NULL,
"ne",NULL,NULL,NULL,NULL,NULL,NULL,NULL
};
static const char *cmpname[4] = {
"cmpw","cmpd","cmplw","cmpld"
};
static const char *b_ext[4] = {
"","l","a","la"
};
static const char *b_condition[8] = {
"ge","le","ne","ns","lt","gt","eq","so"
};
static const char *b_decr[16] = {
"nzf","zf",NULL,NULL,"nzt","zt",NULL,NULL,
"nz","z",NULL,NULL,"nz","z",NULL,NULL
};
static const char *regsel[2] = {
"","r"
};
static const char *oesel[2] = {
"","o"
};
static const char *rcsel[2] = {
"","."
};
static const char *ldstnames[] = {
"lwz","lwzu","lbz","lbzu","stw","stwu","stb","stbu","lhz","lhzu",
"lha","lhau","sth","sthu","lmw","stmw","lfs","lfsu","lfd","lfdu",
"stfs","stfsu","stfd","stfdu"
};
static const char *regnames[] = {
"r0", "sp", "rtoc", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
};
static const char *spr_name(int i)
{
static char def[8];
switch (i)
{
case 1: return "XER";
case 8: return "LR";
case 9: return "CTR";
case 18: return "DSIR";
case 19: return "DAR";
case 22: return "DEC";
case 25: return "SDR1";
case 26: return "SRR0";
case 27: return "SRR1";
case 272: return "SPRG0";
case 273: return "SPRG1";
case 274: return "SPRG2";
case 275: return "SPRG3";
case 282: return "EAR";
case 287: return "PVR";
case 528: return "IBAT0U";
case 529: return "IBAT0L";
case 530: return "IBAT1U";
case 531: return "IBAT1L";
case 532: return "IBAT2U";
case 533: return "IBAT2L";
case 534: return "IBAT3U";
case 535: return "IBAT3L";
case 536: return "DBAT0U";
case 537: return "DBAT0L";
case 538: return "DBAT1U";
case 539: return "DBAT1L";
case 540: return "DBAT2U";
case 541: return "DBAT2L";
case 542: return "DBAT3U";
case 543: return "DBAT3L";
case 912: return "GQR0";
case 913: return "GQR1";
case 914: return "GQR2";
case 915: return "GQR3";
case 916: return "GQR4";
case 917: return "GQR5";
case 918: return "GQR6";
case 919: return "GQR7";
case 920: return "HID2";
case 921: return "WPAR";
case 922: return "DMA_U";
case 923: return "DMA_L";
case 924: return "ECID_U";
case 925: return "ECID_M";
case 926: return "ECID_L";
case 936: return "UMMCR0";
case 937: return "UPMC1";
case 938: return "UPMC2";
case 939: return "USIA";
case 940: return "UMMCR1";
case 941: return "UPMC3";
case 942: return "UPMC4";
case 943: return "USDA";
case 952: return "MMCR0";
case 953: return "PMC1";
case 954: return "PMC2";
case 955: return "SIA";
case 956: return "MMCR1";
case 957: return "PMC3";
case 958: return "PMC4";
case 959: return "SDA";
case 1008: return "HID0";
case 1009: return "HID1";
case 1010: return "IABR";
case 1013: return "DABR";
case 1017: return "L2CR";
case 1019: return "ICTC";
case 1020: return "THRM1";
case 1021: return "THRM2";
case 1022: return "THRM3";
}
sprintf(def, "%i", i);
return def;
}
static void ierror(const char *errtxt,...)
/* display internal error and quit program */
{
va_list vl;
fprintf(stderr,"\nINTERNAL ERROR (PPC disassembler): ");
va_start(vl,errtxt);
vfprintf(stderr,errtxt,vl);
va_end(vl);
fprintf(stderr,".\nAborting.\n");
exit(1);
}
static ppc_word swapda(ppc_word w)
{
return ((w&0xfc00ffff)|((w&PPCAMASK)<<5)|((w&PPCDMASK)>>5));
}
static ppc_word swapab(ppc_word w)
{
return ((w&0xffe007ff)|((w&PPCBMASK)<<5)|((w&PPCAMASK)>>5));
}
static void ill(struct DisasmPara_PPC *dp,ppc_word in)
{
if (in == 0) {
strcpy(dp->opcode, "");
strcpy(dp->operands, "---");
} else {
strcpy(dp->opcode, "( ill )");
sprintf(dp->operands, "%08x", in);
}
dp->flags |= PPCF_ILLEGAL;
}
static void imm(struct DisasmPara_PPC *dp,ppc_word in,int uimm,int type,int hex)
/* Generate immediate instruction operand. */
/* type 0: D-mode, D,A,imm */
/* type 1: S-mode, A,S,imm */
/* type 2: S/D register is ignored (trap,cmpi) */
/* type 3: A register is ignored (li) */
{
int i = (int)(in & 0xffff);
dp->type = PPCINSTR_IMM;
if (!uimm) {
if (i > 0x7fff)
i -= 0x10000;
}
else
dp->flags |= PPCF_UNSIGNED;
dp->displacement = i;
switch (type) {
case 0:
sprintf(dp->operands,"%s, %s, %d",regnames[(int)PPCGETD(in)],regnames[(int)PPCGETA(in)],i);
break;
case 1:
if (hex)
sprintf(dp->operands,"%s, %s, 0x%.4X",regnames[(int)PPCGETA(in)],regnames[(int)PPCGETD(in)],i);
else
sprintf(dp->operands,"%s, %s, %d",regnames[(int)PPCGETA(in)],regnames[(int)PPCGETD(in)],i);
break;
case 2:
sprintf(dp->operands,"%s, %d",regnames[(int)PPCGETA(in)],i);
break;
case 3:
if (hex)
sprintf(dp->operands,"%s, 0x%.4X",regnames[(int)PPCGETD(in)],i);
else
sprintf(dp->operands,"%s, %d",regnames[(int)PPCGETD(in)],i);
break;
default:
ierror("imm(): Wrong type");
break;
}
}
static void ra_rb(char *s,ppc_word in)
{
sprintf(s,"%s, %s",regnames[(int)PPCGETA(in)],regnames[(int)PPCGETB(in)]);
}
static char *rd_ra_rb(char *s,ppc_word in,int mask)
{
static const char *fmt = "%s, ";
if (mask) {
if (mask & 4)
s += sprintf(s,fmt,regnames[(int)PPCGETD(in)]);
if (mask & 2)
s += sprintf(s,fmt,regnames[(int)PPCGETA(in)]);
if (mask & 1)
s += sprintf(s,fmt,regnames[(int)PPCGETB(in)]);
*--s = '\0';
*--s = '\0';
}
else
*s = '\0';
return (s);
}
static char *fd_ra_rb(char *s,ppc_word in,int mask)
{
static const char *ffmt = "f%d,";
static const char *rfmt = "%s,";
if (mask) {
if (mask & 4)
s += sprintf(s,ffmt,(int)PPCGETD(in));
if (mask & 2)
s += sprintf(s,rfmt,regnames[(int)PPCGETA(in)]);
if (mask & 1)
s += sprintf(s,rfmt,regnames[(int)PPCGETB(in)]);
*--s = '\0';
}
else
*s = '\0';
return (s);
}
static void trapi(struct DisasmPara_PPC *dp,ppc_word in,unsigned char dmode)
{
const char *cnd;
if ((cnd = trap_condition[PPCGETD(in)]) != NULL) {
dp->flags |= dmode;
sprintf(dp->opcode,"t%c%s",dmode?'d':'w',cnd);
imm(dp,in,0,2,0);
}
else
ill(dp,in);
}
static void cmpi(struct DisasmPara_PPC *dp,ppc_word in,int uimm)
{
char *oper = dp->operands;
int i = (int)PPCGETL(in);
if (i < 2) {
if (i)
dp->flags |= PPCF_64;
sprintf(dp->opcode,"%si",cmpname[uimm*2+i]);
if ((i = (int)PPCGETCRD(in))) {
sprintf(oper,"cr%c,",'0'+i);
dp->operands += 4;
}
imm(dp,in,uimm,2,0);
dp->operands = oper;
}
else
ill(dp,in);
}
static void addi(struct DisasmPara_PPC *dp,ppc_word in,const char *ext)
{
if ((in&0x08000000) && !PPCGETA(in)) {
sprintf(dp->opcode,"l%s",ext); /* li, lis */
if (!strcmp(ext, "i"))
imm(dp,in,0,3,0);
else
imm(dp,in,1,3,1);
}
else {
sprintf(dp->opcode,"%s%s",(in&0x8000)?"sub":"add",ext);
if (in & 0x8000)
in = (in^0xffff) + 1;
imm(dp,in,1,0,0);
}
}
static int branch(struct DisasmPara_PPC *dp,ppc_word in, const char *bname,int aform,int bdisp)
/* build a branch instr. and return number of chars written to operand */
{
int bo = (int)PPCGETD(in);
int bi = (int)PPCGETA(in);
char y = (char)(bo & 1);
int opercnt = 0;
const char *ext = b_ext[aform*2+(int)(in&1)];
if (bdisp < 0)
y ^= 1;
y = y ? '+':'-';
if (bo & 4) {
/* standard case - no decrement */
if (bo & 16) {
/* branch always */
if (PPCGETIDX(in) != 16) {
sprintf(dp->opcode,"b%s%s",bname,ext);
}
else {
sprintf(dp->opcode,"bc%s",ext);
opercnt = sprintf(dp->operands,"%d, %d",bo,bi);
}
}
else {
/* branch conditional */
sprintf(dp->opcode,"b%s%s%s%c",b_condition[((bo&8)>>1)+(bi&3)],
bname,ext,y);
if (bi >= 4)
opercnt = sprintf(dp->operands,"cr%d",bi>>2);
}
}
else {
/* CTR is decremented and checked */
sprintf(dp->opcode,"bd%s%s%s%c",b_decr[bo>>1],bname,ext,y);
if (!(bo & 16))
opercnt = sprintf(dp->operands,"%d",bi);
}
return (opercnt);
}
static void bc(struct DisasmPara_PPC *dp,ppc_word in)
{
unsigned int d = (int)(in & 0xfffc);
int offs;
char *oper = dp->operands;
if (d & 0x8000) d |= 0xffff0000;
if ((offs = branch(dp,in,"",(in&2)?1:0,d))) {
oper += offs;
*oper++ = ',';
}
if (in & 2) /* AA ? */
sprintf(dp->operands,"->0x%.8X",(unsigned int)d);
else
sprintf(oper,"->0x%.8X",(unsigned int)(*dp->iaddr) + d);
dp->type = PPCINSTR_BRANCH;
dp->displacement = (ppc_word)d;
}
static void bli(struct DisasmPara_PPC *dp,ppc_word in)
{
unsigned int d = (unsigned int)(in & 0x3fffffc);
if (d & 0x02000000) d |= 0xfc000000;
sprintf(dp->opcode,"b%s",b_ext[in&3]);
if (in & 2) /* AA ? */
sprintf(dp->operands,"->0x%.8X",(unsigned int)d);
else
sprintf(dp->operands,"->0x%.8X",(unsigned int)(*dp->iaddr) + d);
dp->type = PPCINSTR_BRANCH;
dp->displacement = (ppc_word)d;
}
static void mcrf(struct DisasmPara_PPC *dp,ppc_word in,char c)
{
if (!(in & 0x0063f801)) {
sprintf(dp->opcode,"mcrf%c",c);
sprintf(dp->operands,"cr%d, cr%d",(int)PPCGETCRD(in),(int)PPCGETCRA(in));
}
else
ill(dp,in);
}
static void crop(struct DisasmPara_PPC *dp,ppc_word in,const char *n1,const char *n2)
{
int crd = (int)PPCGETD(in);
int cra = (int)PPCGETA(in);
int crb = (int)PPCGETB(in);
if (!(in & 1)) {
sprintf(dp->opcode,"cr%s",(cra==crb && n2)?n2:n1);
if (cra == crb && n2)
sprintf(dp->operands,"%d, %d",crd,cra);
else
sprintf(dp->operands,"%d, %d, %d",crd,cra,crb);
}
else
ill(dp,in);
}
static void nooper(struct DisasmPara_PPC *dp,ppc_word in,const char *name,
unsigned char dmode)
{
if (in & (PPCDMASK|PPCAMASK|PPCBMASK|1)) {
ill(dp,in);
}
else {
dp->flags |= dmode;
strcpy(dp->opcode,name);
}
}
static unsigned int Helper_Mask(int mb, int me)
{
//first make 001111111111111 part
unsigned int begin = 0xFFFFFFFF >> mb;
//then make 000000000001111 part, which is used to flip the bits of the first one
unsigned int end = me < 31 ? (0xFFFFFFFF >> (me + 1)) : 0;
//do the bitflip
unsigned int mask = begin ^ end;
//and invert if backwards
if (me < mb)
return ~mask;
else
return mask;
}
static void rlw(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int i)
{
int s = (int)PPCGETD(in);
int a = (int)PPCGETA(in);
int bsh = (int)PPCGETB(in);
int mb = (int)PPCGETC(in);
int me = (int)PPCGETM(in);
sprintf(dp->opcode,"rlw%s%c",name,in&1?'.':'\0');
sprintf(dp->operands,"%s, %s, %s%d, %d, %d (%08x)",regnames[a],regnames[s],regsel[i],bsh,mb,me,Helper_Mask(mb, me));
}
static void ori(struct DisasmPara_PPC *dp,ppc_word in,const char *name)
{
strcpy(dp->opcode,name);
imm(dp,in,1,1,1);
}
static void rld(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int i)
{
int s = (int)PPCGETD(in);
int a = (int)PPCGETA(in);
int bsh = i ? (int)PPCGETB(in) : (int)(((in&2)<<4)+PPCGETB(in));
int m = (int)(in&0x7e0)>>5;
dp->flags |= PPCF_64;
sprintf(dp->opcode,"rld%s%c",name,in&1?'.':'\0');
sprintf(dp->operands,"%s, %s, %s%d, %d",regnames[a],regnames[s],regsel[i],bsh,m);
}
static void cmp(struct DisasmPara_PPC *dp,ppc_word in)
{
char *oper = dp->operands;
int i = (int)PPCGETL(in);
if (i < 2) {
if (i)
dp->flags |= PPCF_64;
strcpy(dp->opcode,cmpname[((in&PPCIDX2MASK)?2:0)+i]);
if ((i = (int)PPCGETCRD(in)))
oper += sprintf(oper,"cr%c,",'0'+i);
ra_rb(oper,in);
}
else
ill(dp,in);
}
static void trap(struct DisasmPara_PPC *dp,ppc_word in,unsigned char dmode)
{
const char *cnd;
int to = (int)PPCGETD(in);
if ((cnd = trap_condition[to])) {
dp->flags |= dmode;
sprintf(dp->opcode,"t%c%s",dmode?'d':'w',cnd);
ra_rb(dp->operands,in);
}
else {
if (to == 31) {
if (dmode) {
dp->flags |= dmode;
strcpy(dp->opcode,"td");
strcpy(dp->operands,"31,0,0");
}
else
strcpy(dp->opcode,"trap");
}
else
ill(dp,in);
}
}
static void dab(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int mask,
int smode,int chkoe,int chkrc,unsigned char dmode)
/* standard instruction: xxxx rD,rA,rB */
{
if (chkrc>=0 && ((in&1)!=(unsigned)chkrc)) {
ill(dp,in);
}
else {
dp->flags |= dmode;
if (smode)
in = swapda(in); /* rA,rS,rB */
sprintf(dp->opcode,"%s%s%s",name,
oesel[chkoe&&(in&PPCOE)],rcsel[(chkrc<0)&&(in&1)]);
rd_ra_rb(dp->operands,in,mask);
}
}
static void rrn(struct DisasmPara_PPC *dp,ppc_word in,const char *name,
int smode,int chkoe,int chkrc,unsigned char dmode)
/* Last operand is no register: xxxx rD,rA,NB */
{
char *s;
if (chkrc>=0 && ((in&1)!=(unsigned)chkrc)) {
ill(dp,in);
}
else {
dp->flags |= dmode;
if (smode)
in = swapda(in); /* rA,rS,NB */
sprintf(dp->opcode,"%s%s%s",name,
oesel[chkoe&&(in&PPCOE)],rcsel[(chkrc<0)&&(in&1)]);
s = rd_ra_rb(dp->operands,in,6);
sprintf(s,",%d",(int)PPCGETB(in));
}
}
static void mtcr(struct DisasmPara_PPC *dp,ppc_word in)
{
int s = (int)PPCGETD(in);
int crm = (int)(in&0x000ff000)>>12;
char *oper = dp->operands;
if (in & 0x00100801) {
ill(dp,in);
}
else {
sprintf(dp->opcode,"mtcr%c",crm==0xff?'\0':'f');
if (crm != 0xff)
oper += sprintf(oper,"0x%02x,",crm);
sprintf(oper,"%s",regnames[s]);
}
}
static void msr(struct DisasmPara_PPC *dp,ppc_word in,int smode)
{
int s = (int)PPCGETD(in);
int sr = (int)(in&0x000f0000)>>16;
if (in & 0x0010f801) {
ill(dp,in);
}
else {
dp->flags |= PPCF_SUPER;
sprintf(dp->opcode,"m%csr",smode?'t':'f');
if (smode)
sprintf(dp->operands,"%d, %s",sr,regnames[s]);
else
sprintf(dp->operands,"%s, %d",regnames[s],sr);
}
}
static void mspr(struct DisasmPara_PPC *dp,ppc_word in,int smode)
{
int d = (int)PPCGETD(in);
int spr = (int)((PPCGETB(in)<<5)+PPCGETA(in));
int fmt = 0;
const char *x;
if (in & 1) {
ill(dp,in);
}
else {
if (spr!=1 && spr!=8 && spr!=9)
dp->flags |= PPCF_SUPER;
switch (spr) {
case 1:
x = "xer";
break;
case 8:
x = "lr";
break;
case 9:
x = "ctr";
break;
default:
x = "spr";
fmt = 1;
break;
}
sprintf(dp->opcode,"m%c%s",smode?'t':'f',x);
if (fmt) {
if (smode)
sprintf(dp->operands,"%s, %s",spr_name(spr),regnames[d]);
else
sprintf(dp->operands,"%s, %s",regnames[d],spr_name(spr));
}
else
sprintf(dp->operands,"%s",regnames[d]);
}
}
static void mtb(struct DisasmPara_PPC *dp,ppc_word in)
{
int d = (int)PPCGETD(in);
int tbr = (int)((PPCGETB(in)<<5)+PPCGETA(in));
char *s = dp->operands;
char x;
if (in & 1) {
ill(dp,in);
}
else {
s += sprintf(s,"%s",regnames[d]);
switch (tbr) {
case 268:
x = 'l';
break;
case 269:
x = 'u';
break;
default:
x = '\0';
dp->flags |= PPCF_SUPER;
sprintf(s,",%d",tbr);
break;
}
sprintf(dp->opcode,"mftb%c",x);
}
}
static void sradi(struct DisasmPara_PPC *dp,ppc_word in)
{
int s = (int)PPCGETD(in);
int a = (int)PPCGETA(in);
int bsh = (int)(((in&2)<<4)+PPCGETB(in));
dp->flags |= PPCF_64;
sprintf(dp->opcode,"sradi%c",in&1?'.':'\0');
sprintf(dp->operands,"%s, %s, %d",regnames[a],regnames[s],bsh);
}
static const char *ldst_offs(unsigned int val)
{
static char buf[8];
if (val == 0)
{
return "0";
}
else
{
if (val & 0x8000)
{
sprintf(buf, "-0x%.4X", ((~val) & 0xffff) + 1);
}
else
{
sprintf(buf, "0x%.4X", val);
}
return buf;
}
}
static void ldst(struct DisasmPara_PPC *dp,ppc_word in,const char *name,
char reg,unsigned char dmode)
{
int s = (int)PPCGETD(in);
int a = (int)PPCGETA(in);
int d = (ppc_word)(in & 0xffff);
dp->type = PPCINSTR_LDST;
dp->flags |= dmode;
dp->sreg = (short)a;
// if (d >= 0x8000)
// d -= 0x10000;
dp->displacement = (ppc_word)d;
strcpy(dp->opcode,name);
if (reg == 'r')
{
sprintf(dp->operands,"%s, %s (%s)", regnames[s], ldst_offs(d), regnames[a]);
}
else
{
sprintf(dp->operands,"%c%d, %s (%s)",reg,s, ldst_offs(d), regnames[a]);
}
}
static void fdabc(struct DisasmPara_PPC *dp,ppc_word in, const char *name,
int mask,unsigned char dmode)
/* standard floating point instruction: xxxx fD,fA,fC,fB */
{
static const char *fmt = "f%d,";
char *s = dp->operands;
int err = 0;
dp->flags |= dmode;
sprintf(dp->opcode,"f%s%s",name,rcsel[in&1]);
s += sprintf(s,fmt,(int)PPCGETD(in));
if (mask & 4)
s += sprintf(s,fmt,(int)PPCGETA(in));
else
err |= (int)PPCGETA(in);
if (mask & 2)
s += sprintf(s,fmt,(int)PPCGETC(in));
else if (PPCGETC(in))
err |= (int)PPCGETC(in);
if (mask & 1)
s += sprintf(s,fmt,(int)PPCGETB(in));
else if (!(mask&8))
err |= (int)PPCGETB(in);
*(s-1) = '\0';
if (err)
ill(dp,in);
}
static void fmr(struct DisasmPara_PPC *dp,ppc_word in)
{
sprintf(dp->opcode, "fmr%s", rcsel[in&1]);
sprintf(dp->operands, "f%d, f%d", (int)PPCGETD(in), (int)PPCGETB(in));
}
static void fdab(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int mask)
/* indexed float instruction: xxxx fD,rA,rB */
{
strcpy(dp->opcode,name);
fd_ra_rb(dp->operands,in,mask);
}
static void fcmp(struct DisasmPara_PPC *dp,ppc_word in,char c)
{
if (in & 0x00600001) {
ill(dp,in);
}
else {
sprintf(dp->opcode,"fcmp%c",c);
sprintf(dp->operands,"cr%d,f%d,f%d",(int)PPCGETCRD(in),
(int)PPCGETA(in),(int)PPCGETB(in));
}
}
static void mtfsb(struct DisasmPara_PPC *dp,ppc_word in,int n)
{
if (in & (PPCAMASK|PPCBMASK)) {
ill(dp,in);
}
else {
sprintf(dp->opcode,"mtfsb%d%s",n,rcsel[in&1]);
sprintf(dp->operands,"%d",(int)PPCGETD(in));
}
}
//////////////////////////////////////////////////////////////////////////////////
//PAIRED
//////////////////////////////////////////////////////////////////////////////////
/*
sprintf(buf, "psq_lx", FD);
sprintf(buf, "psq_stx", FD);
sprintf(buf, "psq_lux", FD);
sprintf(buf, "psq_stux", FD);
*/
#define RA ((inst >> 16) & 0x1f)
#define RB ((inst >> 11) & 0x1f)
#define RC ((inst >> 6) & 0x1f)
#define RD ((inst >> 21) & 0x1f)
#define RS ((inst >> 21) & 0x1f)
#define FA ((inst >> 16) & 0x1f)
#define FB ((inst >> 11) & 0x1f)
#define FC ((inst >> 6) & 0x1f)
#define FD ((inst >> 21) & 0x1f)
#define FS ((inst >> 21) & 0x1f)
#define IMM (inst & 0xffff)
#define UIMM (inst & 0xffff)
#define OFS (inst & 0xffff)
#define OPCD ((inst >> 26) & 0x3f)
#define XO_10 ((inst >> 1) & 0x3ff)
#define XO_9 ((inst >> 1) & 0x1ff)
#define XO_5 ((inst >> 1) & 0x1f)
#define Rc (inst & 1)
#define SH ((inst >> 11) & 0x1f)
#define MB ((inst >> 6) & 0x1f)
#define ME ((inst >> 1) & 0x1f)
#define OE ((inst >> 10) & 1)
#define TO ((inst >> 21) & 0x1f)
#define CRFD ((inst >> 23) & 0x7)
#define CRFS ((inst >> 18) & 0x7)
#define CRBD ((inst >> 21) & 0x1f)
#define CRBA ((inst >> 16) & 0x1f)
#define CRBB ((inst >> 11) & 0x1f)
#define L ((inst >> 21) & 1)
#define NB ((inst >> 11) & 0x1f)
#define AA ((inst >> 1) & 1)
#define LK (inst & 1)
#define LI ((inst >> 2) & 0xffffff)
#define BO ((inst >> 21) & 0x1f)
#define BI ((inst >> 16) & 0x1f)
#define BD ((inst >> 2) & 0x3fff)
#define MTFSFI_IMM ((inst >> 12) & 0xf)
#define FM ((inst >> 17) & 0xff)
#define SR ((inst >> 16) & 0xf)
#define SPR ((inst >> 11) & 0x3ff)
#define TBR ((inst >> 11) & 0x3ff)
#define CRM ((inst >> 12) & 0xff)
inline int SEX12(unsigned int x)
{
return x & 0x800 ? (x|0xFFFFF000) : x;
}
static void ps(struct DisasmPara_PPC *dp,ppc_word inst)
{
char *op = dp->opcode;
char *pr = dp->operands;
switch ((inst>>1)&0x1F)
{
case 6:
strcpy(op, "ps_lux");
sprintf(pr, "p%u, (r%u + r%u)", FD, RA, RB);
return;
case 18:
strcpy(op, "ps_div");
sprintf(pr, "p%u, p%u/p%u", FD, FA, FB);
return;
case 20:
strcpy(op, "ps_sub");
sprintf(pr, "p%u, p%u-p%u", FD, FA, FB);
return;
case 21:
strcpy(op, "ps_add");
sprintf(pr, "p%u, p%u+p%u", FD, FA, FB);
return;
case 23:
strcpy(op, "ps_sel");
sprintf(pr, "p%u>=0?p%u:p%u", FD, FA, FC);
return;
case 24:
strcpy(op, "ps_res");
sprintf(pr, "p%u, (1/p%u)", FD, FB);
return;
case 25:
strcpy(op, "ps_mul");
sprintf(pr, "p%u, p%u*p%u", FD, FA, FC);
return;
case 26: //rsqrte
strcpy(op, "ps_rsqrte");
sprintf(pr, "p%u, p%u", FD, FB);
return;
case 28: //msub
strcpy(op, "ps_msub");
sprintf(pr, "p%u, p%u*p%u-p%u", FD, FA, FC, FB);
return;
case 29: //madd
strcpy(op, "ps_madd");
sprintf(pr, "p%u, p%u*p%u+p%u", FD, FA, FC, FB);
return;
case 30: //nmsub
strcpy(op, "ps_nmsub");
sprintf(pr, "p%u, -(p%u*p%u-p%u)", FD, FA, FC, FB);
return;
case 31: //nmadd
strcpy(op, "ps_nmadd");
sprintf(pr, "p%u, -(p%u*p%u+p%u)", FD, FA, FC, FB);
return;
case 10:
strcpy(op, "ps_sum0");
sprintf(pr, "p%u, 0=p%u+p%u, 1=p%u", FD, FA, FB, FC);
return;
case 11:
strcpy(op, "ps_sum1");
sprintf(pr, "p%u, 0=p%u, 1=p%u+p%u", FD, FC, FA, FB);
return;
case 12:
strcpy(op, "ps_muls0");
sprintf(pr, "p%u, p%u*p%u[0]", FD, FA, FC);
return;
case 13:
strcpy(op, "ps_muls1");
sprintf(pr, "p%u, p%u*p%u[1]", FD, FA, FC);
return;
case 14:
strcpy(op, "ps_madds0");
sprintf(pr, "p%u, p%u*p%u[0]+p%u", FD, FA, FC, FB);
return;
case 15:
strcpy(op, "ps_madds1");
sprintf(pr, "p%u, p%u*p%u[1]+p%u", FD, FA, FC, FB);
return;
}
switch ((inst>>1)&0x3FF)
{
//10-bit suckers (?)
case 40: //nmadd
strcpy(op, "ps_neg");
sprintf(pr, "p%u, -p%u", FD, FB);
return;
case 72: //nmadd
strcpy(op, "ps_mr");
sprintf(pr, "p%u, p%u", FD, FB);
return;
case 136:
strcpy(op, "ps_nabs");
sprintf(pr, "p%u, -|p%u|", FD, FB);
return;
case 264:
strcpy(op, "ps_abs");
sprintf(pr, "p%u, |p%u|", FD, FB);
return;
case 0:
strcpy(op, "ps_cmpu0");
sprintf(pr, "ps_cmpu0");
return;
case 32:
strcpy(op,"ps_cmpq0");
sprintf(pr, "ps_cmpo0");
return;
case 64:
strcpy(op,"ps_cmpu1");
sprintf(pr, "ps_cmpu1");
return;
case 96:
strcpy(op,"ps_cmpo1");
sprintf(pr, "ps_cmpo1");
return;
case 528:
strcpy(op,"ps_merge00");
sprintf(pr, "p%u, p%u[0],p%u[0]", FD, FA, FB);
return;
case 560:
strcpy(op,"ps_merge01");
sprintf(pr, "p%u, p%u[0],p%u[1]", FD, FA, FB);
return;
case 592:
strcpy(op,"ps_merge10");
sprintf(pr, "p%u, p%u[1],p%u[0]", FD, FA, FB);
return;
case 624:
strcpy(op,"ps_merge11");
sprintf(pr, "p%u, p%u[1],p%u[1]", FD, FA, FB);
return;
case 1014:
strcpy(op,"dcbz_l");
*pr = '\0';
return;
}
// default:
sprintf(op, "ps_%i",((inst>>1)&0x1f));
strcpy(pr,"---");
return;
}
static void ps_mem(struct DisasmPara_PPC *dp,ppc_word inst)
{
char *op = dp->opcode;
char *pr = dp->operands;
switch (PPCGETIDX(inst))
{
case 56:
strcpy(op,"psq_l");
sprintf(pr, "p%u, %i(r%u)", RS, SEX12(inst&0xFFF), RA);
break;
case 57:
strcpy(op,"psq_lu");
*pr = '\0';
break;
case 60:
strcpy(op,"psq_st");
sprintf(pr, "%i(r%u), p%u", SEX12(inst&0xFFF), RA, RS);
break;
case 61:
strcpy(op,"psq_stu");
sprintf(pr, "r%u, p%u ?", RA, RS);
break;
}
}
ppc_word *PPC_Disassemble(struct DisasmPara_PPC *dp)
/* Disassemble PPC instruction and return a pointer to the next */
/* instruction, or NULL if an error occured. */
{
ppc_word in = *(dp->instr);
if (!dp->opcode || !dp->operands)
return NULL; /* no buffers */
#if LITTLEENDIAN
in = (in & 0xff)<<24 | (in & 0xff00)<<8 | (in & 0xff0000)>>8 |
(in & 0xff000000)>>24;
#endif
dp->type = PPCINSTR_OTHER;
dp->flags = 0;
*(dp->operands) = 0;
switch (PPCGETIDX(in))
{
case 0:
{
int block = in & 0x3FFFFFF;
if (block) {
sprintf(dp->opcode, "JITblock");
sprintf(dp->operands, "%i", block);
} else {
strcpy(dp->opcode, "");
strcpy(dp->operands, "---");
}
}
break;
case 1:
sprintf(dp->opcode,"HLE");
//HLE call
break;
case 2:
trapi(dp,in,PPCF_64); /* tdi */
break;
case 3:
trapi(dp,in,0); /* twi */
break;
case 4:
ps(dp,in);
break;
case 56:
case 57:
case 60:
case 61:
ps_mem(dp,in);
break;
case 7:
strcpy(dp->opcode,"mulli");
imm(dp,in,0,0,0);
break;
case 8:
strcpy(dp->opcode,"subfic");
imm(dp,in,0,0,0);
break;
case 10:
cmpi(dp,in,1); /* cmpli */
break;
case 11:
cmpi(dp,in,0); /* cmpi */
break;
case 12:
addi(dp,in,"ic"); /* addic */
break;
case 13:
addi(dp,in,"ic."); /* addic. */
break;
case 14:
addi(dp,in,"i"); /* addi */
break;
case 15:
addi(dp,in,"is"); /* addis */
break;
case 16:
bc(dp,in);
break;
case 17:
if ((in & ~PPCIDXMASK) == 2)
strcpy(dp->opcode,"sc");
else
ill(dp,in);
break;
case 18:
bli(dp,in);
break;
case 19:
switch (PPCGETIDX2(in)) {
case 0:
mcrf(dp,in,'\0'); /* mcrf */
break;
case 16:
branch(dp,in,"lr",0,0); /* bclr */
break;
case 33:
crop(dp,in,"nor","not"); /* crnor */
break;
case 50:
nooper(dp,in,"rfi",PPCF_SUPER);
break;
case 129:
crop(dp,in,"andc",NULL); /* crandc */
break;
case 150:
nooper(dp,in,"isync",0);
break;
case 193:
crop(dp,in,"xor","clr"); /* crxor */
break;
case 225:
crop(dp,in,"nand",NULL); /* crnand */
break;
case 257:
crop(dp,in,"and",NULL); /* crand */
break;
case 289:
crop(dp,in,"eqv","set"); /* creqv */
break;
case 417:
crop(dp,in,"orc",NULL); /* crorc */
break;
case 449:
crop(dp,in,"or","move"); /* cror */
break;
case 528:
branch(dp,in,"ctr",0,0); /* bcctr */
break;
default:
ill(dp,in);
break;
}
break;
case 20:
rlw(dp,in,"imi",0); /* rlwimi */
break;
case 21:
rlw(dp,in,"inm",0); /* rlwinm */
break;
case 23:
rlw(dp,in,"nm",1); /* rlwnm */
break;
case 24:
if (in & ~PPCIDXMASK)
ori(dp,in,"ori");
else
strcpy(dp->opcode,"nop");
break;
case 25:
ori(dp,in,"oris");
break;
case 26:
ori(dp,in,"xori");
break;
case 27:
ori(dp,in,"xoris");
break;
case 28:
ori(dp,in,"andi.");
break;
case 29:
ori(dp,in,"andis.");
break;
case 30:
switch (in & 0x1c) {
case 0:
rld(dp,in,"icl",0); /* rldicl */
break;
case 1:
rld(dp,in,"icr",0); /* rldicr */
break;
case 2:
rld(dp,in,"ic",0); /* rldic */
break;
case 3:
rld(dp,in,"imi",0); /* rldimi */
break;
case 4:
rld(dp,in,in&2?"cl":"cr",1); /* rldcl, rldcr */
break;
default:
ill(dp,in);
break;
}
break;
case 31:
switch (PPCGETIDX2(in)) {
case 0:
case 32:
if (in & 1)
ill(dp,in);
else
cmp(dp,in); /* cmp, cmpl */
break;
case 4:
if (in & 1)
ill(dp,in);
else
trap(dp,in,0); /* tw */
break;
case 8:
case (PPCOE>>1)+8:
dab(dp,swapab(in),"subc",7,0,1,-1,0);
break;
case 9:
dab(dp,in,"mulhdu",7,0,0,-1,PPCF_64);
break;
case 10:
case (PPCOE>>1)+10:
dab(dp,in,"addc",7,0,1,-1,0);
break;
case 11:
dab(dp,in,"mulhwu",7,0,0,-1,0);
break;
case 19:
if (in & (PPCAMASK|PPCBMASK))
ill(dp,in);
else
dab(dp,in,"mfcr",4,0,0,0,0);
break;
case 20:
dab(dp,in,"lwarx",7,0,0,0,0);
break;
case 21:
dab(dp,in,"ldx",7,0,0,0,PPCF_64);
break;
case 23:
dab(dp,in,"lwzx",7,0,0,0,0);
break;
case 24:
dab(dp,in,"slw",7,1,0,-1,0);
break;
case 26:
if (in & PPCBMASK)
ill(dp,in);
else
dab(dp,in,"cntlzw",6,1,0,-1,0);
break;
case 27:
dab(dp,in,"sld",7,1,0,-1,PPCF_64);
break;
case 28:
dab(dp,in,"and",7,1,0,-1,0);
break;
case 40:
case (PPCOE>>1)+40:
dab(dp,swapab(in),"sub",7,0,1,-1,0);
break;
case 53:
dab(dp,in,"ldux",7,0,0,0,PPCF_64);
break;
case 54:
if (in & PPCDMASK)
ill(dp,in);
else
dab(dp,in,"dcbst",3,0,0,0,0);
break;
case 55:
dab(dp,in,"lwzux",7,0,0,0,0);
break;
case 58:
if (in & PPCBMASK)
ill(dp,in);
else
dab(dp,in,"cntlzd",6,1,0,-1,PPCF_64);
break;
case 60:
dab(dp,in,"andc",7,1,0,-1,0);
break;
case 68:
trap(dp,in,PPCF_64); /* td */
break;
case 73:
dab(dp,in,"mulhd",7,0,0,-1,PPCF_64);
break;
case 75:
dab(dp,in,"mulhw",7,0,0,-1,0);
break;
case 83:
if (in & (PPCAMASK|PPCBMASK))
ill(dp,in);
else
dab(dp,in,"mfmsr",4,0,0,0,PPCF_SUPER);
break;
case 84:
dab(dp,in,"ldarx",7,0,0,0,PPCF_64);
break;
case 86:
if (in & PPCDMASK)
ill(dp,in);
else
dab(dp,in,"dcbf",3,0,0,0,0);
break;
case 87:
dab(dp,in,"lbzx",7,0,0,0,0);
break;
case 104:
case (PPCOE>>1)+104:
if (in & PPCBMASK)
ill(dp,in);
else
dab(dp,in,"neg",6,0,1,-1,0);
break;
case 119:
dab(dp,in,"lbzux",7,0,0,0,0);
break;
case 124:
if (PPCGETD(in) == PPCGETB(in))
dab(dp,in,"not",6,1,0,-1,0);
else
dab(dp,in,"nor",7,1,0,-1,0);
break;
case 136:
case (PPCOE>>1)+136:
dab(dp,in,"subfe",7,0,1,-1,0);
break;
case 138:
case (PPCOE>>1)+138:
dab(dp,in,"adde",7,0,1,-1,0);
break;
case 144:
mtcr(dp,in);
break;
case 146:
if (in & (PPCAMASK|PPCBMASK))
ill(dp,in);
else
dab(dp,in,"mtmsr",4,0,0,0,PPCF_SUPER);
break;
case 149:
dab(dp,in,"stdx",7,0,0,0,PPCF_64);
break;
case 150:
dab(dp,in,"stwcx.",7,0,0,1,0);
break;
case 151:
dab(dp,in,"stwx",7,0,0,0,0);
break;
case 181:
dab(dp,in,"stdux",7,0,0,0,PPCF_64);
break;
case 183:
dab(dp,in,"stwux",7,0,0,0,0);
break;
case 200:
case (PPCOE>>1)+200:
if (in & PPCBMASK)
ill(dp,in);
else
dab(dp,in,"subfze",6,0,1,-1,0);
break;
case 202:
case (PPCOE>>1)+202:
if (in & PPCBMASK)
ill(dp,in);
else
dab(dp,in,"addze",6,0,1,-1,0);
break;
case 210:
msr(dp,in,1); /* mfsr */
break;
case 214:
dab(dp,in,"stdcx.",7,0,0,1,PPCF_64);
break;
case 215:
dab(dp,in,"stbx",7,0,0,0,0);
break;
case 232:
case (PPCOE>>1)+232:
if (in & PPCBMASK)
ill(dp,in);
else
dab(dp,in,"subfme",6,0,1,-1,0);
break;
case 233:
case (PPCOE>>1)+233:
dab(dp,in,"mulld",7,0,1,-1,PPCF_64);
break;
case 234:
case (PPCOE>>1)+234:
if (in & PPCBMASK)
ill(dp,in);
else
dab(dp,in,"addme",6,0,1,-1,0);
break;
case 235:
case (PPCOE>>1)+235:
dab(dp,in,"mullw",7,0,1,-1,0);
break;
case 242:
if (in & PPCAMASK)
ill(dp,in);
else
dab(dp,in,"mtsrin",5,0,0,0,PPCF_SUPER);
break;
case 246:
if (in & PPCDMASK)
ill(dp,in);
else
dab(dp,in,"dcbtst",3,0,0,0,0);
break;
case 247:
dab(dp,in,"stbux",7,0,0,0,0);
break;
case 266:
case (PPCOE>>1)+266:
dab(dp,in,"add",7,0,1,-1,0);
break;
case 278:
if (in & PPCDMASK)
ill(dp,in);
else
dab(dp,in,"dcbt",3,0,0,0,0);
break;
case 279:
dab(dp,in,"lhzx",7,0,0,0,0);
break;
case 284:
dab(dp,in,"eqv",7,1,0,-1,0);
break;
case 306:
if (in & (PPCDMASK|PPCAMASK))
ill(dp,in);
else
dab(dp,in,"tlbie",1,0,0,0,PPCF_SUPER);
break;
case 310:
dab(dp,in,"eciwx",7,0,0,0,0);
break;
case 311:
dab(dp,in,"lhzux",7,0,0,0,0);
break;
case 316:
dab(dp,in,"xor",7,1,0,-1,0);
break;
case 339:
mspr(dp,in,0); /* mfspr */
break;
case 341:
dab(dp,in,"lwax",7,0,0,0,PPCF_64);
break;
case 343:
dab(dp,in,"lhax",7,0,0,0,0);
break;
case 370:
nooper(dp,in,"tlbia",PPCF_SUPER);
break;
case 371:
mtb(dp,in); /* mftb */
break;
case 373:
dab(dp,in,"lwaux",7,0,0,0,PPCF_64);
break;
case 375:
dab(dp,in,"lhaux",7,0,0,0,0);
break;
case 407:
dab(dp,in,"sthx",7,0,0,0,0);
break;
case 412:
dab(dp,in,"orc",7,1,0,-1,0);
break;
case 413:
sradi(dp,in); /* sradi */
break;
case 434:
if (in & (PPCDMASK|PPCAMASK))
ill(dp,in);
else
dab(dp,in,"slbie",1,0,0,0,PPCF_SUPER|PPCF_64);
break;
case 438:
dab(dp,in,"ecowx",7,0,0,0,0);
break;
case 439:
dab(dp,in,"sthux",7,0,0,0,0);
break;
case 444:
if (PPCGETD(in) == PPCGETB(in))
dab(dp,in,"mr",6,1,0,-1,0);
else
dab(dp,in,"or",7,1,0,-1,0);
break;
case 457:
case (PPCOE>>1)+457:
dab(dp,in,"divdu",7,0,1,-1,PPCF_64);
break;
case 459:
case (PPCOE>>1)+459:
dab(dp,in,"divwu",7,0,1,-1,0);
break;
case 467:
mspr(dp,in,1); /* mtspr */
break;
case 470:
if (in & PPCDMASK)
ill(dp,in);
else
dab(dp,in,"dcbi",3,0,0,0,0);
break;
case 476:
dab(dp,in,"nand",7,1,0,-1,0);
break;
case 489:
case (PPCOE>>1)+489:
dab(dp,in,"divd",7,0,1,-1,PPCF_64);
break;
case 491:
case (PPCOE>>1)+491:
dab(dp,in,"divw",7,0,1,-1,0);
break;
case 498:
nooper(dp,in,"slbia",PPCF_SUPER|PPCF_64);
break;
case 512:
if (in & 0x007ff801)
ill(dp,in);
else {
strcpy(dp->opcode,"mcrxr");
sprintf(dp->operands,"cr%d",(int)PPCGETCRD(in));
}
break;
case 533:
dab(dp,in,"lswx",7,0,0,0,0);
break;
case 534:
dab(dp,in,"lwbrx",7,0,0,0,0);
break;
case 535:
fdab(dp,in,"lfsx",7);
break;
case 536:
dab(dp,in,"srw",7,1,0,-1,0);
break;
case 539:
dab(dp,in,"srd",7,1,0,-1,PPCF_64);
break;
case 566:
nooper(dp,in,"tlbsync",PPCF_SUPER);
break;
case 567:
fdab(dp,in,"lfsux",7);
break;
case 595:
msr(dp,in,0); /* mfsr */
break;
case 597:
rrn(dp,in,"lswi",0,0,0,0);
break;
case 598:
nooper(dp,in,"sync",PPCF_SUPER);
break;
case 599:
fdab(dp,in,"lfdx",7);
break;
case 631:
fdab(dp,in,"lfdux",7);
break;
case 659:
if (in & PPCAMASK)
ill(dp,in);
else
dab(dp,in,"mfsrin",5,0,0,0,PPCF_SUPER);
break;
case 661:
dab(dp,in,"stswx",7,0,0,0,0);
break;
case 662:
dab(dp,in,"stwbrx",7,0,0,0,0);
break;
case 663:
fdab(dp,in,"stfsx",7);
break;
case 695:
fdab(dp,in,"stfsux",7);
break;
case 725:
rrn(dp,in,"stswi",0,0,0,0);
break;
case 727:
fdab(dp,in,"stfdx",7);
break;
case 759:
fdab(dp,in,"stfdux",7);
break;
case 790:
dab(dp,in,"lhbrx",7,0,0,0,0);
break;
case 792:
dab(dp,in,"sraw",7,1,0,-1,0);
break;
case 794:
dab(dp,in,"srad",7,1,0,-1,PPCF_64);
break;
case 824:
rrn(dp,in,"srawi",1,0,-1,0);
break;
case 854:
nooper(dp,in,"eieio",PPCF_SUPER);
break;
case 918:
dab(dp,in,"sthbrx",7,0,0,0,0);
break;
case 922:
if (in & PPCBMASK)
ill(dp,in);
else
dab(dp,in,"extsh",6,1,0,-1,0);
break;
case 954:
if (in & PPCBMASK)
ill(dp,in);
else
dab(dp,in,"extsb",6,1,0,-1,0);
break;
case 982:
if (in & PPCDMASK)
ill(dp,in);
else
dab(dp,in,"icbi",3,0,0,0,0);
break;
case 983:
fdab(dp,in,"stfiwx",7);
break;
case 986:
if (in & PPCBMASK)
ill(dp,in);
else
dab(dp,in,"extsw",6,1,0,-1,PPCF_64);
break;
case 1014:
if (in & PPCDMASK)
ill(dp,in);
else
dab(dp,in,"dcbz",3,0,0,0,0);
break;
default:
ill(dp,in);
break;
}
break;
case 32:
case 33:
case 34:
case 35:
case 36:
case 37:
case 38:
case 39:
case 40:
case 41:
case 42:
case 43:
case 44:
case 45:
case 46:
case 47:
ldst(dp,in,ldstnames[PPCGETIDX(in)-32],'r',0);
break;
case 48:
case 49:
case 50:
case 51:
case 52:
case 53:
case 54:
case 55:
ldst(dp,in,ldstnames[PPCGETIDX(in)-32],'f',0);
break;
case 58:
switch (in & 3) {
case 0:
ldst(dp,in&~3,"ld",'r',PPCF_64);
break;
case 1:
ldst(dp,in&~3,"ldu",'r',PPCF_64);
break;
case 2:
ldst(dp,in&~3,"lwa",'r',PPCF_64);
break;
default:
ill(dp,in);
break;
}
break;
case 59:
switch (in & 0x3e) {
case 36:
fdabc(dp,in,"divs",5,0);
break;
case 40:
fdabc(dp,in,"subs",5,0);
break;
case 42:
fdabc(dp,in,"adds",5,0);
break;
case 44:
fdabc(dp,in,"sqrts",2,0);
break;
case 48:
fdabc(dp,in,"res",2,0);
break;
case 50:
fdabc(dp,in,"muls",6,0);
break;
case 56:
fdabc(dp,in,"msubs",7,0);
break;
case 58:
fdabc(dp,in,"madds",7,0);
break;
case 60:
fdabc(dp,in,"nmsubs",7,0);
break;
case 62:
fdabc(dp,in,"nmadds",7,0);
break;
default:
ill(dp,in);
break;
}
break;
case 62:
switch (in & 3) {
case 0:
ldst(dp,in&~3,"std",'r',PPCF_64);
break;
case 1:
ldst(dp,in&~3,"stdu",'r',PPCF_64);
break;
default:
ill(dp,in);
break;
}
break;
case 63:
if (in & 32) {
switch (in & 0x1e) {
case 4:
fdabc(dp,in,"div",5,0);
break;
case 8:
fdabc(dp,in,"sub",5,0);
break;
case 10:
fdabc(dp,in,"add",5,0);
break;
case 12:
fdabc(dp,in,"sqrt",2,0);
break;
case 14:
fdabc(dp,in,"sel",7,0);
break;
case 18:
fdabc(dp,in,"mul",6,0);
break;
case 20:
fdabc(dp,in,"rsqrte",1,0);
break;
case 24:
fdabc(dp,in,"msub",7,0);
break;
case 26:
fdabc(dp,in,"madd",7,0);
break;
case 28:
fdabc(dp,in,"nmsub",7,0);
break;
case 30:
fdabc(dp,in,"nmadd",7,0);
break;
case 52:
sprintf(dp->opcode, "XXX dp 52");
break;
default:
ill(dp,in);
break;
}
}
else {
switch (PPCGETIDX2(in)) {
case 0:
fcmp(dp,in,'u');
break;
case 12:
fdabc(dp,in,"rsp",1,0); // 10
break;
case 14:
fdabc(dp,in,"ctiw",1,0); // 10
break;
case 15:
fdabc(dp,in,"ctiwz",1,0); // 10
break;
case 32:
fcmp(dp,in,'o');
break;
case 38:
mtfsb(dp,in,1);
break;
case 40:
fdabc(dp,in,"neg",10,0);
break;
case 64:
mcrf(dp,in,'s'); /* mcrfs */
break;
case 70:
mtfsb(dp,in,0);
break;
case 72:
fmr(dp,in);
break;
case 134:
if (!(in & 0x006f0800)) {
sprintf(dp->opcode,"mtfsfi%s",rcsel[in&1]);
sprintf(dp->operands,"cr%d,%d",(int)PPCGETCRD(in),
(int)(in & 0xf000)>>12);
}
else
ill(dp,in);
break;
case 136:
fdabc(dp,in,"nabs",10,0);
break;
case 264:
fdabc(dp,in,"abs",10,0);
break;
case 583:
if (in & (PPCAMASK|PPCBMASK))
ill(dp,in);
else
dab(dp,in,"mffs",4,0,0,-1,0);
break;
case 711:
if (!(in & 0x02010000)) {
sprintf(dp->opcode,"mtfsf%s",rcsel[in&1]);
sprintf(dp->operands,"0x%x,%d",
(unsigned)(in & 0x01fe)>>17,(int)PPCGETB(in));
}
else
ill(dp,in);
break;
case 814:
fdabc(dp,in,"fctid",10,PPCF_64);
break;
case 815:
fdabc(dp,in,"fctidz",10,PPCF_64);
break;
case 846:
fdabc(dp,in,"fcfid",10,PPCF_64);
break;
default:
ill(dp,in);
break;
}
}
break;
default:
ill(dp,in);
break;
}
return (dp->instr + 1);
}
} // namespace
// What were MS thinking?
#ifdef _WIN32
#define snprintf _snprintf
#endif
// simplified interface
void DisassembleGekko(unsigned int opcode, unsigned int curInstAddr, char *dest, int max_size)
{
char opcodeStr[64], operandStr[64];
PPCDisasm::DisasmPara_PPC dp;
unsigned int opc, adr;
opc = opcode;
adr = curInstAddr;
dp.opcode = opcodeStr;
dp.operands = operandStr;
dp.instr = (PPCDisasm::ppc_word *)&opc;
dp.iaddr = (PPCDisasm::ppc_word *)&adr;
PPCDisasm::PPC_Disassemble(&dp);
snprintf(dest, max_size, "%s\t%s", opcodeStr, operandStr);
}
static const char *gprnames[] =
{
" r0", " r1", " r2", " r3", " r4", " r5", " r6", " r7",
" r8", " r9", "r10", "r11", "r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
};
const char *GetGPRName(unsigned int index)
{
if (index < 32)
return gprnames[index];
return 0;
}
static const char *fprnames[] =
{
" f0", " f1", " f2", " f3", " f4", " f5", " f6", " f7",
" f8", " f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"
};
const char *GetFPRName(unsigned int index)
{
if (index < 32)
return fprnames[index];
return 0;
}