diff --git a/InstructionSets/x86/Decoder.cpp b/InstructionSets/x86/Decoder.cpp index 458facbea..45dd5ef71 100644 --- a/InstructionSets/x86/Decoder.cpp +++ b/InstructionSets/x86/Decoder.cpp @@ -429,37 +429,23 @@ std::pair 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 Decoder::decode(const uint8_t * operation_, source_, destination_, + sib_, lock_, segment_override_, repetition_, diff --git a/InstructionSets/x86/Decoder.hpp b/InstructionSets/x86/Decoder.hpp index 59fd09beb..e2c68a907 100644 --- a/InstructionSets/x86/Decoder.hpp +++ b/InstructionSets/x86/Decoder.hpp @@ -168,6 +168,7 @@ class Decoder { repetition_ = Repetition::None; phase_ = Phase::Instruction; source_ = destination_ = Source::None; + sib_ = 0; } }; diff --git a/InstructionSets/x86/Instruction.hpp b/InstructionSets/x86/Instruction.hpp index 23259c27d..897b0a770 100644 --- a/InstructionSets/x86/Instruction.hpp +++ b/InstructionSets/x86/Instruction.hpp @@ -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); } } diff --git a/OSBindings/Mac/Clock SignalTests/x86DecoderTests.mm b/OSBindings/Mac/Clock SignalTests/x86DecoderTests.mm index dc9801728..51617d7b4 100644 --- a/OSBindings/Mac/Clock SignalTests/x86DecoderTests.mm +++ b/OSBindings/Mac/Clock SignalTests/x86DecoderTests.mm @@ -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 {