build segment tool can now be instructed to always place routine above #E000

This commit is contained in:
FeralChild64 committed 2020-06-26 19:15:49 +02:00
1 parent a4d9679019
commit d4d32095d1
3 files changed
+96 -8

No files matched your search

@@ -1,9 +1,8 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# STD * #TAKE-HIGH
// #LAYOUT# * BASIC_0 #TAKE-HIGH
// #LAYOUT# * * #IGNORE
// XXX This can be any address - but definitely $E000 or above
// XXX TODO: extend build_segment tool to allow to specify placement range
// This has to go $E000 or above - as the routines below bank out the main BASIC ROM!
#if CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
+3
View File
@@ -132,6 +132,7 @@ where:
| `#IGNORE` | ignore the file completely |
| `#TAKE` | compile the file normally |
| `#TAKE-FLOAT` | compile the file, but force it to be floating |
| `#TAKE-HIGH` | as above, but always place routine at `$E000` or above |
| `#TAKE-OFFSET` | shifts the fixed-location address by hex offset given as parameter |
The first match counts, all the remaining ones are dropped. Examples:
@@ -184,6 +185,8 @@ ROUTINE_NAME:
#endif
```
Last, but not least - the `#TAKE-HIGH` is intended to be used for BASIC routines, which should still be available after the main BASIC ROM is banked out.
### CPU-specific optimizations
TODO
+90 -4
View File
@@ -88,6 +88,7 @@ public:
bool ignore;
bool floating;
bool high;
std::vector<char> content;
std::string label;
@@ -109,6 +110,7 @@ public:
void addToProblem(SourceFile *routine);
void fillGap(DualStream &logOutput, int gapAddress, const std::list<SourceFile *> &routines);
void placeHighRoutines(DualStream &logOutput);
void performObviousSteps(DualStream &logOutput);
void removeUselessGaps(DualStream &logOutput);
void sortFloatingRoutinesBySize();
@@ -416,9 +418,22 @@ void prepareBinningProblem()
{
std::string spacing;
spacing.resize(GLOBAL_maxFileNameLen + 4 - sourceFile.fileName.length(), ' ');
std::string floating = sourceFile.floating ? "(floating) " : " ";
std::string floating_high;
logOutput << "file: " << floating << sourceFile.fileName << spacing << "size: " << std::to_string(sourceFile.codeLength) << "\n";
if (sourceFile.high)
{
floating_high = "(floating, high) ";
}
else if (sourceFile.floating)
{
floating_high = "(floating) ";
}
else
{
floating_high = " ";
}
logOutput << "file: " << floating_high << sourceFile.fileName << spacing << "size: " << std::to_string(sourceFile.codeLength) << "\n";
}
// Create the binning problem
@@ -569,6 +584,7 @@ SourceFile::SourceFile(const std::string &fileName, const std::string &dirName)
dirName(dirName),
ignore(false),
floating(false),
high(false),
startAddr(-1),
codeLength(-1),
testAddrStart(-1),
@@ -686,12 +702,17 @@ bool SourceFile::preprocessLine(const std::string &line)
if (iter->compare("#IGNORE") == 0)
{
ignore = true;
ignore = true;
}
else if (iter->compare("#TAKE-FLOAT") == 0)
{
floating = true;
}
else if (iter->compare("#TAKE-HIGH") == 0)
{
floating = true;
high = true;
}
else if (iter->compare("#TAKE-OFFSET") == 0)
{
if (++iter == tokens.end()) ERROR("syntax error, missing parameter for '#TAKE-OFFSET'");
@@ -844,10 +865,71 @@ void BinningProblem::fillGap(DualStream &logOutput, int gapAddress, const std::l
gaps.erase(gapAddress);
}
void BinningProblem::placeHighRoutines(DualStream &logOutput)
{
// Place routines which has to be stored in the high ROM area
// It is expected there will be very few of them, so no complicated algorithms here
std::string spacing;
while (!floatingRoutines.empty())
{
// Try to find any high routine
auto iterRoutine = floatingRoutines.begin();
while (iterRoutine != floatingRoutines.end() && !(*iterRoutine)->high) iterRoutine++;
if (iterRoutine == floatingRoutines.end()) break;
// Now we need to find a space to put it - just take the largest gap available,
// which is located in the high ROM area
int routineSize = (*iterRoutine)->codeLength;
int gapAddress = -1;
for (auto &gap : gaps)
{
if (gap.second < routineSize || gap.first < 0xE000) continue;
if (gap.second == routineSize)
{
gapAddress = gap.first;
break;
}
if (gapAddress < 0 || gap.second > gaps[gapAddress])
{
gapAddress = gap.first;
}
}
if (gapAddress < 0) ERROR("no suitable space for a high routine");
// Place routine in the gap found
gaps[gapAddress] -= routineSize;
int targetAddr = gapAddress + gaps[gapAddress];
fixedRoutines[targetAddr] = *iterRoutine;
statFree -= routineSize;
logOutput << "reducing gap $" << std::hex << gapAddress << std::dec <<
" to size " << gaps[gapAddress] << "\n";
spacing.resize(GLOBAL_maxFileNameLen + 4 - (*iterRoutine)->fileName.length(), ' ');
logOutput << " $" << std::hex << targetAddr << std::dec << ": " <<
(*iterRoutine)->fileName << spacing << "size: " <<
(*iterRoutine)->codeLength << "\n";
floatingRoutines.erase(iterRoutine);
if (gaps[gapAddress] == 0) gaps.erase(gapAddress);
}
}
void BinningProblem::performObviousSteps(DualStream &logOutput)
{
// Get the size of the biggest routine; if there is just one gap which
// can handle it - put the roputine exactly there
// can handle it - put the routine exactly there
std::string spacing;
@@ -954,6 +1036,10 @@ void Solver::run()
problem.sortFloatingRoutinesBySize();
// Place routines which should be stored in high-ROM
problem.placeHighRoutines(logOutput);
// Run the solver until all is done
while (!problem.gaps.empty() && !problem.floatingRoutines.empty())