Initial code for the NuInterpreter.

This commit is contained in:
Maxim Poliakovski 2020-11-15 23:11:40 +01:00
parent 6124dfd897
commit d659253f91
6 changed files with 897 additions and 0 deletions

127
cpu/ppc/interpops.h Normal file
View File

@ -0,0 +1,127 @@
GEN_OP(addi, {
ppc_state.gpr[code->d1] = ppc_state.gpr[code->d2] + code->simm;
NEXT;
})
GEN_OP(adde, {
uint32_t xer_ca = !!(ppc_state.spr[SPR::XER] & 0x20000000);
uint32_t val_a = ppc_state.gpr[code->d2];
uint32_t val_b = ppc_state.gpr[code->d3];
uint32_t result = val_a + val_b + xer_ca;
if ((result < val_a) || (xer_ca && (result == val_a))) {
ppc_state.spr[SPR::XER] |= 0x20000000UL;
} else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
}
ppc_state.gpr[code->d1] = result;
NEXT;
})
GEN_OP(addze, {
uint32_t val_a = ppc_state.gpr[code->d2];
uint32_t xer_ca = !!(ppc_state.spr[SPR::XER] & 0x20000000);
uint32_t result = val_a + xer_ca;
if (result < val_a) {
ppc_state.spr[SPR::XER] |= 0x20000000UL;
} else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
}
ppc_state.gpr[code->d1] = result;
NEXT;
})
GEN_OP(andidot, {
uint32_t result = ppc_state.gpr[code->d1] & code->uimm;
ppc_state.gpr[code->d2] = result;
ppc_changecrf0(result);
NEXT;
})
GEN_OP(lwz, {
ppc_state.gpr[code->d1] = (mem_grab_dword((
(code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm));
NEXT;
})
GEN_OP(lwzu, {
uint32_t ea = ppc_state.gpr[code->d2] + code->simm;
ppc_state.gpr[code->d1] = mem_grab_dword(ea);
ppc_state.gpr[code->d2] = ea;
NEXT;
})
GEN_OP(lbz, {
ppc_state.gpr[code->d1] = (mem_grab_byte((
(code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm));
NEXT;
})
GEN_OP(lhz, {
ppc_state.gpr[code->d1] = (mem_grab_word((
(code->d2) ? ppc_state.gpr[code->d2] : 0) + code->simm));
NEXT;
})
GEN_OP(rlwinm, {
uint32_t val_s = ppc_state.gpr[code->d1];
uint32_t r = ((val_s << code->d3) | (val_s >> (32 - code->d3)));
uint32_t result = r & code->uimm;
ppc_state.gpr[code->d2] = result;
if (code->d4) {
ppc_changecrf0(result);
}
NEXT;
})
GEN_OP(srawidot, {
uint32_t val_s = ppc_state.gpr[code->d1];
uint32_t result = (int32_t)val_s >> code->d2;
if ((val_s & 0x80000000UL) && (val_s & code->uimm)) {
ppc_state.spr[SPR::XER] |= 0x20000000UL;
} else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
}
ppc_state.gpr[code->d2] = result;
ppc_changecrf0(result);
NEXT;
})
GEN_OP(bc, {
if (ppc_state.cr & code->uimm) {
interp_tpc += code->bt;
} else {
NEXT;
}
})
GEN_OP(mtspr, {
ppc_state.spr[code->uimm] = ppc_state.gpr[code->d1];
NEXT;
})
GEN_OP(bdnz, {
if (--ppc_state.spr[SPR::CTR]) {
interp_tpc += code->bt;
} else {
NEXT;
}
})
GEN_OP(bdz, {
if (!(--ppc_state.spr[SPR::CTR])) {
interp_tpc += code->bt;
} else {
NEXT;
}
})
GEN_OP(bclr, {
// PLACEHOLDER
})
GEN_OP(bexit, {
ppc_state.pc = code->uimm; // write source pc
interp_running = false;
})

185
cpu/ppc/jittables.cpp Normal file
View File

@ -0,0 +1,185 @@
#include <cinttypes>
#include <map>
#include "jittables.h"
#include "ppcdefs.h"
uint16_t main_index_tab[64] = {
PPCInstr::illegal, PPCInstr::illegal, PPCInstr::illegal,
PPCInstr::twi, PPCInstr::illegal, PPCInstr::illegal,
PPCInstr::illegal, PPCInstr::mulli, PPCInstr::subfic,
PPCInstr::dozi, PPCInstr::cmpli, PPCInstr::cmpi,
PPCInstr::addic, PPCInstr::addicdot, PPCInstr::addi,
PPCInstr::addis, PPCInstr::illegal, PPCInstr::sc,
PPCInstr::illegal, PPCInstr::illegal, PPCInstr::rlwimix,
PPCInstr::rlwinmx, PPCInstr::rlmi, PPCInstr::rlwnmx,
PPCInstr::ori, PPCInstr::oris, PPCInstr::xori,
PPCInstr::xoris, PPCInstr::andidot, PPCInstr::andisdot,
PPCInstr::illegal, PPCInstr::illegal, PPCInstr::lwz,
PPCInstr::lwzu, PPCInstr::lbz, PPCInstr::lbzu,
PPCInstr::stw, PPCInstr::stwu, PPCInstr::stb,
PPCInstr::stbu, PPCInstr::lhz, PPCInstr::lhzu,
PPCInstr::lha, PPCInstr::lhau, PPCInstr::sth,
PPCInstr::sthu, PPCInstr::lmw, PPCInstr::stmw,
PPCInstr::lfs, PPCInstr::lfsu, PPCInstr::lfd,
PPCInstr::lfdu, PPCInstr::stfs, PPCInstr::stfsu,
PPCInstr::stfd, PPCInstr::stfdu, PPCInstr::illegal,
PPCInstr::illegal, PPCInstr::illegal, PPCInstr::illegal,
PPCInstr::illegal, PPCInstr::illegal, PPCInstr::illegal,
PPCInstr::illegal
};
uint16_t subgrp16_index_tab[4] = {
PPCInstr::bc, PPCInstr::bcl, PPCInstr::bca, PPCInstr::bcla
};
uint16_t subgrp18_index_tab[4] = {
PPCInstr::b, PPCInstr::bl, PPCInstr::ba, PPCInstr::bla
};
uint16_t subgrp19_index_tab[2048] = { PPCInstr::illegal };
uint16_t subgrp31_index_tab[2048] = { PPCInstr::illegal };
uint16_t subgrp59_index_tab[64] = { PPCInstr::illegal };
uint16_t subgrp63_index_tab[2048] = { PPCInstr::illegal };
static std::map<uint16_t, PPCInstr> Subop19Init = {
{ 32, PPCInstr::bclr },
{ 33, PPCInstr::bclrl },
{ 66, PPCInstr::crnor },
{ 100, PPCInstr::rfi },
{ 258, PPCInstr::crandc },
{ 300, PPCInstr::isync },
{ 386, PPCInstr::crxor },
{ 450, PPCInstr::crnand },
{ 514, PPCInstr::crand },
{ 578, PPCInstr::creqv },
{ 834, PPCInstr::crorc },
{ 898, PPCInstr::cror },
{ 1056, PPCInstr::bcctr },
{ 1057, PPCInstr::bcctrl }
};
static std::map<uint16_t, PPCInstr> Subop31Init = {
{ 0, PPCInstr::cmp}, { 8, PPCInstr::tw},
{ 16, PPCInstr::subfc}, { 17, PPCInstr::subfcdot},
{ 20, PPCInstr::addc}, { 21, PPCInstr::addcdot},
{ 22, PPCInstr::mulhwu}, { 23, PPCInstr::mulhwudot},
{ 38, PPCInstr::mfcr}, { 40, PPCInstr::lwarx},
{ 46, PPCInstr::lwzx}, { 48, PPCInstr::slw},
{ 49, PPCInstr::slwdot}, { 52, PPCInstr::cntlzw},
{ 53, PPCInstr::cntlzwdot}, { 56, PPCInstr::ppc_and},
{ 57, PPCInstr::anddot}, { 58, PPCInstr::maskg},
{ 59, PPCInstr::maskgdot}, { 64, PPCInstr::cmpl},
{ 80, PPCInstr::subf}, { 81, PPCInstr::subfdot},
{ 108, PPCInstr::dcbst}, { 110, PPCInstr::lwzux},
{ 120, PPCInstr::andc}, { 121, PPCInstr::andcdot},
{ 150, PPCInstr::mulhw}, { 151, PPCInstr::mulhwdot},
{ 166, PPCInstr::mfmsr}, { 172, PPCInstr::dcbf},
{ 174, PPCInstr::lbzx}, { 208, PPCInstr::neg},
{ 209, PPCInstr::negdot}, { 214, PPCInstr::mul},
{ 215, PPCInstr::muldot}, { 238, PPCInstr::lbzux},
{ 248, PPCInstr::nor}, { 249, PPCInstr::nordot},
{ 272, PPCInstr::subfe}, { 273, PPCInstr::subfedot},
{ 276, PPCInstr::adde}, { 277, PPCInstr::addedot},
{ 288, PPCInstr::mtcrf}, { 292, PPCInstr::mtmsr},
{ 301, PPCInstr::stwcx}, { 302, PPCInstr::stwx},
{ 304, PPCInstr::slq}, { 305, PPCInstr::slqdot},
{ 306, PPCInstr::sle}, { 307, PPCInstr::sledot},
{ 366, PPCInstr::stwux}, { 368, PPCInstr::sliq},
{ 400, PPCInstr::subfze}, { 401, PPCInstr::subfzedot},
{ 404, PPCInstr::addze}, { 405, PPCInstr::addzedot},
{ 420, PPCInstr::mtsr}, { 430, PPCInstr::stbx},
{ 432, PPCInstr::sllq}, { 433, PPCInstr::sllqdot},
{ 434, PPCInstr::sleq}, { 436, PPCInstr::sleqdot},
{ 464, PPCInstr::subfme}, { 465, PPCInstr::subfmedot},
{ 468, PPCInstr::addme}, { 469, PPCInstr::addmedot},
{ 470, PPCInstr::mullw}, { 471, PPCInstr::mullwdot},
{ 484, PPCInstr::mtsrin}, { 492, PPCInstr::dcbtst},
{ 494, PPCInstr::stbux}, { 496, PPCInstr::slliq},
{ 497, PPCInstr::slliqdot}, { 528, PPCInstr::doz},
{ 529, PPCInstr::dozdot}, { 532, PPCInstr::add},
{ 533, PPCInstr::adddot}, { 554, PPCInstr::lscbx},
{ 555, PPCInstr::lscbxdot}, { 556, PPCInstr::dcbt},
{ 558, PPCInstr::lhzx}, { 568, PPCInstr::eqv},
{ 569, PPCInstr::eqvdot}, { 612, PPCInstr::tlbie},
{ 622, PPCInstr::lhzux}, { 632, PPCInstr::ppc_xor},
{ 633, PPCInstr::xordot}, { 662, PPCInstr::div},
{ 663, PPCInstr::divdot}, { 678, PPCInstr::mfspr},
{ 686, PPCInstr::lhax}, { 720, PPCInstr::abs},
{ 721, PPCInstr::absdot}, { 726, PPCInstr::divs},
{ 727, PPCInstr::divsdot}, { 740, PPCInstr::tlbia},
{ 742, PPCInstr::mftb}, { 750, PPCInstr::lhaux},
{ 814, PPCInstr::sthx}, { 824, PPCInstr::orc},
{ 825, PPCInstr::orcdot}, { 878, PPCInstr::sthux},
{ 888, PPCInstr::ppc_or}, { 889, PPCInstr::ordot},
{ 918, PPCInstr::divwu}, { 919, PPCInstr::divwudot},
{ 934, PPCInstr::mtspr}, { 940, PPCInstr::dcbi},
{ 952, PPCInstr::nand}, { 953, PPCInstr::nanddot},
{ 976, PPCInstr::nabs}, { 977, PPCInstr::nabsdot},
{ 982, PPCInstr::divw}, { 983, PPCInstr::divwdot},
{ 1024, PPCInstr::mcrxr}, { 1040, PPCInstr::subfco},
{ 1041, PPCInstr::subfcodot}, { 1044, PPCInstr::addco},
{ 1045, PPCInstr::addcodot}, { 1062, PPCInstr::clcs},
{ 1063, PPCInstr::clcsdot}, { 1066, PPCInstr::lswx},
{ 1068, PPCInstr::lwbrx}, { 1070, PPCInstr::lfsx},
{ 1072, PPCInstr::srw}, { 1073, PPCInstr::srwdot},
{ 1074, PPCInstr::rrib}, { 1075, PPCInstr::rribdot},
{ 1082, PPCInstr::maskir}, { 1083, PPCInstr::maskirdot},
{ 1104, PPCInstr::subfo}, { 1105, PPCInstr::subfodot},
{ 1132, PPCInstr::tlbsync}, { 1134, PPCInstr::lfsux},
{ 1190, PPCInstr::mfsr}, { 1194, PPCInstr::lswi},
{ 1196, PPCInstr::sync}, { 1198, PPCInstr::lfdx},
{ 1232, PPCInstr::nego}, { 1233, PPCInstr::negodot},
{ 1238, PPCInstr::mulo}, { 1239, PPCInstr::mulodot},
{ 1262, PPCInstr::lfdux}, { 1296, PPCInstr::subfeo},
{ 1297, PPCInstr::subfeodot}, { 1300, PPCInstr::addeo},
{ 1301, PPCInstr::addeodot}, { 1318, PPCInstr::mfsrin},
{ 1322, PPCInstr::stswx}, { 1324, PPCInstr::stwbrx},
{ 1326, PPCInstr::stfsx}, { 1328, PPCInstr::srq},
{ 1329, PPCInstr::srqdot}, { 1330, PPCInstr::sre},
{ 1331, PPCInstr::sredot}, { 1390, PPCInstr::stfsux},
{ 1392, PPCInstr::sriq}, { 1393, PPCInstr::sriqdot},
{ 1424, PPCInstr::subfzeo}, { 1425, PPCInstr::subfzeodot},
{ 1428, PPCInstr::addzeo}, { 1429, PPCInstr::addzeodot},
{ 1450, PPCInstr::stswi}, { 1454, PPCInstr::stfdx},
{ 1456, PPCInstr::srlq}, { 1457, PPCInstr::srlqdot},
{ 1458, PPCInstr::sreq }, { 1459, PPCInstr::sreqdot},
{ 1488, PPCInstr::subfmeo }, { 1489, PPCInstr::subfmeodot},
{ 1492, PPCInstr::addmeo }, { 1493, PPCInstr::addmeodot},
{ 1494, PPCInstr::mullwo }, { 1495, PPCInstr::mullwodot},
{ 1518, PPCInstr::stfdux }, { 1520, PPCInstr::srliq},
{ 1521, PPCInstr::srliqdot }, { 1552, PPCInstr::dozo},
{ 1553, PPCInstr::dozodot }, { 1556, PPCInstr::addo},
{ 1557, PPCInstr::addodot }, { 1580, PPCInstr::lhbrx},
{ 1584, PPCInstr::sraw }, { 1585, PPCInstr::srawdot},
{ 1648, PPCInstr::srawi }, { 1649, PPCInstr::srawidot},
{ 1686, PPCInstr::divo }, { 1687, PPCInstr::divodot},
{ 1708, PPCInstr::eieio }, { 1744, PPCInstr::abso},
{ 1745, PPCInstr::absodot }, { 1750, PPCInstr::divso},
{ 1751, PPCInstr::divsodot }, { 1836, PPCInstr::sthbrx},
{ 1840, PPCInstr::sraq }, { 1841, PPCInstr::sraqdot},
{ 1842, PPCInstr::srea }, { 1843, PPCInstr::sreadot},
{ 1844, PPCInstr::extsh }, { 1845, PPCInstr::extshdot},
{ 1904, PPCInstr::sraiq }, { 1905, PPCInstr::sraiqdot},
{ 1908, PPCInstr::extsb }, { 1909, PPCInstr::extsbdot},
{ 1942, PPCInstr::divwuo }, { 1943, PPCInstr::divwuodot},
{ 1956, PPCInstr::tlbld }, { 1964, PPCInstr::icbi},
{ 1966, PPCInstr::stfiwx }, { 2000, PPCInstr::nabso},
{ 2001, PPCInstr::nabsodot }, { 2006, PPCInstr::divwo},
{ 2007, PPCInstr::divwodot }, { 2020, PPCInstr::tlbli},
{ 2028, PPCInstr::dcbz }
};
void init_jit_tables() {
std::map<uint16_t, PPCInstr>::iterator it;
for (it = Subop19Init.begin(); it != Subop19Init.end(); it++ ) {
subgrp19_index_tab[it->first] = it->second;
}
for (it = Subop31Init.begin(); it != Subop31Init.end(); it++ ) {
subgrp31_index_tab[it->first] = it->second;
}
}

48
cpu/ppc/jittables.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef JIT_TABLES_H
#define JIT_TABLES_H
#include <cinttypes>
#include "ppcemu.h"
/** Instruction operands formats. */
enum class InstrOps {
opNone,
opDA,
opDAB,
opDASimm,
opSAUimm,
opSASh,
opRot,
opSSpr,
opBrRel,
opBrLink,
};
/* Control flow kind. */
enum class CFlowType {
CFL_NONE,
CFL_COND_BRANCH,
CFL_UNCOND_BRANCH,
CFL_TRAP,
};
struct InstrInfo {
InstrOps ops_fmt; // describes operands format
CFlowType cflow_type; // control flow type
int num_cycles;
// Required by JIT
//int flags; // flags updated by this instruction
};
extern uint16_t main_index_tab[];
extern uint16_t subgrp16_index_tab[];
extern uint16_t subgrp18_index_tab[];
extern uint16_t subgrp19_index_tab[];
extern uint16_t subgrp31_index_tab[];
extern uint16_t subgrp59_index_tab[];
extern uint16_t subgrp63_index_tab[];
void init_jit_tables(void);
#endif /* JIT_TABLES_H */

238
cpu/ppc/nuinterpreter.cpp Normal file
View File

@ -0,0 +1,238 @@
#include <cinttypes>
#include <thirdparty/loguru/loguru.hpp>
#include "ppcemu.h"
#include "ppcmmu.h"
#include "ppcdefs.h"
#include "jittables.h"
struct CachedInstr; // forward declaration
typedef void (*ImplSubr)(const CachedInstr *);
struct CachedInstr {
ImplSubr call_me;
union {
struct {
uint8_t d1;
uint8_t d2;
uint8_t d3;
uint8_t d4;
};
int32_t bt; // branch target
};
union {
int32_t simm;
uint32_t uimm;
};
};
CachedInstr* interp_tpc;
bool interp_running;
#define GEN_OP(name,body) void impl_##name(const CachedInstr* code) {body}
#define NEXT interp_tpc++
#include "interpops.h"
struct InterpInstr {
ImplSubr emu_fn; // pointer to the instruction emulation routine
InstrInfo info;
};
/* 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}},
{impl_addi, {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
{impl_adde, {InstrOps::opDAB, CFlowType::CFL_NONE, 1}},
{impl_addze, {InstrOps::opDA, CFlowType::CFL_NONE, 1}},
{impl_andidot, {InstrOps::opSAUimm, CFlowType::CFL_NONE, 1}},
{impl_lwz, {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
{impl_lwzu, {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
{impl_lbz, {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
{impl_lhz, {InstrOps::opDASimm, CFlowType::CFL_NONE, 1}},
{impl_rlwinm, {InstrOps::opRot, CFlowType::CFL_NONE, 1}},
{impl_srawidot, {InstrOps::opSASh, CFlowType::CFL_NONE, 1}},
{impl_bc, {InstrOps::opBrRel, CFlowType::CFL_COND_BRANCH, 0}},
{impl_bdnz, {InstrOps::opBrRel, CFlowType::CFL_COND_BRANCH, 0}},
{impl_bdz, {InstrOps::opBrRel, CFlowType::CFL_COND_BRANCH, 0}},
{impl_bclr, {InstrOps::opBrLink, CFlowType::CFL_COND_BRANCH, 0}},
{impl_mtspr, {InstrOps::opSSpr, CFlowType::CFL_NONE, 2}},
{impl_bexit, {InstrOps::opNone, CFlowType::CFL_UNCOND_BRANCH, 0}},
};
CachedInstr code_block[256];
#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)))
/** 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);
}
bool PreDecode(uint32_t next_pc, CachedInstr* c_instr)
{
uint32_t opcode, main_opcode;
unsigned instr_index;
uint8_t* pc_real;
bool done;
pc_real = quickinstruction_translate(next_pc);
//CachedInstr* c_instr = &code[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(ERROR, "Illegal opcode 0x%08X - Program exception!", opcode);
return false;
}
}
const InterpInstr* p_instr = &interp_tab[instr_index];
c_instr->call_me = p_instr->emu_fn;
if (p_instr->info.cflow_type == CFlowType::CFL_UNCOND_BRANCH) {
// finish translation block when an uncoditional branch is encountered
done = true;
continue;
}
/* pre-decode operands, immediate values etc. */
switch (p_instr->info.ops_fmt) {
case InstrOps::opDA:
c_instr->d1 = REG_D(opcode);
c_instr->d2 = REG_A(opcode);
break;
case InstrOps::opDAB:
c_instr->d1 = REG_D(opcode);
c_instr->d2 = REG_A(opcode);
c_instr->d3 = REG_B(opcode);
break;
case InstrOps::opDASimm:
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::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 false;
}
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 false;
}
break;
default:
LOG_F(ERROR, "Unknown opcode format %d!", p_instr->info.ops_fmt);
return false;
}
c_instr++;
next_pc += 4;
pc_real += 4;
ppc_set_cur_instruction(pc_real);
} // while
return true;
}
void NuInterpExec(uint32_t start_addr) {
interp_tpc = &code_block[0];
if (!PreDecode(start_addr, interp_tpc)) {
return;
}
interp_running = true;
while(interp_running) {
interp_tpc->call_me(interp_tpc);
}
}

2
cpu/ppc/nuinterpreter.h Normal file
View File

@ -0,0 +1,2 @@
//void PreDecode(uint32_t next_pc);
void NuInterpExec(uint32_t start_addr);

297
cpu/ppc/ppcdefs.h Normal file
View File

@ -0,0 +1,297 @@
#ifndef PPC_DEFS_H
#define PPC_DEFS_H
/* Enumerate all supported PowerPC instructions. */
enum PPCInstr : int {
illegal = 0,
addi,
adde,
addze,
andidot,
lwz,
lwzu,
lbz,
lhz,
rlwinmx,
srawidot,
bc,
bdnz,
bdz,
bclr,
mtspr,
bexit, // arificial block exit opcode
twi,
mulli,
subfic,
cmpli,
cmpi,
addic,
addicdot,
addis,
sc,
rlwimix,
rlwnmx,
ori,
oris,
xori,
xoris,
andisdot,
lbzu,
stw,
stwu,
stb,
stbu,
lhzu,
lha,
lhau,
sth,
sthu,
lmw,
stmw,
lfs,
lfsu,
lfd,
lfdu,
stfs,
stfsu,
stfd,
stfdu,
bcl,
bca,
bcla,
b,
bl,
ba,
bla,
bclrl,
crnor,
rfi,
crandc,
isync,
crxor,
crnand,
crand,
creqv,
crorc,
cror,
bcctr,
bcctrl,
cmp,
tw,
subfc,
subfcdot,
addc,
addcdot,
mulhwu,
mulhwudot,
mfcr,
lwarx,
lwzx,
slw,
slwdot,
cntlzw,
cntlzwdot,
ppc_and,
anddot,
cmpl,
subf,
subfdot,
dcbst,
lwzux,
andc,
andcdot,
mulhw,
mulhwdot,
mfmsr,
dcbf,
lbzx,
neg,
negdot,
mul,
muldot,
lbzux,
nor,
nordot,
subfe,
subfedot,
addedot,
mtcrf,
mtmsr,
stwcx,
stwx,
stwux,
subfze,
subfzedot,
addzedot,
mtsr,
stbx,
subfme,
subfmedot,
addme,
addmedot,
mullw,
mullwdot,
mtsrin,
dcbtst,
stbux,
add,
adddot,
lscbx,
lscbxdot,
dcbt,
lhzx,
eqv,
eqvdot,
tlbie,
lhzux,
ppc_xor,
xordot,
div,
divdot,
mfspr,
lhax,
abs,
absdot,
divs,
divsdot,
tlbia,
mftb,
lhaux,
sthx,
orc,
orcdot,
sthux,
ppc_or,
ordot,
divwu,
divwudot,
dcbi,
nand,
nanddot,
divw,
divwdot,
mcrxr,
subfco,
subfcodot,
addco,
addcodot,
lswx,
lwbrx,
lfsx,
srw,
srwdot,
subfo,
subfodot,
tlbsync,
lfsux,
mfsr,
lswi,
sync,
lfdx,
nego,
negodot,
mulo,
mulodot,
lfdux,
subfeo,
subfeodot,
addeo,
addeodot,
mfsrin,
stswx,
stwbrx,
stfsx,
stfsux,
subfzeo,
subfzeodot,
addzeo,
addzeodot,
stswi,
stfdx,
subfmeo,
subfmeodot,
addmeo,
addmeodot,
mullwo,
mullwodot,
stfdux,
addo,
addodot,
lhbrx,
sraw,
srawdot,
srawi,
eieio,
sthbrx,
extsh,
extshdot,
extsb,
extsbdot,
divwuo,
divwuodot,
tlbld,
icbi,
stfiwx,
divwo,
divwodot,
tlbli,
dcbz,
// POWER-specific
dozi,
rlmi,
maskg,
maskgdot,
slq,
slqdot,
sle,
sledot,
sliq,
sllq,
sllqdot,
sleq,
sleqdot,
slliq,
slliqdot,
doz,
dozdot,
nabs,
nabsdot,
clcs,
clcsdot,
rrib,
rribdot,
maskir,
maskirdot,
srq,
srqdot,
sre,
sredot,
sriq,
sriqdot,
srlq,
srlqdot,
sreq,
sreqdot,
srliq,
srliqdot,
dozo,
dozodot,
divo,
divodot,
abso,
absodot,
divso,
divsodot,
sraq,
sraqdot,
srea,
sreadot,
sraiq,
sraiqdot,
nabso,
nabsodot,
};
#endif /* PPC_DEFS_H */