#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <strings.h>
#include "decode.h"
#include "core.h"
#include "misc.h"
#include "ppcinsts.h"
#include "sprs.h"
void decode(uint32_t inst, uint64_t pc, istate *is, regfile *rg) {
int32_t majop, xop, ret;
iType *it;
ppcinst *ppci, *fop;
is->opr = isNone;
is->op[0] = 0;
is->oper[0] = 0;
majop = (inst >> 26) & 0x3F;
ppci = majops[majop];
if(!(uint32_t)ppci) {
is->opr = isInvalid;
return;
}
fop = (ppcinst *)0;
while(1) {
if(ppci->extended < 0) break;
it = ppci->insttype;
xop = (inst >> it->ishift) & it->imask;
if(ppci->extended == xop) {
fop = ppci;
break;
}
ppci++;
}
if(!(uint32_t)fop) {
is->opr = isInvalid;
return;
}
is->opr = fop->opr;
is->memsize = fop->oprsize;
is->mods = fop->mods;
is->targtype = fop->dflags & dTrgtyp;
is->trakBtarg = gTnu;
is->trakResult = gTnu;
is->trakExplicit = gTnu;
is->trakTarget = gTnu;
is->trakSourcea = gTnu;
is->trakSourceb = gTnu;
is->trakSourcec = gTnu;
is->trakSourced = gTnu;
is->btarg = 0;
is->result = 0;
ret = (*fop->insttype->idecode)(inst, fop, is, rg);
if(!ret) {
is->opr = isInvalid;
return;
}
if((uint32_t)fop->xinst) {
ret = (*fop->xinst)(inst, fop, pc, is, rg);
if(!ret) is->opr = isInvalid;
}
return;
}
int dcdFormA(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
uint8_t ex;
is->target = (inst >> (31 - 10)) & 0x1F;
is->sourcea = (inst >> (31 - 15)) & 0x1F;
is->sourceb = (inst >> (31 - 20)) & 0x1F;
is->sourcec = (inst >> (31 - 25)) & 0x1F;
strcpy(is->op, instb->opcode);
if(inst & 1) {
strcat(is->op, ".");
is->mods |= modSetCRF;
}
ex = gTset;
if(is->mods & modUnimpl) ex |= gTundef;
switch(is->mods &modRgVal) {
case modFAtabc:
is->trakResult = trackReg(is, 0, ex, rg->trakFpr[is->target], rg->trakFpr[is->sourcea], rg->trakFpr[is->sourceb], rg->trakFpr[is->sourcec], 0);
sprintf(is->oper, "f%d,f%d,f%d,f%d", is->target, is->sourcea, is->sourceb, is->sourcec);
break;
case modFAtab:
is->trakResult = trackReg(is, 0, ex, rg->trakFpr[is->target], rg->trakFpr[is->sourcea], rg->trakFpr[is->sourceb], 0, 0);
sprintf(is->oper, "f%d,f%d,f%d", is->target, is->sourcea, is->sourceb);
break;
case modFAtb:
is->trakResult = trackReg(is, 0, ex, rg->trakFpr[is->target], 0, rg->trakFpr[is->sourceb], 0, 0);
sprintf(is->oper, "f%d,f%d", is->target, is->sourceb);
break;
case modFAtac:
is->trakResult = trackReg(is, 0, ex, rg->trakFpr[is->target], 0, 0, rg->trakFpr[is->sourcec], 0);
sprintf(is->oper, "f%d,f%d", is->target, is->sourcec);
break;
default:
return 0;
break;
}
return 1;
}
int dcdFormB(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
return 1;
}
int dcdFormD(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
uint8_t ex = 0;
if(instb->dflags & dSkip) return 1;
if(instb->dflags & dSwapTA) {
is->sourcea = (inst >> (31 - 10)) & 0x1F;
is->target = (inst >> (31 - 15)) & 0x1F;
}
else {
is->target = (inst >> (31 - 10)) & 0x1F;
is->sourcea = (inst >> (31 - 15)) & 0x1F;
}
is->immediate = inst & 0xFFFF;
if((!(instb->dflags & dImmUn)) && (is->immediate & 0x8000)) is->immediate |= 0xFFFFFFFFFFFF0000ULL;
if(is->sourcea) {
is->btarg = rg->gprs[is->sourcea] + is->immediate;
is->trakSourcea = rg->trakGpr[is->sourcea];
}
else {
is->btarg = is->immediate;
is->trakSourcea = gTgen | gTset;
}
if(!(instb->dflags & dNoFmt)) {
strcpy(is->op, instb->opcode);
if(instb->dflags & dBd) {
if(is->mods & modTFpu) sprintf(is->oper, "f%d,0x%04X(r%d)", is->target, (uint16_t)is->immediate, is->sourcea);
else sprintf(is->oper, "r%d,0x%X(r%d)", is->target, (uint16_t)is->immediate, is->sourcea);
}
else {
if(is->mods & modTFpu) sprintf(is->oper, "f%d,r%d,0x%04X", is->target, is->sourcea, (uint16_t)is->immediate);
else sprintf(is->oper, "r%d,r%d,0x%04X", is->target, is->sourcea, (uint16_t)is->immediate);
}
}
if(!(is->mods & modTnomod)) {
ex = gTset;
if(is->mods & modUnimpl) ex |= gTundef;
}
is->trakResult = trackReg(is, 0, ex, rg->trakGpr[is->target], is->trakSourcea, gTgen | gTset, 0, 0);
is->trakBtarg = is->trakResult | gTset;
return 1;
}
int dcdFormDS(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
uint8_t ex = 0;
if(instb->dflags & dSkip) return 1;
is->target = (inst >> (31 - 10)) & 0x1F;
is->sourcea = (inst >> (31 - 15)) & 0x1F;
is->immediate = inst & 0xFFFC;
if((!(instb->dflags & dImmUn)) && (is->immediate & 0x8000)) is->immediate |= 0xFFFFFFFFFFFF0000ULL;
if(is->sourcea) {
is->btarg = rg->gprs[is->sourcea] + is->immediate;
is->trakSourcea = rg->trakGpr[is->sourcea];
}
else {
is->btarg = is->immediate;
is->trakSourcea = gTgen;
}
if(!(instb->dflags & dNoFmt)) {
strcpy(is->op, instb->opcode);
sprintf(is->oper, "r%d,0x%04X(r%d)", is->target, (uint16_t)is->immediate, is->sourcea);
}
if(!(is->mods & modTnomod)) {
ex = gTset;
if(is->mods & modUnimpl) ex |= gTundef;
}
is->trakResult = trackReg(is, 0, ex, rg->trakGpr[is->target], is->trakSourcea, gTgen | gTset, 0, 0);
is->trakBtarg = is->trakResult | gTset;
return 1;
}
int dcdFormI(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
return 1;
}
int dcdFormM(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
uint8_t ex = 0;
is->target = (inst >> (31 - 15)) & 0x1F;
is->sourcea = (inst >> (31 - 10)) & 0x1F;
is->sourceb = (inst >> (31 - 20)) & 0x1F;
is->sourcec = (inst >> (31 - 25)) & 0x1F;
is->sourced = (inst >> (31 - 30)) & 0x1F;
strcpy(is->op, instb->opcode);
if(inst & 1) {
strcat(is->op, ".");
is->mods |= modSetCRF;
}
if(!(is->mods & modUseRB)) {
is->trakSourceb = gTgen | gTset;
sprintf(is->oper, "r%d,r%d,%d,%d,%d", is->target, is->sourcea, is->sourceb, is->sourcec, is->sourced);
}
else {
is->trakSourceb = rg->trakGpr[is->sourceb];
sprintf(is->oper, "r%d,r%d,r%d,%d,%d", is->target, is->sourcea, is->sourceb, is->sourcec, is->sourced);
}
is->sourcec += 32;
is->sourced += 32;
if(!(is->mods & modTnomod)) {
ex = gTset;
if(is->mods & modUnimpl) ex |= gTundef;
}
is->trakResult = trackReg(is, 0, ex, rg->trakGpr[is->target], is->trakSourcea, is->trakSourceb, 0, 0);
return 1;
}
int dcdFormMD(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
uint8_t ex = 0;
is->target = (inst >> (31 - 15)) & 0x1F;
is->sourcea = (inst >> (31 - 10)) & 0x1F;
is->sourceb = ((inst >> (31 - 20)) & 0x1F) | ((inst << 4) & 0x20);
is->sourcec = (inst >> (31 - 26)) & 0x3F;
is->sourcec = (is->sourcec >> 1 | (is->sourcec << 5)) & 0x3F;
is->sourced = is->sourcec;
strcpy(is->op, instb->opcode);
if(inst & 1) {
strcat(is->op, ".");
is->mods |= modSetCRF;
}
if(!(is->mods & modTnomod)) {
ex = gTset;
if(is->mods & modUnimpl) ex |= gTundef;
}
is->trakResult = trackReg(is, 0, ex, rg->trakGpr[is->target], rg->trakGpr[is->sourcea], gTgen | gTset, gTgen | gTset, gTgen | gTset);
sprintf(is->oper, "r%d,r%d,%d,%d", is->target, is->sourcea, is->sourceb, is->sourcec);
return 1;
}
int dcdFormMDS(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
uint8_t ex = 0;
is->target = (inst >> (31 - 15)) & 0x1F;
is->sourcea = (inst >> (31 - 10)) & 0x1F;
is->sourceb = ((inst >> (31 - 20)) & 0x1F);
is->sourcec = (inst >> (31 - 26)) & 0x3F;
is->sourcec = (is->sourcec >> 1 | (is->sourcec << 5)) & 0x3F;
is->sourced = is->sourcec;
strcpy(is->op, instb->opcode);
if(inst & 1) {
strcat(is->op, ".");
is->mods |= modSetCRF;
}
if(!(is->mods & modTnomod)) {
ex = gTset;
if(is->mods & modUnimpl) ex |= gTundef;
}
is->trakResult = trackReg(is, 0, ex, rg->trakGpr[is->target],
rg->trakGpr[is->sourcea], rg->trakGpr[is->sourceb],
gTgen | gTset, gTgen | gTset);
sprintf(is->oper, "r%d,r%d,r%d,%d", is->target, is->sourcea, is->sourceb, is->sourcec);
return 1;
}
int dcdFormSC(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
return 1;
}
int dcdFormVA(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
uint8_t ex = 0;
is->target = (inst >> (31 - 10)) & 0x1F;
is->sourcea = (inst >> (31 - 15)) & 0x1F;
is->sourceb = (inst >> (31 - 20)) & 0x1F;
is->sourcec = (inst >> (31 - 25)) & 0x1F;
if(!(is->mods & modTnomod)) {
ex = gTset;
if(is->mods & modUnimpl) ex |= gTundef;
}
is->trakResult = trackReg(is, 0, ex, rg->trakVpr[is->target],
rg->trakVpr[is->sourcea], rg->trakVpr[is->sourceb],
rg->trakVpr[is->sourcec], 0);
strcpy(is->op, instb->opcode);
sprintf(is->oper, "v%d,v%d,v%d,v%d", is->target, is->sourcea, is->sourceb, is->sourcec);
return 1;
}
int dcdFormVX(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
int simm;
uint8_t ex = 0;
strcpy(is->op, instb->opcode);
is->trakTarget = 0;
switch(is->mods & 0x0000E000) {
case mod3op:
is->target = (inst >> (31 - 10)) & 0x1F;
is->sourcea = (inst >> (31 - 15)) & 0x1F;
is->sourceb = (inst >> (31 - 20)) & 0x1F;
is->trakTarget = rg->trakVpr[is->target];
is->trakSourcea = rg->trakVpr[is->sourcea];
is->trakSourceb = rg->trakVpr[is->sourceb];
sprintf(is->oper, "v%d,v%d,v%d", is->target, is->sourcea, is->sourceb);
break;
case mod2op:
is->target = (inst >> (31 - 10)) & 0x1F;
is->sourcea = (inst >> (31 - 20)) & 0x1F;
is->trakTarget = rg->trakVpr[is->target];
is->trakSourcea = rg->trakVpr[is->sourcea];
sprintf(is->oper, "v%d,v%d", is->target, is->sourcea);
break;
case mod1opt:
is->target = (inst >> (31 - 10)) & 0x1F;
is->trakTarget = rg->trakVpr[is->target];
sprintf(is->oper, "v%d", is->target);
break;
case mod1opb:
is->sourcea = (inst >> (31 - 20)) & 0x1F;
is->trakSourcea = rg->trakVpr[is->sourcea];
sprintf(is->oper, "v%d", is->sourcea);
break;
case moduim:
is->target = (inst >> (31 - 10)) & 0x1F;
is->immediate = (inst >> (31 - 15)) & 0x1F;
is->sourcea = (inst >> (31 - 20)) & 0x1F;
is->trakTarget = rg->trakVpr[is->target];
is->trakSourcea = rg->trakVpr[is->sourcea];
sprintf(is->oper, "v%d,v%d,%lld", is->target, is->sourcea, is->immediate);
break;
case modsim:
is->target = (inst >> (31 - 10)) & 0x1F;
simm = (inst >> (31 - 15)) & 0x1F;
if(simm & 0x10) {
simm = simm | 0xFFFFFFF0;
is->immediate = simm | 0xFFFFFFFFFFFFFFF0ULL;
}
sprintf(is->oper, "v%d,%d", is->target, simm);
break;
default:
printf("Form VX decode error: inst = %08X, mod = %08X\n", inst, is->mods);
exit(1);
break;
}
if(!(is->mods & modTnomod)) {
ex = gTset;
if(is->mods & modUnimpl) ex |= gTundef;
}
ex = trackReg(is, 0, ex, rg->trakVpr[is->target],
rg->trakVpr[is->sourcea], rg->trakVpr[is->sourceb], 0, 0);
is->trakResult = (is->mods & modTnomod) ? is->trakTarget : ex;
return 1;
}
int dcdFormVXR(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
uint8_t ex = 0;
strcpy(is->op, instb->opcode);
is->target = (inst >> (31 - 10)) & 0x1F;
is->sourcea = (inst >> (31 - 15)) & 0x1F;
is->sourceb = (inst >> (31 - 20)) & 0x1F;
if(inst & 0x00000400) strcat(is->op, ".");
if(!(is->mods & modTnomod)) {
ex = gTset;
if(is->mods & modUnimpl) ex |= gTundef;
}
is->trakResult = trackReg(is, 0, ex, rg->trakVpr[is->target], rg->trakVpr[is->sourcea], rg->trakVpr[is->sourceb], 0, 0);
sprintf(is->oper, "v%d,v%d,v%d", is->target, is->sourcea, is->sourceb);
return 1;
}
int dcdFormX(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
uint8_t ex = 0;
if(instb->dflags & dSkip) return 1;
if(instb->dflags & dSwapTA) {
is->sourcea = (inst >> (31 - 10)) & 0x1F;
is->target = (inst >> (31 - 15)) & 0x1F;
}
else {
is->sourcea = (inst >> (31 - 15)) & 0x1F;
is->target = (inst >> (31 - 10)) & 0x1F;
}
is->sourceb = (inst >> (31 - 20)) & 0x1F;
if(is->sourcea) {
is->btarg = rg->gprs[is->sourcea] + rg->gprs[is->sourceb];
is->trakBtarg = trackReg(is, 0, gTset, 0, rg->trakGpr[is->sourcea], rg->trakGpr[is->sourceb], 0, 0);
}
else {
is->btarg = rg->gprs[is->sourceb];
is->trakBtarg = trackReg(is, 0, gTset, 0, gTgen, rg->trakGpr[is->sourceb], 0, 0);
}
if(is->opr == isRead) {
if(is->sourcea && (rg->trakGpr[is->sourcea] & gTbrtbl)){
is->btarg = rg->gprs[is->sourcea];
is->trakBtarg = trackReg(is, 0, gTset, 0, rg->trakGpr[is->sourcea], 0, 0, 0);
if(trace) printf(" (Load from branch table, index register discarded)\n");
}
else if(rg->trakGpr[is->sourceb] & gTbrtbl) {
is->btarg = rg->gprs[is->sourceb];
is->trakBtarg = trackReg(is, 0, gTset, 0, 0, rg->trakGpr[is->sourceb], 0, 0);
if(trace) printf(" (Load from branch table, base register discarded)\n");
}
}
if(inst & 1) is->mods |= modSetCRF;
if(!(is->mods & modTnomod)) {
ex = gTset;
if(is->mods & modUnimpl) ex |= gTundef;
}
is->trakResult = trackRegNS(is, 0, ex, 0, is->trakBtarg ,0, 0, 0);
if(!(instb->dflags & dNoFmt)) {
strcpy(is->op, instb->opcode);
if(is->mods & modSetCRF) strcat(is->op, ".");
if(is->mods & modTFpu) sprintf(is->oper, "f%d,r%d,r%d", is->target, is->sourcea, is->sourceb);
else if(is->mods & modTVec) sprintf(is->oper, "v%d,r%d,r%d", is->target, is->sourcea, is->sourceb);
else sprintf(is->oper, "r%d,r%d,r%d", is->target, is->sourcea, is->sourceb);
}
return 1;
}
int dcdFormXFL(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
int ffld;
ffld = (inst >> (31 - 14)) & 0xFF;
is->target = sPfpscr;
is->targtype = rfSpr;
is->sourceb = (inst >> (31 - 20)) & 0x1F;
strcpy(is->op, instb->opcode);
if(inst & 1) {
strcat(is->op, ".");
is->mods |= modSetCRF;
}
sprintf(is->oper, "%d,f%d", ffld, is->sourceb);
return 1;
}
int dcdFormXFX(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
is->target = (inst >> (31 - 10)) & 0x1F;
strcpy(is->op, instb->opcode);
is->trakResult = trackReg(is, 0, gTset | gTundef, 0, 0, 0, 0, 0);
return 1;
}
int dcdFormXL(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
is->target = (inst >> (31 - 10)) & 0x1F;
is->sourcea = (inst >> (31 - 15)) & 0x1F;
is->sourceb = (inst >> (31 - 20)) & 0x1F;
if(instb->dflags & dSkip) return 1;
strcpy(is->op, instb->opcode);
sprintf(is->oper, "cr%d,cr%d,cr%d", is->target, is->sourcea, is->sourceb);
return 1;
}
int dcdFormXO(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
uint8_t ui = 0;
is->target = (inst >> (31 - 10)) & 0x1F;
is->sourcea = (inst >> (31 - 15)) & 0x1F;
is->sourceb = (inst >> (31 - 20)) & 0x1F;
strcpy(is->op, instb->opcode);
if(inst & 0x00000400) {
strcat(is->op, "o");
is->mods |= modOflow;
}
if(inst & 1) {
strcat(is->op, ".");
is->mods |= modSetCRF;
}
if(!(is->mods & modTnomod)) {
ui = gTset;
if(is->mods & modUnimpl) ui |= gTundef;
}
is->trakResult = trackReg(is, 0, ui, rg->trakGpr[is->target], rg->trakGpr[is->sourcea], rg->trakGpr[is->sourceb], 0, 0);
sprintf(is->oper, "r%d,r%d,r%d", is->target, is->sourcea, is->sourceb);
return 1;
}
int dcdFormXS(uint32_t inst, struct ppcinst *instb, istate *is, regfile *rg) {
uint8_t ex;
is->sourcea = (inst >> (31 - 10)) & 0x1F;
is->target = (inst >> (31 - 15)) & 0x1F;
is->sourceb = ((inst << 4) & 0x20) | ((inst >> (31 - 20)) & 0x1F);
if(!(is->mods & modTnomod)) {
ex = gTset;
if(is->mods & modUnimpl) ex |= gTundef;
is->trakResult = trackReg(is, 0, ex, rg->trakGpr[is->target], rg->trakGpr[is->sourcea], 0, 0, 0);
}
strcpy(is->op, instb->opcode);
if(inst & 1) strcat(is->op, ".");
sprintf(is->oper, "r%d,r%d,%d", is->target, is->sourcea, is->sourceb);
return 1;
}
sprtb *decodeSPR(uint32_t spr) {
if(spr > sprmax) return 0;
return &sprs[spr];
}