dingusppc/cpu/ppc/dtcinterpreter.cpp

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