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:
parent
d318ab4e70
commit
0ef42f93ff
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user