mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-19 08:31:11 +00:00
Execute some tests at some facile level.
This commit is contained in:
parent
a0ca0bb3c0
commit
2d17d9d316
@ -63,7 +63,7 @@ IntT overflow(IntT lhs, IntT rhs, IntT result) {
|
||||
// Order Number 243191; e.g. https://www.ardent-tool.com/CPU/docs/Intel/IA/243191-002.pdf
|
||||
//
|
||||
|
||||
inline void aaa(CPU::RegisterPair16 &ax, Status &status) {
|
||||
inline void aaa(CPU::RegisterPair16 &ax, Status &status) { // P. 313
|
||||
/*
|
||||
IF ((AL AND 0FH) > 9) OR (AF = 1)
|
||||
THEN
|
||||
|
@ -74,6 +74,15 @@ struct Status {
|
||||
|
||||
// TODO: the rest.
|
||||
}
|
||||
|
||||
uint16_t get() const {
|
||||
return
|
||||
(carry ? ConditionCode::Carry : 0);
|
||||
}
|
||||
|
||||
bool operator ==(const Status &rhs) const {
|
||||
return get() == rhs.get();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -27,6 +27,87 @@ namespace {
|
||||
// provide their real path here.
|
||||
constexpr char TestSuiteHome[] = "/Users/tharte/Projects/ProcessorTests/8088/v1";
|
||||
|
||||
struct Registers {
|
||||
CPU::RegisterPair16 ax_;
|
||||
uint8_t &al() { return ax_.halves.low; }
|
||||
uint8_t &ah() { return ax_.halves.high; }
|
||||
uint16_t &ax() { return ax_.full; }
|
||||
|
||||
CPU::RegisterPair16 &axp() { return ax_; }
|
||||
|
||||
CPU::RegisterPair16 cx_;
|
||||
uint8_t &cl() { return cx_.halves.low; }
|
||||
uint8_t &ch() { return cx_.halves.high; }
|
||||
uint16_t &cx() { return cx_.full; }
|
||||
|
||||
CPU::RegisterPair16 dx_;
|
||||
uint8_t &dl() { return dx_.halves.low; }
|
||||
uint8_t &dh() { return dx_.halves.high; }
|
||||
uint16_t &dx() { return dx_.full; }
|
||||
|
||||
CPU::RegisterPair16 bx_;
|
||||
uint8_t &bl() { return bx_.halves.low; }
|
||||
uint8_t &bh() { return bx_.halves.high; }
|
||||
uint16_t &bx() { return bx_.full; }
|
||||
|
||||
uint16_t sp_;
|
||||
uint16_t &sp() { return sp_; }
|
||||
|
||||
uint16_t bp_;
|
||||
uint16_t &bp() { return bp_; }
|
||||
|
||||
uint16_t si_;
|
||||
uint16_t &si() { return si_; }
|
||||
|
||||
uint16_t di_;
|
||||
uint16_t &di() { return di_; }
|
||||
|
||||
uint16_t es_, cs_, ds_, ss_;
|
||||
uint16_t ip_;
|
||||
|
||||
bool operator ==(const Registers &rhs) const {
|
||||
return
|
||||
ax_.full == rhs.ax_.full &&
|
||||
cx_.full == rhs.cx_.full &&
|
||||
dx_.full == rhs.dx_.full &&
|
||||
bx_.full == rhs.bx_.full &&
|
||||
sp_ == rhs.sp_ &&
|
||||
bp_ == rhs.bp_ &&
|
||||
si_ == rhs.si_ &&
|
||||
di_ == rhs.di_ &&
|
||||
es_ == rhs.es_ &&
|
||||
cs_ == rhs.cs_ &&
|
||||
ds_ == rhs.ds_ &&
|
||||
si_ == rhs.si_ &&
|
||||
ip_ == rhs.ip_;
|
||||
}
|
||||
};
|
||||
struct Memory {
|
||||
std::vector<uint8_t> memory;
|
||||
const Registers ®isters_;
|
||||
|
||||
Memory(Registers ®isters) : registers_(registers) {
|
||||
memory.resize(1024*1024);
|
||||
}
|
||||
|
||||
template <typename IntT> IntT &access([[maybe_unused]] InstructionSet::x86::Source segment, uint16_t address) {
|
||||
uint32_t physical_address;
|
||||
using Source = InstructionSet::x86::Source;
|
||||
switch(segment) {
|
||||
default: physical_address = registers_.ds_; break;
|
||||
case Source::ES: physical_address = registers_.es_; break;
|
||||
case Source::CS: physical_address = registers_.cs_; break;
|
||||
case Source::DS: physical_address = registers_.ds_; break;
|
||||
}
|
||||
physical_address = ((physical_address << 4) + address) & 0xf'ffff;
|
||||
return *reinterpret_cast<IntT *>(&memory[physical_address]);
|
||||
}
|
||||
};
|
||||
struct IO {
|
||||
};
|
||||
struct FlowController {
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@interface i8088Tests : XCTestCase
|
||||
@ -37,6 +118,7 @@ constexpr char TestSuiteHome[] = "/Users/tharte/Projects/ProcessorTests/8088/v1"
|
||||
- (NSArray<NSString *> *)testFiles {
|
||||
NSString *path = [NSString stringWithUTF8String:TestSuiteHome];
|
||||
NSSet *allowList = [NSSet setWithArray:@[
|
||||
@"D4.json.gz"
|
||||
]];
|
||||
|
||||
NSSet *ignoreList = nil;
|
||||
@ -168,75 +250,30 @@ constexpr char TestSuiteHome[] = "/Users/tharte/Projects/ProcessorTests/8088/v1"
|
||||
return isEqual;
|
||||
}
|
||||
|
||||
- (void)populate:(Registers &)registers status:(InstructionSet::x86::Status &)status value:(NSDictionary *)value {
|
||||
registers.ax_.full = [value[@"ax"] intValue];
|
||||
registers.bx_.full = [value[@"bx"] intValue];
|
||||
registers.cx_.full = [value[@"cx"] intValue];
|
||||
registers.dx_.full = [value[@"dx"] intValue];
|
||||
|
||||
registers.bp_ = [value[@"bp"] intValue];
|
||||
registers.cs_ = [value[@"cs"] intValue];
|
||||
registers.di_ = [value[@"di"] intValue];
|
||||
registers.ds_ = [value[@"ds"] intValue];
|
||||
registers.es_ = [value[@"es"] intValue];
|
||||
registers.si_ = [value[@"si"] intValue];
|
||||
registers.sp_ = [value[@"sp"] intValue];
|
||||
registers.ss_ = [value[@"ss"] intValue];
|
||||
registers.ip_ = [value[@"ip"] intValue];
|
||||
|
||||
status.set([value[@"flags"] intValue]);
|
||||
}
|
||||
|
||||
- (bool)applyExecutionTest:(NSDictionary *)test file:(NSString *)file assert:(BOOL)assert {
|
||||
InstructionSet::x86::Decoder<InstructionSet::x86::Model::i8086> decoder;
|
||||
const auto data = [self bytes:test[@"bytes"]];
|
||||
const auto decoded = decoder.decode(data.data(), data.size());
|
||||
|
||||
struct Registers {
|
||||
CPU::RegisterPair16 ax_;
|
||||
uint8_t &al() { return ax_.halves.low; }
|
||||
uint8_t &ah() { return ax_.halves.high; }
|
||||
uint16_t &ax() { return ax_.full; }
|
||||
|
||||
CPU::RegisterPair16 &axp() { return ax_; }
|
||||
|
||||
CPU::RegisterPair16 cx_;
|
||||
uint8_t &cl() { return cx_.halves.low; }
|
||||
uint8_t &ch() { return cx_.halves.high; }
|
||||
uint16_t &cx() { return cx_.full; }
|
||||
|
||||
CPU::RegisterPair16 dx_;
|
||||
uint8_t &dl() { return dx_.halves.low; }
|
||||
uint8_t &dh() { return dx_.halves.high; }
|
||||
uint16_t &dx() { return dx_.full; }
|
||||
|
||||
CPU::RegisterPair16 bx_;
|
||||
uint8_t &bl() { return bx_.halves.low; }
|
||||
uint8_t &bh() { return bx_.halves.high; }
|
||||
uint16_t &bx() { return bx_.full; }
|
||||
|
||||
uint16_t sp_;
|
||||
uint16_t &sp() { return sp_; }
|
||||
|
||||
uint16_t bp_;
|
||||
uint16_t &bp() { return bp_; }
|
||||
|
||||
uint16_t si_;
|
||||
uint16_t &si() { return si_; }
|
||||
|
||||
uint16_t di_;
|
||||
uint16_t &di() { return di_; }
|
||||
|
||||
uint16_t es_, cs_, ds_, ss_;
|
||||
uint16_t ip_;
|
||||
};
|
||||
struct Memory {
|
||||
std::vector<uint8_t> memory;
|
||||
const Registers ®isters_;
|
||||
|
||||
Memory(Registers ®isters) : registers_(registers) {
|
||||
memory.resize(1024*1024);
|
||||
}
|
||||
|
||||
template <typename IntT> IntT &access([[maybe_unused]] InstructionSet::x86::Source segment, uint16_t address) {
|
||||
uint32_t physical_address;
|
||||
using Source = InstructionSet::x86::Source;
|
||||
switch(segment) {
|
||||
default: physical_address = registers_.ds_; break;
|
||||
case Source::ES: physical_address = registers_.es_; break;
|
||||
case Source::CS: physical_address = registers_.cs_; break;
|
||||
case Source::DS: physical_address = registers_.ds_; break;
|
||||
}
|
||||
physical_address = ((physical_address << 4) + address) & 0xf'ffff;
|
||||
return *reinterpret_cast<IntT *>(&memory[physical_address]);
|
||||
}
|
||||
};
|
||||
struct IO {
|
||||
};
|
||||
struct FlowController {
|
||||
};
|
||||
|
||||
InstructionSet::x86::Status status;
|
||||
FlowController flow_controller;
|
||||
Registers registers;
|
||||
@ -244,28 +281,14 @@ constexpr char TestSuiteHome[] = "/Users/tharte/Projects/ProcessorTests/8088/v1"
|
||||
IO io;
|
||||
|
||||
// Apply initial state.
|
||||
NSDictionary *const initial = test[@"initial"];
|
||||
for(NSArray<NSNumber *> *ram in initial[@"ram"]) {
|
||||
NSDictionary *const initial_state = test[@"initial"];
|
||||
for(NSArray<NSNumber *> *ram in initial_state[@"ram"]) {
|
||||
memory.memory[[ram[0] intValue]] = [ram[1] intValue];
|
||||
}
|
||||
NSDictionary *const initial_registers = initial[@"regs"];
|
||||
registers.ax_.full = [initial_registers[@"ax"] intValue];
|
||||
registers.bx_.full = [initial_registers[@"bx"] intValue];
|
||||
registers.cx_.full = [initial_registers[@"cx"] intValue];
|
||||
registers.dx_.full = [initial_registers[@"dx"] intValue];
|
||||
|
||||
registers.bp_ = [initial_registers[@"bp"] intValue];
|
||||
registers.cs_ = [initial_registers[@"cs"] intValue];
|
||||
registers.di_ = [initial_registers[@"di"] intValue];
|
||||
registers.ds_ = [initial_registers[@"ds"] intValue];
|
||||
registers.es_ = [initial_registers[@"es"] intValue];
|
||||
registers.si_ = [initial_registers[@"si"] intValue];
|
||||
registers.sp_ = [initial_registers[@"sp"] intValue];
|
||||
registers.ss_ = [initial_registers[@"ss"] intValue];
|
||||
registers.ip_ = [initial_registers[@"ip"] intValue];
|
||||
|
||||
status.set([initial_registers[@"flags"] intValue]);
|
||||
[self populate:registers status:status value:initial_state[@"regs"]];
|
||||
|
||||
// Execute instruction.
|
||||
registers.ip_ += decoded.first;
|
||||
InstructionSet::x86::perform<InstructionSet::x86::Model::i8086>(
|
||||
decoded.second,
|
||||
status,
|
||||
@ -275,7 +298,41 @@ constexpr char TestSuiteHome[] = "/Users/tharte/Projects/ProcessorTests/8088/v1"
|
||||
io
|
||||
);
|
||||
|
||||
return false;
|
||||
// Compare final state.
|
||||
NSDictionary *const final_state = test[@"final"];
|
||||
Registers intended_registers;
|
||||
InstructionSet::x86::Status intended_status;
|
||||
|
||||
bool ramEqual = true;
|
||||
for(NSArray<NSNumber *> *ram in final_state[@"ram"]) {
|
||||
ramEqual &= memory.memory[[ram[0] intValue]] == [ram[1] intValue];
|
||||
}
|
||||
|
||||
[self populate:intended_registers status:intended_status value:final_state[@"regs"]];
|
||||
const bool registersEqual = intended_registers == registers;
|
||||
const bool statusEqual = intended_status == status;
|
||||
|
||||
if(assert) {
|
||||
XCTAssert(
|
||||
statusEqual,
|
||||
"Status doesn't match — differs in %02x after %@",
|
||||
intended_status.get() ^ status.get(),
|
||||
test[@"name"]
|
||||
);
|
||||
// TODO: should probably say more about the following two.
|
||||
XCTAssert(
|
||||
registersEqual,
|
||||
"Register mismatch after %@",
|
||||
test[@"name"]
|
||||
);
|
||||
XCTAssert(
|
||||
ramEqual,
|
||||
"Memory contents mismatch after %@",
|
||||
test[@"name"]
|
||||
);
|
||||
}
|
||||
|
||||
return statusEqual && registersEqual && ramEqual;
|
||||
}
|
||||
|
||||
- (void)printFailures:(NSArray<NSString *> *)failures {
|
||||
|
Loading…
Reference in New Issue
Block a user