diff --git a/OSBindings/Mac/Clock SignalTests/x86DecoderTests.mm b/OSBindings/Mac/Clock SignalTests/x86DecoderTests.mm index 310d4723f..6d4321818 100644 --- a/OSBindings/Mac/Clock SignalTests/x86DecoderTests.mm +++ b/OSBindings/Mac/Clock SignalTests/x86DecoderTests.mm @@ -33,6 +33,10 @@ namespace { // MARK: - Specific instruction asserts. +- (void)assert:(Instruction &)instruction operation:(Operation)operation { + XCTAssertEqual(instruction.operation, operation); +} + - (void)assert:(Instruction &)instruction operation:(Operation)operation size:(int)size source:(Source)source destination:(Source)destination { XCTAssertEqual(instruction.operation, operation); XCTAssertEqual(instruction.operation_size(), CPU::Decoder::x86::Size(size)); @@ -53,6 +57,10 @@ namespace { XCTAssertEqual(instruction.displacement(), displacement); } +- (void)assert:(Instruction &)instruction operation:(Operation)operation operand:(uint16_t)operand { + XCTAssertEqual(instruction.operation, operation); + XCTAssertEqual(instruction.operand(), operand); +} // MARK: - Decoder @@ -108,23 +116,35 @@ namespace { // dec %bx // mov $0x28,%ch [self assert:instructions[0] operation:Operation::SUB size:2 operand:0xea77 destination:Source::AX]; - [self assert:instructions[1] operation:Operation::JB displacement:0x01]; + [self assert:instructions[1] operation:Operation::JB displacement:0xfffc]; [self assert:instructions[2] operation:Operation::DEC size:2 source:Source::BX destination:Source::BX]; [self assert:instructions[3] operation:Operation::MOV size:1 operand:0x28 destination:Source::CH]; // ret // lret $0x4826 - // gs insw (%dx),%es:(%di) + // [[ gs insw (%dx),%es:(%di) ]] // jnp 0xffffffaf // ret $0x4265 + [self assert:instructions[4] operation:Operation::RETN]; + [self assert:instructions[5] operation:Operation::RETF operand:0x4826]; + [self assert:instructions[6] operation:Operation::JNP displacement:0xff9f]; + [self assert:instructions[7] operation:Operation::RETN operand:0x4265]; + // dec %si // out %ax,(%dx) // jo 0x00000037 // xchg %ax,%sp + [self assert:instructions[8] operation:Operation::DEC size:2 source:Source::SI destination:Source::SI]; + [self assert:instructions[9] operation:Operation::OUT size:2 source:Source::AX destination:Source::DX]; + [self assert:instructions[10] operation:Operation::JO displacement:0x20]; + [self assert:instructions[11] operation:Operation::XCHG size:2 source:Source::AX destination:Source::SP]; + // (bad) // aam $0x93 // inc %bx // cmp $0x8e,%al +// [self assert:instructions[12] operation:Operation::Invalid]; + // push $0x65 // sbb 0x45(%bx,%si),%bh // adc %bh,0x3c(%bx) diff --git a/Processors/Decoders/x86/x86.cpp b/Processors/Decoders/x86/x86.cpp index d4814f388..0b63a6399 100644 --- a/Processors/Decoders/x86/x86.cpp +++ b/Processors/Decoders/x86/x86.cpp @@ -65,7 +65,7 @@ std::pair Decoder::decode(const uint8_t *source, size_t length #define Jump(op) \ operation_ = Operation::op; \ phase_ = Phase::AwaitingDisplacementOrOperand; \ - operand_size_ = 1 + displacement_size_ = 1 /// Handles far CALL and far JMP — fixed four byte operand operations. #define Far(op) \ @@ -298,7 +298,7 @@ std::pair Decoder::decode(const uint8_t *source, size_t length case 0xec: Complete(IN, DX, AL, 1); break; case 0xed: Complete(IN, DX, AX, 1); break; case 0xee: Complete(OUT, AL, DX, 1); break; - case 0xef: Complete(OUT, AX, DX, 1); break; + case 0xef: Complete(OUT, AX, DX, 2); break; case 0xf4: Complete(HLT, None, None, 1); break; case 0xf5: Complete(CMC, None, None, 1); break; @@ -540,14 +540,28 @@ std::pair Decoder::decode(const uint8_t *source, size_t length const int outstanding_bytes = required_bytes - operand_bytes_; const int bytes_to_consume = std::min(int(end - source), outstanding_bytes); - // TODO: fill displacement_ and operand_ here... efficiently? + // TODO: I can surely do better than this? + for(int c = 0; c < bytes_to_consume; c++) { + inward_data_ = (inward_data_ >> 8) | (uint64_t(source[0]) << 56); + ++source; + } - source += bytes_to_consume; consumed_ += bytes_to_consume; operand_bytes_ += bytes_to_consume; if(bytes_to_consume == outstanding_bytes) { phase_ = Phase::ReadyToPost; + + switch(operand_size_) { + default: operand_ = 0; break; + case 1: operand_ = inward_data_ >> 56; inward_data_ <<= 8; break; + case 2: operand_ = inward_data_ >> 48; inward_data_ <<= 16; break; + } + switch(displacement_size_) { + default: displacement_ = 0; break; + case 1: displacement_ = int8_t(inward_data_ >> 56); break; + case 2: displacement_ = int16_t(inward_data_ >> 48); break; + } } else { // Provide a genuine measure of further bytes required. return std::make_pair(-(outstanding_bytes - bytes_to_consume), Instruction()); diff --git a/Processors/Decoders/x86/x86.hpp b/Processors/Decoders/x86/x86.hpp index d39da8f88..0c7894bfe 100644 --- a/Processors/Decoders/x86/x86.hpp +++ b/Processors/Decoders/x86/x86.hpp @@ -273,6 +273,7 @@ struct Decoder { // Immediate fields. int16_t displacement_ = 0; uint16_t operand_ = 0; + uint64_t inward_data_ = 0; // Facts about the instruction. int displacement_size_ = 0; // i.e. size of in-stream displacement, if any.