2017-11-10 22:41:50 +00:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "Bus.h"
|
2018-09-15 13:35:59 +00:00
|
|
|
#include "Ram.h"
|
|
|
|
#include "EightBitCompilerDefinitions.h"
|
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <cassert>
|
2017-11-10 22:41:50 +00:00
|
|
|
|
|
|
|
uint8_t EightBit::Bus::read() {
|
2018-06-10 21:00:52 +00:00
|
|
|
ReadingByte.fire(EventArgs::empty());
|
2018-06-09 23:40:56 +00:00
|
|
|
DATA() = reference();
|
2018-06-10 21:00:52 +00:00
|
|
|
ReadByte.fire(EventArgs::empty());
|
2018-06-09 23:40:56 +00:00
|
|
|
return DATA();
|
2017-11-10 22:41:50 +00:00
|
|
|
}
|
|
|
|
|
2018-06-09 23:40:56 +00:00
|
|
|
void EightBit::Bus::write() {
|
2018-06-10 21:00:52 +00:00
|
|
|
WritingByte.fire(EventArgs::empty());
|
2018-06-09 23:40:56 +00:00
|
|
|
reference() = DATA();
|
2018-06-10 21:00:52 +00:00
|
|
|
WrittenByte.fire(EventArgs::empty());
|
2017-11-10 22:41:50 +00:00
|
|
|
}
|
|
|
|
|
2018-06-09 23:40:56 +00:00
|
|
|
void EightBit::Bus::write(const uint8_t value) {
|
|
|
|
DATA() = value;
|
|
|
|
write();
|
|
|
|
}
|
2018-09-15 13:35:59 +00:00
|
|
|
|
|
|
|
void EightBit::Bus::loadHexFile(const std::string path) {
|
|
|
|
const auto chunks = parseHexFile(path);
|
|
|
|
for (const auto& chunk : chunks) {
|
|
|
|
const auto address = chunk.first;
|
|
|
|
const auto content = chunk.second;
|
|
|
|
const auto mapped = mapping(address);
|
2018-09-16 16:54:53 +00:00
|
|
|
const uint16_t offset = address - mapped.begin;
|
|
|
|
mapped.memory.load(content, offset);
|
2018-09-15 13:35:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-09-20 23:16:00 +00:00
|
|
|
uint8_t& EightBit::Bus::reference(const uint16_t address) {
|
2018-09-15 13:35:59 +00:00
|
|
|
const auto mapped = mapping(address);
|
|
|
|
const uint16_t offset = address - mapped.begin;
|
|
|
|
if (mapped.access == MemoryMapping::ReadOnly)
|
|
|
|
return DATA() = mapped.memory.peek(offset);
|
|
|
|
Ram& ram = (Ram&)(mapped.memory);
|
|
|
|
return ram.reference(offset);
|
|
|
|
}
|