420 lines
23 KiB
C++
420 lines
23 KiB
C++
#include <cinttypes>
|
|
#include <thirdparty/loguru/loguru.hpp>
|
|
#include "ppcemu.h"
|
|
#include "ppcmmu.h"
|
|
#include "ppcdefs.h"
|
|
#include "jittables.h"
|
|
#include "nuinterpreter.h"
|
|
|
|
#if defined(USE_DTC)
|
|
|
|
#define CAST(name) &&lab_##name
|
|
|
|
struct InterpInstr {
|
|
void* emu_fn;
|
|
InstrInfo info;
|
|
};
|
|
|
|
#define REG_D(opcode) ((opcode >> 21) & 0x1F)
|
|
#define REG_A(opcode) ((opcode >> 16) & 0x1F)
|
|
#define REG_B(opcode) ((opcode >> 11) & 0x1F)
|
|
#define REG_S REG_D
|
|
#define BR_BO REG_D
|
|
#define BR_BI REG_A
|
|
#define SIMM(opcode) ((int32_t)((int16_t)(opcode & 0xFFFF)))
|
|
#define UIMM(opcode) ((uint32_t)((uint16_t)(opcode & 0xFFFF)))
|
|
#define REG_TO(opcode) ((opcode >> 21) & 0x1F)
|
|
#define REG_CRFD(opcode) (((opcode >> 23) & 7) << 2)
|
|
#define REG_CRFS(opcode) (((opcode >> 18) & 7) << 2)
|
|
#define REG_SR(opcode) (opcode >> 16) & 15
|
|
#define LI(opcode) (opcode >> 2) & 0xFFFFFF
|
|
|
|
/** mask generator for rotate and shift instructions (§ 4.2.1.4 PowerpC PEM) */
|
|
static inline uint32_t rot_mask(unsigned rot_mb, unsigned rot_me) {
|
|
uint32_t m1 = 0xFFFFFFFFUL >> rot_mb;
|
|
uint32_t m2 = 0xFFFFFFFFUL << (31 - rot_me);
|
|
return ((rot_mb <= rot_me) ? m2 & m1 : m1 | m2);
|
|
}
|
|
|
|
CachedInstr code_block[256];
|
|
|
|
void NuInterpExec(uint32_t next_pc) {
|
|
/* WARNING: entries in this table MUST be in the same order as constants in PPCInstr! */
|
|
InterpInstr interp_tab[] = {
|
|
{nullptr, {InstrOps::opNone, CFlowType::CFL_NONE, 0}},
|
|
{CAST(addi), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(adde), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(addze), {InstrOps::opDA, CFlowType::CFL_NONE, 1}},
|
|
{CAST(andidot), {InstrOps::opSAUimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lwz), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lwzu), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lbz), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lhz), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(rlwinm), {InstrOps::opRot, CFlowType::CFL_NONE, 1}},
|
|
{CAST(srawidot), {InstrOps::opSASh, CFlowType::CFL_NONE, 1}},
|
|
{CAST(bc), {InstrOps::opBrRel, CFlowType::CFL_COND_BRANCH, 0}},
|
|
{CAST(bdnz), {InstrOps::opBrRel, CFlowType::CFL_COND_BRANCH, 0}},
|
|
{CAST(bdz), {InstrOps::opBrRel, CFlowType::CFL_COND_BRANCH, 0}},
|
|
{CAST(bclr), {InstrOps::opBrLink, CFlowType::CFL_COND_BRANCH, 0}},
|
|
{CAST(mtspr), {InstrOps::opSSpr, CFlowType::CFL_NONE, 2}},
|
|
{CAST(bexit), {InstrOps::opNone, CFlowType::CFL_UNCOND_BRANCH, 0}},
|
|
{CAST(twi), {InstrOps::opTOASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(mulli), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(cmpli), {InstrOps::opCrfDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(cmpi), {InstrOps::opCrfDAUimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(addic), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(addicdot), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(sc), {InstrOps::opNone, CFlowType::CFL_NONE, 1}},
|
|
{CAST(rlwimix), {InstrOps::opRot, CFlowType::CFL_NONE, 1}},
|
|
{CAST(rlwnmx), {InstrOps::opRot, CFlowType::CFL_NONE, 1}},
|
|
{CAST(ori), {InstrOps::opSAUimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(oris), {InstrOps::opSAUimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(xori), {InstrOps::opSAUimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(xoris), {InstrOps::opSAUimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(andisdot), {InstrOps::opSAUimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lbzu), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stw), {InstrOps::opSASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stwu), {InstrOps::opSASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stb), {InstrOps::opSASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stbu), {InstrOps::opSASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lhzu), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lha), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lhau), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(sth), {InstrOps::opSASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(sthu), {InstrOps::opSASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lmw), {InstrOps::opSASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stmw), {InstrOps::opSASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lfs), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lfsu), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lfd), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lfdu), {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stfs), {InstrOps::opSASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stfsu), {InstrOps::opSASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stfd), {InstrOps::opSASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stfdu), {InstrOps::opSASimm, CFlowType::CFL_NONE, 1}},
|
|
{CAST(bcl), {InstrOps::opBrRel, CFlowType::CFL_COND_BRANCH, 0}},
|
|
{CAST(bca), {InstrOps::opBrRel, CFlowType::CFL_COND_BRANCH, 0}},
|
|
{CAST(bcla), {InstrOps::opBrRel, CFlowType::CFL_COND_BRANCH, 0}},
|
|
{CAST(b), {InstrOps::opBrRel, CFlowType::CFL_COND_BRANCH, 0}},
|
|
{CAST(bl), {InstrOps::opBrRel, CFlowType::CFL_COND_BRANCH, 0}},
|
|
{CAST(ba), {InstrOps::opBrRel, CFlowType::CFL_COND_BRANCH, 0}},
|
|
{CAST(bla), {InstrOps::opBrRel, CFlowType::CFL_COND_BRANCH, 0}},
|
|
{CAST(crnor), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(rfi), {InstrOps::opNone, CFlowType::CFL_COND_BRANCH, 1}},
|
|
{CAST(crandc), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(isync), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(crxor), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(crnand), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(crand), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(creqv), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(crorc), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(cror), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(bcctr), {InstrOps::opBrRel, CFlowType::CFL_NONE, 1}},
|
|
{CAST(bcctrl), {InstrOps::opBrRel, CFlowType::CFL_NONE, 1}},
|
|
{CAST(cmp), {InstrOps::opCrfDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(tw), {InstrOps::opTOAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(subfc), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(subfcdot), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(addc), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(addcdot), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(mulhwu), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(mulhwudot), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(mfcr), {InstrOps::opD, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lwarx), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lwzx), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(slw), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(slwdot), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(cntlzw), {InstrOps::opSA, CFlowType::CFL_NONE, 1}},
|
|
{CAST(cntlzwdot), {InstrOps::opSA, CFlowType::CFL_NONE, 1}},
|
|
{CAST(ppc_and), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(anddot), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(cmpl), {InstrOps::opCrfDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(subf), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(subfdot), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(dcbst), {InstrOps::opAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lwzux), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(andc), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(andcdot), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(mulhw), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(mulhwdot), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
/*
|
|
|
|
{CAST(lbzux), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lbzx), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lfdux), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lfdx), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lfsux), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lfsx), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lhaux), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lhax), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lhbrx), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lhzux), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lhzx), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lswi), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lswx), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(lwbrx), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
|
|
{CAST(add), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(adddot), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(addc), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(addcdot), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(addedot), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(addme), {InstrOps::opDA, CFlowType::CFL_NONE, 1}},
|
|
{CAST(addmedot), {InstrOps::opDA, CFlowType::CFL_NONE, 1}},
|
|
{CAST(addze), {InstrOps::opDA, CFlowType::CFL_NONE, 1}},
|
|
{CAST(addzedot), {InstrOps::opDA, CFlowType::CFL_NONE, 1}},
|
|
{CAST(and), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(anddot), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(divw), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(divwdot), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(divwu), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(divwudot), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(eieio), {InstrOps::opNone, CFlowType::CFL_NONE, 1}},
|
|
|
|
{CAST(cmpl), {InstrOps::opCrfDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(eqv), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(eqvdot), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(extsb), {InstrOps::opSA, CFlowType::CFL_NONE, 1}},
|
|
{CAST(extsbdot), {InstrOps::opSA, CFlowType::CFL_NONE, 1}},
|
|
{CAST(extsh), {InstrOps::opSA, CFlowType::CFL_NONE, 1}},
|
|
{CAST(extshdot), {InstrOps::opSA, CFlowType::CFL_NONE, 1}},
|
|
|
|
{CAST(fmr), {InstrOps::opDB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(icbi), {InstrOps::opAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(isync), {InstrOps::opNone, CFlowType::CFL_NONE, 1}},
|
|
|
|
{CAST(mtcrf), {InstrOps::opNone, CFlowType::CFL_NONE, 1}},
|
|
{CAST(mulhwu), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(mullw), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(nand), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(nanddot), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(neg), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(negdot), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(nor), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(nordot), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(or), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(ordot), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(orc), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(orcdot), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(slw), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(slwdot), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(sraw), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(srawdot), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(srawi), {InstrOps::opSASh, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stbux), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stbx), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stfdux), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stfdx), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stfiwx), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stfsux), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stfsx), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(sthbrx), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(sthux), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(sthx), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stswi), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stswx), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stwbrx), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stwcx), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stwux), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(stwx), {InstrOps::opSAB, CFlowType::CFL_NONE, 1}},
|
|
|
|
{CAST(addedot), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(addeo), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
{CAST(addeodot), {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
|
|
|
|
*/
|
|
};
|
|
|
|
CachedInstr* c_instr;
|
|
uint32_t opcode, main_opcode;
|
|
unsigned instr_index;
|
|
uint8_t* pc_real;
|
|
bool done;
|
|
|
|
pc_real = quickinstruction_translate(next_pc);
|
|
|
|
c_instr = &code_block[0];
|
|
|
|
done = false;
|
|
|
|
while (!done) {
|
|
opcode = ppc_cur_instruction;
|
|
main_opcode = opcode >> 26;
|
|
|
|
instr_index = main_index_tab[main_opcode];
|
|
if (!instr_index) {
|
|
switch (main_opcode) {
|
|
case 16:
|
|
instr_index = subgrp16_index_tab[opcode & 3];
|
|
break;
|
|
case 18:
|
|
instr_index = subgrp18_index_tab[opcode & 3];
|
|
break;
|
|
case 19:
|
|
instr_index = subgrp19_index_tab[opcode & 0x7FF];
|
|
break;
|
|
case 31:
|
|
instr_index = subgrp31_index_tab[opcode & 0x7FF];
|
|
break;
|
|
case 59:
|
|
instr_index = subgrp59_index_tab[opcode & 0x3F];
|
|
break;
|
|
case 63:
|
|
instr_index = subgrp63_index_tab[opcode & 0x7FF];
|
|
break;
|
|
default:
|
|
instr_index = 0;
|
|
}
|
|
|
|
if (!instr_index) {
|
|
LOG_F(INFO, "Illegal opcode 0x%08X - Program exception!", opcode);
|
|
return;
|
|
}
|
|
}
|
|
|
|
const InterpInstr* p_instr = &interp_tab[instr_index];
|
|
|
|
c_instr->call_me = p_instr->emu_fn;
|
|
|
|
/* pre-decode operands, immediate values etc. */
|
|
switch (p_instr->info.ops_fmt) {
|
|
case InstrOps::opDA:
|
|
case InstrOps::opSA:
|
|
c_instr->d1 = REG_D(opcode);
|
|
c_instr->d2 = REG_A(opcode);
|
|
break;
|
|
case InstrOps::opDAB:
|
|
case InstrOps::opSAB:
|
|
c_instr->d1 = REG_D(opcode);
|
|
c_instr->d2 = REG_A(opcode);
|
|
c_instr->d3 = REG_B(opcode);
|
|
break;
|
|
case InstrOps::opAB:
|
|
c_instr->d2 = REG_A(opcode);
|
|
c_instr->d3 = REG_B(opcode);
|
|
break;
|
|
case InstrOps::opTOAB:
|
|
c_instr->d1 = REG_TO(opcode);
|
|
c_instr->d2 = REG_A(opcode);
|
|
c_instr->d3 = REG_B(opcode);
|
|
break;
|
|
case InstrOps::opCrfDAB:
|
|
c_instr->d1 = REG_CRFD(opcode);
|
|
c_instr->d2 = REG_A(opcode);
|
|
c_instr->d3 = REG_B(opcode);
|
|
break;
|
|
case InstrOps::opDASimm:
|
|
case InstrOps::opSASimm:
|
|
c_instr->d1 = REG_D(opcode);
|
|
c_instr->d2 = REG_A(opcode);
|
|
c_instr->simm = SIMM(opcode);
|
|
break;
|
|
case InstrOps::opSAUimm:
|
|
c_instr->d1 = REG_S(opcode);
|
|
c_instr->d2 = REG_A(opcode);
|
|
c_instr->uimm = UIMM(opcode);
|
|
break;
|
|
case InstrOps::opSASh:
|
|
c_instr->d1 = REG_S(opcode);
|
|
c_instr->d2 = REG_A(opcode);
|
|
c_instr->d3 = (opcode >> 11) & 0x1F; // shift
|
|
c_instr->uimm = (1 << c_instr->d3) - 1; // mask
|
|
break;
|
|
case InstrOps::opRot:
|
|
c_instr->d1 = REG_S(opcode);
|
|
c_instr->d2 = REG_A(opcode);
|
|
c_instr->d3 = (opcode >> 11) & 0x1F; // shift
|
|
c_instr->d4 = opcode & 1; // Rc bit
|
|
c_instr->uimm = rot_mask((opcode >> 6) & 31, (opcode >> 1) & 31); //mask
|
|
break;
|
|
case InstrOps::opSSpr:
|
|
c_instr->d1 = REG_S(opcode);
|
|
c_instr->uimm = (REG_B(opcode) << 5) | REG_A(opcode);
|
|
break;
|
|
case InstrOps::opD:
|
|
c_instr->d1 = REG_D(opcode);
|
|
break;
|
|
case InstrOps::opTOASimm:
|
|
c_instr->d1 = REG_TO(opcode);
|
|
c_instr->d2 = REG_A(opcode);
|
|
c_instr->simm = SIMM(opcode);
|
|
break;
|
|
case InstrOps::opTOB:
|
|
c_instr->d1 = REG_TO(opcode);
|
|
c_instr->d2 = REG_A(opcode);
|
|
c_instr->d3 = REG_B(opcode);
|
|
break;
|
|
case InstrOps::opCrfDASimm:
|
|
c_instr->d1 = REG_CRFD(opcode);
|
|
c_instr->d2 = REG_A(opcode);
|
|
c_instr->simm = SIMM(opcode);
|
|
break;
|
|
case InstrOps::opCrfDAUimm:
|
|
c_instr->d1 = REG_CRFD(opcode);
|
|
c_instr->d2 = REG_A(opcode);
|
|
c_instr->simm = UIMM(opcode);
|
|
break;
|
|
case InstrOps::opDSR:
|
|
c_instr->d1 = REG_D(opcode);
|
|
c_instr->d2 = REG_SR(opcode);
|
|
case InstrOps::opDB:
|
|
c_instr->d1 = REG_D(opcode);
|
|
c_instr->d2 = REG_B(opcode);
|
|
case InstrOps::opNone:
|
|
break;
|
|
case InstrOps::opBrRel:
|
|
c_instr->bt = SIMM(opcode) >> 2;
|
|
switch (BR_BO(opcode) & 0x1E) {
|
|
case 12:
|
|
case 14:
|
|
c_instr->call_me = interp_tab[PPCInstr::bc].emu_fn;
|
|
c_instr->uimm = 0x80000000UL >> BR_BI(opcode);
|
|
break;
|
|
case 16:
|
|
c_instr->call_me = interp_tab[PPCInstr::bdnz].emu_fn;
|
|
break;
|
|
case 18:
|
|
c_instr->call_me = interp_tab[PPCInstr::bdz].emu_fn;
|
|
break;
|
|
default:
|
|
LOG_F(ERROR, "Unsupported opcode 0x%08X - Program exception!", opcode);
|
|
return;
|
|
}
|
|
break;
|
|
case InstrOps::opBrLink:
|
|
switch (BR_BO(opcode) & 0x1E) {
|
|
case 20: // blr
|
|
c_instr->call_me = interp_tab[PPCInstr::bexit].emu_fn;
|
|
c_instr->uimm = next_pc;
|
|
done = true;
|
|
continue;
|
|
default:
|
|
LOG_F(ERROR, "Unsupported opcode 0x%08X - Program exception!", opcode);
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
LOG_F(ERROR, "Unknown opcode format %d!", p_instr->info.ops_fmt);
|
|
return;
|
|
}
|
|
|
|
c_instr++;
|
|
|
|
next_pc += 4;
|
|
pc_real += 4;
|
|
ppc_set_cur_instruction(pc_real);
|
|
} // while
|
|
|
|
//LOG_F(INFO, "PreDecode completed!");
|
|
|
|
CachedInstr* code = &code_block[0];
|
|
|
|
goto *(code->call_me); // begin code execution
|
|
|
|
#define GEN_OP(name,body) lab_##name: { body; }
|
|
#define NEXT goto *((++code)->call_me)
|
|
|
|
#include "interpops.h" // auto-generate labeled emulation blocks
|
|
}
|
|
|
|
#endif |