mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Eliminate Ind[BXPlusSI/etc] in favour of specifying everything via a ScaleIndexBase.
This commit is contained in:
parent
546b4edbf1
commit
9e9e160c43
@ -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_,
|
||||
|
@ -168,6 +168,7 @@ class Decoder {
|
||||
repetition_ = Repetition::None;
|
||||
phase_ = Phase::Instruction;
|
||||
source_ = destination_ = Source::None;
|
||||
sib_ = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user