mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-05 21:32:55 +00:00
Adds operand/displacement capture.
This gets unit test as far as a disagreement over how to handle bad 0xc4 suffixes.
This commit is contained in:
parent
9ba5b7c1d4
commit
762ecab3aa
@ -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)
|
||||
|
@ -65,7 +65,7 @@ std::pair<int, Instruction> 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<int, Instruction> 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<int, Instruction> 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());
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user