mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2024-12-28 01:29:18 +00:00
First stab at using the Harte randomised processor tests. Some failures detected in the M6502 run.
Signed-off-by: Adrian Conlon <adrian.conlon@gmail.com>
This commit is contained in:
parent
6c3ef821bf
commit
6a59bfbcd8
189
M6502/HarteTest_6502/HarteTest_6502.vcxproj
Normal file
189
M6502/HarteTest_6502/HarteTest_6502.vcxproj
Normal file
@ -0,0 +1,189 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{894eb6ef-4c8d-4401-bbaa-aba05a021abb}</ProjectGuid>
|
||||
<RootNamespace>HarteTest_6502</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>HarteTest_6502</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>..\inc;..\..\inc;C:\Libraries\boost_1_77_0;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>..\inc;..\..\inc;C:\Libraries\boost_1_77_0;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>..\inc;..\..\inc;C:\Libraries\boost_1_77_0;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Libraries\boost_1_77_0\lib64-msvc-14.2;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>..\inc;..\..\inc;C:\Libraries\boost_1_77_0;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Libraries\boost_1_77_0\lib64-msvc-14.2;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="json_t.cpp" />
|
||||
<ClCompile Include="opcode_test_suite_t.cpp" />
|
||||
<ClCompile Include="state_t.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TestRunner.cpp" />
|
||||
<ClCompile Include="tests.cpp" />
|
||||
<ClCompile Include="test_t.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="json_t.h" />
|
||||
<ClInclude Include="opcode_test_suite_t.h" />
|
||||
<ClInclude Include="state_t.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="TestRunner.h" />
|
||||
<ClInclude Include="test_t.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\EightBit.vcxproj">
|
||||
<Project>{a9c24bd9-0cb4-4c84-b09b-46b815f9da47}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\src\M6502.vcxproj">
|
||||
<Project>{d8726a1b-bbfe-47ef-9860-26b90140ba66}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
56
M6502/HarteTest_6502/HarteTest_6502.vcxproj.filters
Normal file
56
M6502/HarteTest_6502/HarteTest_6502.vcxproj.filters
Normal file
@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="tests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="json_t.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="state_t.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="test_t.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="opcode_test_suite_t.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TestRunner.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="json_t.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="state_t.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="test_t.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="opcode_test_suite_t.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TestRunner.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
138
M6502/HarteTest_6502/TestRunner.cpp
Normal file
138
M6502/HarteTest_6502/TestRunner.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
#include "stdafx.h"
|
||||
#include "TestRunner.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <Disassembly.h>
|
||||
|
||||
TestRunner::TestRunner(const test_t& test)
|
||||
: m_test(test) {}
|
||||
|
||||
EightBit::MemoryMapping TestRunner::mapping(uint16_t address) noexcept {
|
||||
return { RAM(), 0x0000, 0xffff, EightBit::MemoryMapping::AccessLevel::ReadWrite };
|
||||
}
|
||||
|
||||
void TestRunner::raisePOWER() {
|
||||
EightBit::Bus::raisePOWER();
|
||||
CPU().raisePOWER();
|
||||
CPU().raiseRESET();
|
||||
CPU().raiseINT();
|
||||
CPU().raiseNMI();
|
||||
CPU().raiseSO();
|
||||
CPU().raiseRDY();
|
||||
}
|
||||
|
||||
void TestRunner::lowerPOWER() {
|
||||
CPU().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::initialise() {
|
||||
|
||||
ReadByte.connect([this](EightBit::EventArgs&) {
|
||||
addActualEvent(test_t::action::read, ADDRESS().word, DATA());
|
||||
});
|
||||
|
||||
WrittenByte.connect([this](EightBit::EventArgs&) {
|
||||
addActualEvent(test_t::action::write, ADDRESS().word, DATA());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void TestRunner::raise(std::string what, uint16_t expected, uint16_t actual) {
|
||||
std::cout
|
||||
<< "** Failure: " << what
|
||||
<< ": expected: " << EightBit::Disassembly::dump_WordValue(expected)
|
||||
<< ", actual: " << EightBit::Disassembly::dump_WordValue(actual)
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
void TestRunner::raise(std::string what, uint8_t expected, uint8_t actual) {
|
||||
std::cout
|
||||
<< "** Failure: " << what
|
||||
<< ": expected: " << EightBit::Disassembly::dump_ByteValue(expected)
|
||||
<< "(" << EightBit::Disassembly::dump_Flags(expected) << ")"
|
||||
<< ", actual: " << EightBit::Disassembly::dump_ByteValue(actual)
|
||||
<< "(" << EightBit::Disassembly::dump_Flags(actual) << ")"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
void TestRunner::raise(std::string what, test_t::action expected, test_t::action actual) {
|
||||
std::cout
|
||||
<< "** Failure: " << what
|
||||
<< ": expected: " << test_t::to_string(expected)
|
||||
<< ", actual: " << test_t::to_string(actual)
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
void TestRunner::initialiseState() {
|
||||
|
||||
const auto& starting = test().initial_state();
|
||||
|
||||
CPU().PC().word = starting.pc();
|
||||
CPU().S() = starting.s();
|
||||
CPU().A() = starting.a();
|
||||
CPU().X() = starting.x();
|
||||
CPU().Y() = starting.y();
|
||||
CPU().P() = starting.p();
|
||||
const auto& ram = starting.ram();
|
||||
for (const auto& entry : ram) {
|
||||
const auto [address, value] = entry;
|
||||
RAM().poke(address, value);
|
||||
}
|
||||
|
||||
m_actualEvents.clear();
|
||||
}
|
||||
|
||||
void TestRunner::verifyState() {
|
||||
|
||||
const auto& finished = test().final_state();
|
||||
|
||||
const auto& expected_events = test().cycles();
|
||||
const auto& actual_events = m_actualEvents;
|
||||
if (expected_events.size() != actual_events.size()) {
|
||||
//std::cout << "** event count mismatch" << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
const auto pc_good = check("PC", finished.pc(), CPU().PC().word);
|
||||
const auto s_good = check("S", finished.s(), CPU().S());
|
||||
const auto a_good = check("A", finished.a(), CPU().A());
|
||||
const auto x_good = check("X", finished.x(), CPU().X());
|
||||
const auto y_good = check("Y", finished.y(), CPU().Y());
|
||||
const auto p_good = check("P", finished.p(), CPU().P());
|
||||
|
||||
const auto& ram = finished.ram();
|
||||
bool ram_problem = false;
|
||||
for (const auto& entry : ram) {
|
||||
const auto [address, value] = entry;
|
||||
const auto ram_good = check("RAM: " + EightBit::Disassembly::dump_WordValue(address), value, RAM().peek(address));
|
||||
if (!ram_good && !ram_problem)
|
||||
ram_problem = true;
|
||||
}
|
||||
|
||||
const auto good = pc_good && s_good && a_good && x_good && y_good && p_good && !ram_problem;
|
||||
std::cout << (good ? "+" : "-");
|
||||
}
|
||||
|
||||
void TestRunner::run() {
|
||||
initialise();
|
||||
raisePOWER();
|
||||
initialiseState();
|
||||
const int cycles = CPU().step();
|
||||
verifyState();
|
||||
lowerPOWER();
|
||||
}
|
50
M6502/HarteTest_6502/TestRunner.h
Normal file
50
M6502/HarteTest_6502/TestRunner.h
Normal file
@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <Bus.h>
|
||||
#include <Ram.h>
|
||||
#include <mos6502.h>
|
||||
|
||||
#include "test_t.h"
|
||||
|
||||
class TestRunner final : public EightBit::Bus {
|
||||
private:
|
||||
EightBit::Ram m_ram = 0x10000;
|
||||
EightBit::MOS6502 m_cpu = { *this };
|
||||
const test_t& m_test;
|
||||
|
||||
test_t::events_t m_actualEvents;
|
||||
|
||||
void initialiseState();
|
||||
void verifyState();
|
||||
|
||||
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);
|
||||
|
||||
template<class T>
|
||||
bool check(std::string what, T expected, T actual) {
|
||||
const auto success = actual == expected;
|
||||
if (!success)
|
||||
raise(what, expected, actual);
|
||||
return success;
|
||||
}
|
||||
|
||||
void addActualEvent(test_t::action action, uint16_t address, uint8_t value);
|
||||
|
||||
protected:
|
||||
virtual EightBit::MemoryMapping mapping(uint16_t address) noexcept final;
|
||||
|
||||
public:
|
||||
TestRunner(const test_t& test);
|
||||
|
||||
virtual void raisePOWER() final;
|
||||
virtual void lowerPOWER() final;
|
||||
|
||||
virtual void initialise() final;
|
||||
|
||||
constexpr auto& RAM() noexcept { return m_ram; }
|
||||
constexpr auto& CPU() noexcept { return m_cpu; }
|
||||
constexpr const auto& test() const noexcept { return m_test; }
|
||||
|
||||
void run();
|
||||
};
|
53
M6502/HarteTest_6502/json_t.cpp
Normal file
53
M6502/HarteTest_6502/json_t.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include "stdafx.h"
|
||||
#include "json_t.h"
|
||||
#include <cassert>
|
||||
|
||||
const boost::json::value& json_t::get_value(const boost::json::object& object, std::string key) {
|
||||
auto* value = object.if_contains(key);
|
||||
assert(value != nullptr);
|
||||
return *value;
|
||||
}
|
||||
|
||||
int64_t json_t::get_int64(const boost::json::value& value) {
|
||||
assert(value.is_number());
|
||||
assert(value.is_int64());
|
||||
return value.get_int64();
|
||||
}
|
||||
|
||||
uint16_t json_t::get_uint16(const boost::json::value& value) {
|
||||
return static_cast<uint16_t>(get_int64(value));
|
||||
}
|
||||
|
||||
uint8_t json_t::get_uint8(const boost::json::value& value) {
|
||||
return static_cast<uint8_t>(get_int64(value));
|
||||
}
|
||||
|
||||
int64_t json_t::get_int64(const boost::json::object& object, std::string key) {
|
||||
return get_int64(get_value(object, key));
|
||||
}
|
||||
|
||||
uint16_t json_t::get_uint16(const boost::json::object& object, std::string key) {
|
||||
return static_cast<uint16_t>(get_int64(object, key));
|
||||
}
|
||||
|
||||
uint8_t json_t::get_uint8(const boost::json::object& object, std::string key) {
|
||||
return static_cast<uint8_t>(get_int64(object, key));
|
||||
}
|
||||
|
||||
const boost::json::array& json_t::get_array(const boost::json::value& value) {
|
||||
assert(value.is_array());
|
||||
return value.get_array();
|
||||
}
|
||||
|
||||
const boost::json::array& json_t::get_array(const boost::json::object& object, std::string key) {
|
||||
return get_array(get_value(object, key));
|
||||
}
|
||||
|
||||
const boost::json::string& json_t::get_string(const boost::json::value& value) {
|
||||
assert(value.is_string());
|
||||
return value.get_string();
|
||||
}
|
||||
|
||||
const boost::json::string& json_t::get_string(const boost::json::object& object, std::string key) {
|
||||
return get_string(get_value(object, key));
|
||||
}
|
24
M6502/HarteTest_6502/json_t.h
Normal file
24
M6502/HarteTest_6502/json_t.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/json.hpp>
|
||||
|
||||
class json_t {
|
||||
protected:
|
||||
static const boost::json::value& get_value(const boost::json::object& object, std::string key);
|
||||
|
||||
static int64_t get_int64(const boost::json::value& value);
|
||||
static uint16_t get_uint16(const boost::json::value& value);
|
||||
static uint8_t get_uint8(const boost::json::value& value);
|
||||
|
||||
static int64_t get_int64(const boost::json::object& object, std::string key);
|
||||
static uint16_t get_uint16(const boost::json::object& object, std::string key);
|
||||
static uint8_t get_uint8(const boost::json::object& object, std::string key);
|
||||
|
||||
static const boost::json::array& get_array(const boost::json::value& value);
|
||||
static const boost::json::array& get_array(const boost::json::object& object, std::string key);
|
||||
|
||||
static const boost::json::string& get_string(const boost::json::value& value);
|
||||
static const boost::json::string& get_string(const boost::json::object& object, std::string key);
|
||||
};
|
27
M6502/HarteTest_6502/opcode_test_suite_t.cpp
Normal file
27
M6502/HarteTest_6502/opcode_test_suite_t.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "stdafx.h"
|
||||
#include "opcode_test_suite_t.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
std::string opcode_test_suite_t::read(std::string path) {
|
||||
std::ifstream file(path, std::ios::in | std::ios::binary);
|
||||
const auto size = std::filesystem::file_size(path);
|
||||
std::string result(size, '\0');
|
||||
file.read(result.data(), size);
|
||||
return result;
|
||||
}
|
||||
|
||||
opcode_test_suite_t::opcode_test_suite_t(std::string path)
|
||||
: m_path(path) {}
|
||||
|
||||
const boost::json::array& opcode_test_suite_t::get_array() const noexcept {
|
||||
assert(raw().is_array());
|
||||
return raw().get_array();
|
||||
}
|
||||
|
||||
void opcode_test_suite_t::load() {
|
||||
const auto contents = read(path());
|
||||
m_raw = boost::json::parse(contents);
|
||||
}
|
21
M6502/HarteTest_6502/opcode_test_suite_t.h
Normal file
21
M6502/HarteTest_6502/opcode_test_suite_t.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <boost/json.hpp>
|
||||
|
||||
class opcode_test_suite_t final {
|
||||
private:
|
||||
static std::string read(std::string path);
|
||||
|
||||
std::string m_path;
|
||||
boost::json::value m_raw;
|
||||
|
||||
public:
|
||||
opcode_test_suite_t(std::string path);
|
||||
|
||||
constexpr const auto& path() const noexcept { return m_path; }
|
||||
constexpr const auto& raw() const noexcept { return m_raw; }
|
||||
const boost::json::array& get_array() const noexcept;
|
||||
|
||||
void load();
|
||||
};
|
40
M6502/HarteTest_6502/state_t.cpp
Normal file
40
M6502/HarteTest_6502/state_t.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include "stdafx.h"
|
||||
#include "state_t.h"
|
||||
#include <cassert>
|
||||
|
||||
void state_t::initialise(const boost::json::object& serialised) {
|
||||
|
||||
assert(!initialised());
|
||||
|
||||
m_pc = get_uint16(serialised, "pc");
|
||||
m_s = get_uint8(serialised, "s");
|
||||
m_a = get_uint8(serialised, "a");
|
||||
m_x = get_uint8(serialised, "x");
|
||||
m_y = get_uint8(serialised, "y");
|
||||
m_p = get_uint8(serialised, "p");
|
||||
|
||||
const auto& ram_entries = get_array(serialised, "ram");
|
||||
for (const auto& ram_entry : ram_entries) {
|
||||
assert(ram_entry.is_array());
|
||||
const auto& ram_entry_array = ram_entry.as_array();
|
||||
assert(ram_entry_array.size() == 2);
|
||||
const auto address = get_uint16(ram_entry_array[0]);
|
||||
const auto value = get_uint8(ram_entry_array[1]);
|
||||
m_ram[address] = value;
|
||||
}
|
||||
|
||||
m_initialised = true;
|
||||
}
|
||||
|
||||
state_t::state_t() {}
|
||||
|
||||
state_t::state_t(const boost::json::object& serialised) {
|
||||
initialise(serialised);
|
||||
assert(initialised());
|
||||
}
|
||||
|
||||
state_t::state_t(const boost::json::value& serialised) {
|
||||
assert(serialised.is_object());
|
||||
initialise(serialised.get_object());
|
||||
assert(initialised());
|
||||
}
|
37
M6502/HarteTest_6502/state_t.h
Normal file
37
M6502/HarteTest_6502/state_t.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <boost/json.hpp>
|
||||
|
||||
#include "json_t.h"
|
||||
|
||||
class state_t final : public json_t {
|
||||
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::unordered_map<uint16_t, uint8_t> m_ram;
|
||||
|
||||
constexpr auto initialised() const noexcept { return m_initialised; }
|
||||
|
||||
void initialise(const boost::json::object& serialised);
|
||||
|
||||
public:
|
||||
state_t();
|
||||
state_t(const boost::json::object& serialised);
|
||||
state_t(const boost::json::value& serialised);
|
||||
|
||||
constexpr auto pc() const noexcept { return m_pc; }
|
||||
constexpr auto s() const noexcept { return m_s; }
|
||||
constexpr auto a() const noexcept { return m_a; }
|
||||
constexpr auto x() const noexcept { return m_x; }
|
||||
constexpr auto y() const noexcept { return m_y; }
|
||||
constexpr auto p() const noexcept { return m_p; }
|
||||
constexpr const auto& ram() const noexcept { return m_ram; }
|
||||
};
|
1
M6502/HarteTest_6502/stdafx.cpp
Normal file
1
M6502/HarteTest_6502/stdafx.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "stdafx.h"
|
14
M6502/HarteTest_6502/stdafx.h
Normal file
14
M6502/HarteTest_6502/stdafx.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/json.hpp>
|
48
M6502/HarteTest_6502/test_t.cpp
Normal file
48
M6502/HarteTest_6502/test_t.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
void test_t::initialise(const boost::json::object& serialised) {
|
||||
|
||||
m_name = get_string(serialised, "name");
|
||||
m_initial_state = state_t(get_value(serialised, "initial"));
|
||||
m_final_state = state_t(get_value(serialised, "final"));
|
||||
|
||||
const auto& cycles_array = get_array(serialised, "cycles");
|
||||
m_cycles.reserve(cycles_array.size());
|
||||
|
||||
for (const auto& cycles_entry : cycles_array) {
|
||||
const auto& cycle_array = get_array(cycles_entry);
|
||||
assert(cycle_array.size() == 3);
|
||||
const auto address = get_uint16(cycle_array[0]);
|
||||
const auto contents = get_uint8(cycle_array[1]);
|
||||
const auto action = to_action((std::string)get_string(cycle_array[2]));
|
||||
m_cycles.push_back( { address, contents, action } );
|
||||
}
|
||||
}
|
||||
|
||||
test_t::test_t(const boost::json::object& serialised) {
|
||||
initialise(serialised);
|
||||
}
|
||||
|
||||
test_t::test_t(const boost::json::value& serialised) {
|
||||
assert(serialised.is_object());
|
||||
initialise(serialised.get_object());
|
||||
}
|
38
M6502/HarteTest_6502/test_t.h
Normal file
38
M6502/HarteTest_6502/test_t.h
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <boost/json.hpp>
|
||||
|
||||
#include "state_t.h"
|
||||
#include "json_t.h"
|
||||
|
||||
class test_t final : public json_t {
|
||||
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;
|
||||
|
||||
static action to_action(std::string value);
|
||||
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;
|
||||
|
||||
void initialise(const boost::json::object& serialised);
|
||||
|
||||
public:
|
||||
test_t(const boost::json::object& serialised);
|
||||
test_t(const boost::json::value& serialised);
|
||||
|
||||
constexpr const auto& name() const noexcept { return m_name; }
|
||||
constexpr const auto& initial_state() const noexcept { return m_initial_state; }
|
||||
constexpr const auto& final_state() const noexcept { return m_final_state; }
|
||||
constexpr const auto& cycles() const noexcept { return m_cycles; }
|
||||
};
|
32
M6502/HarteTest_6502/tests.cpp
Normal file
32
M6502/HarteTest_6502/tests.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
|
||||
#include "TestRunner.h"
|
||||
#include "test_t.h"
|
||||
#include "opcode_test_suite_t.h"
|
||||
|
||||
|
||||
int main() {
|
||||
std::filesystem::path location = "C:\\github\\spectrum\\libraries\\EightBit\\modules\\ProcessorTests\\6502\\v1";
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator{ location }) {
|
||||
|
||||
const auto path = entry.path();
|
||||
std::cout << "** path: " << path << std::endl;
|
||||
|
||||
opcode_test_suite_t opcode(path.string());
|
||||
opcode.load();
|
||||
const auto& opcode_test_array = opcode.get_array();
|
||||
for (const auto& opcode_test_element : opcode_test_array) {
|
||||
|
||||
const auto opcode_test = test_t(opcode_test_element);
|
||||
|
||||
TestRunner runner(opcode_test);
|
||||
runner.run();
|
||||
}
|
||||
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user