1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-06 13:31:55 +00:00

Improves exposition, adds decoding of the 0xbx patch of MOVs.

This commit is contained in:
Thomas Harte 2021-01-03 19:33:16 -05:00
parent adcb2e03e8
commit 0ae217f51d
2 changed files with 55 additions and 17 deletions

View File

@ -27,6 +27,15 @@ Instruction Decoder::decode(uint8_t *source, size_t length) {
phase_ = Phase::phs; \
break
#define MapRegData(value, op, lrg, dest) \
case value: \
operation_ = Operation::op; \
large_operand_ = lrg; \
source_ = Source::Immediate; \
destination_ = Source::dest; \
phase_ = Phase::AwaitingOperands; \
break
#define MapComplete(value, op, src, dest) \
case value: \
operation_ = Operation::op; \
@ -50,8 +59,8 @@ Instruction Decoder::decode(uint8_t *source, size_t length) {
MapPartial(start + 0x01, operation, true, MemReg_Reg, ModRM); \
MapPartial(start + 0x02, operation, false, Reg_MemReg, ModRM); \
MapPartial(start + 0x03, operation, true, Reg_MemReg, ModRM); \
MapPartial(start + 0x04, operation, false, Ac_Data, AwaitingOperands); \
MapPartial(start + 0x05, operation, true, Ac_Data, AwaitingOperands);
MapRegData(start + 0x04, operation, false, AL); \
MapRegData(start + 0x05, operation, true, AX);
PartialBlock(0x00, ADD);
MapComplete(0x06, PUSH, ES, None);
@ -164,6 +173,15 @@ Instruction Decoder::decode(uint8_t *source, size_t length) {
MapPartial(0xa0, MOV, false, Reg_Addr, AwaitingOperands);
MapRegData(0xb0, MOV, false, AL); MapRegData(0xb1, MOV, false, CL);
MapRegData(0xb2, MOV, false, DL); MapRegData(0xb3, MOV, false, BL);
MapRegData(0xb4, MOV, false, AH); MapRegData(0xb5, MOV, false, CH);
MapRegData(0xb6, MOV, false, DH); MapRegData(0xb7, MOV, false, BH);
MapRegData(0xb8, MOV, true, AX); MapRegData(0xb9, MOV, true, CX);
MapRegData(0xba, MOV, true, DX); MapRegData(0xbb, MOV, true, BX);
MapRegData(0xbc, MOV, true, SP); MapRegData(0xbd, MOV, true, BP);
MapRegData(0xbe, MOV, true, SI); MapRegData(0xbf, MOV, true, DI);
// Other prefix bytes.
case 0xf0: lock_ = true; break;
case 0xf2: repetition_ = Repetition::RepNE; break;
@ -256,12 +274,8 @@ Instruction Decoder::decode(uint8_t *source, size_t length) {
if(phase_ == Phase::ReadyToPost) {
Instruction result;
switch(format_) {
case Format::Ac_Data:
if(large_operand_) {
result = Instruction(operation_, Size::Word, Source::AX, Source::Immediate, consumed_);
} else {
result = Instruction(operation_, Size::Byte, Source::AL, Source::Immediate, consumed_);
}
case Format::Reg_Data:
result = Instruction(operation_, large_operand_ ? Size::Word : Size::Byte, source_, destination_, consumed_);
break;
case Format::Disp:

View File

@ -115,31 +115,46 @@ struct Decoder {
private:
enum class Phase {
/// Captures all prefixes and continues until an instruction byte is encountered.
Instruction,
/// Receives a ModRM byte and either populates the source_ and dest_ fields appropriately
/// or completes decoding of the instruction, as per the instruction format.
ModRM,
/// Waits for sufficiently many bytes to pass for all associated operands to be captured.
AwaitingOperands,
/// Forms and returns an Instruction, and resets parsing state.
ReadyToPost
} phase_ = Phase::Instruction;
/// During the ModRM phase, format dictates interpretation of the ModRM byte.
///
/// During the ReadyToPost phase, format determines how transiently-recorded fields
/// are packaged into an Instruction.
enum class Format: uint8_t {
Implied,
// In both cases: pass the ModRM for mode, register and register/memory
// flags and populate the source_ and destination_ fields appropriate.
// During the ModRM phase they'll be populated as source_ = register,
// destination_ = register/memory; the ReadyToPost phase should switch
// those around as necessary.
MemReg_Reg,
Reg_MemReg,
Ac_Data,
MemReg_Data,
SegReg_MemReg,
Reg_Data,
//
Reg_Addr,
Addr_Reg,
SegReg_MemReg,
Disp,
Addr
} format_ = Format::MemReg_Reg;
// TODO: figure out which Formats can be folded together,
// and which are improperly elided.
enum class Repetition: uint8_t {
None, RepE, RepNE
} repetition_ = Repetition::None;
// Ephemeral decoding state.
Operation operation_ = Operation::Invalid;
bool large_operand_ = false;
Source source_ = Source::None;
@ -148,14 +163,23 @@ struct Decoder {
bool add_offset_ = false;
bool large_offset_ = false;
int consumed_ = 0;
int operand_bytes_ = 0;
// Prefix capture fields.
enum class Repetition: uint8_t {
None, RepE, RepNE
} repetition_ = Repetition::None;
bool lock_ = false;
Source segment_override_ = Source::None;
// Size capture.
int consumed_ = 0;
int operand_bytes_ = 0;
/// Resets size capture and all fields with default values.
void reset_parsing() {
consumed_ = operand_bytes_ = 0;
lock_ = false;
segment_override_ = Source::None;
repetition_ = Repetition::None;
}
};