2017-08-10 19:34:17 +00:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "FuseTestRunner.h"
|
|
|
|
#include "Disassembler.h"
|
|
|
|
|
|
|
|
Fuse::TestRunner::TestRunner(const Test& test, const ExpectedTestResult& expected)
|
|
|
|
: m_test(test),
|
2018-11-11 16:48:44 +00:00
|
|
|
m_expected(expected) {
|
2017-08-10 19:34:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
|
2019-01-14 02:10:17 +00:00
|
|
|
void Fuse::TestRunner::raisePOWER() {
|
|
|
|
EightBit::Bus::raisePOWER();
|
|
|
|
CPU().raisePOWER();
|
|
|
|
CPU().raiseRESET();
|
|
|
|
CPU().raiseINT();
|
2017-08-10 19:34:17 +00:00
|
|
|
initialiseRegisters();
|
|
|
|
initialiseMemory();
|
|
|
|
}
|
|
|
|
|
2019-01-14 02:10:17 +00:00
|
|
|
void Fuse::TestRunner::lowerPOWER() {
|
|
|
|
CPU().lowerPOWER();
|
|
|
|
EightBit::Bus::lowerPOWER();
|
2018-11-11 16:48:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Fuse::TestRunner::initialise() {
|
|
|
|
disableGameRom();
|
|
|
|
}
|
|
|
|
|
2017-08-10 19:34:17 +00:00
|
|
|
void Fuse::TestRunner::initialiseRegisters() {
|
|
|
|
|
|
|
|
const auto& testState = m_test.registerState;
|
|
|
|
const auto& inputRegisters = testState.registers;
|
|
|
|
|
2018-11-11 16:48:44 +00:00
|
|
|
CPU().AF() = inputRegisters[Fuse::RegisterState::AF];
|
|
|
|
CPU().BC() = inputRegisters[Fuse::RegisterState::BC];
|
|
|
|
CPU().DE() = inputRegisters[Fuse::RegisterState::DE];
|
|
|
|
CPU().HL() = inputRegisters[Fuse::RegisterState::HL];
|
2017-08-10 19:34:17 +00:00
|
|
|
|
2018-11-11 16:48:44 +00:00
|
|
|
CPU().SP() = inputRegisters[Fuse::RegisterState::SP];
|
|
|
|
CPU().PC() = inputRegisters[Fuse::RegisterState::PC];
|
2017-08-10 19:34:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Fuse::TestRunner::initialiseMemory() {
|
|
|
|
for (auto memoryDatum : m_test.memoryData) {
|
|
|
|
auto address = memoryDatum.address;
|
|
|
|
auto bytes = memoryDatum.bytes;
|
|
|
|
for (int i = 0; i < bytes.size(); ++i)
|
2017-09-07 00:15:28 +00:00
|
|
|
poke(address + i, bytes[i]);
|
2017-08-10 19:34:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
void Fuse::TestRunner::check() {
|
|
|
|
checkregisters();
|
|
|
|
checkMemory();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fuse::TestRunner::dumpDifference(const std::string& description, uint8_t actual, uint8_t expected) const {
|
|
|
|
std::cerr
|
|
|
|
<< "**** " << description << ", Expected: "
|
2017-09-07 00:15:28 +00:00
|
|
|
<< EightBit::GameBoy::Disassembler::hex(expected)
|
2017-08-10 19:34:17 +00:00
|
|
|
<< ", Got: "
|
2017-09-07 00:15:28 +00:00
|
|
|
<< EightBit::GameBoy::Disassembler::hex(actual)
|
2017-08-10 19:34:17 +00:00
|
|
|
<< std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fuse::TestRunner::dumpDifference(
|
|
|
|
const std::string& highDescription,
|
|
|
|
const std::string& lowDescription,
|
|
|
|
EightBit::register16_t actual, EightBit::register16_t expected) const {
|
|
|
|
|
|
|
|
auto expectedHigh = expected.high;
|
|
|
|
auto expectedLow = expected.low;
|
|
|
|
|
|
|
|
auto actualHigh = actual.high;
|
|
|
|
auto actualLow = actual.low;
|
|
|
|
|
|
|
|
if (expectedHigh != actualHigh)
|
|
|
|
dumpDifference(highDescription, actualHigh, expectedHigh);
|
|
|
|
|
|
|
|
if (expectedLow != actualLow)
|
|
|
|
dumpDifference(lowDescription, actualLow, expectedLow);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fuse::TestRunner::checkregisters() {
|
|
|
|
|
|
|
|
const auto& expectedState = m_expected.registerState;
|
|
|
|
const auto& expectedRegisters = expectedState.registers;
|
|
|
|
|
2018-11-11 16:48:44 +00:00
|
|
|
auto af = CPU().AF() == expectedRegisters[Fuse::RegisterState::AF];
|
|
|
|
auto bc = CPU().BC() == expectedRegisters[Fuse::RegisterState::BC];
|
|
|
|
auto de = CPU().DE() == expectedRegisters[Fuse::RegisterState::DE];
|
|
|
|
auto hl = CPU().HL() == expectedRegisters[Fuse::RegisterState::HL];
|
2017-08-10 19:34:17 +00:00
|
|
|
|
2018-11-11 16:48:44 +00:00
|
|
|
auto sp = CPU().SP() == expectedRegisters[Fuse::RegisterState::SP];
|
|
|
|
auto pc = CPU().PC() == expectedRegisters[Fuse::RegisterState::PC];
|
2017-08-10 19:34:17 +00:00
|
|
|
|
|
|
|
auto success =
|
|
|
|
af && bc && de && hl
|
|
|
|
&& sp && pc;
|
|
|
|
|
|
|
|
if (!success) {
|
|
|
|
m_failed = true;
|
|
|
|
std::cerr << "**** Failed test (Register): " << m_test.description << std::endl;
|
|
|
|
|
|
|
|
if (!af) {
|
|
|
|
auto expectedA = expectedRegisters[Fuse::RegisterState::AF].high;
|
2018-11-11 16:48:44 +00:00
|
|
|
auto gotA = CPU().A();
|
2017-08-10 19:34:17 +00:00
|
|
|
if (expectedA != gotA)
|
|
|
|
dumpDifference("A", gotA, expectedA);
|
|
|
|
|
|
|
|
auto expectedF = expectedRegisters[Fuse::RegisterState::AF].low;
|
2018-11-11 16:48:44 +00:00
|
|
|
auto gotF = CPU().F();
|
2017-08-10 19:34:17 +00:00
|
|
|
if (expectedF != gotF) {
|
|
|
|
std::cerr
|
|
|
|
<< "**** F, Expected: "
|
2017-09-07 00:15:28 +00:00
|
|
|
<< EightBit::GameBoy::Disassembler::flags(expectedF)
|
2017-08-10 19:34:17 +00:00
|
|
|
<< ", Got: "
|
2017-09-07 00:15:28 +00:00
|
|
|
<< EightBit::GameBoy::Disassembler::flags(gotF)
|
2017-08-10 19:34:17 +00:00
|
|
|
<< std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bc) {
|
|
|
|
auto expectedWord = expectedRegisters[Fuse::RegisterState::BC];
|
2018-11-11 16:48:44 +00:00
|
|
|
auto actualWord = CPU().BC();
|
2017-08-10 19:34:17 +00:00
|
|
|
dumpDifference("B", "C", actualWord, expectedWord);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!de) {
|
|
|
|
auto expectedWord = expectedRegisters[Fuse::RegisterState::DE];
|
2018-11-11 16:48:44 +00:00
|
|
|
auto actualWord = CPU().DE();
|
2017-08-10 19:34:17 +00:00
|
|
|
dumpDifference("D", "E", actualWord, expectedWord);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hl) {
|
|
|
|
auto expectedWord = expectedRegisters[Fuse::RegisterState::HL];
|
2018-11-11 16:48:44 +00:00
|
|
|
auto actualWord = CPU().HL();
|
2017-08-10 19:34:17 +00:00
|
|
|
dumpDifference("H", "L", actualWord, expectedWord);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sp) {
|
|
|
|
auto expectedWord = expectedRegisters[Fuse::RegisterState::SP];
|
2018-11-11 16:48:44 +00:00
|
|
|
auto actualWord = CPU().SP();
|
2017-08-10 19:34:17 +00:00
|
|
|
dumpDifference("SPH", "SPL", actualWord, expectedWord);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pc) {
|
|
|
|
auto expectedWord = expectedRegisters[Fuse::RegisterState::PC];
|
2018-11-11 16:48:44 +00:00
|
|
|
auto actualWord = CPU().PC();
|
2017-08-10 19:34:17 +00:00
|
|
|
dumpDifference("PCH", "PCL", actualWord, expectedWord);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fuse::TestRunner::checkMemory() {
|
|
|
|
|
|
|
|
bool first = true;
|
|
|
|
|
|
|
|
for (auto memoryDatum : m_expected.memoryData) {
|
|
|
|
auto bytes = memoryDatum.bytes;
|
|
|
|
for (int i = 0; i < bytes.size(); ++i) {
|
|
|
|
auto expected = bytes[i];
|
|
|
|
uint16_t address = memoryDatum.address + i;
|
2018-10-20 19:52:41 +00:00
|
|
|
auto actual = peek(address);
|
2017-08-10 19:34:17 +00:00
|
|
|
if (expected != actual) {
|
|
|
|
m_failed = true;
|
|
|
|
if (first) {
|
|
|
|
first = false;
|
|
|
|
std::cerr << "**** Failed test (Memory): " << m_test.description << std::endl;
|
|
|
|
}
|
|
|
|
std::cerr
|
|
|
|
<< "**** Difference: "
|
2017-09-07 00:15:28 +00:00
|
|
|
<< "Address: " << EightBit::GameBoy::Disassembler::hex(address)
|
|
|
|
<< " Expected: " << EightBit::GameBoy::Disassembler::hex(expected)
|
|
|
|
<< " Actual: " << EightBit::GameBoy::Disassembler::hex(actual)
|
2017-08-10 19:34:17 +00:00
|
|
|
<< std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fuse::TestRunner::run() {
|
|
|
|
|
2019-01-14 02:10:17 +00:00
|
|
|
raisePOWER();
|
|
|
|
initialise();
|
2017-08-10 19:34:17 +00:00
|
|
|
auto allowedCycles = m_test.registerState.tstates;
|
|
|
|
try {
|
2018-11-11 16:48:44 +00:00
|
|
|
CPU().run(allowedCycles);
|
2017-08-10 19:34:17 +00:00
|
|
|
check();
|
2017-08-29 21:35:56 +00:00
|
|
|
} catch (std::logic_error& error) {
|
2017-08-10 19:34:17 +00:00
|
|
|
m_unimplemented = true;
|
|
|
|
std::cerr << "**** Error: " << error.what() << std::endl;
|
|
|
|
}
|
|
|
|
}
|