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;
// 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);
}

View File

@ -9,6 +9,7 @@
#ifndef PowerPC_hpp
#define PowerPC_hpp
#include <cstddef>
#include <cstdint>
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 {