spo/simulator_SIC_XE/src/loader.cpp
2025-11-17 15:21:25 +01:00

128 lines
3.8 KiB
C++

#include "loader.h"
#include "file_reader.h"
#include "machine.h"
#include "constants.h"
#include <algorithm>
Loader::~Loader()
{
_machine.reset();
}
void Loader::load()
{
HeaderMetadata header = readHeader();
while(true) {
RecordType type = parseRecordType(static_cast<char>(_file_reader->readByte()));
switch (type) {
case RecordType::TEXT: {
TextRecord textRecord = readTextRecord();
if (!load_into_memory(textRecord.start_address, textRecord.data)) {
throw std::runtime_error("Failed to load text record into memory");
}
break;
}
case RecordType::END: {
EndRecord endRecord = readEndRecord();
_machine->setPC(endRecord.execution_start_address);
return; // Loading complete
}
case RecordType::UNKNOWN:
default:
throw std::runtime_error("Unknown record type encountered");
}
}
}
Loader::RecordType Loader::parseRecordType(char c)
{
switch (c) {
case 'H': return RecordType::HEADER;
case 'T': return RecordType::TEXT;
case 'E': return RecordType::END;
default: return RecordType::UNKNOWN; // fallback; adjust as needed
}
}
Loader::HeaderMetadata Loader::readHeader()
{
RecordType type = parseRecordType(static_cast<char>(_file_reader->readByte()));
if (type != RecordType::HEADER) {
throw std::runtime_error("Expected HEADER record");
}
if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte();
HeaderMetadata header;
// Read program name (6 bytes)
header.program_name = _file_reader->readString(6);
if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte();
// Read start address (6 hex digits)
header.start_address = std::stoi(_file_reader->readString(6), nullptr, 16);
if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte();
// Read length (6 hex digits)
header.length = std::stoi(_file_reader->readString(6), nullptr, 16);
// consume newline
_file_reader->readLine();
return header;
}
Loader::TextRecord Loader::readTextRecord()
{
if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte();
TextRecord record;
// Assume 'T' has already been read
record.start_address = std::stoi(_file_reader->readString(6), nullptr, 16);
if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte();
// Read length (1 byte, 2 hex digits)
int length = std::stoi(_file_reader->readString(2), nullptr, 16);
if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte();
record.data.resize(length);
int index = 0;
string byteStr = _file_reader->readLine();
// Remove spaces, newlines, and other whitespace characters
byteStr.erase(std::remove_if(byteStr.begin(), byteStr.end(), ::isspace), byteStr.end());
for (int i = 0; i < length; ++i) {
std::string byteHex = byteStr.substr(i * 2, 2);
record.data[i] = static_cast<uint8_t>(std::stoi(byteHex, nullptr, 16));
}
return record;
}
Loader::EndRecord Loader::readEndRecord()
{
EndRecord record;
if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte();
// Assume 'E' has already been read
std::string addrStr = _file_reader->readString(6);
if (!addrStr.empty()) {
record.execution_start_address = std::stoi(addrStr, nullptr, 16);
} else {
record.execution_start_address = 0;
}
// consume newline
_file_reader->readLine();
return record;
}
bool Loader::load_into_memory(int start_address, const std::vector<uint8_t> &data)
{
for(size_t i = 0; i < data.size(); ++i) {
int addr = start_address + static_cast<int>(i);
if (addr < 0 || addr >= MEMORY_SIZE) {
return false;
}
_machine->setByte(addr, data[i]);
}
return true;
}