mirror of
https://github.com/mrkite/regs.git
synced 2024-06-10 08:29:30 +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
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
typedef std::shared_ptr<class TheHandle> Handle;
|
typedef std::shared_ptr<class TheHandle> Handle;
|
||||||
|
|
||||||
class TheHandle {
|
class TheHandle {
|
||||||
public:
|
public:
|
||||||
static Handle createFromFile(const char *filename);
|
static Handle createFromFile(const char *filename);
|
||||||
|
static Handle createFromArray(const std::vector<uint8_t> &data);
|
||||||
~TheHandle();
|
~TheHandle();
|
||||||
bool isOpen() const;
|
bool isOpen() const;
|
||||||
bool eof() const;
|
bool eof() const;
|
||||||
|
@ -19,10 +21,13 @@ class TheHandle {
|
||||||
uint8_t r8();
|
uint8_t r8();
|
||||||
void seek(int64_t pos);
|
void seek(int64_t pos);
|
||||||
void skip(int64_t length);
|
void skip(int64_t length);
|
||||||
|
std::string read(int32_t length);
|
||||||
|
std::vector<uint8_t> readBytes(int32_t length);
|
||||||
|
|
||||||
int64_t length;
|
int64_t length;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit TheHandle(const char *filename);
|
explicit TheHandle(const char *filename);
|
||||||
|
explicit TheHandle(const std::vector<uint8_t> &data);
|
||||||
uint8_t *data, *pos;
|
uint8_t *data, *pos;
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,7 +21,7 @@ static struct argp_option options[] = {
|
||||||
struct arguments {
|
struct arguments {
|
||||||
const char *filename;
|
const char *filename;
|
||||||
uint32_t org;
|
uint32_t org;
|
||||||
int32_t flags;
|
uint32_t flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline uint32_t parseNum(const char *s) {
|
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) {
|
Map::Map(const char *filename, uint32_t org, uint32_t flags) {
|
||||||
std::string mapname = filename;
|
std::string mapname = filename;
|
||||||
mapname += ".regs";
|
mapname += ".regs";
|
||||||
std::ifstream f(mapname, std::ios::in | std::ios::binary | std::ios::ate);
|
File file(mapname);
|
||||||
if (!f.is_open()) {
|
if (!file.is_open()) {
|
||||||
Symbol symbol;
|
Entry entry;
|
||||||
symbol.org = org;
|
entry.org = org;
|
||||||
symbol.flags = flags;
|
this->org = org;
|
||||||
symbols.push_back(symbol);
|
entry.flags = flags;
|
||||||
|
entryPoints.push_back(entry);
|
||||||
return;
|
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
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
#include "disasm.h"
|
#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 {
|
class Map {
|
||||||
public:
|
public:
|
||||||
Map(const char *filename, uint32_t org, uint32_t flags);
|
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 "omf.h"
|
||||||
#include <set>
|
#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) {
|
OMF::OMF(const Map &map) : map(map) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,9 +50,9 @@ bool OMF::isOMF() {
|
||||||
handle->skip(11);
|
handle->skip(11);
|
||||||
uint8_t version = handle->r8();
|
uint8_t version = handle->r8();
|
||||||
if (version == 1) {
|
if (version == 1) {
|
||||||
ofs += version * 512;
|
ofs += bytecnt * 512;
|
||||||
} else if (version == 2) {
|
} else if (version == 2) {
|
||||||
ofs += version;
|
ofs += bytecnt;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -89,19 +100,20 @@ bool OMF::loadSegments() {
|
||||||
ofs += seg.bytecnt;
|
ofs += seg.bytecnt;
|
||||||
segments.push_back(seg);
|
segments.push_back(seg);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OMF::mapSegments() {
|
bool OMF::mapSegments() {
|
||||||
// for ease of disassembly, first attempt to map each segment to a bank.
|
// for ease of disassembly, first attempt to map each segment to a bank.
|
||||||
auto canDirectmap = true;
|
auto canDirectMap = true;
|
||||||
for (auto &seg : segments) {
|
for (auto &seg : segments) {
|
||||||
if (seg.org) { // segment wants to be somewhere specific, no direct map
|
if (seg.org) { // segment wants to be somewhere specific, no direct map
|
||||||
canDirectMap = false;
|
canDirectMap = false;
|
||||||
} else if (seg.length > 0xffff) { // segment too long for a single bank
|
} else if (seg.length > 0xffff) { // segment too long for a single bank
|
||||||
canDirectmap = false;
|
canDirectMap = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (canDirectmap) {
|
if (canDirectMap) {
|
||||||
for (auto &seg : segments) {
|
for (auto &seg : segments) {
|
||||||
seg.mapped = seg.segnum << 16;
|
seg.mapped = seg.segnum << 16;
|
||||||
}
|
}
|
||||||
|
@ -109,8 +121,8 @@ bool OMF::mapSegments() {
|
||||||
}
|
}
|
||||||
// use a memory map that denotes runs of available ram
|
// use a memory map that denotes runs of available ram
|
||||||
std::set<uint32_t> memory;
|
std::set<uint32_t> memory;
|
||||||
memory.push_back(0x10000); // min
|
memory.insert(0x10000); // min
|
||||||
memory.push_back(0xf80000); // max
|
memory.insert(0xf80000); // max
|
||||||
// first map any segments that know where they belong
|
// first map any segments that know where they belong
|
||||||
for (auto &seg : segments) {
|
for (auto &seg : segments) {
|
||||||
if (seg.org) {
|
if (seg.org) {
|
||||||
|
@ -121,13 +133,8 @@ bool OMF::mapSegments() {
|
||||||
}
|
}
|
||||||
bool collision = false;
|
bool collision = false;
|
||||||
// verify we aren't overlapping anything
|
// verify we aren't overlapping anything
|
||||||
for (auto node = 0; node < memory.length(); node += 2) {
|
for (auto it = memory.begin(); it != memory.end(); it++) {
|
||||||
if (seg.mapped < memory[node] &&
|
if (seg.mapped < *it && seg.mapped + seg.length > *it) {
|
||||||
seg.mapped + seg.length > memory[node]) {
|
|
||||||
collision = true;
|
|
||||||
}
|
|
||||||
if (seg.mapped < memory[node + 1] &&
|
|
||||||
seg.mapped + seg.length > memory[node + 1]) {
|
|
||||||
collision = true;
|
collision = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,34 +143,31 @@ bool OMF::mapSegments() {
|
||||||
seg.segnum, seg.name.c_str());
|
seg.segnum, seg.name.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memory.push_back(seg.mapped);
|
memory.insert(seg.mapped);
|
||||||
memory.push_back(seg.mapped + seg.length);
|
memory.insert(seg.mapped + seg.length);
|
||||||
if (seg.mapped < memory[0]) { // below the minimum
|
|
||||||
memory[0] = seg.mapped; // calc new min
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now map everything else by first fit
|
// now map everything else by first fit
|
||||||
for (auto &seg : segments) {
|
for (auto &seg : segments) {
|
||||||
if (seg.mapped == 0) {
|
if (seg.mapped == 0) {
|
||||||
for (auto i = 0; i < memory.length(); i += 2) {
|
for (auto it = memory.begin(); it != memory.end(); it++) {
|
||||||
auto base = memory[i];
|
auto base = *it;
|
||||||
if (seg.align && (base & (seg.align - 1))) {
|
if (seg.align && (base & (seg.align - 1))) {
|
||||||
base += seg.align;
|
base += seg.align;
|
||||||
base &= ~(seg.align - 1);
|
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
|
~(seg.banksize - 1))) { // crosses bank
|
||||||
base += seg.banksize;
|
base += seg.banksize;
|
||||||
base &= ~(seg.banksize - 1);
|
base &= ~(seg.banksize - 1);
|
||||||
}
|
}
|
||||||
// does it fit?
|
// 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;
|
seg.mapped = base;
|
||||||
memory.push_back(seg.mapped);
|
memory.insert(seg.mapped);
|
||||||
memory.push_back(seg.mapped + seg.length);
|
memory.insert(seg.mapped + seg.length);
|
||||||
std::sort(memory.begin(), memory.end());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,7 +235,8 @@ bool OMF::relocSegments() {
|
||||||
case LCONST:
|
case LCONST:
|
||||||
{
|
{
|
||||||
auto count = handle->r32();
|
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;
|
pc += count;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -279,7 +284,7 @@ bool OMF::relocSegments() {
|
||||||
while (handle->tell() < superLen) {
|
while (handle->tell() < superLen) {
|
||||||
auto numOfs = handle->r8();
|
auto numOfs = handle->r8();
|
||||||
if (numOfs & 0x80) {
|
if (numOfs & 0x80) {
|
||||||
superPage += 256 * (nuMofs & 0x7f);
|
superPage += 256 * (numOfs & 0x7f);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto subHandle = TheHandle::createFromArray(data);
|
auto subHandle = TheHandle::createFromArray(data);
|
||||||
|
@ -287,7 +292,7 @@ bool OMF::relocSegments() {
|
||||||
auto offset = superPage | handle->r8();
|
auto offset = superPage | handle->r8();
|
||||||
uint8_t numBytes = 0;
|
uint8_t numBytes = 0;
|
||||||
subHandle->seek(offset);
|
subHandle->seek(offset);
|
||||||
int32_t subOfset = subHandle->r16();
|
int32_t subOffset = subHandle->r16();
|
||||||
if (superType == 0 || superType == 1) {
|
if (superType == 0 || superType == 1) {
|
||||||
subOffset += seg.mapped;
|
subOffset += seg.mapped;
|
||||||
numBytes = superType + 2;
|
numBytes = superType + 2;
|
||||||
|
@ -328,7 +333,8 @@ bool OMF::relocSegments() {
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (opcode < 0xe0) {
|
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;
|
pc += opcode;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Unknown segment opcode: $%02x\n", opcode);
|
fprintf(stderr, "Unknown segment opcode: $%02x\n", opcode);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user