mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2024-09-01 00:28:55 +00:00
Refactor the Intel hex file loader into it's own class.
Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
parent
ef09696ea2
commit
36465ce1c8
@ -2,8 +2,6 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#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<uint16_t, std::vector<uint8_t>> parseHexFile(std::string path);
|
||||
void loadHexFile(std::string path);
|
||||
|
||||
private:
|
||||
|
32
inc/IntelHexFile.h
Normal file
32
inc/IntelHexFile.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
namespace EightBit {
|
||||
class IntelHexFile {
|
||||
public:
|
||||
IntelHexFile(std::string path);
|
||||
|
||||
[[nodiscard]] std::map<uint16_t, std::vector<uint8_t>> parse();
|
||||
|
||||
private:
|
||||
[[nodiscard]] std::optional<std::pair<uint16_t, std::vector<uint8_t>>> parse(std::string line);
|
||||
[[nodiscard]] std::vector<uint8_t> parseDataRecord(std::string line, uint8_t count);
|
||||
|
||||
template <class T> T fromHex(std::string input) {
|
||||
std::istringstream converter(input);
|
||||
unsigned output;
|
||||
converter >> std::hex >> output;
|
||||
return static_cast<T>(output);
|
||||
}
|
||||
|
||||
std::ifstream m_file;
|
||||
bool m_eof;
|
||||
};
|
||||
}
|
60
src/Bus.cpp
60
src/Bus.cpp
@ -1,13 +1,9 @@
|
||||
#include "stdafx.h"
|
||||
#include "Bus.h"
|
||||
#include "Ram.h"
|
||||
#include "IntelHexFile.h"
|
||||
#include "EightBitCompilerDefinitions.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
|
||||
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<uint16_t, std::vector<uint8_t>> EightBit::Bus::parseHexFile(const std::string path) {
|
||||
|
||||
std::ifstream file;
|
||||
file.open(path);
|
||||
|
||||
std::map<uint16_t, std::vector<uint8_t>> 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<uint8_t> 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;
|
||||
|
@ -23,7 +23,7 @@
|
||||
<ProjectGuid>{A9C24BD9-0CB4-4C84-B09B-46B815F9DA47}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>EightBit</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
@ -72,15 +72,19 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<IncludePath>..\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<IncludePath>..\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>..\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<IncludePath>..\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
@ -120,6 +124,7 @@
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<ControlFlowGuard>false</ControlFlowGuard>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@ -139,6 +144,7 @@
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<ControlFlowGuard>false</ControlFlowGuard>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@ -155,6 +161,7 @@
|
||||
<ClInclude Include="..\inc\EightBitCompilerDefinitions.h" />
|
||||
<ClInclude Include="..\inc\EventArgs.h" />
|
||||
<ClInclude Include="..\inc\InputOutput.h" />
|
||||
<ClInclude Include="..\inc\IntelHexFile.h" />
|
||||
<ClInclude Include="..\inc\IntelProcessor.h" />
|
||||
<ClInclude Include="..\inc\LittleEndianProcessor.h" />
|
||||
<ClInclude Include="..\inc\Mapper.h" />
|
||||
@ -176,6 +183,7 @@
|
||||
<ClCompile Include="Device.cpp" />
|
||||
<ClCompile Include="EventArgs.cpp" />
|
||||
<ClCompile Include="InputOutput.cpp" />
|
||||
<ClCompile Include="IntelHexFile.cpp" />
|
||||
<ClCompile Include="IntelProcessor.cpp" />
|
||||
<ClCompile Include="LittleEndianProcessor.cpp" />
|
||||
<ClCompile Include="Memory.cpp" />
|
||||
|
@ -74,6 +74,9 @@
|
||||
<ClInclude Include="..\inc\ClockedChip.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\inc\IntelHexFile.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
@ -118,5 +121,8 @@
|
||||
<ClCompile Include="Device.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IntelHexFile.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
69
src/IntelHexFile.cpp
Normal file
69
src/IntelHexFile.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
#include "stdafx.h"
|
||||
#include "IntelHexFile.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
EightBit::IntelHexFile::IntelHexFile(std::string path)
|
||||
: m_eof(false) {
|
||||
m_file.open(path);
|
||||
}
|
||||
|
||||
std::map<uint16_t, std::vector<uint8_t>> EightBit::IntelHexFile::parse() {
|
||||
|
||||
std::map<uint16_t, std::vector<uint8_t>> 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<std::pair<uint16_t, std::vector<uint8_t>>> 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<uint8_t>(countString);
|
||||
|
||||
const auto addressString = line.substr(3, 4);
|
||||
const auto address = fromHex<uint16_t>(addressString);
|
||||
|
||||
const auto recordTypeString = line.substr(7, 2);
|
||||
const auto recordType = fromHex<uint8_t>(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<uint8_t> EightBit::IntelHexFile::parseDataRecord(std::string line, uint8_t count) {
|
||||
std::vector<uint8_t> 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<uint8_t>(datumString);
|
||||
data.at(i) = datum;
|
||||
}
|
||||
return data;
|
||||
}
|
Loading…
Reference in New Issue
Block a user