1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-10-01 13:58:20 +00:00

Decodes operations for the simplest 45.

This commit is contained in:
Thomas Harte 2020-12-31 16:02:52 -05:00
parent ed63e7ea75
commit 233a69a1d8
2 changed files with 79 additions and 162 deletions

View File

@ -13,162 +13,70 @@ using namespace CPU::Decoder::PowerPC;
Decoder::Decoder(Model model) : model_(model) {} Decoder::Decoder(Model model) : model_(model) {}
Instruction Decoder::decode(uint32_t opcode) { Instruction Decoder::decode(uint32_t opcode) {
switch(opcode >> 26) { // Quick bluffer's guide to PowerPC instruction encoding:
case 31: //
const uint8_t dest = (opcode >> 21) & 0x1f; // There is a six-bit field at the very top of the instruction.
const uint8_t a = (opcode >> 16) & 0x1f; // Sometimes that fully identifies an instruction, but usually
const uint8_t b = (opcode >> 11) & 0x1f; // it doesn't.
//
#define OECase(x) case x: case 0x200 + x // There is an addition 9- or 10-bit field starting one bit above
switch((opcode >> 1) & 0x3ff) { // least significant that disambiguates the rest. Strictly speaking
case 0: // it's a 10-bit field, but the mnemonics for many instructions treat
// cmp; 601 10-26 // it as a 9-bit field with a flag at the top.
break; //
case 4: // I've decided to hew directly to the mnemonics.
// tw; 601 10-214
break;
OECase(8):
// subfcx; 601 10-207
break;
// case 9:
// // mulhdux
// break;
OECase(10):
// addcx; 601 10-9
break;
case 11:
// mulhwux; 601 10-142
break;
case 19:
// mfcr; 601 10-122
break;
case 20:
// lwarx
break;
case 21:
// ldx
break;
// lwzx
// slwx
// cntlzwx
// sldx
// andx
// ampl
// subfx
// ldux
// dcbst
// lwzux
// cntlzdx
// andcx
// td
// mulhx
// mulhwx
// mfmsr
// ldarx
// dcbf
// lbzx
// negx
// norx
// subfex
// adex
// mtcrf
// mtmsr
// stfx
// stwcx.
// stwx
// stdux
// stwux
// subfzex
// addzex
// mtsr
// stdcx.
// stbx
// subfmex
// mulld
// addmex
// mullwx
// mtsrin
// scbtst
// stbux
// addx
// dcbt
// lhzx
// eqvx
// tlbie
// eciwx
// lhzux
// xorx
// mfspr
// lwax
// lhax
// lbia
// mftb
// lwaux
// lhaux
// sthx
// orcx
// sradix
// slbie
// ecowx
// sthux
// orx
// divdux
// divwux
// mtspr
// dcbi
// nandx
// divdx
// divwx
// slbia
// mcrxr
// lswx
// lwbrx
// lfsx
// srwx
// srdx
// tlbsync
// lfsux
// mfsr
// lswi
// sync
// lfdx
// lfdux
// mfsrin
// stswx
// stwbrx
// stfsx
// stfsux
// stswi
// stfdx
// stfdux
// lhbrx
// srawx
// sradx
// srawix
// eieio
// ethbrx
// extshx
// extsbx
// lcbi
// stfiwx
// extsw
// dcbz
OECase(138):
// addex
break;
OECase(266):
// addx
break;
case 28:
// andx
break;
case 60:
// andcx
break;
}
#undef OECase
break;
}
return Instruction(); #define Bind(mask, operation) case mask: return Instruction(Operation::operation, opcode);
#define BindConditional(condition, mask, operation) \
case mask: \
if(condition()) return Instruction(Operation::operation, opcode); \
return Instruction(opcode);
#define Six(x) (unsigned(x) << 26)
// First pass: weed out all those instructions identified entirely by the
// top six bits.
switch(opcode & Six(0b111111)) {
default: break;
BindConditional(is64bit, Six(0b000010), tdi);
Bind(Six(0b000011), twi);
Bind(Six(0b000111), mulli);
Bind(Six(0b001000), subfic);
Bind(Six(0b001100), addic); Bind(Six(0b001101), addic_);
Bind(Six(0b001110), addi); Bind(Six(0b001111), addis);
Bind(Six(0b010000), bcx);
Bind(Six(0b010010), bx);
Bind(Six(0b010100), rlwimix);
Bind(Six(0b010101), rlwinmx);
Bind(Six(0b010111), rlwnmx);
Bind(Six(0b011000), ori); Bind(Six(0b011001), oris);
Bind(Six(0b011010), xori); Bind(Six(0b011011), xoris);
Bind(Six(0b011100), andi_); Bind(Six(0b011101), andis_);
Bind(Six(0b100000), lwz); Bind(Six(0b100001), lwzu);
Bind(Six(0b100010), lbz); Bind(Six(0b100011), lbzu);
Bind(Six(0b100100), stw); Bind(Six(0b100101), stwu);
Bind(Six(0b100110), stb); Bind(Six(0b100111), stbu);
Bind(Six(0b101000), lhz); Bind(Six(0b101001), lhzu);
Bind(Six(0b101010), lha); Bind(Six(0b101011), lhau);
Bind(Six(0b101100), sth); Bind(Six(0b101101), sthu);
Bind(Six(0b101110), lmw); Bind(Six(0b101111), stmw);
Bind(Six(0b110000), lfs); Bind(Six(0b110001), lfsu);
Bind(Six(0b110010), lfd); Bind(Six(0b110011), lfdu);
Bind(Six(0b110100), stfs); Bind(Six(0b110101), stfsu);
Bind(Six(0b110110), stfd); Bind(Six(0b110111), stfdu);
// Assumed below here: reserved bits can be ignored.
// This might need to be a function of CPU model.
Bind(Six(0b001010), cmpli); Bind(Six(0b001011), cmpi);
}
#undef Six
#undef Bind
#undef BindConditional
return Instruction(opcode);
} }

View File

@ -55,16 +55,17 @@ enum class Operation: uint8_t {
fresx, frsqrtex, fselx, fsqrtx, frsqrtsx, slbia, slbie, fresx, frsqrtex, fselx, fsqrtx, frsqrtsx, slbia, slbie,
// 64-bit only PowerPC instructions. // 64-bit only PowerPC instructions.
cntlzdx, divdx, divdux, extswx, fcfidx, fctidx, fctidzx cntlzdx, divdx, divdux, extswx, fcfidx, fctidx, fctidzx, tdi
}; };
struct Instruction { struct Instruction {
Operation operation = Operation::Undefined; const Operation operation = Operation::Undefined;
const uint32_t opcode = 0;
// Instruction(uint32_t opcode) : opcode(opcode) {}
Instruction(Operation operation, uint32_t opcode) : operation(operation), opcode(opcode) {}
Instruction() {} // TODO: all field decoding here.
Instruction(Operation operation) : operation(operation) {}
}; };
struct Decoder { struct Decoder {
@ -75,6 +76,14 @@ struct Decoder {
private: private:
Model model_; Model model_;
bool is64bit() {
return false;
}
bool is601() {
return model_ == Model::MPC601;
}
}; };
} }