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:
parent
306df7554e
commit
86577b772b
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {}
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
// b0–b5: source;
|
// b0–b5: source;
|
||||||
// b6–b11: repetition;
|
// b6–b11: destination;
|
||||||
// b12–b14: segment override;
|
// b12–b14: 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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user