mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Adds byte-by-byte decoder test; corrects divergences.
This commit is contained in:
parent
8c0e06e645
commit
2c72a77a25
@ -23,7 +23,7 @@ namespace {
|
||||
@end
|
||||
|
||||
/*!
|
||||
Tests PowerPC decoding by throwing a bunch of randomly-generated
|
||||
Tests 8086 decoding by throwing a bunch of randomly-generated
|
||||
word streams and checking that the result matches what I got from a
|
||||
disassembler elsewhere.
|
||||
*/
|
||||
@ -98,26 +98,30 @@ namespace {
|
||||
// MARK: - Decoder
|
||||
|
||||
- (void)decode:(const std::initializer_list<uint8_t> &)stream {
|
||||
// Decode by offering up all data at once.
|
||||
CPU::Decoder::x86::Decoder decoder(CPU::Decoder::x86::Model::i8086);
|
||||
|
||||
// TODO: test that byte-at-a-time decoding gives the same results, as a freebie.
|
||||
// instructions.clear();
|
||||
// for(auto item: stream) {
|
||||
// const auto next = decoder.decode(&item, 1);
|
||||
// if(next.size() > 0) {
|
||||
// instructions.push_back(next);
|
||||
// }
|
||||
// }
|
||||
|
||||
instructions.clear();
|
||||
const uint8_t *byte = stream.begin();
|
||||
while(byte != stream.end()) {
|
||||
const auto [size, next] = decoder.decode(byte, stream.end() - byte);
|
||||
if(size <= 0) break;
|
||||
NSLog(@"%@ %@", @(instructions.size()), @(size));
|
||||
instructions.push_back(next);
|
||||
byte += size;
|
||||
}
|
||||
|
||||
// Grab a byte-at-a-time decoding and check that it matches the previous.
|
||||
{
|
||||
CPU::Decoder::x86::Decoder decoder(CPU::Decoder::x86::Model::i8086);
|
||||
|
||||
auto previous_instruction = instructions.begin();
|
||||
for(auto item: stream) {
|
||||
const auto [size, next] = decoder.decode(&item, 1);
|
||||
if(size > 0) {
|
||||
XCTAssert(next == *previous_instruction);
|
||||
++previous_instruction;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Tests
|
||||
@ -256,7 +260,7 @@ namespace {
|
||||
// sahf
|
||||
// fdiv %st(3),%st
|
||||
// iret
|
||||
[self assert:instructions[42] operation:Operation::LDS size:4];
|
||||
[self assert:instructions[42] operation:Operation::LDS size:2];
|
||||
[self assert:instructions[43] operation:Operation::SAHF];
|
||||
[self assert:instructions[44] operation:Operation::ESC];
|
||||
[self assert:instructions[45] operation:Operation::IRET];
|
||||
|
@ -238,8 +238,8 @@ std::pair<int, Instruction> Decoder::decode(const uint8_t *source, size_t length
|
||||
|
||||
case 0xc2: RegData(RETN, None, 2); break;
|
||||
case 0xc3: Complete(RETN, None, None, 2); break;
|
||||
case 0xc4: MemRegReg(LES, Reg_MemReg, 4); break;
|
||||
case 0xc5: MemRegReg(LDS, Reg_MemReg, 4); break;
|
||||
case 0xc4: MemRegReg(LES, Reg_MemReg, 2); break;
|
||||
case 0xc5: MemRegReg(LDS, Reg_MemReg, 2); break;
|
||||
case 0xc6: MemRegReg(MOV, MemRegMOV, 1); break;
|
||||
case 0xc7: MemRegReg(MOV, MemRegMOV, 2); break;
|
||||
|
||||
@ -552,7 +552,7 @@ std::pair<int, Instruction> Decoder::decode(const uint8_t *source, size_t length
|
||||
default: assert(false);
|
||||
}
|
||||
|
||||
phase_ = Phase::AwaitingDisplacementOrOperand;
|
||||
phase_ = (displacement_size_ + operand_size_) ? Phase::AwaitingDisplacementOrOperand : Phase::ReadyToPost;
|
||||
}
|
||||
|
||||
// MARK: - Displacement and operand.
|
||||
@ -560,9 +560,6 @@ std::pair<int, Instruction> Decoder::decode(const uint8_t *source, size_t length
|
||||
if(phase_ == Phase::AwaitingDisplacementOrOperand && source != end) {
|
||||
const int required_bytes = displacement_size_ + operand_size_;
|
||||
|
||||
if(!required_bytes) {
|
||||
phase_ = Phase::ReadyToPost;
|
||||
} else {
|
||||
const int outstanding_bytes = required_bytes - operand_bytes_;
|
||||
const int bytes_to_consume = std::min(int(end - source), outstanding_bytes);
|
||||
|
||||
@ -584,7 +581,7 @@ std::pair<int, Instruction> Decoder::decode(const uint8_t *source, size_t length
|
||||
operand_ = inward_data_ >> 56; inward_data_ <<= 8;
|
||||
|
||||
// Sign extend if a single byte operand is feeding a two-byte instruction.
|
||||
if(operation_size_ == 2) {
|
||||
if(operation_size_ == 2 && operation_ != Operation::IN && operation_ != Operation::OUT) {
|
||||
operand_ |= (operand_ & 0x80) ? 0xff00 : 0x0000;
|
||||
}
|
||||
break;
|
||||
@ -600,7 +597,6 @@ std::pair<int, Instruction> Decoder::decode(const uint8_t *source, size_t length
|
||||
return std::make_pair(-(outstanding_bytes - bytes_to_consume), Instruction());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Check for completion.
|
||||
|
||||
|
@ -122,6 +122,14 @@ class Instruction {
|
||||
public:
|
||||
Operation operation = Operation::Invalid;
|
||||
|
||||
bool operator ==(const Instruction &rhs) const {
|
||||
return
|
||||
repetition_size_ == rhs.repetition_size_ &&
|
||||
sources_ == rhs.sources_ &&
|
||||
displacement_ == rhs.displacement_ &&
|
||||
operand_ == rhs.operand_;
|
||||
}
|
||||
|
||||
private:
|
||||
// b0, b1: a Repetition;
|
||||
// b2+: operation size.
|
||||
@ -300,6 +308,7 @@ struct Decoder {
|
||||
segment_override_ = Source::None;
|
||||
repetition_ = Repetition::None;
|
||||
phase_ = Phase::Instruction;
|
||||
source_ = destination_ = Source::None;
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user