From 233a69a1d875d30802ad7419a9d6fcad85efd816 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 31 Dec 2020 16:02:52 -0500 Subject: [PATCH] Decodes operations for the simplest 45. --- Processors/Decoders/PowerPC/PowerPC.cpp | 222 +++++++----------------- Processors/Decoders/PowerPC/PowerPC.hpp | 19 +- 2 files changed, 79 insertions(+), 162 deletions(-) diff --git a/Processors/Decoders/PowerPC/PowerPC.cpp b/Processors/Decoders/PowerPC/PowerPC.cpp index 6e9b70f82..e21c900c7 100644 --- a/Processors/Decoders/PowerPC/PowerPC.cpp +++ b/Processors/Decoders/PowerPC/PowerPC.cpp @@ -13,162 +13,70 @@ using namespace CPU::Decoder::PowerPC; Decoder::Decoder(Model model) : model_(model) {} Instruction Decoder::decode(uint32_t opcode) { - switch(opcode >> 26) { - case 31: - const uint8_t dest = (opcode >> 21) & 0x1f; - const uint8_t a = (opcode >> 16) & 0x1f; - const uint8_t b = (opcode >> 11) & 0x1f; - -#define OECase(x) case x: case 0x200 + x - switch((opcode >> 1) & 0x3ff) { - case 0: - // cmp; 601 10-26 - break; - case 4: - // 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; - } + // Quick bluffer's guide to PowerPC instruction encoding: + // + // There is a six-bit field at the very top of the instruction. + // Sometimes that fully identifies an instruction, but usually + // it doesn't. + // + // There is an addition 9- or 10-bit field starting one bit above + // least significant that disambiguates the rest. Strictly speaking + // it's a 10-bit field, but the mnemonics for many instructions treat + // it as a 9-bit field with a flag at the top. + // + // I've decided to hew directly to the mnemonics. - 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); } diff --git a/Processors/Decoders/PowerPC/PowerPC.hpp b/Processors/Decoders/PowerPC/PowerPC.hpp index 80a709725..f9f7e9761 100644 --- a/Processors/Decoders/PowerPC/PowerPC.hpp +++ b/Processors/Decoders/PowerPC/PowerPC.hpp @@ -55,16 +55,17 @@ enum class Operation: uint8_t { fresx, frsqrtex, fselx, fsqrtx, frsqrtsx, slbia, slbie, // 64-bit only PowerPC instructions. - cntlzdx, divdx, divdux, extswx, fcfidx, fctidx, fctidzx + cntlzdx, divdx, divdux, extswx, fcfidx, fctidx, fctidzx, tdi }; 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() {} - Instruction(Operation operation) : operation(operation) {} + // TODO: all field decoding here. }; struct Decoder { @@ -75,6 +76,14 @@ struct Decoder { private: Model model_; + + bool is64bit() { + return false; + } + + bool is601() { + return model_ == Model::MPC601; + } }; }