1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00

Further rounds out decoder.

This commit is contained in:
Thomas Harte 2021-01-01 11:46:26 -05:00
parent d318ab4e70
commit 0ef42f93ff
2 changed files with 148 additions and 50 deletions

View File

@ -10,18 +10,6 @@
using namespace CPU::Decoder::PowerPC; 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) {} Decoder::Decoder(Model model) : model_(model) {}
Instruction Decoder::decode(uint32_t opcode) { 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. // it as a 9-bit field with a flag at the top.
// //
// I've decided to hew directly to the mnemonics. // 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 Bind(mask, operation) case mask: return Instruction(Operation::operation, opcode);
#define BindSupervisor(mask, operation) case mask: return Instruction(Operation::operation, opcode, true); #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); return Instruction(opcode);
#define Six(x) (unsigned(x) << 26) #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 // First pass: weed out all those instructions identified entirely by the
// top six bits. // top six bits.
@ -86,8 +80,9 @@ Instruction Decoder::decode(uint32_t opcode) {
Bind(Six(0b110100), stfs); Bind(Six(0b110101), stfsu); Bind(Six(0b110100), stfs); Bind(Six(0b110101), stfsu);
Bind(Six(0b110110), stfd); Bind(Six(0b110111), stfdu); Bind(Six(0b110110), stfd); Bind(Six(0b110111), stfdu);
// Assumed below here: reserved bits can be ignored. BindConditional(is601, Six(9), dozi);
// This might need to be a function of CPU model. BindConditional(is601, Six(22), rlmix);
Bind(Six(0b001010), cmpli); Bind(Six(0b001011), cmpi); Bind(Six(0b001010), cmpli); Bind(Six(0b001011), cmpi);
} }
@ -95,27 +90,59 @@ Instruction Decoder::decode(uint32_t opcode) {
switch(opcode & SixTen(0b111111, 0b1111111111)) { switch(opcode & SixTen(0b111111, 0b1111111111)) {
default: break; 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, 0b0000010101), ldx);
BindConditional(is64bit, SixTen(0b011111, 0b0000011011), sldx); BindConditional(is64bit, SixTen(0b011111, 0b0000011011), sldx);
BindConditional(is64bit, SixTen(0b011111, 0b0000110101), ldux); BindConditional(is64bit, SixTen(0b011111, 0b0000110101), ldux);
BindConditional(is64bit, SixTen(0b011111, 0b0000111010), cntlzdx); BindConditional(is64bit, SixTen(0b011111, 0b0000111010), cntlzdx);
BindConditional(is64bit, SixTen(0b011111, 0b0001000100), td); 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, 0b0001010100), ldarx);
BindConditional(is64bit, SixTen(0b011111, 0b0010010101), stdx); BindConditional(is64bit, SixTen(0b011111, 0b0010010101), stdx);
BindConditional(is64bit, SixTen(0b011111, 0b0010110101), stdux); BindConditional(is64bit, SixTen(0b011111, 0b0010110101), stdux);
BindConditional(is64bit, SixTen(0b011111, 0b0011101001), mulld); BindConditional(is64bit, SixTen(0b011111, 0b1011101001), mulld); BindConditional(is64bit, SixTen(0b011111, 0b0011101001), mulld); BindConditional(is64bit, SixTen(0b011111, 0b1011101001), mulld);
BindConditional(is64bit, SixTen(0b011111, 0b0101010101), lwax); BindConditional(is64bit, SixTen(0b011111, 0b0101010101), lwax);
BindConditional(is64bit, SixTen(0b011111, 0b0101110101), lwaux); 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, 0b0110110010), slbie);
BindConditional(is64bit, SixTen(0b011111, 0b0111001001), divdux); BindConditional(is64bit, SixTen(0b011111, 0b1111001001), divdux); 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, 0b0111101001), divdx); BindConditional(is64bit, SixTen(0b011111, 0b1111101001), divdx);
BindConditional(is64bit, SixTen(0b011111, 0b1000011011), srdx); BindConditional(is64bit, SixTen(0b011111, 0b1000011011), srdx);
BindConditional(is64bit, SixTen(0b011111, 0b1100011010), sradx); 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, 0b0000000000), mcrf);
Bind(SixTen(0b010011, 0b0000010000), bclrx); Bind(SixTen(0b010011, 0b0000010000), bclrx);
Bind(SixTen(0b010011, 0b0000100001), crnor); Bind(SixTen(0b010011, 0b0000100001), crnor);
@ -133,7 +160,7 @@ Instruction Decoder::decode(uint32_t opcode) {
Bind(SixTen(0b011111, 0b0000000100), tw); Bind(SixTen(0b011111, 0b0000000100), tw);
Bind(SixTen(0b011111, 0b0000001000), subfcx); Bind(SixTen(0b011111, 0b1000001000), subfcx); Bind(SixTen(0b011111, 0b0000001000), subfcx); Bind(SixTen(0b011111, 0b1000001000), subfcx);
Bind(SixTen(0b011111, 0b0000001010), addcx); Bind(SixTen(0b011111, 0b1000001010), addcx); 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, 0b0000010011), mfcr);
Bind(SixTen(0b011111, 0b0000010100), lwarx); Bind(SixTen(0b011111, 0b0000010100), lwarx);
Bind(SixTen(0b011111, 0b0000010111), lwzx); Bind(SixTen(0b011111, 0b0000010111), lwzx);
@ -145,7 +172,7 @@ Instruction Decoder::decode(uint32_t opcode) {
Bind(SixTen(0b011111, 0b0000110110), dcbst); Bind(SixTen(0b011111, 0b0000110110), dcbst);
Bind(SixTen(0b011111, 0b0000110111), lwzux); Bind(SixTen(0b011111, 0b0000110111), lwzux);
Bind(SixTen(0b011111, 0b0000111100), andcx); 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, 0b0001010011), mfmsr);
Bind(SixTen(0b011111, 0b0001010110), dcbf); Bind(SixTen(0b011111, 0b0001010110), dcbf);
Bind(SixTen(0b011111, 0b0001010111), lbzx); Bind(SixTen(0b011111, 0b0001010111), lbzx);
@ -279,10 +306,22 @@ Instruction Decoder::decode(uint32_t opcode) {
Bind(SixTen(0b111111, 0b11010), frsqrtex); 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. // std and stdu
if((opcode & 0b010001'00000'00000'00000000000000'1'0) == 0b010001'00000'00000'00000000000000'1'0) { 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); return Instruction(Operation::sc, opcode);
} }

View File

@ -9,6 +9,7 @@
#ifndef PowerPC_hpp #ifndef PowerPC_hpp
#define PowerPC_hpp #define PowerPC_hpp
#include <cstddef>
#include <cstdint> #include <cstdint>
namespace CPU { namespace CPU {
@ -54,12 +55,12 @@ enum class Operation: uint8_t {
tlbia, tlbie, tlbsync, tlbia, tlbie, tlbsync,
// Optional. // Optional.
fresx, frsqrtex, fselx, fsqrtx, frsqrtsx, slbia, slbie, stfiwx, fresx, frsqrtex, fselx, fsqrtx, slbia, slbie, stfiwx,
// 64-bit only PowerPC instructions. // 64-bit only PowerPC instructions.
cntlzdx, divdx, divdux, extswx, fcfidx, fctidx, fctidzx, tdi, mulhdux, cntlzdx, divdx, divdux, extswx, fcfidx, fctidx, fctidzx, tdi, mulhdux,
ldx, sldx, ldux, td, mulhdx, ldarx, stdx, stdux, mulld, lwax, lwaux, 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 bool is_supervisor = false;
const uint32_t opcode = 0; const uint32_t opcode = 0;
// PowerPC uses a fixed-size instruction word.
size_t size() {
return 4;
}
Instruction(uint32_t opcode) : opcode(opcode) {} 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(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 // Instruction fields are decoded below; naming is a compromise between
// Motorola's documentation, and the definitions below are sorted by synonym. // 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); } 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); } 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; } /// Specifies the conditions on which to trap.
int d() { return (opcode >> 21) & 0x1f; } int32_t to() { return (opcode >> 21) & 0x1f; }
int bo() { return (opcode >> 21) & 0x1f; }
int crbD() { return (opcode >> 21) & 0x1f; }
int s() { return (opcode >> 21) & 0x1f; }
int a() { return (opcode >> 16) & 0x1f; } /// Register source A or destination.
int bi() { return (opcode >> 16) & 0x1f; } uint32_t rA() { return (opcode >> 16) & 0x1f; }
int crbA() { 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; } /// Floating point register source A.
int crbB() { return (opcode >> 11) & 0x1f; } 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; } /// 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; }
int bd() { return (opcode >> 2) & 0x3fff; } /// 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; }
int li() { return (opcode >> 2) & 0x0fff; } /// Mask identifying fields to be updated by mtcrf.
uint32_t crm() { return (opcode >> 12) & 0xff; }
// Various single bit fields. /// Mask identifying fields to be updated by mtfsf.
int l() { return (opcode >> 21) & 0x01; } uint32_t fm() { return (opcode >> 17) & 0xff; }
int aa() { return (opcode >> 1) & 0x01; }
int lk() { return opcode & 0x01; } /// A 24-bit signed number; provided as already sign extended.
int rc() { return opcode & 0x01; } 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 { struct Decoder {