1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-10-05 23:56:33 +00:00

Rethinks size; packs all captured information into an x86 Instruction.

Albeit that operand and displacement are't yet captured. Or extractable.
This commit is contained in:
Thomas Harte 2021-01-08 22:22:07 -05:00
parent 306df7554e
commit 86577b772b
4 changed files with 80 additions and 43 deletions

View File

@ -50,10 +50,10 @@ namespace {
instructions.clear(); instructions.clear();
const uint8_t *byte = stream.begin(); const uint8_t *byte = stream.begin();
while(byte != stream.end()) { while(byte != stream.end()) {
const auto next = decoder.decode(byte, stream.end() - byte); const auto [size, next] = decoder.decode(byte, stream.end() - byte);
if(next.size() <= 0) break; if(size <= 0) break;
instructions.push_back(next); instructions.push_back(next);
byte += next.size(); byte += size;
} }
} }

View File

@ -73,17 +73,15 @@ enum class Operation: uint8_t {
Implementation note: because the PowerPC encoding is particularly straightforward, Implementation note: because the PowerPC encoding is particularly straightforward,
only the operation has been decoded ahead of time; all other fields are decoded on-demand. only the operation has been decoded ahead of time; all other fields are decoded on-demand.
It would be possible to partition the ordering of Operations into user followed by supervisor,
eliminating the storage necessary for a flag, but it wouldn't save anything due to alignment.
*/ */
struct Instruction { struct Instruction {
Operation operation = Operation::Undefined; Operation operation = Operation::Undefined;
bool is_supervisor = false; bool is_supervisor = false;
uint32_t opcode = 0; uint32_t opcode = 0;
// PowerPC uses a fixed-size instruction word.
int size() const {
return 4;
}
Instruction() {} Instruction() {}
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) {}

View File

@ -10,13 +10,14 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <utility>
using namespace CPU::Decoder::x86; using namespace CPU::Decoder::x86;
// Only 8086 is suppoted for now. // Only 8086 is suppoted for now.
Decoder::Decoder(Model) {} Decoder::Decoder(Model) {}
Instruction Decoder::decode(const uint8_t *source, size_t length) { std::pair<int, Instruction> Decoder::decode(const uint8_t *source, size_t length) {
const uint8_t *const end = source + length; const uint8_t *const end = source + length;
// MARK: - Prefixes (if present) and the opcode. // MARK: - Prefixes (if present) and the opcode.
@ -36,6 +37,7 @@ Instruction Decoder::decode(const uint8_t *source, size_t length) {
/// Handles instructions of the form rr, kk and rr, jjkk, i.e. a destination register plus an operand. /// Handles instructions of the form rr, kk and rr, jjkk, i.e. a destination register plus an operand.
#define RegData(op, dest, size) \ #define RegData(op, dest, size) \
SetOpSrcDestSize(op, DirectAddress, dest, size); \ SetOpSrcDestSize(op, DirectAddress, dest, size); \
operand_size_ = size; \
phase_ = Phase::AwaitingDisplacementOrOperand phase_ = Phase::AwaitingDisplacementOrOperand
/// Handles instructions of the form Ax, jjkk where the latter is implicitly an address. /// Handles instructions of the form Ax, jjkk where the latter is implicitly an address.
@ -79,9 +81,9 @@ Instruction Decoder::decode(const uint8_t *source, size_t length) {
switch(instr_) { switch(instr_) {
default: { default: {
const Instruction instruction(consumed_); const auto result = std::make_pair(consumed_, Instruction());
reset_parsing(); reset_parsing();
return instruction; return result;
} }
#define PartialBlock(start, operation) \ #define PartialBlock(start, operation) \
@ -390,9 +392,11 @@ Instruction Decoder::decode(const uint8_t *source, size_t length) {
source_ = destination_ = memreg; source_ = destination_ = memreg;
switch(reg) { switch(reg) {
default: default: {
const auto result = std::make_pair(consumed_, Instruction());
reset_parsing(); reset_parsing();
return Instruction(consumed_); return result;
}
case 0: operation_ = Operation::TEST; break; case 0: operation_ = Operation::TEST; break;
case 2: operation_ = Operation::NOT; break; case 2: operation_ = Operation::NOT; break;
@ -413,8 +417,9 @@ Instruction Decoder::decode(const uint8_t *source, size_t length) {
}; };
if(reg & 4) { if(reg & 4) {
const auto result = std::make_pair(consumed_, Instruction());
reset_parsing(); reset_parsing();
return Instruction(consumed_); return result;
} }
destination_ = seg_table[reg]; destination_ = seg_table[reg];
@ -424,9 +429,11 @@ Instruction Decoder::decode(const uint8_t *source, size_t length) {
destination_ = memreg; destination_ = memreg;
switch(reg) { switch(reg) {
default: default: {
const auto result = std::make_pair(consumed_, Instruction());
reset_parsing(); reset_parsing();
return Instruction(consumed_); return result;
}
case 0: operation_ = Operation::ROL; break; case 0: operation_ = Operation::ROL; break;
case 2: operation_ = Operation::ROR; break; case 2: operation_ = Operation::ROR; break;
@ -442,9 +449,11 @@ Instruction Decoder::decode(const uint8_t *source, size_t length) {
source_ = destination_ = memreg; source_ = destination_ = memreg;
switch(reg) { switch(reg) {
default: default: {
const auto result = std::make_pair(consumed_, Instruction());
reset_parsing(); reset_parsing();
return Instruction(consumed_); return result;
}
case 0: operation_ = Operation::INC; break; case 0: operation_ = Operation::INC; break;
case 1: operation_ = Operation::DEC; break; case 1: operation_ = Operation::DEC; break;
@ -455,9 +464,11 @@ Instruction Decoder::decode(const uint8_t *source, size_t length) {
source_ = destination_ = memreg; source_ = destination_ = memreg;
switch(reg) { switch(reg) {
default: default: {
const auto result = std::make_pair(consumed_, Instruction());
reset_parsing(); reset_parsing();
return Instruction(consumed_); return result;
}
case 0: operation_ = Operation::INC; break; case 0: operation_ = Operation::INC; break;
case 1: operation_ = Operation::DEC; break; case 1: operation_ = Operation::DEC; break;
@ -482,7 +493,7 @@ Instruction Decoder::decode(const uint8_t *source, size_t length) {
if(reg != 0) { if(reg != 0) {
reset_parsing(); reset_parsing();
return Instruction(consumed_); return std::make_pair(consumed_, Instruction());
} }
break; break;
@ -513,19 +524,31 @@ Instruction Decoder::decode(const uint8_t *source, size_t length) {
phase_ = Phase::ReadyToPost; phase_ = Phase::ReadyToPost;
} else { } else {
// Provide a genuine measure of further bytes required. // Provide a genuine measure of further bytes required.
return Instruction(-(outstanding_bytes - bytes_to_consume)); return std::make_pair(-(outstanding_bytes - bytes_to_consume), Instruction());
} }
} }
// MARK: - Check for completion. // MARK: - Check for completion.
if(phase_ == Phase::ReadyToPost) { if(phase_ == Phase::ReadyToPost) {
Instruction result(operation_, Size(operation_size_), source_, destination_, consumed_); const auto result = std::make_pair(
consumed_,
Instruction(
operation_,
source_,
destination_,
lock_,
segment_override_,
repetition_,
Size(operation_size_),
0,
0)
);
reset_parsing(); reset_parsing();
phase_ = Phase::Instruction; phase_ = Phase::Instruction;
return result; return result;
} }
// i.e. not done yet. // i.e. not done yet.
return Instruction(); return std::make_pair(0, Instruction());
} }

View File

@ -124,42 +124,58 @@ class Instruction {
private: private:
// b0, b1: a Repetition; // b0, b1: a Repetition;
// b2+: size. // b2+: operation size.
uint8_t repetition_size_ = 0; uint8_t repetition_size_ = 0;
// b0b5: source; // b0b5: source;
// b6b11: repetition; // b6b11: destination;
// b12b14: segment override; // b12b14: segment override;
// b15: lock. // b15: lock.
uint16_t sources_ = 0; uint16_t sources_ = 0;
// Unpackable fields. // Unpackable fields.
int16_t displacement_ = 0; uint16_t displacement_ = 0;
int16_t operand_ = 0; // ... or used to store a segment for far operations. uint16_t operand_ = 0; // ... or used to store a segment for far operations.
public: public:
Source source() const { return Source(sources_ & 0x3f); } Source source() const { return Source(sources_ & 0x3f); }
Source destination() const { return Source((sources_ >> 6) & 0x3f); } Source destination() const { return Source((sources_ >> 6) & 0x3f); }
bool lock() const { return sources_ & 0x8000; } bool lock() const { return sources_ & 0x8000; }
Source segment_override() const { return Source((sources_ >> 12) & 7); } Source segment_override() const { return Source((sources_ >> 12) & 7); }
Size operand_size() const { return Size::Implied; }
Size operation_size() const { return Size::Implied; }
uint16_t segment() const { return uint16_t(operand_); }
Repetition repetition() const { return Repetition(repetition_size_ & 3); } Repetition repetition() const { return Repetition(repetition_size_ & 3); }
int size() const { return int(repetition_size_ >> 2); } Size operation_size() const { return Size(repetition_size_ >> 2); }
uint16_t segment() const { return uint16_t(operand_); }
template <typename type> type displacement(); template <typename type> type displacement();
template <typename type> type immediate(); template <typename type> type immediate();
Instruction() {} Instruction() {}
Instruction(int) {} Instruction(
Instruction(Operation, Size, Source, Source, int) {} Operation operation,
Source source,
Source destination,
bool lock,
Source segment_override,
Repetition repetition,
Size operation_size,
uint16_t displacement,
uint16_t operand) :
operation(operation),
repetition_size_(uint8_t((int(operation_size) << 2) | int(repetition))),
sources_(uint16_t(
int(source) |
(int(destination) << 6) |
(int(segment_override) << 12) |
(int(lock) << 15)
)),
displacement_(displacement),
operand_(operand) {}
}; };
static_assert(sizeof(Instruction) <= 8);
/*! /*!
Implements Intel x86 instruction decoding. Implements Intel x86 instruction decoding.
@ -170,13 +186,13 @@ struct Decoder {
Decoder(Model model); Decoder(Model model);
/*! /*!
@returns an @c Instruction with a positive size to indicate successful decoding; a @returns an @c Instruction plus a size; a positive size to indicate successful decoding; a
negative size specifies the [negatived] number of further bytes the caller should ideally negative size specifies the [negatived] number of further bytes the caller should ideally
collect before calling again. The caller is free to call with fewer, but may not get a decoded collect before calling again. The caller is free to call with fewer, but may not get a decoded
instruction in response, and the decoder may still not be able to complete decoding instruction in response, and the decoder may still not be able to complete decoding
even if given that number of bytes. even if given that number of bytes.
*/ */
Instruction decode(const uint8_t *source, size_t length); std::pair<int, Instruction> decode(const uint8_t *source, size_t length);
private: private:
enum class Phase { enum class Phase {