diff --git a/inc/Bus.h b/inc/Bus.h index ef1bc3a..6821cc7 100644 --- a/inc/Bus.h +++ b/inc/Bus.h @@ -2,8 +2,6 @@ #include #include -#include -#include #include "Chip.h" #include "Signal.h" @@ -58,7 +56,6 @@ namespace EightBit { [[nodiscard]] auto& reference(const register16_t address) { return reference(address.word); } [[nodiscard]] uint8_t& reference() { return reference(ADDRESS()); } - [[nodiscard]] static std::map> parseHexFile(std::string path); void loadHexFile(std::string path); private: diff --git a/inc/IntelHexFile.h b/inc/IntelHexFile.h new file mode 100644 index 0000000..8765d4d --- /dev/null +++ b/inc/IntelHexFile.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace EightBit { + class IntelHexFile { + public: + IntelHexFile(std::string path); + + [[nodiscard]] std::map> parse(); + + private: + [[nodiscard]] std::optional>> parse(std::string line); + [[nodiscard]] std::vector parseDataRecord(std::string line, uint8_t count); + + template T fromHex(std::string input) { + std::istringstream converter(input); + unsigned output; + converter >> std::hex >> output; + return static_cast(output); + } + + std::ifstream m_file; + bool m_eof; + }; +} diff --git a/src/Bus.cpp b/src/Bus.cpp index 7232bed..a9c801b 100644 --- a/src/Bus.cpp +++ b/src/Bus.cpp @@ -1,13 +1,9 @@ #include "stdafx.h" #include "Bus.h" #include "Ram.h" +#include "IntelHexFile.h" #include "EightBitCompilerDefinitions.h" -#include -#include -#include -#include - void EightBit::Bus::raisePOWER() {} void EightBit::Bus::lowerPOWER() {} @@ -31,7 +27,8 @@ void EightBit::Bus::write(const uint8_t value) { } void EightBit::Bus::loadHexFile(const std::string path) { - const auto chunks = parseHexFile(path); + IntelHexFile file(path); + const auto chunks = file.parse(); for (const auto& chunk : chunks) { const auto address = chunk.first; const auto content = chunk.second; @@ -41,57 +38,6 @@ void EightBit::Bus::loadHexFile(const std::string path) { } } -std::map> EightBit::Bus::parseHexFile(const std::string path) { - - std::ifstream file; - file.open(path); - - std::map> returned; - - bool eof = false; - while (!file.eof() && !eof) { - - std::string line; - std::getline(file, line); - - const auto colon = line.substr(0, 1); - if (colon != ":") - throw std::out_of_range("Invalid hex file: line does not begin with a colon"); - - const auto countString = line.substr(1, 2); - const auto count = (uint8_t)strtoul(countString.c_str(), nullptr, 16); - - const auto addressString = line.substr(3, 4); - const auto address = (uint16_t)strtoul(addressString.c_str(), nullptr, 16); - - const auto recordTypeString = line.substr(7, 2); - const auto recordType = strtoul(recordTypeString.c_str(), nullptr, 16); - - switch (recordType) { - case 0x00: { - std::vector data(count); - const auto requiredLength = 9 + 2 + (count * 2); - if (line.length() != requiredLength) - throw std::out_of_range("Invalid hex file: line is not the required length"); - for (int i = 0; i < count; ++i) { - const auto position = 9 + i * 2; - const auto datumString = line.substr(position, 2); - const auto datum = (uint8_t)strtoul(datumString.c_str(), nullptr, 16); - data[i] = datum; - } - returned[address] = data; - } - break; - case 0x01: - eof = true; - break; - default: - throw std::out_of_range("Unhandled hex file record."); - } - } - return returned; -} - uint8_t& EightBit::Bus::reference(const uint16_t address) { const auto mapped = mapping(address); const uint16_t offset = (address - mapped.begin) & mapped.mask; diff --git a/src/EightBit.vcxproj b/src/EightBit.vcxproj index 6c5293b..5da3ac1 100644 --- a/src/EightBit.vcxproj +++ b/src/EightBit.vcxproj @@ -23,7 +23,7 @@ {A9C24BD9-0CB4-4C84-B09B-46B815F9DA47} Win32Proj EightBit - 10.0 + 8.1 @@ -72,15 +72,19 @@ ..\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + AllRules.ruleset ..\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + AllRules.ruleset ..\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + AllRules.ruleset ..\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + AllRules.ruleset @@ -120,6 +124,7 @@ stdcpp17 true false + Speed Windows @@ -139,6 +144,7 @@ stdcpp17 true false + Speed Windows @@ -155,6 +161,7 @@ + @@ -176,6 +183,7 @@ + diff --git a/src/EightBit.vcxproj.filters b/src/EightBit.vcxproj.filters index e32659c..f685ed9 100644 --- a/src/EightBit.vcxproj.filters +++ b/src/EightBit.vcxproj.filters @@ -74,6 +74,9 @@ Header Files + + Header Files + @@ -118,5 +121,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/src/IntelHexFile.cpp b/src/IntelHexFile.cpp new file mode 100644 index 0000000..0bd364d --- /dev/null +++ b/src/IntelHexFile.cpp @@ -0,0 +1,69 @@ +#include "stdafx.h" +#include "IntelHexFile.h" + +#include + +EightBit::IntelHexFile::IntelHexFile(std::string path) +: m_eof(false) { + m_file.open(path); +} + +std::map> EightBit::IntelHexFile::parse() { + + std::map> returned; + + while (!m_file.eof() && !m_eof) { + + std::string line; + std::getline(m_file, line); + + const auto parsed = parse(line); + if (parsed.has_value()) + returned[parsed.value().first] = parsed.value().second; + } + + if (!m_eof) + throw std::out_of_range("File is missing an EOF record"); + + return returned; +} + +std::optional>> EightBit::IntelHexFile::parse(std::string line) { + + const auto colon = line.substr(0, 1); + if (colon != ":") + throw std::out_of_range("Invalid hex file: line does not begin with a colon"); + + const auto countString = line.substr(1, 2); + const auto count = fromHex(countString); + + const auto addressString = line.substr(3, 4); + const auto address = fromHex(addressString); + + const auto recordTypeString = line.substr(7, 2); + const auto recordType = fromHex(recordTypeString); + + switch (recordType) { + case 0x00: + return std::make_pair(address, parseDataRecord(line, count)); + case 0x01: + m_eof = true; + return {}; + default: + throw std::out_of_range("Unhandled hex file record."); + } +} + +std::vector EightBit::IntelHexFile::parseDataRecord(std::string line, uint8_t count) { + std::vector data(count); + const auto requiredLength = 9 + 2 + (count * 2); + if (line.length() != requiredLength) + throw std::out_of_range("Invalid hex file: line is not the required length"); + for (int i = 0; i < count; ++i) { + const auto position = 9 + i * 2; + const auto datumString = line.substr(position, 2); + const auto datum = fromHex(datumString); + data.at(i) = datum; + } + return data; +}