loads omf

This commit is contained in:
Sean 2020-02-17 16:58:22 -07:00
parent 6c456df3be
commit 8197f75ce8
No known key found for this signature in database
GPG Key ID: B111C910D99B42B8
7 changed files with 295 additions and 44 deletions

91
src/handle.cc Normal file
View File

@ -0,0 +1,91 @@
/** @copyright 2020 Sean Kasun */
#include <fstream>
#include "handle.h"
Handle TheHandle::createFromFile(const char *filename) {
return std::shared_ptr<TheHandle>(new TheHandle(filename));
}
Handle TheHandle::createFromArray(const std::vector<uint8_t> &data) {
return std::shared_ptr<TheHandle>(new TheHandle(data));
}
TheHandle::TheHandle(const char *filename) {
data = pos = nullptr;
std::ifstream f(filename, std::ios::in | std::ios::binary | std::ios::ate);
if (!f.is_open()) {
return;
}
length = f.tellg();
data = new uint8_t[length];
f.seekg(0, std::ios::beg);
f.read(reinterpret_cast<char*>(data), length);
f.close();
pos = data;
}
TheHandle::TheHandle(const std::vector<uint8_t> &data) {
length = data.size();
this->data = new uint8_t[length];
std::copy(data.begin(), data.end(), this->data);
pos = this->data;
}
TheHandle::~TheHandle() {
if (data != nullptr) {
delete [] data;
}
}
bool TheHandle::isOpen() const {
return data != nullptr;
}
bool TheHandle::eof() const {
return pos - data >= length;
}
int64_t TheHandle::tell() const {
return pos - data;
}
uint32_t TheHandle::r32() {
uint32_t r = *pos++;
r |= *pos++ << 8;
r |= *pos++ << 16;
r |= *pos++ << 24;
return r;
}
uint16_t TheHandle::r16() {
uint16_t r = *pos++;
r |= *pos++ << 8;
return r;
}
uint8_t TheHandle::r8() {
return *pos++;
}
std::string TheHandle::read(int32_t len) {
std::string r;
for (auto i = 0; i < len; i++) {
r += static_cast<char>(*pos++);
}
return r;
}
std::vector<uint8_t> TheHandle::readBytes(int32_t len) {
std::vector<uint8_t> r(pos, pos + len);
pos += len;
return r;
}
void TheHandle::seek(int64_t pos) {
this->pos = data + pos;
}
void TheHandle::skip(int64_t ofs) {
pos += ofs;
}

View File

@ -2,12 +2,14 @@
#pragma once
#include <memory>
#include <vector>
typedef std::shared_ptr<class TheHandle> Handle;
class TheHandle {
public:
static Handle createFromFile(const char *filename);
static Handle createFromArray(const std::vector<uint8_t> &data);
~TheHandle();
bool isOpen() const;
bool eof() const;
@ -19,10 +21,13 @@ class TheHandle {
uint8_t r8();
void seek(int64_t pos);
void skip(int64_t length);
std::string read(int32_t length);
std::vector<uint8_t> readBytes(int32_t length);
int64_t length;
private:
explicit TheHandle(const char *filename);
explicit TheHandle(const std::vector<uint8_t> &data);
uint8_t *data, *pos;
};

View File

@ -21,7 +21,7 @@ static struct argp_option options[] = {
struct arguments {
const char *filename;
uint32_t org;
int32_t flags;
uint32_t flags;
};
static inline uint32_t parseNum(const char *s) {

View File

@ -6,20 +6,138 @@
Map::Map(const char *filename, uint32_t org, uint32_t flags) {
std::string mapname = filename;
mapname += ".regs";
std::ifstream f(mapname, std::ios::in | std::ios::binary | std::ios::ate);
if (!f.is_open()) {
Symbol symbol;
symbol.org = org;
symbol.flags = flags;
symbols.push_back(symbol);
File file(mapname);
if (!file.is_open()) {
Entry entry;
entry.org = org;
this->org = org;
entry.flags = flags;
entryPoints.push_back(entry);
return;
}
std::streamoff len = f.tellg();
char *data = new char[len + 1];
f.seekg(0, std::ios::beg);
f.read(data, len);
f.close();
data[len] = 0;
ConfigFile c(data, len);
while (!file.eof()) {
uint32_t ofs = file.hex();
if (!ofs) {
return;
}
if (file.check(':')) {
Entry entry;
entry.org = ofs;
entry.flags = 0;
uint8_t ch;
while ((ch = file.oneOf("oemx")) != 0) {
switch (ch) {
case 'o':
if (this->org) {
file.error("Duplicate org address");
return;
}
this->org = ofs;
break;
case 'e':
entry.flags |= IsEmu;
break;
case 'm':
entry.flags |= IsM8;
break;
case 'x':
entry.flags |= IsX8;
break;
}
}
entryPoints.push_back(entry);
}
if (file.check('<')) {
symbols[ofs] = file.until('>');
}
}
}
File::File(const std::string &filename) {
data = p = nullptr;
std::ifstream f(filename, std::ios::in | std::ios::binary | std::ios::ate);
if (!f.is_open()) {
return;
}
auto length = f.tellg();
data = new uint8_t[length];
f.seekg(0, std::ios::beg);
f.read(reinterpret_cast<char*>(data), length);
f.close();
p = data;
end = data + length;
curLine = 1;
}
bool File::is_open() const {
return data != nullptr;
}
void File::ws() {
while (p < end && isspace(*p)) {
if (*p == '\n') {
curLine++;
}
p++;
}
}
bool File::eof() {
ws();
return p < end;
}
uint32_t File::hex() {
uint32_t bank = 0;
uint32_t res = 0;
if (*p == '$') {
p++;
}
while (p < end && (isxdigit(*p) || *p == '/')) {
if (*p == '/') {
bank = res;
res = 0;
} else if (isdigit(*p)) {
res <<= 4;
res |= *p - '0';
} else if (*p >= 'a' && *p <= 'f') {
res <<= 4;
res |= *p - 'a' + 10;
} else {
res <<= 4;
res |= *p - 'A' + 10;
}
p++;
}
return res | (bank << 16);
}
bool File::check(uint8_t ch) {
ws();
if (p < end && ch == *p) {
return true;
}
return false;
}
char File::oneOf(const std::string &str) {
ws();
if (p < end && str.find(*p) != std::string::npos) {
return *p++;
}
return 0;
}
void File::error(const char *msg) {
fprintf(stderr, "%s Line %d: %s\n", filename.c_str(), curLine, msg);
}
std::string File::until(uint8_t ch) {
std::string r;
while (*p != ch) {
r += *p++;
}
p++; // skip ending character
return r;
}

View File

@ -2,9 +2,39 @@
#pragma once
#include <cstdint>
#include <map>
#include <vector>
#include <string>
#include "disasm.h"
class File {
public:
File(const std::string &filename);
bool is_open() const;
bool eof();
uint32_t hex();
bool check(uint8_t ch);
char oneOf(const std::string &str);
std::string until(uint8_t ch);
void error(const char *msg);
private:
uint8_t *data, *p, *end;
int curLine;
std::string filename;
void ws();
};
struct Entry {
uint32_t org;
uint32_t flags;
};
class Map {
public:
Map(const char *filename, uint32_t org, uint32_t flags);
uint32_t org;
private:
std::vector<Entry> entryPoints;
std::map<uint32_t, std::string> symbols;
};

View File

@ -2,6 +2,17 @@
#include "omf.h"
#include <set>
enum SegOp {
DONE = 0x00,
RELOC = 0xe2,
INTERSEG = 0xe3,
DS = 0xf1,
LCONST = 0xf2,
cRELOC = 0xf5,
cINTERSEG = 0xf6,
SUPER = 0xf7,
};
OMF::OMF(const Map &map) : map(map) {
}
@ -39,9 +50,9 @@ bool OMF::isOMF() {
handle->skip(11);
uint8_t version = handle->r8();
if (version == 1) {
ofs += version * 512;
ofs += bytecnt * 512;
} else if (version == 2) {
ofs += version;
ofs += bytecnt;
} else {
return false;
}
@ -89,19 +100,20 @@ bool OMF::loadSegments() {
ofs += seg.bytecnt;
segments.push_back(seg);
}
return true;
}
bool OMF::mapSegments() {
// for ease of disassembly, first attempt to map each segment to a bank.
auto canDirectmap = true;
auto canDirectMap = true;
for (auto &seg : segments) {
if (seg.org) { // segment wants to be somewhere specific, no direct map
canDirectMap = false;
} else if (seg.length > 0xffff) { // segment too long for a single bank
canDirectmap = false;
canDirectMap = false;
}
}
if (canDirectmap) {
if (canDirectMap) {
for (auto &seg : segments) {
seg.mapped = seg.segnum << 16;
}
@ -109,8 +121,8 @@ bool OMF::mapSegments() {
}
// use a memory map that denotes runs of available ram
std::set<uint32_t> memory;
memory.push_back(0x10000); // min
memory.push_back(0xf80000); // max
memory.insert(0x10000); // min
memory.insert(0xf80000); // max
// first map any segments that know where they belong
for (auto &seg : segments) {
if (seg.org) {
@ -121,13 +133,8 @@ bool OMF::mapSegments() {
}
bool collision = false;
// verify we aren't overlapping anything
for (auto node = 0; node < memory.length(); node += 2) {
if (seg.mapped < memory[node] &&
seg.mapped + seg.length > memory[node]) {
collision = true;
}
if (seg.mapped < memory[node + 1] &&
seg.mapped + seg.length > memory[node + 1]) {
for (auto it = memory.begin(); it != memory.end(); it++) {
if (seg.mapped < *it && seg.mapped + seg.length > *it) {
collision = true;
}
}
@ -136,34 +143,31 @@ bool OMF::mapSegments() {
seg.segnum, seg.name.c_str());
return false;
}
memory.push_back(seg.mapped);
memory.push_back(seg.mapped + seg.length);
if (seg.mapped < memory[0]) { // below the minimum
memory[0] = seg.mapped; // calc new min
}
memory.insert(seg.mapped);
memory.insert(seg.mapped + seg.length);
}
}
// now map everything else by first fit
for (auto &seg : segments) {
if (seg.mapped == 0) {
for (auto i = 0; i < memory.length(); i += 2) {
auto base = memory[i];
for (auto it = memory.begin(); it != memory.end(); it++) {
auto base = *it;
if (seg.align && (base & (seg.align - 1))) {
base += seg.align;
base &= ~(seg.align - 1);
}
if (seg.banksize && (((baes & (seg.banksize - 1)) + seg.length) &
if (seg.banksize && (((base & (seg.banksize - 1)) + seg.length) &
~(seg.banksize - 1))) { // crosses bank
base += seg.banksize;
base &= ~(seg.banksize - 1);
}
// does it fit?
if (base < memory[i + 1] && memory[i + 1] - base >= seg.length) {
it++;
if (base < *it && *it - base >= seg.length) {
seg.mapped = base;
memory.push_back(seg.mapped);
memory.push_back(seg.mapped + seg.length);
std::sort(memory.begin(), memory.end());
memory.insert(seg.mapped);
memory.insert(seg.mapped + seg.length);
break;
}
}
@ -231,7 +235,8 @@ bool OMF::relocSegments() {
case LCONST:
{
auto count = handle->r32();
data.replace(pc - seg.mapped, count, handle->read(count), count);
auto v = handle->readBytes(count);
std::copy(v.begin(), v.end(), data.begin() + (pc - seg.mapped));
pc += count;
}
break;
@ -279,7 +284,7 @@ bool OMF::relocSegments() {
while (handle->tell() < superLen) {
auto numOfs = handle->r8();
if (numOfs & 0x80) {
superPage += 256 * (nuMofs & 0x7f);
superPage += 256 * (numOfs & 0x7f);
continue;
}
auto subHandle = TheHandle::createFromArray(data);
@ -287,7 +292,7 @@ bool OMF::relocSegments() {
auto offset = superPage | handle->r8();
uint8_t numBytes = 0;
subHandle->seek(offset);
int32_t subOfset = subHandle->r16();
int32_t subOffset = subHandle->r16();
if (superType == 0 || superType == 1) {
subOffset += seg.mapped;
numBytes = superType + 2;
@ -328,7 +333,8 @@ bool OMF::relocSegments() {
break;
default:
if (opcode < 0xe0) {
data.replace(pc - seg.mapped, opcode, handle->read(opcode), opcode);
auto v = handle->readBytes(opcode);
std::copy(v.begin(), v.end(), data.begin() + (pc - seg.mapped));
pc += opcode;
} else {
fprintf(stderr, "Unknown segment opcode: $%02x\n", opcode);

View File

@ -4,6 +4,7 @@
#include "handle.h"
#include "map.h"
#include <vector>
#include <string>
struct Segment {
int32_t bytecnt;