1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-04 18:29:40 +00:00

Eliminate Ind[BXPlusSI/etc] in favour of specifying everything via a ScaleIndexBase.

This commit is contained in:
Thomas Harte 2022-02-21 11:45:46 -05:00
parent 546b4edbf1
commit 9e9e160c43
4 changed files with 91 additions and 73 deletions

View File

@ -429,37 +429,23 @@ std::pair<int, InstructionSet::x86::Instruction> Decoder::decode(const uint8_t *
}
};
switch(mod) {
case 0: {
constexpr Source rm_table[8] = {
Source::IndBXPlusSI, Source::IndBXPlusDI,
Source::IndBPPlusSI, Source::IndBPPlusDI,
Source::IndSI, Source::IndDI,
Source::DirectAddress, Source::IndBX,
};
memreg = rm_table[rm];
} break;
default: {
// TODO: switch to this table.
// constexpr ScaleIndexBase rm_table[8] = {
// ScaleIndexBase(0, Source::eBX, Source::eSI),
// ScaleIndexBase(0, Source::eBX, Source::eDI),
// ScaleIndexBase(0, Source::eBP, Source::eSI),
// ScaleIndexBase(0, Source::eBP, Source::eDI),
// ScaleIndexBase(0, Source::None, Source::eSI),
// ScaleIndexBase(0, Source::None, Source::eDI),
// ScaleIndexBase(0, Source::None, Source::eBP),
// ScaleIndexBase(0, Source::None, Source::eBX),
// };
constexpr Source rm_table[8] = {
Source::IndBXPlusSI, Source::IndBXPlusDI,
Source::IndBPPlusSI, Source::IndBPPlusDI,
Source::IndSI, Source::IndDI,
Source::IndBP, Source::IndBX,
};
memreg = rm_table[rm];
default:
displacement_size_ = 1 + (mod == 2);
[[fallthrough]];
case 0: {
constexpr ScaleIndexBase rm_table[8] = {
ScaleIndexBase(0, Source::eBX, Source::eSI),
ScaleIndexBase(0, Source::eBX, Source::eDI),
ScaleIndexBase(0, Source::eBP, Source::eSI),
ScaleIndexBase(0, Source::eBP, Source::eDI),
ScaleIndexBase(0, Source::None, Source::eSI),
ScaleIndexBase(0, Source::None, Source::eDI),
ScaleIndexBase(0, Source::None, Source::eBP),
ScaleIndexBase(0, Source::None, Source::eBX),
};
memreg = Source::Indirect;
sib_ = rm_table[rm];
} break;
// Other operand is just a register.
@ -710,6 +696,7 @@ std::pair<int, InstructionSet::x86::Instruction> Decoder::decode(const uint8_t *
operation_,
source_,
destination_,
sib_,
lock_,
segment_override_,
repetition_,

View File

@ -168,6 +168,7 @@ class Decoder {
repetition_ = Repetition::None;
phase_ = Phase::Instruction;
source_ = destination_ = Source::None;
sib_ = 0;
}
};

View File

@ -329,28 +329,21 @@ enum class Source: uint8_t {
// Legacy 8-bit registers that can't be described as e.g. 8-bit eAX.
AH, BH, CH, DH,
// Sources that are not a register.
/// The address included within this instruction should be used as the source.
DirectAddress,
/// The immediate value included within this instruction should be used as the source.
Immediate,
/// The ScaleIndexBase associated with this source should be used.
Indirect,
// TODO: compact and replace with a reference to a SIB.
IndBXPlusSI,
IndBXPlusDI,
IndBPPlusSI,
IndBPPlusDI,
IndSI,
IndDI,
IndBP,
IndBX,
/// @c None can be treated as a source that produces 0 when encountered;
/// it is semantically valid to receive it with that meaning in some contexts —
/// e.g. to indicate no index in indirect addressing.
None,
/// The ScaleIndexBase associated with this source should be used.
Indirect = 0b11000,
// Elsewhere, as an implementation detail, the low three bits of an indirect source
// are reused.
};
enum class Repetition: uint8_t {
@ -367,6 +360,8 @@ class ScaleIndexBase {
constexpr ScaleIndexBase() noexcept {}
constexpr ScaleIndexBase(uint8_t sib) noexcept : sib_(sib) {}
constexpr ScaleIndexBase(int scale, Source index, Source base) noexcept : sib_(uint8_t(scale << 6 | (int(index != Source::None ? index : Source::eSI) << 3) | int(base))) {}
constexpr ScaleIndexBase(Source index, Source base) noexcept : ScaleIndexBase(0, index, base) {}
constexpr explicit ScaleIndexBase(Source base) noexcept : ScaleIndexBase(0, Source::None, base) {}
/// @returns the power of two by which to multiply @c index() before adding it to @c base().
constexpr int scale() const {
@ -387,6 +382,18 @@ class ScaleIndexBase {
return Source(sib_ & 0x7);
}
bool operator ==(const ScaleIndexBase &rhs) const {
// Permit either exact equality or index and base being equal
// but transposed with a scale of 1.
return
(sib_ == rhs.sib_) ||
(
!scale() && !rhs.scale() &&
rhs.index() == base() &&
rhs.base() == index()
);
}
private:
// Data is stored directly as an 80386 SIB byte.
uint8_t sib_ = 0;
@ -394,6 +401,20 @@ class ScaleIndexBase {
static_assert(sizeof(ScaleIndexBase) == 1);
static_assert(alignof(ScaleIndexBase) == 1);
// TODO: improve the naming of SourceSIB.
struct SourceSIB {
SourceSIB(Source source) : source(source) {}
SourceSIB(ScaleIndexBase sib) : sib(sib) {}
SourceSIB(Source source, ScaleIndexBase sib) : source(source), sib(sib) {}
bool operator ==(const SourceSIB &rhs) const {
return source == rhs.source && (source != Source::Indirect || sib == rhs.sib);
}
Source source = Source::Indirect;
ScaleIndexBase sib;
};
class Instruction {
public:
Operation operation = Operation::Invalid;
@ -403,7 +424,8 @@ class Instruction {
repetition_size_ == rhs.repetition_size_ &&
sources_ == rhs.sources_ &&
displacement_ == rhs.displacement_ &&
operand_ == rhs.operand_;
operand_ == rhs.operand_ &&
sib_ == rhs.sib_;
}
private:
@ -421,9 +443,12 @@ class Instruction {
int16_t displacement_ = 0;
uint16_t operand_ = 0; // ... or used to store a segment for far operations.
// Fields yet to be properly incorporated...
ScaleIndexBase sib_;
public:
Source source() const { return Source(sources_ & 0x3f); }
Source destination() const { return Source((sources_ >> 6) & 0x3f); }
SourceSIB source() const { return SourceSIB(Source(sources_ & 0x3f), sib_); }
SourceSIB destination() const { return SourceSIB(Source((sources_ >> 6) & 0x3f), sib_); }
bool lock() const { return sources_ & 0x8000; }
Source segment_override() const { return Source((sources_ >> 12) & 7); }
@ -441,6 +466,7 @@ class Instruction {
Operation operation,
Source source,
Source destination,
ScaleIndexBase sib,
bool lock,
Source segment_override,
Repetition repetition,
@ -456,10 +482,12 @@ class Instruction {
(int(lock) << 15)
)),
displacement_(displacement),
operand_(operand) {}
operand_(operand),
sib_(sib) {}
};
static_assert(sizeof(Instruction) <= 8);
// TODO: repack.
//static_assert(sizeof(Instruction) <= 8);
}
}

View File

@ -17,6 +17,8 @@ namespace {
using Instruction = InstructionSet::x86::Instruction;
using Source = InstructionSet::x86::Source;
using Size = InstructionSet::x86::Size;
using ScaleIndexBase = InstructionSet::x86::ScaleIndexBase;
using SourceSIB = InstructionSet::x86::SourceSIB;
}
@interface x86DecoderTests : XCTestCase
@ -42,42 +44,42 @@ namespace {
XCTAssertEqual(instruction.operation_size(), InstructionSet::x86::Size(size));
}
- (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size source:(Source)source destination:(Source)destination displacement:(int16_t)displacement {
- (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size source:(SourceSIB)source destination:(SourceSIB)destination displacement:(int16_t)displacement {
XCTAssertEqual(instruction.operation, operation);
XCTAssertEqual(instruction.operation_size(), InstructionSet::x86::Size(size));
XCTAssertEqual(instruction.source(), source);
XCTAssertEqual(instruction.destination(), destination);
XCTAssert(instruction.source() == source);
XCTAssert(instruction.destination() == destination);
XCTAssertEqual(instruction.displacement(), displacement);
}
- (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size source:(Source)source destination:(Source)destination displacement:(int16_t)displacement operand:(uint16_t)operand {
- (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size source:(SourceSIB)source destination:(SourceSIB)destination displacement:(int16_t)displacement operand:(uint16_t)operand {
[self assert:instruction operation:operation size:size source:source destination:destination displacement:displacement];
XCTAssertEqual(instruction.operand(), operand);
}
- (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size source:(Source)source destination:(Source)destination operand:(uint16_t)operand {
- (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size source:(SourceSIB)source destination:(SourceSIB)destination operand:(uint16_t)operand {
[self assert:instruction operation:operation size:size source:source destination:destination displacement:0 operand:operand];
}
- (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size source:(Source)source destination:(Source)destination {
- (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size source:(SourceSIB)source destination:(SourceSIB)destination {
[self assert:instruction operation:operation size:size source:source destination:destination displacement:0];
}
- (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size source:(Source)source {
- (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size source:(SourceSIB)source {
XCTAssertEqual(instruction.operation, operation);
XCTAssertEqual(instruction.operation_size(), InstructionSet::x86::Size(size));
XCTAssertEqual(instruction.source(), source);
XCTAssert(instruction.source() == source);
}
- (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size destination:(Source)destination {
- (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size destination:(SourceSIB)destination {
[self assert:instruction operation:operation size:size];
XCTAssertEqual(instruction.destination(), destination);
XCTAssert(instruction.destination() == destination);
}
- (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size operand:(uint16_t)operand destination:(Source)destination {
- (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size operand:(uint16_t)operand destination:(SourceSIB)destination {
[self assert:instruction operation:operation size:size];
XCTAssertEqual(instruction.destination(), destination);
XCTAssertEqual(instruction.source(), Source::Immediate);
XCTAssert(instruction.destination() == destination);
XCTAssert(instruction.source() == SourceSIB(Source::Immediate));
XCTAssertEqual(instruction.operand(), operand);
XCTAssertEqual(instruction.displacement(), 0);
}
@ -200,15 +202,15 @@ namespace {
// adc %bh,0x3c(%bx)
[self assert:instructions[14] operation:Operation::INC size:2 source:Source::eBX destination:Source::eBX];
[self assert:instructions[15] operation:Operation::CMP size:1 operand:0x8e destination:Source::eAX];
[self assert:instructions[16] operation:Operation::SBB size:1 source:Source::IndBXPlusSI destination:Source::BH displacement:0x45];
[self assert:instructions[17] operation:Operation::ADC size:1 source:Source::BH destination:Source::IndBX displacement:0x3c];
[self assert:instructions[16] operation:Operation::SBB size:1 source:ScaleIndexBase(Source::eBX, Source::eSI) destination:Source::BH displacement:0x45];
[self assert:instructions[17] operation:Operation::ADC size:1 source:Source::BH destination:ScaleIndexBase(Source::eBX) displacement:0x3c];
// sbb %bx,0x16(%bp,%si)
// xor %sp,0x2c(%si)
// out %ax,$0xc6
// jge 0xffffffe0
[self assert:instructions[18] operation:Operation::SBB size:2 source:Source::eBX destination:Source::IndBPPlusSI displacement:0x16];
[self assert:instructions[19] operation:Operation::XOR size:2 source:Source::eSP destination:Source::IndSI displacement:0x2c];
[self assert:instructions[18] operation:Operation::SBB size:2 source:Source::eBX destination:ScaleIndexBase(Source::eBP, Source::eSI) displacement:0x16];
[self assert:instructions[19] operation:Operation::XOR size:2 source:Source::eSP destination:ScaleIndexBase(Source::eSI) displacement:0x2c];
[self assert:instructions[20] operation:Operation::OUT size:2 source:Source::eAX destination:Source::DirectAddress operand:0xc6];
[self assert:instructions[21] operation:Operation::JNL displacement:0xffb0];
@ -228,7 +230,7 @@ namespace {
// in $0xc9,%ax
[self assert:instructions[26] operation:Operation::PUSH size:2 source:Source::eAX];
[self assert:instructions[27] operation:Operation::JS displacement:0x3d];
[self assert:instructions[28] operation:Operation::ADD size:2 source:Source::IndDI destination:Source::eBX];
[self assert:instructions[28] operation:Operation::ADD size:2 source:ScaleIndexBase(Source::eDI) destination:Source::eBX];
[self assert:instructions[29] operation:Operation::IN size:2 source:Source::DirectAddress destination:Source::eAX operand:0xc9];
// xchg %ax,%di
@ -274,7 +276,7 @@ namespace {
// adc $0xb8c3,%ax
// lods %ds:(%si),%ax
[self assert:instructions[46] operation:Operation::XCHG size:2 source:Source::eAX destination:Source::eDX];
[self assert:instructions[47] operation:Operation::CMP size:2 source:Source::eBX destination:Source::IndDI displacement:0xff90];
[self assert:instructions[47] operation:Operation::CMP size:2 source:Source::eBX destination:ScaleIndexBase(Source::eDI) displacement:0xff90];
[self assert:instructions[48] operation:Operation::ADC size:2 operand:0xb8c3 destination:Source::eAX];
[self assert:instructions[49] operation:Operation::LODS size:2];
@ -300,10 +302,10 @@ namespace {
// sub %dl,%dl
// negw 0x18(%bx)
// xchg %dl,0x6425(%bx,%si)
[self assert:instructions[58] operation:Operation::AND size:2 source:Source::IndBPPlusSI destination:Source::eBP displacement:0x5b2c];
[self assert:instructions[58] operation:Operation::AND size:2 source:ScaleIndexBase(Source::eBP, Source::eSI) destination:Source::eBP displacement:0x5b2c];
[self assert:instructions[59] operation:Operation::SUB size:1 source:Source::eDX destination:Source::eDX];
[self assert:instructions[60] operation:Operation::NEG size:2 source:Source::IndBX destination:Source::IndBX displacement:0x18];
[self assert:instructions[61] operation:Operation::XCHG size:1 source:Source::IndBXPlusSI destination:Source::eDX displacement:0x6425];
[self assert:instructions[60] operation:Operation::NEG size:2 source:ScaleIndexBase(Source::eBX) destination:ScaleIndexBase(Source::eBX) displacement:0x18];
[self assert:instructions[61] operation:Operation::XCHG size:1 source:ScaleIndexBase(Source::eBX, Source::eSI) destination:Source::eDX displacement:0x6425];
// mov $0xc3,%bh
[self assert:instructions[62] operation:Operation::MOV size:1 operand:0xc3 destination:Source::BH];
@ -317,9 +319,9 @@ namespace {
}];
XCTAssertEqual(instructions.size(), 3);
[self assert:instructions[0] operation:Operation::ADC size:2 source:Source::Immediate destination:Source::IndBXPlusSI operand:0xff80];
[self assert:instructions[1] operation:Operation::CMP size:2 source:Source::Immediate destination:Source::IndBPPlusDI operand:0x4];
[self assert:instructions[2] operation:Operation::SUB size:2 source:Source::Immediate destination:Source::IndBX operand:0x9];
[self assert:instructions[0] operation:Operation::ADC size:2 source:Source::Immediate destination:ScaleIndexBase(Source::eBX, Source::eSI) operand:0xff80];
[self assert:instructions[1] operation:Operation::CMP size:2 source:Source::Immediate destination:ScaleIndexBase(Source::eBP, Source::eDI) operand:0x4];
[self assert:instructions[2] operation:Operation::SUB size:2 source:Source::Immediate destination:ScaleIndexBase(Source::eBX) operand:0x9];
}
- (void)testFar {