diff --git a/Processors/Decoders/PowerPC/PowerPC.cpp b/Processors/Decoders/PowerPC/PowerPC.cpp index 45874a408..39fcea43a 100644 --- a/Processors/Decoders/PowerPC/PowerPC.cpp +++ b/Processors/Decoders/PowerPC/PowerPC.cpp @@ -10,18 +10,6 @@ using namespace CPU::Decoder::PowerPC; -// Unmapped: -// -// absx, clcs, divx, divsx, dozx, dozi, lscbxx, maskgx, maskirx, mulx, -// nabsx, rlmix, rribx, slex, sleqx, sliqx, slliqx, sllqx, slqx, -// sraiqx, sraqx, srex, sreax, sreqx, sriqx, srliqx, srlqx, srqx, -// -// stwcx_, -// -// frsqrtsx, -// -// extswx, - Decoder::Decoder(Model model) : model_(model) {} Instruction Decoder::decode(uint32_t opcode) { @@ -37,6 +25,12 @@ Instruction Decoder::decode(uint32_t opcode) { // it as a 9-bit field with a flag at the top. // // I've decided to hew directly to the mnemonics. + // + // Various opcodes in the 1995 documentation define reserved bits, + // which are given the nominal value of 0. It does not give a formal + // definition of a reserved bit. As a result this code does not + // currently check the value of reserved bits. That may need to change + // if/when I add support for extended instruction sets. #define Bind(mask, operation) case mask: return Instruction(Operation::operation, opcode); #define BindSupervisor(mask, operation) case mask: return Instruction(Operation::operation, opcode, true); @@ -50,7 +44,7 @@ Instruction Decoder::decode(uint32_t opcode) { return Instruction(opcode); #define Six(x) (unsigned(x) << 26) -#define SixTen(x, y) (Six(x) | (y << 1)) +#define SixTen(x, y) (Six(x) | ((y) << 1)) // First pass: weed out all those instructions identified entirely by the // top six bits. @@ -86,36 +80,69 @@ Instruction Decoder::decode(uint32_t opcode) { 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. + BindConditional(is601, Six(9), dozi); + BindConditional(is601, Six(22), rlmix); + Bind(Six(0b001010), cmpli); Bind(Six(0b001011), cmpi); } // Second pass: all those with a top six bits and a bottom nine or ten. switch(opcode & SixTen(0b111111, 0b1111111111)) { default: break; - - BindConditional(is64bit, SixTen(0b011111, 0b0000001001), mulhdux); + + // 64-bit instructions. + BindConditional(is64bit, SixTen(0b011111, 0b0000001001), mulhdux); BindConditional(is64bit, SixTen(0b011111, 0b1000001001), mulhdux); BindConditional(is64bit, SixTen(0b011111, 0b0000010101), ldx); BindConditional(is64bit, SixTen(0b011111, 0b0000011011), sldx); BindConditional(is64bit, SixTen(0b011111, 0b0000110101), ldux); BindConditional(is64bit, SixTen(0b011111, 0b0000111010), cntlzdx); BindConditional(is64bit, SixTen(0b011111, 0b0001000100), td); - BindConditional(is64bit, SixTen(0b011111, 0b0001001001), mulhdx); + BindConditional(is64bit, SixTen(0b011111, 0b0001001001), mulhdx); BindConditional(is64bit, SixTen(0b011111, 0b1001001001), mulhdx); BindConditional(is64bit, SixTen(0b011111, 0b0001010100), ldarx); BindConditional(is64bit, SixTen(0b011111, 0b0010010101), stdx); BindConditional(is64bit, SixTen(0b011111, 0b0010110101), stdux); BindConditional(is64bit, SixTen(0b011111, 0b0011101001), mulld); BindConditional(is64bit, SixTen(0b011111, 0b1011101001), mulld); BindConditional(is64bit, SixTen(0b011111, 0b0101010101), lwax); BindConditional(is64bit, SixTen(0b011111, 0b0101110101), lwaux); -// BindConditional(is64bit, SixTen(0b011111, 0b1100111011), sradix); // TODO: encoding is unclear re: the sh flag. + BindConditional(is64bit, SixTen(0b011111, 0b1100111011), sradix); BindConditional(is64bit, SixTen(0b011111, 0b1100111010), sradix); BindConditional(is64bit, SixTen(0b011111, 0b0110110010), slbie); BindConditional(is64bit, SixTen(0b011111, 0b0111001001), divdux); BindConditional(is64bit, SixTen(0b011111, 0b1111001001), divdux); BindConditional(is64bit, SixTen(0b011111, 0b0111101001), divdx); BindConditional(is64bit, SixTen(0b011111, 0b1111101001), divdx); BindConditional(is64bit, SixTen(0b011111, 0b1000011011), srdx); BindConditional(is64bit, SixTen(0b011111, 0b1100011010), sradx); - BindConditional(is64bit, SixTen(0b011111, 0b1111011010), extsw); + BindConditional(is64bit, SixTen(0b111111, 0b1111011010), extsw); + // Power instructions; these are all taken from the MPC601 manual rather than + // the PowerPC Programmer's Reference Guide, hence the decimal encoding of the + // ten-bit field. + BindConditional(is601, SixTen(0b011111, 360), absx); BindConditional(is601, SixTen(0b011111, 512 + 360), absx); + BindConditional(is601, SixTen(0b011111, 531), clcs); + BindConditional(is601, SixTen(0b011111, 331), divx); BindConditional(is601, SixTen(0b011111, 512 + 331), divx); + BindConditional(is601, SixTen(0b011111, 363), divsx); BindConditional(is601, SixTen(0b011111, 512 + 363), divsx); + BindConditional(is601, SixTen(0b011111, 264), dozx); BindConditional(is601, SixTen(0b011111, 512 + 264), dozx); + BindConditional(is601, SixTen(0b011111, 277), lscbxx); + BindConditional(is601, SixTen(0b011111, 29), maskgx); + BindConditional(is601, SixTen(0b011111, 541), maskirx); + BindConditional(is601, SixTen(0b011111, 107), mulx); BindConditional(is601, SixTen(0b011111, 512 + 107), mulx); + BindConditional(is601, SixTen(0b011111, 488), nabsx); BindConditional(is601, SixTen(0b011111, 512 + 488), nabsx); + BindConditional(is601, SixTen(0b011111, 537), rribx); + BindConditional(is601, SixTen(0b011111, 153), slex); + BindConditional(is601, SixTen(0b011111, 217), sleqx); + BindConditional(is601, SixTen(0b011111, 184), sliqx); + BindConditional(is601, SixTen(0b011111, 248), slliqx); + BindConditional(is601, SixTen(0b011111, 216), sllqx); + BindConditional(is601, SixTen(0b011111, 152), slqx); + BindConditional(is601, SixTen(0b011111, 952), sraiqx); + BindConditional(is601, SixTen(0b011111, 920), sraqx); + BindConditional(is601, SixTen(0b011111, 665), srex); + BindConditional(is601, SixTen(0b011111, 921), sreax); + BindConditional(is601, SixTen(0b011111, 729), sreqx); + BindConditional(is601, SixTen(0b011111, 696), sriqx); + BindConditional(is601, SixTen(0b011111, 760), srliqx); + BindConditional(is601, SixTen(0b011111, 728), srlqx); + BindConditional(is601, SixTen(0b011111, 664), srqx); + + // 32-bit instructions. Bind(SixTen(0b010011, 0b0000000000), mcrf); Bind(SixTen(0b010011, 0b0000010000), bclrx); Bind(SixTen(0b010011, 0b0000100001), crnor); @@ -133,7 +160,7 @@ Instruction Decoder::decode(uint32_t opcode) { Bind(SixTen(0b011111, 0b0000000100), tw); Bind(SixTen(0b011111, 0b0000001000), subfcx); Bind(SixTen(0b011111, 0b1000001000), subfcx); Bind(SixTen(0b011111, 0b0000001010), addcx); Bind(SixTen(0b011111, 0b1000001010), addcx); - Bind(SixTen(0b011111, 0b0000001011), mulhwux); + Bind(SixTen(0b011111, 0b0000001011), mulhwux); Bind(SixTen(0b011111, 0b1000001011), mulhwux); Bind(SixTen(0b011111, 0b0000010011), mfcr); Bind(SixTen(0b011111, 0b0000010100), lwarx); Bind(SixTen(0b011111, 0b0000010111), lwzx); @@ -145,7 +172,7 @@ Instruction Decoder::decode(uint32_t opcode) { Bind(SixTen(0b011111, 0b0000110110), dcbst); Bind(SixTen(0b011111, 0b0000110111), lwzux); Bind(SixTen(0b011111, 0b0000111100), andcx); - Bind(SixTen(0b011111, 0b0001001011), mulhwx); + Bind(SixTen(0b011111, 0b0001001011), mulhwx); Bind(SixTen(0b011111, 0b1001001011), mulhwx); Bind(SixTen(0b011111, 0b0001010011), mfmsr); Bind(SixTen(0b011111, 0b0001010110), dcbf); Bind(SixTen(0b011111, 0b0001010111), lbzx); @@ -279,10 +306,22 @@ Instruction Decoder::decode(uint32_t opcode) { Bind(SixTen(0b111111, 0b11010), frsqrtex); } - // TODO: stwcx., stdcx. stwcx_ + // stwcx. and stdcx. + switch(opcode & 0b111111'00'00000000'000'111111111'1){ + case 0b011111'00'00000000'00000'0010010110'1: return Instruction(Operation::stwcx_, opcode); + case 0b011111'00'00000000'00000'0011010110'1: + if(is64bit()) return Instruction(Operation::stdcx_, opcode); + return Instruction(opcode); + } - // Check for sc. - if((opcode & 0b010001'00000'00000'00000000000000'1'0) == 0b010001'00000'00000'00000000000000'1'0) { + // std and stdu + switch(opcode & 0b111111'00'00000000'00000000'000000'11){ + case 0b111110'00'00000000'00000000'000000'00: return Instruction(Operation::std, opcode); + case 0b111110'00'00000000'00000000'000000'01: return Instruction(Operation::stdu, opcode); + } + + // sc + if((opcode & 0b111111'00'00000000'00000000'000000'1'0) == 0b010001'00'00000000'00000000'000000'1'0) { return Instruction(Operation::sc, opcode); } diff --git a/Processors/Decoders/PowerPC/PowerPC.hpp b/Processors/Decoders/PowerPC/PowerPC.hpp index e13228e46..39a713fa1 100644 --- a/Processors/Decoders/PowerPC/PowerPC.hpp +++ b/Processors/Decoders/PowerPC/PowerPC.hpp @@ -9,6 +9,7 @@ #ifndef PowerPC_hpp #define PowerPC_hpp +#include #include namespace CPU { @@ -54,12 +55,12 @@ enum class Operation: uint8_t { tlbia, tlbie, tlbsync, // Optional. - fresx, frsqrtex, fselx, fsqrtx, frsqrtsx, slbia, slbie, stfiwx, + fresx, frsqrtex, fselx, fsqrtx, slbia, slbie, stfiwx, // 64-bit only PowerPC instructions. cntlzdx, divdx, divdux, extswx, fcfidx, fctidx, fctidzx, tdi, mulhdux, ldx, sldx, ldux, td, mulhdx, ldarx, stdx, stdux, mulld, lwax, lwaux, - sradix, srdx, sradx, extsw, fsqrtsx + sradix, srdx, sradx, extsw, fsqrtsx, std, stdu, stdcx_, }; /*! @@ -73,40 +74,98 @@ struct Instruction { const bool is_supervisor = false; const uint32_t opcode = 0; + // PowerPC uses a fixed-size instruction word. + size_t size() { + return 4; + } + Instruction(uint32_t opcode) : opcode(opcode) {} Instruction(Operation operation, uint32_t opcode, bool is_supervisor = false) : operation(operation), is_supervisor(is_supervisor), opcode(opcode) {} - // Instruction fields are decoded below; naming is as directly dictated by - // Motorola's documentation, and the definitions below are sorted by synonym. + // Instruction fields are decoded below; naming is a compromise between + // Motorola's documentation and IBM's. + // + // I've dutifully implemented various synonyms with unique entry points, + // in order to capture that information here rather than thrusting it upon + // the reader of whatever implementation may follow. + + // TODO: d, ds, FM, MB, ME, NB, OPCD, SH, SR, XO + + /// Immediate field used to specify an unsigned 16-bit integer. uint16_t uimm() { return uint16_t(opcode & 0xffff); } + /// Immediate field used to specify a signed 16-bit integer. int16_t simm() { return int16_t(opcode & 0xffff); } + /// Immediate field used as data to be placed into a field in the floating point status and condition register. + int32_t imm() { return (opcode >> 12) & 0xf; } - int to() { return (opcode >> 21) & 0x1f; } - int d() { return (opcode >> 21) & 0x1f; } - int bo() { return (opcode >> 21) & 0x1f; } - int crbD() { return (opcode >> 21) & 0x1f; } - int s() { return (opcode >> 21) & 0x1f; } + /// Specifies the conditions on which to trap. + int32_t to() { return (opcode >> 21) & 0x1f; } - int a() { return (opcode >> 16) & 0x1f; } - int bi() { return (opcode >> 16) & 0x1f; } - int crbA() { return (opcode >> 16) & 0x1f; } + /// Register source A or destination. + uint32_t rA() { return (opcode >> 16) & 0x1f; } + /// Register source B. + uint32_t rB() { return (opcode >> 11) & 0x1f; } + /// Register destination. + uint32_t rD() { return (opcode >> 21) & 0x1f; } + /// Register source. + uint32_t rS() { return (opcode >> 21) & 0x1f; } - int b() { return (opcode >> 11) & 0x1f; } - int crbB() { return (opcode >> 11) & 0x1f; } + /// Floating point register source A. + uint32_t frA() { return (opcode >> 16) & 0x1f; } + /// Floating point register source B. + uint32_t frB() { return (opcode >> 11) & 0x1f; } + /// Floating point register source C. + uint32_t frC() { return (opcode >> 6) & 0x1f; } + /// Floating point register source. + uint32_t frS() { return (opcode >> 21) & 0x1f; } + /// Floating point register destination. + uint32_t frD() { return (opcode >> 21) & 0x1f; } - int c() { return (opcode >> 6) & 0x1f; } + /// Branch conditional options. + uint32_t bo() { return (opcode >> 21) & 0x1f; } + /// Source condition register bit for branch conditionals. + uint32_t bi() { return (opcode >> 16) & 0x1f; } + /// Branch displacement; provided as already sign extended. + int16_t bd() { return int16_t(opcode & 0xfffc); } - int crfd() { return (opcode >> 23) & 0x07; } - - int bd() { return (opcode >> 2) & 0x3fff; } - - int li() { return (opcode >> 2) & 0x0fff; } + /// Condition register source bit A. + uint32_t crbA() { return (opcode >> 16) & 0x1f; } + /// Condition register source bit B. + uint32_t crbB() { return (opcode >> 11) & 0x1f; } + /// Condition register (or floating point status & condition register) destination bit. + uint32_t crbD() { return (opcode >> 21) & 0x1f; } - // Various single bit fields. - int l() { return (opcode >> 21) & 0x01; } - int aa() { return (opcode >> 1) & 0x01; } - int lk() { return opcode & 0x01; } - int rc() { return opcode & 0x01; } + /// Condition register (or floating point status & condition register) destination field. + uint32_t crfD() { return (opcode >> 23) & 0x07; } + /// Condition register (or floating point status & condition register) source field. + uint32_t crfS() { return (opcode >> 18) & 0x07; } + + /// Mask identifying fields to be updated by mtcrf. + uint32_t crm() { return (opcode >> 12) & 0xff; } + + /// Mask identifying fields to be updated by mtfsf. + uint32_t fm() { return (opcode >> 17) & 0xff; } + + /// A 24-bit signed number; provided as already sign extended. + int32_t li() { + constexpr uint32_t extensions[2] = { + 0x0000'0000, + 0xfc00'0000 + }; + const uint32_t value = (opcode & 0x3fff'fffc) | extensions[(opcode >> 26) & 1]; + return int32_t(value); + } + + /// Absolute address bit; @c 0 or @c non-0. + uint32_t aa() { return opcode & 0x02; } + /// Link bit; @c 0 or @c non-0. + uint32_t lk() { return opcode & 0x01; } + /// Record bit; @c 0 or @c non-0. + uint32_t rc() { return opcode & 0x01; } + /// Whether to compare 32-bit or 64-bit numbers [for 64-bit implementations only]; @c 0 or @c non-0. + uint32_t l() { return opcode & 0x200000; } + /// Enables setting of OV and SO in the XER; @c 0 or @c non-0. + uint32_t oe() { return opcode & 0x800; } }; struct Decoder {