Refactor the code to isolate the cycles parsing. Interesting speed up!

Signed-off-by: Adrian Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon 2021-10-18 11:54:01 +01:00
parent 50cea1b81a
commit 79f3e3ac6c
14 changed files with 469 additions and 320 deletions

View File

@ -161,6 +161,8 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="cycles_t.cpp" />
<ClCompile Include="cycle_t.cpp" />
<ClCompile Include="opcode_test_suite_t.cpp" />
<ClCompile Include="simdjson\simdjson.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
@ -180,6 +182,8 @@
<ClCompile Include="test_t.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="cycles_t.h" />
<ClInclude Include="cycle_t.h" />
<ClInclude Include="nlohmann\json.hpp" />
<ClInclude Include="opcode_test_suite_t.h" />
<ClInclude Include="simdjson\simdjson.h" />

View File

@ -38,6 +38,12 @@
<ClCompile Include="simdjson\simdjson.cpp">
<Filter>Header Files\simdjson</Filter>
</ClCompile>
<ClCompile Include="cycle_t.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="cycles_t.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
@ -61,6 +67,12 @@
<ClInclude Include="simdjson\simdjson.h">
<Filter>Header Files\simdjson</Filter>
</ClInclude>
<ClInclude Include="cycle_t.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cycles_t.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@ -25,27 +25,42 @@ void TestRunner::lowerPOWER() {
EightBit::Bus::lowerPOWER();
}
void TestRunner::addActualEvent(test_t::action action, uint16_t address, uint8_t value) {
m_actualEvents.push_back( { address, value, action } );
void TestRunner::addActualCycle(const cycle_t& value) {
m_actualCycles.add(value);
}
void TestRunner::dumpEvents(std::string which, const test_t::events_t& events) {
void TestRunner::addActualCycle(uint16_t address, uint8_t value, cycle_t::action_t action) {
addActualCycle({ address, value, action });
}
void TestRunner::addActualCycle(EightBit::register16_t address, uint8_t value, cycle_t::action_t action) {
addActualCycle(address.word, value, action);
}
void TestRunner::addActualReadCycle(EightBit::register16_t address, uint8_t value) {
addActualCycle(address, value, cycle_t::action_t::read);
}
void TestRunner::addActualWriteCycle(EightBit::register16_t address, uint8_t value) {
addActualCycle(address, value, cycle_t::action_t::write);
}
void TestRunner::dumpCycles(std::string which, const cycles_t& events) {
m_messages.push_back(which);
dumpEvents(events);
dumpCycles(events);
}
void TestRunner::dumpEvents(const test_t::events_t& events) {
void TestRunner::dumpCycles(const cycles_t& cycles) {
os() << std::hex << std::uppercase << std::setfill('0');
for (const auto& event: events)
dumpEvent(event);
for (const auto& cycle: cycles)
dumpCycle(cycle);
}
void TestRunner::dumpEvent(const test_t::event_t& event) {
const auto [address, contents, action] = event;
void TestRunner::dumpCycle(const cycle_t& cycle) {
os()
<< "Address: " << std::setw(4) << address
<< ", contents: " << std::setw(2) << (int)contents
<< ", action: " << test_t::to_string(action);
<< "Address: " << std::setw(4) << cycle.address()
<< ", value: " << std::setw(2) << (int)cycle.value()
<< ", action: " << cycle_t::to_string(cycle.action());
m_messages.push_back(os().str());
os().str("");
}
@ -53,11 +68,11 @@ void TestRunner::dumpEvent(const test_t::event_t& event) {
void TestRunner::initialise() {
ReadByte.connect([this](EightBit::EventArgs&) {
addActualEvent(test_t::action::read, ADDRESS().word, DATA());
addActualReadCycle(ADDRESS(), DATA());
});
WrittenByte.connect([this](EightBit::EventArgs&) {
addActualEvent(test_t::action::write, ADDRESS().word, DATA());
addActualWriteCycle(ADDRESS(), DATA());
});
os() << std::hex << std::uppercase << std::setfill('0');
@ -85,11 +100,11 @@ void TestRunner::raise(std::string what, uint8_t expected, uint8_t actual) {
os().str("");
}
void TestRunner::raise(std::string what, test_t::action expected, test_t::action actual) {
void TestRunner::raise(std::string what, cycle_t::action_t expected, cycle_t::action_t actual) {
os()
<< what
<< ": expected: " << test_t::to_string(expected)
<< ", actual: " << test_t::to_string(actual);
<< ": expected: " << cycle_t::to_string(expected)
<< ", actual: " << cycle_t::to_string(actual);
m_messages.push_back(os().str());
os().str("");
}
@ -120,27 +135,25 @@ void TestRunner::initialiseState() {
RAM().poke(address, value);
}
m_actualEvents.clear();
m_actualCycles.clear();
}
bool TestRunner::checkState() {
const auto& finished = test().final_state();
const auto& expected_events = test().cycles();
const auto& actual_events = m_actualEvents;
m_event_count_mismatch = expected_events.size() != actual_events.size();
if (m_event_count_mismatch)
const auto& expected_cycles = test().cycles();
const auto& actual_cycles = m_actualCycles;
m_cycle_count_mismatch = expected_cycles.size() != actual_cycles.size();
if (m_cycle_count_mismatch)
return false;
for (int i = 0; i < expected_events.size(); ++i) {
const auto& expected = expected_events[i];
const auto [expectedAddress, expectedContents, expectedAction] = expected;
const auto& actual = actual_events.at(i); // actual could be less than expected
const auto [actualAddress, actualContents, actualAction] = actual;
check("Event action", expectedAction, actualAction);
check("Event address", expectedAddress, actualAddress);
check("Event contents", expectedContents, actualContents);
for (int i = 0; i < expected_cycles.size(); ++i) {
const auto& expected = expected_cycles.at(i);
const auto& actual = actual_cycles.at(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());
}
const auto pc_good = check("PC", finished.pc(), CPU().PC().word);
@ -168,7 +181,7 @@ bool TestRunner::check() {
initialiseState();
const int cycles = CPU().step();
const auto valid = checkState();
if (m_event_count_mismatch) {
if (m_cycle_count_mismatch) {
if (cycles == 1) {
m_messages.push_back("Unimplemented");
} else {
@ -177,12 +190,12 @@ bool TestRunner::check() {
<< std::dec << std::setfill(' ')
<< "Stepped cycles: " << cycles
<< ", expected events: " << test().cycles().size()
<< ", actual events: " << m_actualEvents.size();
<< ", actual events: " << m_actualCycles.size();
m_messages.push_back(os().str());
os().str("");
dumpEvents("-- Expected cycles", test().cycles());
dumpEvents("-- Actual cycles", m_actualEvents);
dumpCycles("-- Expected cycles", test().cycles());
dumpCycles("-- Actual cycles", m_actualCycles);
}
}
lowerPOWER();

View File

@ -20,15 +20,15 @@ private:
std::ostringstream m_os;
std::vector<std::string> m_messages;
test_t::events_t m_actualEvents;
bool m_event_count_mismatch = false;
cycles_t m_actualCycles;
bool m_cycle_count_mismatch = false;
void initialiseState();
[[nodiscard]] bool checkState();
void raise(std::string what, uint16_t expected, uint16_t actual);
void raise(std::string what, uint8_t expected, uint8_t actual);
void raise(std::string what, test_t::action expected, test_t::action actual);
void raise(std::string what, cycle_t::action_t expected, cycle_t::action_t actual);
template<class T>
bool check(std::string what, T expected, T actual) {
@ -40,11 +40,16 @@ private:
bool check(std::string what, uint16_t address, uint8_t expected, uint8_t actual);
void addActualEvent(test_t::action action, uint16_t address, uint8_t value);
void addActualCycle(const cycle_t& value);
void addActualCycle(uint16_t address, uint8_t value, cycle_t::action_t action);
void addActualCycle(EightBit::register16_t address, uint8_t value, cycle_t::action_t action);
void dumpEvents(std::string which, const test_t::events_t& events);
void dumpEvents(const test_t::events_t& events);
void dumpEvent(const test_t::event_t& event);
void addActualReadCycle(EightBit::register16_t address, uint8_t value);
void addActualWriteCycle(EightBit::register16_t address, uint8_t value);
void dumpCycles(std::string which, const cycles_t& cycles);
void dumpCycles(const cycles_t& cycles);
void dumpCycle(const cycle_t& cycle);
[[nodiscard]] auto& os() { return m_os; }

View File

@ -0,0 +1,91 @@
#include "stdafx.h"
#include "cycle_t.h"
#include <cassert>
#include <stdexcept>
cycle_t::action_t cycle_t::to_action(std::string value) {
if (value == "read")
return action_t::read;
if (value == "write")
return action_t::write;
throw new std::out_of_range("Unknown action");
}
std::string cycle_t::to_string(action_t value) {
if (value == action_t::read)
return "read";
if (value == action_t::write)
return "write";
throw new std::out_of_range("Unknown action");
}
cycle_t::cycle_t(uint16_t address, uint8_t value, action_t action)
: m_address(address),
m_value(value),
m_action(action) {}
cycle_t::cycle_t(uint16_t address, uint8_t value, std::string action)
: m_address(address),
m_value(value),
m_action(to_action(action)) {}
#ifdef USE_SIMDJSON_JSON
cycle_t::cycle_t(simdjson::dom::element input)
: cycle_t(input.get_array()) {}
cycle_t::cycle_t(simdjson::dom::array input)
: m_address((uint16_t)(uint64_t)input.at(0)),
m_value((uint8_t)(uint64_t)input.at(1)),
m_action(to_action((std::string)input.at(2))) {
assert(input.size() == 3);
}
#endif
#ifdef USE_BOOST_JSON
cycle_t::cycle_t(const boost::json::value& input)
: cycle_t(input.as_array()) {}
cycle_t::cycle_t(const boost::json::array& input)
: m_address((uint16_t)input.at(0).as_int64()),
m_value((uint8_t)input.at(1).as_int64()),
m_action(to_action((std::string)input.at(2).as_string())) {
assert(input.size() == 3);
};
#endif
#ifdef USE_NLOHMANN_JSON
cycle_t::cycle_t(const nlohmann::json& input)
: m_address(input[0].get<uint16_t>()),
m_value(input[1].get<uint8_t>()),
m_action(to_action(input[2].get<std::string>())) {
assert(input.size() == 3);
}
#endif
#ifdef USE_JSONCPP_JSON
//cycle_t(const Json::Value& input);
cycle_t::cycle_t(const Json::Value& input)
: m_address(input[0].asUInt()),
m_value(input[1].asUInt()),
m_action(to_action(input[2].asString())) {
assert(input.size() == 3);
}
//for (const auto& cycles_entry : cycles_array) {
// assert(cycles_entry.size() == 3);
// const auto address = cycles_entry[0].asUInt();
// const auto contents = cycles_entry[1].asUInt();
// const auto action = to_action(cycles_entry[2].asString());
// m_cycles.push_back({ address, contents, action });
//}
#endif

View File

@ -0,0 +1,61 @@
#pragma once
#include <cstdint>
#include <string>
#ifdef USE_SIMDJSON_JSON
# include "simdjson/simdjson.h"
#endif
#ifdef USE_BOOST_JSON
# include <boost/json.hpp>
#endif
#ifdef USE_NLOHMANN_JSON
# include "nlohmann/json.hpp"
#endif
#ifdef USE_JSONCPP_JSON
# include <json/json.h>
#endif
class cycle_t final {
public:
enum class action_t { read, write, unknown };
private:
uint16_t m_address = 0xffff;
uint8_t m_value = 0xff;
action_t m_action = action_t::unknown;
public:
[[nodiscard]] static action_t to_action(std::string value);
[[nodiscard]] static std::string to_string(action_t value);
cycle_t() {}
cycle_t(uint16_t address, uint8_t value, action_t action);
cycle_t(uint16_t address, uint8_t value, std::string action);
#ifdef USE_SIMDJSON_JSON
cycle_t(simdjson::dom::element input);
cycle_t(simdjson::dom::array input);
#endif
#ifdef USE_BOOST_JSON
cycle_t(const boost::json::value& input);
cycle_t(const boost::json::array& input);
#endif
#ifdef USE_NLOHMANN_JSON
cycle_t(const nlohmann::json& input);
#endif
#ifdef USE_JSONCPP_JSON
cycle_t(const Json::Value& input);
#endif
[[nodiscard]] constexpr auto address() const noexcept { return m_address; }
[[nodiscard]] constexpr auto value() const noexcept { return m_value; }
[[nodiscard]] constexpr auto action() const noexcept { return m_action; }
};

View File

@ -0,0 +1,53 @@
#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) {
m_cycles.push_back(cycle);
}
#ifdef USE_SIMDJSON_JSON
cycles_t::cycles_t(simdjson::dom::array input) {
m_cycles.reserve(input.size());
for (const auto& entry : input)
add(entry);
}
#endif
#ifdef USE_BOOST_JSON
cycles_t::cycles_t(const boost::json::value& input)
: cycles_t(input.as_array()) {}
cycles_t::cycles_t(const boost::json::array& input) {
m_cycles.reserve(input.size());
for (const auto& entry : input)
add(entry);
}
#endif
#ifdef USE_NLOHMANN_JSON
cycles_t::cycles_t(const nlohmann::json& input) {
m_cycles.reserve(input.size());
for (const auto& entry : input)
add(entry);
}
#endif
#ifdef USE_JSONCPP_JSON
cycles_t::cycles_t(const Json::Value& input) {
m_cycles.reserve(input.size());
for (const auto& entry : input)
add(entry);
}
#endif

View File

@ -0,0 +1,58 @@
#pragma once
#include <vector>
#ifdef USE_SIMDJSON_JSON
# include "simdjson/simdjson.h"
#endif
#ifdef USE_BOOST_JSON
# include <boost/json.hpp>
#endif
#ifdef USE_NLOHMANN_JSON
# include "nlohmann/json.hpp"
#endif
#ifdef USE_JSONCPP_JSON
# include <json/json.h>
#endif
#include "cycle_t.h"
class cycles_t final {
private:
std::vector<cycle_t> m_cycles;
public:
cycles_t(size_t reserved = 10);
#ifdef USE_SIMDJSON_JSON
cycles_t(simdjson::dom::array input);
#endif
#ifdef USE_BOOST_JSON
cycles_t(const boost::json::value& input);
cycles_t(const boost::json::array& input);
#endif
#ifdef USE_NLOHMANN_JSON
cycles_t(const nlohmann::json& input);
#endif
#ifdef USE_JSONCPP_JSON
cycles_t(const Json::Value& input);
#endif
void add(const cycle_t& cycle);
[[nodiscard]] auto begin() const { return m_cycles.begin(); }
[[nodiscard]] auto end() const { return m_cycles.end(); }
[[nodiscard]] auto size() const noexcept { return m_cycles.size(); }
void clear() { m_cycles.clear(); }
[[nodiscard]] auto& at(size_t idx) { return m_cycles.at(idx); }
[[nodiscard]] const auto& at(size_t idx) const { return m_cycles.at(idx); }
};

View File

@ -4,61 +4,65 @@
state_t::state_t() {}
#ifdef USE_SIMDJSON_JSON
state_t::state_t(const simdjson::dom::element serialised)
: m_pc((uint16_t)(uint64_t)serialised["pc"]),
m_s((uint8_t)(uint64_t)serialised["s"]),
m_a((uint8_t)(uint64_t)serialised["a"]),
m_x((uint8_t)(uint64_t)serialised["x"]),
m_y((uint8_t)(uint64_t)serialised["y"]),
m_p((uint8_t)(uint64_t)serialised["p"]) {
const auto ram_entries = serialised["ram"].get_array();
m_ram.reserve(ram_entries.size());
for (const auto ram_entry : ram_entries) {
assert(ram_entry.is_array());
const auto ram_entry_array = ram_entry.get_array();
assert(ram_entry_array.size() == 2);
const auto address = (uint16_t)(uint64_t)ram_entry_array.at(0);
const auto value = (uint8_t)(uint64_t)ram_entry_array.at(1);
m_ram.push_back({ address, value });
}
}
#endif
#ifdef USE_BOOST_JSON
state_t::state_t(const boost::json::object& serialised) {
initialise(serialised);
assert(initialised());
}
state_t::state_t(const boost::json::value& serialised) {
initialise(serialised.as_object());
assert(initialised());
}
void state_t::initialise(const boost::json::object& serialised) {
assert(!initialised());
m_pc = (uint16_t)serialised.at("pc").as_int64();
m_s = (uint8_t)serialised.at("s").as_int64();
m_a = (uint8_t)serialised.at("a").as_int64();
m_x = (uint8_t)serialised.at("x").as_int64();
m_y = (uint8_t)serialised.at("y").as_int64();
m_p = (uint8_t)serialised.at("p").as_int64();
state_t::state_t(const boost::json::object& serialised)
: m_pc((uint16_t)serialised.at("pc").as_int64()),
m_s((uint8_t)serialised.at("s").as_int64()),
m_a((uint8_t)serialised.at("a").as_int64()),
m_x((uint8_t)serialised.at("x").as_int64()),
m_y((uint8_t)serialised.at("y").as_int64()),
m_p((uint8_t)serialised.at("p").as_int64()) {
const auto& ram_entries = serialised.at("ram").as_array();
m_ram.reserve(ram_entries.size());
for (const auto& ram_entry : ram_entries) {
const auto& ram_entry_array = ram_entry.as_array();
assert(ram_entry_array.size() == 2);
const auto address = (uint16_t)ram_entry_array.at(0).as_int64();
const auto value = (uint8_t)ram_entry_array.at(0).as_int64();
m_ram[address] = value;
const auto value = (uint8_t)ram_entry_array.at(1).as_int64();
m_ram.push_back({ address, value });
}
m_initialised = true;
}
state_t::state_t(const boost::json::value& serialised)
: state_t(serialised.as_object()) {}
#endif
#ifdef USE_NLOHMANN_JSON
state_t::state_t(const nlohmann::json& serialised) {
assert(serialised.is_object());
initialise(serialised);
assert(initialised());
}
void state_t::initialise(const nlohmann::json& serialised) {
assert(!initialised());
m_pc = serialised["pc"].get<uint16_t>();
m_s = serialised["s"].get<uint8_t>();
m_a = serialised["a"].get<uint8_t>();
m_x = serialised["x"].get<uint8_t>();
m_y = serialised["y"].get<uint8_t>();
m_p = serialised["p"].get<uint8_t>();
state_t::state_t(const nlohmann::json& serialised)
: m_pc(serialised["pc"].get<uint16_t>()),
m_s(serialised["s"].get<uint8_t>()),
m_a(serialised["a"].get<uint8_t>()),
m_x(serialised["x"].get<uint8_t>()),
m_y(serialised["y"].get<uint8_t>()),
m_p(serialised["p"].get<uint8_t>()) {
const auto& ram_entries = serialised["ram"];
assert(ram_entries.is_array());
@ -67,32 +71,21 @@ void state_t::initialise(const nlohmann::json& serialised) {
assert(ram_entry.size() == 2);
const auto address = ram_entry[0].get<uint16_t>();
const auto value = ram_entry[1].get<uint8_t>();
m_ram[address] = value;
m_ram.push_back({ address, value });
}
m_initialised = true;
}
#endif
#ifdef USE_JSONCPP_JSON
state_t::state_t(const Json::Value& serialised) {
assert(serialised.isObject());
initialise(serialised);
assert(initialised());
}
void state_t::initialise(const Json::Value& serialised) {
assert(!initialised());
m_pc = serialised["pc"].asUInt();
m_s = serialised["s"].asUInt();
m_a = serialised["a"].asUInt();
m_x = serialised["x"].asUInt();
m_y = serialised["y"].asUInt();
m_p = serialised["p"].asUInt();
state_t::state_t(const Json::Value& serialised)
: m_pc(serialised["pc"].asUInt()),
m_s(serialised["s"].asUInt()),
m_a(serialised["a"].asUInt()),
m_x(serialised["x"].asUInt()),
m_y(serialised["y"].asUInt()),
m_p(serialised["p"].asUInt()) {
const auto& ram_entries = serialised["ram"];
assert(ram_entries.isArray());
@ -101,45 +94,8 @@ void state_t::initialise(const Json::Value& serialised) {
assert(ram_entry.size() == 2);
const auto address = ram_entry[0].asUInt();
const auto value = ram_entry[1].asUInt();
m_ram[address] = value;
m_ram.push_back({ address, value });
}
m_initialised = true;
}
#endif
#ifdef USE_SIMDJSON_JSON
state_t::state_t(const simdjson::dom::element serialised) {
assert(serialised.is_object());
initialise(serialised);
assert(initialised());
}
void state_t::initialise(const simdjson::dom::element serialised) {
assert(!initialised());
m_pc = (uint16_t)(uint64_t)serialised["pc"];
m_s = (uint8_t)(uint64_t)serialised["s"];
m_a = (uint8_t)(uint64_t)serialised["a"];
m_x = (uint8_t)(uint64_t)serialised["x"];
m_y = (uint8_t)(uint64_t)serialised["y"];
m_p = (uint8_t)(uint64_t)serialised["p"];
const auto ram_entries = serialised["ram"];
assert(ram_entries.is_array());
for (const auto ram_entry : ram_entries) {
assert(ram_entry.is_array());
const auto ram_entry_array = ram_entry.get_array();
assert(ram_entry_array.size() == 2);
const auto address = (uint64_t)ram_entry_array.at(0);
const auto value = (uint64_t)ram_entry_array.at(1);
m_ram[(uint16_t)address] = (uint8_t)value;
}
m_initialised = true;
}
#endif

View File

@ -1,7 +1,12 @@
#pragma once
#include <cstdint>
#include <map>
#include <tuple>
#include <vector>
#ifdef USE_SIMDJSON_JSON
# include "simdjson/simdjson.h"
#endif
#ifdef USE_BOOST_JSON
# include <boost/json.hpp>
@ -15,43 +20,27 @@
# include <json/json.h>
#endif
#ifdef USE_SIMDJSON_JSON
# include "simdjson/simdjson.h"
#endif
class state_t final {
private:
bool m_initialised = false;
uint16_t m_pc = 0xffff;
uint8_t m_s = 0xff;
uint8_t m_a = 0xff;
uint8_t m_x = 0xff;
uint8_t m_y = 0xff;
uint8_t m_p = 0xff;
std::map<uint16_t, uint8_t> m_ram;
[[nodiscard]] constexpr auto initialised() const noexcept { return m_initialised; }
#ifdef USE_BOOST_JSON
void initialise(const boost::json::object& serialised);
#endif
#ifdef USE_NLOHMANN_JSON
void initialise(const nlohmann::json& serialised);
#endif
std::vector<std::pair<uint16_t, uint8_t>> m_ram;
#ifdef USE_JSONCPP_JSON
void initialise(const Json::Value& serialised);
#endif
#ifdef USE_SIMDJSON_JSON
void initialise(simdjson::dom::element serialised);
#endif
public:
state_t();
#ifdef USE_SIMDJSON_JSON
state_t(simdjson::dom::element serialised);
#endif
#ifdef USE_BOOST_JSON
state_t(const boost::json::object& serialised);
state_t(const boost::json::value& serialised);
@ -65,10 +54,6 @@ public:
state_t(const Json::Value& serialised);
#endif
#ifdef USE_SIMDJSON_JSON
state_t(simdjson::dom::element serialised);
#endif
[[nodiscard]] constexpr auto pc() const noexcept { return m_pc; }
[[nodiscard]] constexpr auto s() const noexcept { return m_s; }
[[nodiscard]] constexpr auto a() const noexcept { return m_a; }

View File

@ -11,12 +11,18 @@
#include <map>
#include <vector>
//#define TEST_JSON_PERFORMANCE
#define TEST_JSON_PERFORMANCE
#define USE_SIMDJSON_JSON // 16 seconds
//#define USE_SIMDJSON_JSON // 14 seconds
//#define USE_BOOST_JSON // 28 seconds
//#define USE_NLOHMANN_JSON // 73 seconds
//#define USE_JSONCPP_JSON // 105 seconds
//#define USE_NLOHMANN_JSON // 56 seconds
#define USE_JSONCPP_JSON // 105 seconds
#ifdef USE_SIMDJSON_JSON
# define JSON_PREFER_PASS_BY_VALUE
# define JSON_PREFER_REUSE_OF_PARSER
# include "simdjson/simdjson.h"
#endif
#ifdef USE_BOOST_JSON
# include <boost/json.hpp>
@ -30,9 +36,3 @@
# define JSON_PREFER_REUSE_OF_PARSER
# include <json/json.h>
#endif
#ifdef USE_SIMDJSON_JSON
# define JSON_PREFER_PASS_BY_VALUE
# define JSON_PREFER_REUSE_OF_PARSER
# include "simdjson/simdjson.h"
#endif

View File

@ -1,133 +1,64 @@
#include "stdafx.h"
#include "test_t.h"
#include <cassert>
#include <stdexcept>
test_t::action test_t::to_action(std::string value) {
if (value == "read")
return action::read;
if (value == "write")
return action::write;
throw new std::out_of_range("Unknown action");
}
#ifdef USE_SIMDJSON_JSON
std::string test_t::to_string(action value) {
if (value == action::read)
return "read";
if (value == action::write)
return "write";
throw new std::out_of_range("Unknown action");
}
test_t::test_t(const simdjson::dom::element serialised)
: m_name(serialised["name"]),
m_initial_state(serialised["initial"]),
m_final_state(serialised["final"]),
m_cycles(serialised["cycles"].get_array()) {}
#endif
#ifdef USE_BOOST_JSON
test_t::test_t(const boost::json::object& serialised) {
initialise(serialised);
}
test_t::test_t(const boost::json::object& serialised)
: m_name(serialised.at("name").as_string()),
m_initial_state(serialised.at("initial")),
m_final_state(serialised.at("final")),
m_cycles(serialised.at("cycles")) {}
test_t::test_t(const boost::json::value& serialised) {
initialise(serialised.as_object());
}
void test_t::initialise(const boost::json::object& serialised) {
m_name = serialised.at("name").as_string();
m_initial_state = state_t(serialised.at("initial"));
m_final_state = state_t(serialised.at("final"));
const auto& cycles_array = serialised.at("cycles").as_array();
m_cycles.reserve(cycles_array.size());
for (const auto& cycles_entry : cycles_array) {
const auto& cycle_array = cycles_entry.as_array();
assert(cycle_array.size() == 3);
const auto address = (uint16_t)cycle_array.at(0).as_int64();
const auto contents = (uint8_t)cycle_array.at(1).as_int64();
const auto action = to_action((std::string)cycle_array.at(2).as_string());
m_cycles.push_back({ address, contents, action });
}
}
test_t::test_t(const boost::json::value& serialised)
: test_t(serialised.as_object()) {}
#endif
#ifdef USE_NLOHMANN_JSON
test_t::test_t(const nlohmann::json& serialised) {
assert(serialised.is_object());
initialise(serialised);
}
void test_t::initialise(const nlohmann::json& serialised) {
m_name = serialised["name"].get<std::string>();
m_initial_state = state_t(serialised["initial"]);
m_final_state = state_t(serialised["final"]);
const auto& cycles_array = serialised["cycles"];
m_cycles.reserve(cycles_array.size());
for (const auto& cycles_entry : cycles_array) {
assert(cycles_entry.size() == 3);
const auto address = cycles_entry[0].get<uint16_t>();
const auto contents = cycles_entry[1].get<uint8_t>();
const auto action = to_action(cycles_entry[2].get<std::string>());
m_cycles.push_back({ address, contents, action });
}
}
test_t::test_t(const nlohmann::json& serialised)
: m_name(serialised["name"].get<std::string>()),
m_initial_state(serialised["initial"]),
m_final_state(serialised["final"]),
m_cycles(serialised["cycles"]) {}
#endif
#ifdef USE_JSONCPP_JSON
test_t::test_t(const Json::Value& serialised) {
assert(serialised.isObject());
initialise(serialised);
}
test_t::test_t(const Json::Value& serialised)
: m_name(serialised["name"].asString()),
m_initial_state(serialised["initial"]),
m_final_state(serialised["final"]),
m_cycles(serialised["cycles"]) {}
void test_t::initialise(const Json::Value& serialised) {
m_name = serialised["name"].asString();
m_initial_state = state_t(serialised["initial"]);
m_final_state = state_t(serialised["final"]);
const auto& cycles_array = serialised["cycles"];
m_cycles.reserve(cycles_array.size());
//m_name = serialised["name"].asString();
//m_initial_state = state_t(serialised["initial"]);
//m_final_state = state_t(serialised["final"]);
for (const auto& cycles_entry : cycles_array) {
assert(cycles_entry.size() == 3);
const auto address = cycles_entry[0].asUInt();
const auto contents = cycles_entry[1].asUInt();
const auto action = to_action(cycles_entry[2].asString());
m_cycles.push_back({ address, contents, action });
}
}
#endif
#ifdef USE_SIMDJSON_JSON
test_t::test_t(const simdjson::dom::element serialised) {
assert(serialised.is_object());
initialise(serialised);
}
void test_t::initialise(const simdjson::dom::element serialised) {
m_name = serialised["name"];
m_initial_state = state_t(serialised["initial"]);
m_final_state = state_t(serialised["final"]);
const auto cycles_array = serialised["cycles"].get_array();
m_cycles.reserve(cycles_array.size());
for (const auto cycles_entry : cycles_array) {
const auto cycle_array = cycles_entry.get_array();
assert(cycle_array.size() == 3);
const auto address = (uint16_t)(uint64_t)cycle_array.at(0);
const auto contents = (uint8_t)(uint64_t)cycle_array.at(1);
const auto action = to_action((std::string)cycle_array.at(2));
m_cycles.push_back({ address, contents, action });
}
}
//const auto& cycles_array = serialised["cycles"];
//m_cycles.reserve(cycles_array.size());
//for (const auto& cycles_entry : cycles_array) {
// assert(cycles_entry.size() == 3);
// const auto address = cycles_entry[0].asUInt();
// const auto contents = cycles_entry[1].asUInt();
// const auto action = to_action(cycles_entry[2].asString());
// m_cycles.push_back({ address, contents, action });
//}
//}
#endif

View File

@ -5,6 +5,10 @@
#include <vector>
#include <tuple>
#ifdef USE_SIMDJSON_JSON
# include "simdjson/simdjson.h"
#endif
#ifdef USE_BOOST_JSON
# include <boost/json.hpp>
#endif
@ -17,46 +21,26 @@
# include <json/json.h>
#endif
#ifdef USE_SIMDJSON_JSON
# include "simdjson/simdjson.h"
#endif
#include "cycles_t.h"
#include "state_t.h"
class test_t final {
public:
enum class action { read, write };
typedef std::tuple<uint16_t, uint8_t, action> event_t; // address, contents, action
typedef std::vector<event_t> events_t;
[[nodiscard]] static action to_action(std::string value);
[[nodiscard]] static std::string to_string(action value);
private:
std::string m_name;
state_t m_initial_state;
state_t m_final_state;
events_t m_cycles;
cycles_t m_cycles;
#ifdef USE_BOOST_JSON
void initialise(const boost::json::object& serialised);
#endif
#ifdef USE_NLOHMANN_JSON
void initialise(const nlohmann::json& serialised);
#endif
#ifdef USE_JSONCPP_JSON
void initialise(const Json::Value& serialised);
#endif
#ifdef USE_SIMDJSON_JSON
void initialise(simdjson::dom::element serialised);
#endif
//#ifdef USE_JSONCPP_JSON
// void initialise(const Json::Value& serialised);
//#endif
public:
#ifdef USE_SIMDJSON_JSON
test_t(simdjson::dom::element serialised);
#endif
#ifdef USE_BOOST_JSON
test_t(const boost::json::object& serialised);
test_t(const boost::json::value& serialised);
@ -70,12 +54,8 @@ public:
test_t(const Json::Value& serialised);
#endif
#ifdef USE_SIMDJSON_JSON
test_t(simdjson::dom::element serialised);
#endif
[[nodiscard]] constexpr const auto& name() const noexcept { return m_name; }
[[nodiscard]] constexpr const auto& initial_state() const noexcept { return m_initial_state; }
[[nodiscard]] constexpr const auto& final_state() const noexcept { return m_final_state; }
[[nodiscard]] constexpr const auto& cycles() const noexcept { return m_cycles; }
};
};

View File

@ -23,20 +23,20 @@ int main() {
opcode.load();
opcode.parse();
#ifdef USE_SIMDJSON_JSON
const auto opcode_test_array = opcode.raw().get_array();
#endif
#ifdef USE_BOOST_JSON
const auto& opcode_test_array = opcode.raw().as_array();
#endif
#ifdef USE_NLOHMANN_JSON
const auto& opcode_test_array = opcode.raw();
assert(opcode_test_array).is_array());
assert(opcode_test_array.is_array());
#endif
#ifdef USE_JSONCPP_JSON
const auto& opcode_test_array = opcode.raw();
assert(opcode_test_array.is_array());
#endif
#ifdef USE_SIMDJSON_JSON
const auto opcode_test_array = opcode.raw().get_array();
#endif
bool opcode_bad = false;
for (const auto& opcode_test_element : opcode_test_array) {