mirror of
https://github.com/mrkite/regs.git
synced 2024-09-07 11:54:25 +00:00
loads omf
This commit is contained in:
parent
6c456df3be
commit
8197f75ce8
91
src/handle.cc
Normal file
91
src/handle.cc
Normal 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;
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
@ -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) {
|
||||
|
144
src/map.cc
144
src/map.cc
@ -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;
|
||||
}
|
||||
|
30
src/map.h
30
src/map.h
@ -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;
|
||||
};
|
||||
|
66
src/omf.cc
66
src/omf.cc
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user