1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-30 04:50:08 +00:00

Adds byte-by-byte decoder test; corrects divergences.

This commit is contained in:
Thomas Harte 2021-01-13 21:51:18 -05:00
parent 8c0e06e645
commit 2c72a77a25
3 changed files with 62 additions and 53 deletions

View File

@ -23,7 +23,7 @@ namespace {
@end @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 word streams and checking that the result matches what I got from a
disassembler elsewhere. disassembler elsewhere.
*/ */
@ -98,26 +98,30 @@ namespace {
// MARK: - Decoder // MARK: - Decoder
- (void)decode:(const std::initializer_list<uint8_t> &)stream { - (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); 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(); instructions.clear();
const uint8_t *byte = stream.begin(); const uint8_t *byte = stream.begin();
while(byte != stream.end()) { while(byte != stream.end()) {
const auto [size, next] = decoder.decode(byte, stream.end() - byte); const auto [size, next] = decoder.decode(byte, stream.end() - byte);
if(size <= 0) break; if(size <= 0) break;
NSLog(@"%@ %@", @(instructions.size()), @(size));
instructions.push_back(next); instructions.push_back(next);
byte += size; 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 // MARK: - Tests
@ -256,7 +260,7 @@ namespace {
// sahf // sahf
// fdiv %st(3),%st // fdiv %st(3),%st
// iret // 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[43] operation:Operation::SAHF];
[self assert:instructions[44] operation:Operation::ESC]; [self assert:instructions[44] operation:Operation::ESC];
[self assert:instructions[45] operation:Operation::IRET]; [self assert:instructions[45] operation:Operation::IRET];

View File

@ -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 0xc2: RegData(RETN, None, 2); break;
case 0xc3: Complete(RETN, None, None, 2); break; case 0xc3: Complete(RETN, None, None, 2); break;
case 0xc4: MemRegReg(LES, Reg_MemReg, 4); break; case 0xc4: MemRegReg(LES, Reg_MemReg, 2); break;
case 0xc5: MemRegReg(LDS, Reg_MemReg, 4); break; case 0xc5: MemRegReg(LDS, Reg_MemReg, 2); break;
case 0xc6: MemRegReg(MOV, MemRegMOV, 1); break; case 0xc6: MemRegReg(MOV, MemRegMOV, 1); break;
case 0xc7: MemRegReg(MOV, MemRegMOV, 2); 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); default: assert(false);
} }
phase_ = Phase::AwaitingDisplacementOrOperand; phase_ = (displacement_size_ + operand_size_) ? Phase::AwaitingDisplacementOrOperand : Phase::ReadyToPost;
} }
// MARK: - Displacement and operand. // 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) { if(phase_ == Phase::AwaitingDisplacementOrOperand && source != end) {
const int required_bytes = displacement_size_ + operand_size_; 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 outstanding_bytes = required_bytes - operand_bytes_;
const int bytes_to_consume = std::min(int(end - source), outstanding_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; operand_ = inward_data_ >> 56; inward_data_ <<= 8;
// Sign extend if a single byte operand is feeding a two-byte instruction. // 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; operand_ |= (operand_ & 0x80) ? 0xff00 : 0x0000;
} }
break; 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()); return std::make_pair(-(outstanding_bytes - bytes_to_consume), Instruction());
} }
} }
}
// MARK: - Check for completion. // MARK: - Check for completion.

View File

@ -122,6 +122,14 @@ class Instruction {
public: public:
Operation operation = Operation::Invalid; 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: private:
// b0, b1: a Repetition; // b0, b1: a Repetition;
// b2+: operation size. // b2+: operation size.
@ -300,6 +308,7 @@ struct Decoder {
segment_override_ = Source::None; segment_override_ = Source::None;
repetition_ = Repetition::None; repetition_ = Repetition::None;
phase_ = Phase::Instruction; phase_ = Phase::Instruction;
source_ = destination_ = Source::None;
} }
}; };