Refactor to share JSON implementation details.

Signed-off-by: Adrian Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon 2021-10-22 13:10:23 +01:00
parent 8b7607f5e9
commit 17b71aafc3
21 changed files with 148 additions and 140 deletions

View File

@ -161,9 +161,11 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="array_t.cpp" />
<ClCompile Include="byte_t.cpp" />
<ClCompile Include="cycles_t.cpp" />
<ClCompile Include="cycle_t.cpp" />
<ClCompile Include="element_t.cpp" />
<ClCompile Include="opcode_test_suite_t.cpp" />
<ClCompile Include="ram_t.cpp" />
<ClCompile Include="simdjson\simdjson.cpp">
@ -184,9 +186,11 @@
<ClCompile Include="test_t.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="array_t.h" />
<ClInclude Include="byte_t.h" />
<ClInclude Include="cycles_t.h" />
<ClInclude Include="cycle_t.h" />
<ClInclude Include="element_t.h" />
<ClInclude Include="opcode_test_suite_t.h" />
<ClInclude Include="ram_t.h" />
<ClInclude Include="simdjson\simdjson.h" />

View File

@ -47,6 +47,12 @@
<ClCompile Include="byte_t.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="array_t.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="element_t.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
@ -79,5 +85,11 @@
<ClInclude Include="byte_t.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="array_t.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="element_t.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -26,12 +26,8 @@ void TestRunner::lowerPOWER() {
EightBit::Bus::lowerPOWER();
}
void TestRunner::addActualCycle(const cycle_t& value) {
m_actualCycles.add(value);
}
void TestRunner::addActualCycle(uint16_t address, uint8_t value, std::string action) {
addActualCycle({ address, value, action });
m_actualCycles.push_back({ address, value, action });
}
void TestRunner::addActualCycle(EightBit::register16_t address, uint8_t value, std::string action) {
@ -46,23 +42,41 @@ void TestRunner::addActualWriteCycle(EightBit::register16_t address, uint8_t val
addActualCycle(address, value, "write");
}
void TestRunner::dumpCycles(std::string which, const cycles_t& events) {
void TestRunner::dumpCycle(uint16_t address, uint8_t value, std::string action) {
os()
<< std::setfill('0') << std::hex
<< "Address: " << std::setw(4) << (int)address
<< ", value: " << std::setw(2) << (int)value
<< ", action: " << action;
pushCurrentMessage();
}
void TestRunner::dumpCycles(std::string which, const actual_cycles_t& events) {
m_messages.push_back(which);
dumpCycles(events);
}
void TestRunner::dumpCycles(const cycles_t& cycles) {
void TestRunner::dumpCycles(const actual_cycles_t& cycles) {
for (const auto& cycle: cycles)
dumpCycle(cycle);
}
void TestRunner::dumpCycle(const cycle_t& cycle) {
os()
<< std::setfill('0') << std::hex
<< "Address: " << std::setw(4) << cycle.address()
<< ", value: " << std::setw(2) << (int)cycle.value()
<< ", action: " << cycle.action();
pushCurrentMessage();
void TestRunner::dumpCycle(const actual_cycle_t& cycle) {
dumpCycle(std::get<0>(cycle), std::get<1>(cycle), std::get<2>(cycle));
}
void TestRunner::dumpCycles(std::string which, cycles_t events) {
m_messages.push_back(which);
dumpCycles(events);
}
void TestRunner::dumpCycles(cycles_t cycles) {
for (auto cycle: cycles)
dumpCycle(cycle_t(cycle));
}
void TestRunner::dumpCycle(cycle_t cycle) {
dumpCycle(cycle.address(), cycle.value(), cycle.action());
}
void TestRunner::initialise() {
@ -144,12 +158,13 @@ bool TestRunner::checkState() {
if (m_cycle_count_mismatch)
return false;
for (int i = 0; i < expected_cycles.size(); ++i) {
const auto& expected = expected_cycles[i];
const auto& actual = actual_cycles[i]; // actual could be less than expected
check("Cycle address", expected.address(), actual.address());
check("Cycle value", expected.value(), actual.value());
check("Cycle action", expected.action(), actual.action());
size_t actual_idx = 0;
for (auto expected_cycle : expected_cycles) {
const auto expected = cycle_t(expected_cycle);
const auto actual = actual_cycles.at(actual_idx++); // actual could be less than expected
check("Cycle address", expected.address(), std::get<0>(actual));
check("Cycle value", expected.value(), std::get<1>(actual));
check("Cycle action", expected.action(), std::get<2>(actual));
}
const auto final = test().final();

View File

@ -13,6 +13,7 @@
#include <Symbols.h>
#include "test_t.h"
#include "cycle_t.h"
class TestRunner final : public EightBit::Bus {
private:
@ -29,7 +30,9 @@ private:
std::ostringstream m_os;
std::vector<std::string> m_messages;
cycles_t m_actualCycles;
typedef std::tuple<uint16_t, uint8_t, std::string> actual_cycle_t;
typedef std::vector<actual_cycle_t> actual_cycles_t;
actual_cycles_t m_actualCycles;
bool m_cycle_count_mismatch = false;
int m_cycles = 0;
@ -56,7 +59,7 @@ private:
bool check(std::string what, uint16_t address, uint8_t expected, uint8_t actual);
void addActualCycle(const cycle_t& value);
void addActualCycle(const actual_cycle_t& value);
void addActualCycle(uint16_t address, uint8_t value, std::string action);
void addActualCycle(EightBit::register16_t address, uint8_t value, std::string action);
@ -65,9 +68,15 @@ private:
void disassemble(uint16_t address);
void dumpCycles(std::string which, const cycles_t& cycles);
void dumpCycles(const cycles_t& cycles);
void dumpCycle(const cycle_t& cycle);
void dumpCycle(uint16_t address, uint8_t value, std::string action);
void dumpCycles(std::string which, cycles_t cycles);
void dumpCycles(cycles_t cycles);
void dumpCycle(cycle_t cycle);
void dumpCycles(std::string which, const actual_cycles_t& cycles);
void dumpCycles(const actual_cycles_t& cycles);
void dumpCycle(const actual_cycle_t& cycle);
[[nodiscard]] auto& os() { return m_os; }

View File

@ -0,0 +1,5 @@
#include "stdafx.h"
#include "array_t.h"
array_t::array_t(simdjson::dom::array input) noexcept
: m_raw(input) {}

View File

@ -0,0 +1,26 @@
#pragma once
#include <cstdint>
#include "simdjson/simdjson.h"
class array_t {
private:
const simdjson::dom::array m_raw;
protected:
array_t(simdjson::dom::array input) noexcept;
auto raw() const noexcept { return m_raw; }
[[nodiscard]] auto at(size_t idx) const noexcept { return raw().at(idx); }
[[nodiscard]] auto integer_at(size_t idx) const noexcept { return (int64_t)at(idx); }
[[nodiscard]] auto address_at(size_t idx) const noexcept { return (uint16_t)integer_at(idx); }
[[nodiscard]] auto byte_at(size_t idx) const noexcept { return (uint8_t)integer_at(idx); }
public:
[[nodiscard]] auto begin() const noexcept { return m_raw.begin(); }
[[nodiscard]] auto end() const noexcept { return m_raw.end(); }
[[nodiscard]] auto size() const noexcept { return m_raw.size(); }
[[nodiscard]] auto operator[](size_t idx) const noexcept { return m_raw.at(idx); }
};

View File

@ -2,4 +2,4 @@
#include "byte_t.h"
byte_t::byte_t(simdjson::dom::array input) noexcept
: m_raw(input) {}
: array_t(input) {}

View File

@ -1,18 +1,10 @@
#pragma once
#include <cstdint>
#include "simdjson/simdjson.h"
class byte_t final {
private:
const simdjson::dom::array m_raw;
[[nodiscard]] auto at(size_t idx) const noexcept { return m_raw.at(idx); }
[[nodiscard]] auto integer_at(size_t idx) const noexcept { return (int64_t)at(idx); }
[[nodiscard]] auto address_at(size_t idx) const noexcept { return (uint16_t)integer_at(idx); }
[[nodiscard]] auto byte_at(size_t idx) const noexcept { return (uint8_t)integer_at(idx); }
#include "array_t.h"
class byte_t : public array_t {
public:
byte_t(simdjson::dom::array input) noexcept;

View File

@ -1,15 +1,5 @@
#include "stdafx.h"
#include "cycle_t.h"
cycle_t::cycle_t(uint16_t address, uint8_t value, std::string action) noexcept
: m_address(address),
m_value(value),
m_action(action) {}
cycle_t::cycle_t(simdjson::dom::element input) noexcept
: cycle_t(input.get_array()) {}
cycle_t::cycle_t(simdjson::dom::array input) noexcept
: m_address((uint16_t)(int64_t)input.at(0)),
m_value((uint8_t)(int64_t)input.at(1)),
m_action((std::string)input.at(2)) {}
: byte_t(input) {}

View File

@ -1,23 +1,14 @@
#pragma once
#include <cstdint>
#include <string>
#include "simdjson/simdjson.h"
class cycle_t final {
private:
const uint16_t m_address = 0xffff;
const uint8_t m_value = 0xff;
const std::string m_action;
#include "byte_t.h"
class cycle_t final : public byte_t {
public:
cycle_t(uint16_t address, uint8_t value, std::string action) noexcept;
cycle_t(simdjson::dom::element input) noexcept;
cycle_t(simdjson::dom::array input) noexcept;
[[nodiscard]] constexpr auto address() const noexcept { return m_address; }
[[nodiscard]] constexpr auto value() const noexcept { return m_value; }
[[nodiscard]] auto action() const noexcept { return m_action; }
[[nodiscard]] auto action() const noexcept { return (std::string)at(2); }
};

View File

@ -1,18 +1,5 @@
#include "stdafx.h"
#include "cycles_t.h"
cycles_t::cycles_t(size_t reserved) {
m_cycles.reserve(reserved);
}
void cycles_t::add(const cycle_t& cycle) {
assert(m_cycles.capacity() >= (m_cycles.size() + 1));
m_cycles.push_back(cycle);
}
cycles_t::cycles_t(simdjson::dom::array input) {
assert(m_cycles.empty());
m_cycles.reserve(input.size());
for (auto entry : input)
add(entry);
}
cycles_t::cycles_t(simdjson::dom::array input) noexcept
: array_t(input) {}

View File

@ -1,25 +1,10 @@
#pragma once
#include <vector>
#include "simdjson/simdjson.h"
#include "cycle_t.h"
class cycles_t final {
private:
std::vector<cycle_t> m_cycles;
#include "array_t.h"
class cycles_t final : public array_t {
public:
cycles_t(size_t reserved = 10);
cycles_t(simdjson::dom::array input);
void add(const cycle_t& cycle);
[[nodiscard]] auto begin() const noexcept { return m_cycles.begin(); }
[[nodiscard]] auto end() const noexcept { return m_cycles.end(); }
[[nodiscard]] auto size() const noexcept { return m_cycles.size(); }
[[nodiscard]] const auto& operator[](size_t idx) const noexcept { return m_cycles[idx]; }
cycles_t(simdjson::dom::array input) noexcept;
};

View File

@ -0,0 +1,5 @@
#include "stdafx.h"
#include "element_t.h"
element_t::element_t(const simdjson::dom::element input) noexcept
: m_raw(input) {}

View File

@ -0,0 +1,20 @@
#pragma once
#include <cstdint>
#include <string>
#include "simdjson/simdjson.h"
class element_t {
private:
simdjson::dom::element m_raw;
protected:
element_t(simdjson::dom::element input) noexcept;
auto raw() const noexcept { return m_raw; }
[[nodiscard]] auto at(std::string key) const noexcept { return raw()[key]; }
[[nodiscard]] auto array_at(std::string key) const noexcept { return at(key).get_array(); }
[[nodiscard]] auto integer_at(std::string key) const noexcept { return (int64_t)at(key); }
};

View File

@ -2,4 +2,4 @@
#include "ram_t.h"
ram_t::ram_t(simdjson::dom::array input) noexcept
: m_raw(input) {}
: array_t(input) {}

View File

@ -2,15 +2,9 @@
#include "simdjson/simdjson.h"
#include "byte_t.h"
class ram_t final {
private:
simdjson::dom::array m_raw;;
#include "array_t.h"
class ram_t final : public array_t {
public:
ram_t(simdjson::dom::array input) noexcept;
[[nodiscard]] auto begin() const noexcept { return m_raw.begin(); }
[[nodiscard]] auto end() const noexcept { return m_raw.end(); }
};

View File

@ -2,4 +2,4 @@
#include "state_t.h"
state_t::state_t(const simdjson::dom::element input) noexcept
: m_raw(input) {}
: element_t(input) {}

View File

@ -1,20 +1,16 @@
#pragma once
#include <cstdint>
#include <string>
#include "simdjson/simdjson.h"
#include "element_t.h"
#include "ram_t.h"
class state_t final {
class state_t final : public element_t {
private:
const simdjson::dom::element m_raw;
[[nodiscard]] auto at(std::string key) const noexcept { return m_raw[key]; }
[[nodiscard]] auto integer_at(std::string key) const noexcept { return (int64_t)at(key); }
[[nodiscard]] auto address_at(std::string key) const noexcept { return (uint16_t)integer_at(key); }
[[nodiscard]] auto byte_at(std::string key) const noexcept { return (uint8_t)integer_at(key); }
[[nodiscard]] auto array_at(std::string key) const noexcept { return at(key).get_array(); }
public:
state_t(simdjson::dom::element input) noexcept;

View File

@ -2,4 +2,4 @@
#include "test_t.h"
test_t::test_t(const simdjson::dom::element input) noexcept
: m_raw(input) {}
: element_t(input) {}

View File

@ -1,19 +1,12 @@
#pragma once
#include <string>
#include "simdjson/simdjson.h"
#include "element_t.h"
#include "cycles_t.h"
#include "state_t.h"
class test_t final {
private:
simdjson::dom::element m_raw;
[[nodiscard]] auto at(std::string key) const noexcept { return m_raw[key]; }
[[nodiscard]] auto array_at(std::string key) const noexcept { return at(key).get_array(); }
class test_t final : public element_t {
public:
test_t(simdjson::dom::element input) noexcept;

View File

@ -26,41 +26,25 @@ int main() {
opcode_test_suite_t opcode(path.string());
opcode.load();
bool opcode_undocumented = false;
bool opcode_unimplemented = false;
bool opcode_invalid = false;
for (auto opcode_test_element : opcode) {
const auto opcode_test = test_t(opcode_test_element);
TestRunner runner(opcode_test);
runner.check();
auto undocumented = runner.undocumented();
auto unimplemented = runner.unimplemented();
auto implemented = runner.implemented();
auto invalid = runner.invalid();
if (invalid) {
opcode_invalid = true;
if (unimplemented)
opcode_unimplemented = true;
if (undocumented)
opcode_undocumented = true;
++invalid_opcode_count;
if (runner.unimplemented())
++unimplemented_opcode_count;
if (runner.undocumented())
++undocumented_opcode_count;
std::cout << "** Failed: " << opcode_test.name() << "\n";
for (const auto& message : runner.messages())
std::cout << "**** " << message << "\n";
break;
}
}
if (opcode_undocumented)
++undocumented_opcode_count;
if (opcode_unimplemented)
++unimplemented_opcode_count;
if (opcode_invalid)
++invalid_opcode_count;
}
const auto finish_time = std::chrono::steady_clock::now();