From be5873d13cfa97ae573ba77212e101db2d8f6628 Mon Sep 17 00:00:00 2001 From: Sean Date: Tue, 21 May 2024 19:19:11 -0700 Subject: [PATCH] improved segment mapping --- src/omf.cc | 149 +++++++++++++++++++++++++++++------------------------ src/omf.h | 4 ++ 2 files changed, 86 insertions(+), 67 deletions(-) diff --git a/src/omf.cc b/src/omf.cc index f94f797..aed2a7b 100644 --- a/src/omf.cc +++ b/src/omf.cc @@ -20,6 +20,19 @@ static bool compareSegments(const Segment &a, const Segment &b) { return a.mapped < b.mapped; } +void Segment::initDPS() { + kind = 0x12; + length = 1024; + resspc = 1024; + bytecnt = 0; + name = "Direct"; +} + +bool Segment::isDPS() { + return (kind & 0x1f) == 0x12; +} + + bool OMF::load(const char *filename, uint32_t org) { handle = TheHandle::createFromFile(filename); if (!handle->isOpen()) { @@ -123,86 +136,88 @@ bool OMF::loadSegments() { } bool OMF::mapSegments() { - // for ease of disassembly, first attempt to map each segment to a bank. - 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 > 0xfffff) { // segment too long for a single bank - canDirectMap = false; - } - } - if (canDirectMap) { - for (auto &seg : segments) { - seg.mapped = seg.segnum << 20; - } - return true; - } // use a memory map that denotes runs of available ram std::vector memory; - memory.push_back(0x10000); // min + memory.push_back(0x300); // min memory.push_back(0x7f0000); // max // first map any segments that know where they belong for (auto &seg : segments) { - if (seg.org) { - if ((seg.kind & 0x1f) == 0x11) { // absolute bank - seg.mapped = seg.org << 16; - } else { - seg.mapped = seg.org; - } - bool collision = false; - // verify we aren't overlapping anything - for (auto it = memory.begin(); it != memory.end(); it++) { - if (seg.mapped < *it && seg.mapped + seg.length > *it) { - collision = true; - } - } - if (collision) { - fprintf(stderr, "Segment $%x (%s) collides with another segment\n", - 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; // new min - } - std::sort(memory.begin(), memory.end()); - } + seg.map(memory, false); + std::sort(memory.begin(), memory.end()); } // now map everything else by first fit + for (auto &seg : segments) { // map.true + seg.map(memory, true); + std::sort(memory.begin(), memory.end()); + } + // create direct-page if it doesn't exist + bool found = false; for (auto &seg : segments) { - if (seg.mapped == 0) { - 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 && (((base & (seg.banksize - 1)) + seg.length) & - ~(seg.banksize - 1))) { // crosses bank - base += seg.banksize; - base &= ~(seg.banksize - 1); - } - // does it fit? - 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()); - break; - } - } - if (seg.mapped == 0) { - fprintf(stderr, "Failed to map Segment #$%x (%s), no room\n", - seg.segnum, seg.name.c_str()); + if (seg.isDPS()) { + found = true; + } + } + if (!found) { + Segment seg; + seg.initDPS(); + seg.map(memory, true); + segments.push_back(seg); + } + return true; +} + +bool Segment::map(std::vector &memory, bool force) { + if (mapped) { + return false; + } + if (org && ((org & 0xffff) != 0 || (kind & 0x800) == 0)) { + mapped = org; + // verif we're not overlapping + for (auto m : memory) { + if (mapped < m && mapped + length > m) { + fprintf(stderr, "Segment %d (%s) collides with another segment!\n", segnum, name.c_str()); return false; } } + memory.push_back(mapped); + memory.push_back(mapped + length); + if (mapped < memory[0]) { // below the min? + memory[0] = mapped; + } + return true; } - return true; + if (force) { + for (auto it = memory.begin(); it != memory.end(); it++) { + auto base = *it; + // skip special? + if ((kind & 0x1f) != 0x12 && (base & 0xff0000) == 0) { + base += 0x10000; // not in bank 0 + } + // are we aligned? + if (align != 0 && (base & (align - 1)) != 0) { + base += align; + base &= ~(align - 1); + } + // does it cross bank boundaries? + if (banksize != 0 && + (((base & (banksize - 1)) + length) & ~(banksize - 1)) != 0) { + base += banksize; + base &= ~(banksize - 1); + } + // does it fit?! + it++; + uint32_t end = *it; + if (base < end && end - base >= length) { + mapped = base; + memory.push_back(mapped); + memory.push_back(mapped + length); + return true; + } + } + fprintf(stderr, "Segment %d (%s) doesn't fit in memory\n", segnum, name.c_str()); + } + return false; } bool OMF::relocSegments() { diff --git a/src/omf.h b/src/omf.h index 37afe27..9ea0229 100644 --- a/src/omf.h +++ b/src/omf.h @@ -22,6 +22,10 @@ struct Segment { int64_t offset; Handle data; int32_t mapped; + + bool map(std::vector &memory, bool force); + void initDPS(); + bool isDPS(); }; class OMF {