diff --git a/cpu/ppc/interpops.h b/cpu/ppc/interpops.h new file mode 100644 index 0000000..b28fb80 --- /dev/null +++ b/cpu/ppc/interpops.h @@ -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; +}) diff --git a/cpu/ppc/jittables.cpp b/cpu/ppc/jittables.cpp new file mode 100644 index 0000000..7adc8d8 --- /dev/null +++ b/cpu/ppc/jittables.cpp @@ -0,0 +1,185 @@ +#include +#include +#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 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 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::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; + } +} diff --git a/cpu/ppc/jittables.h b/cpu/ppc/jittables.h new file mode 100644 index 0000000..96be4da --- /dev/null +++ b/cpu/ppc/jittables.h @@ -0,0 +1,48 @@ +#ifndef JIT_TABLES_H +#define JIT_TABLES_H + +#include +#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 */ diff --git a/cpu/ppc/nuinterpreter.cpp b/cpu/ppc/nuinterpreter.cpp new file mode 100644 index 0000000..0506402 --- /dev/null +++ b/cpu/ppc/nuinterpreter.cpp @@ -0,0 +1,238 @@ +#include +#include +#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); + } +} diff --git a/cpu/ppc/nuinterpreter.h b/cpu/ppc/nuinterpreter.h new file mode 100644 index 0000000..b8a91aa --- /dev/null +++ b/cpu/ppc/nuinterpreter.h @@ -0,0 +1,2 @@ +//void PreDecode(uint32_t next_pc); +void NuInterpExec(uint32_t start_addr); diff --git a/cpu/ppc/ppcdefs.h b/cpu/ppc/ppcdefs.h new file mode 100644 index 0000000..d497e14 --- /dev/null +++ b/cpu/ppc/ppcdefs.h @@ -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 */