1
0
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:
Thomas Harte 2021-01-10 22:55:25 -05:00
parent 9ba5b7c1d4
commit 762ecab3aa
3 changed files with 41 additions and 6 deletions

View File

@ -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)

View File

@ -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());

View File

@ -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.