Use SectionTypeInfo struct member functions for section type info

This commit is contained in:
ISSOtm
2026-09-17 09:33:21 -04:00
committed by Rangi
parent b2967ff509
commit 9f175f7923
8 changed files with 83 additions and 80 deletions
+2
View File
@@ -42,6 +42,8 @@ struct Section {
std::deque<Patch> patches;
std::vector<uint8_t> data;
SectionTypeInfo const &typeInfo() const { return sectionTypeInfo[type]; }
uint32_t getID() const; // ID of the section in the object file (`UINT32_MAX` if none)
bool isSizeKnown() const;
};
+2
View File
@@ -51,6 +51,8 @@ struct Section {
std::vector<Symbol *> symbols;
std::unique_ptr<Section> nextPiece; // The next fragment or union "piece" of this section
SectionTypeInfo const &typeInfo() const { return sectionTypeInfo[type]; }
private:
// Template class for both const and non-const iterators over the "pieces" of this section
template<QualifiedEquivalent<Section> SectionT>
+17 -17
View File
@@ -82,6 +82,13 @@ static constexpr uint8_t SECTTYPE_TYPE_MASK = 0b111;
static constexpr uint8_t SECTTYPE_UNION_BIT = 7;
static constexpr uint8_t SECTTYPE_FRAGMENT_BIT = 6;
// Tells whether a section has data in its object file definition,
// depending on type.
static inline bool sectTypeHasData(SectionType type) {
assume(type != SECTTYPE_INVALID);
return type == SECTTYPE_ROM0 || type == SECTTYPE_ROMX;
}
enum FileStackNodeType {
NODE_REPT,
NODE_FILE,
@@ -90,31 +97,24 @@ enum FileStackNodeType {
static constexpr uint8_t FSTACKNODE_QUIET_BIT = 7;
// Nont-`const` members may be patched in RGBLINK depending on CLI flags
extern struct SectionTypeInfo {
// Non-`const` members may be patched in RGBLINK depending on CLI flags
struct SectionTypeInfo {
std::string const name;
uint16_t const startAddr;
uint16_t size;
uint32_t const firstBank;
uint32_t lastBank;
} sectionTypeInfo[SECTTYPE_INVALID];
// Tells whether a section has data in its object file definition,
// depending on type.
static inline bool sectTypeHasData(SectionType type) {
assume(type != SECTTYPE_INVALID);
return type == SECTTYPE_ROM0 || type == SECTTYPE_ROMX;
}
// Returns a memory region's end address (last byte), e.g. 0x7FFF
uint16_t endAddr() const { return startAddr + size - 1; }
// Returns a memory region's end address (last byte), e.g. 0x7FFF
static inline uint16_t sectTypeEndAddr(SectionType type) {
return sectionTypeInfo[type].startAddr + sectionTypeInfo[type].size - 1;
}
// Returns a memory region's number of banks, or 1 for regions without banking
uint32_t nbBanks() const { return lastBank - firstBank + 1; }
// Returns a memory region's number of banks, or 1 for regions without banking
static inline uint32_t sectTypeBanks(SectionType type) {
return sectionTypeInfo[type].lastBank - sectionTypeInfo[type].firstBank + 1;
}
bool isBanked() const { return nbBanks() != 1; }
};
extern SectionTypeInfo sectionTypeInfo[SECTTYPE_INVALID];
enum SectionModifier { SECTION_NORMAL, SECTION_UNION, SECTION_FRAGMENT };
+17 -17
View File
@@ -100,7 +100,7 @@ void sect_ForEach(void (*callback)(Section &)) {
void sect_CheckSizes() {
for (Section const &sect : sections) {
if (uint32_t maxSize = sectionTypeInfo[sect.type].size; sect.size > maxSize) {
if (uint32_t maxSize = sect.typeInfo().size; sect.size > maxSize) {
error(
"Section \"%s\" grew too big (max size = 0x%" PRIX32 " bytes, reached 0x%" PRIX32
")",
@@ -309,7 +309,7 @@ static void mergeSections(
sectError(
"Section \"%s\" already exists but with type `%s`",
sect.name.c_str(),
sectionTypeInfo[sect.type].name.c_str()
sect.typeInfo().name.c_str()
);
}
@@ -377,8 +377,8 @@ static Section *createSection(
out_RegisterNode(sect.src);
// It is only needed to allocate memory for ROM sections.
if (sectTypeHasData(type)) {
sect.data.resize(sectionTypeInfo[type].size);
if (sectTypeHasData(sect.type)) {
sect.data.resize(sect.typeInfo().size);
}
return &sect;
@@ -403,7 +403,7 @@ static Section *createSectionFragmentLiteral(Section const &parent) {
// Section fragment literals must be ROM sections.
assume(sectTypeHasData(sect.type));
sect.data.resize(sectionTypeInfo[sect.type].size);
sect.data.resize(sect.typeInfo().size);
return &sect;
}
@@ -424,24 +424,24 @@ static Section *getSection(
uint32_t alignMask = alignSize - 1;
// First, validate parameters, and normalize them if applicable
SectionTypeInfo const &typeInfo = sectionTypeInfo[type];
if (bank != UINT32_MAX) {
if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM && type != SECTTYPE_SRAM
&& type != SECTTYPE_WRAMX) {
error("`BANK` only allowed for `ROMX`, `WRAMX`, `SRAM`, or `VRAM` sections");
} else if (bank < sectionTypeInfo[type].firstBank
|| bank > sectionTypeInfo[type].lastBank) {
} else if (bank < typeInfo.firstBank || bank > typeInfo.lastBank) {
error(
"%s bank value $%04" PRIx32 " out of range ($%04" PRIx32 " to $%04" PRIx32 ")",
sectionTypeInfo[type].name.c_str(),
typeInfo.name.c_str(),
bank,
sectionTypeInfo[type].firstBank,
sectionTypeInfo[type].lastBank
typeInfo.firstBank,
typeInfo.lastBank
);
}
} else if (sectTypeBanks(type) == 1) {
} else if (!typeInfo.isBanked()) {
// If the section type only has a single bank, implicitly force it
bank = sectionTypeInfo[type].firstBank;
bank = typeInfo.firstBank;
}
// This should be redundant, as the parser guarantees that `AlignmentSpec` will be valid.
@@ -457,14 +457,14 @@ static Section *getSection(
}
if (org != UINT32_MAX) {
if (org < sectionTypeInfo[type].startAddr || org > sectTypeEndAddr(type)) {
if (org < typeInfo.startAddr || org > typeInfo.endAddr()) {
error(
"Section \"%s\"'s fixed address $%04" PRIx32 " is outside of range [$%04" PRIx16
"; $%04" PRIx16 "]",
name.c_str(),
org,
sectionTypeInfo[type].startAddr,
sectTypeEndAddr(type)
typeInfo.startAddr,
typeInfo.endAddr()
);
}
}
@@ -476,11 +476,11 @@ static Section *getSection(
error("Section \"%s\"'s fixed address does not match its alignment", name.c_str());
}
alignment = 0; // Ignore it if it's satisfied
} else if (sectionTypeInfo[type].startAddr & alignMask) {
} else if (typeInfo.startAddr & alignMask) {
error(
"Section \"%s\"'s alignment cannot be attained in %s",
name.c_str(),
sectionTypeInfo[type].name.c_str()
typeInfo.name.c_str()
);
alignment = 0; // Ignore it if it's unattainable
org = 0;
+17 -16
View File
@@ -79,7 +79,7 @@ static MemoryLocation getStartLocation(Section const &section) {
if (section.isBankFixed) {
location.bank = section.bank;
} else {
location.bank = sectionTypeInfo[section.type].firstBank;
location.bank = section.typeInfo().firstBank;
// Scramble the bank if applicable
if (options.scrambleROMX && section.type == SECTTYPE_ROMX) {
@@ -106,14 +106,14 @@ static MemoryLocation getStartLocation(Section const &section) {
// Returns a suitable free space index into `memory[section->type]` at which to place the given
// section, or `std::nullopt` if none was found.
static std::optional<size_t> getPlacement(Section const &section, MemoryLocation &location) {
SectionTypeInfo const &typeInfo = sectionTypeInfo[section.type];
SectionTypeInfo const &typeInfo = section.typeInfo();
for (;;) {
if (location.bank < typeInfo.firstBank
|| location.bank >= memory[section.type].size() + typeInfo.firstBank) {
fatal(
"Invalid bank for %s section \"%s\": %" PRIu32,
sectionTypeInfo[section.type].name.c_str(),
typeInfo.name.c_str(),
section.name.c_str(),
location.bank
);
@@ -217,9 +217,8 @@ static std::optional<size_t> getPlacement(Section const &section, MemoryLocation
}
static std::string getSectionDescription(Section const &section) {
std::string description =
"\"" + section.name + "\" (" + sectionTypeInfo[section.type].name + " section) ";
if (section.isBankFixed && sectTypeBanks(section.type) != 1) {
std::string description = "\"" + section.name + "\" (" + section.typeInfo().name + " section) ";
if (section.isBankFixed && section.typeInfo().isBanked()) {
char bank[8];
snprintf(bank, sizeof(bank), "%02" PRIx32, section.bank);
if (section.isAddressFixed) {
@@ -253,14 +252,15 @@ static std::string getSectionDescription(Section const &section) {
// Places a section in a suitable location, or error out if it fails to.
// Due to the implemented algorithm, this should be called with sections of decreasing size!
static void placeSection(Section &section) {
SectionTypeInfo const &typeInfo = section.typeInfo();
// Specially handle 0-byte SECTIONs, as they can't overlap anything
if (section.size == 0) {
// Unless the SECTION's address was fixed, the starting address
// is fine for any alignment, as checked in sect_DoSanityChecks.
MemoryLocation location = {
.address =
section.isAddressFixed ? section.org : sectionTypeInfo[section.type].startAddr,
.bank = section.isBankFixed ? section.bank : sectionTypeInfo[section.type].firstBank,
.address = section.isAddressFixed ? section.org : typeInfo.startAddr,
.bank = section.isBankFixed ? section.bank : typeInfo.firstBank,
};
assignSection(section, location);
return;
@@ -270,8 +270,7 @@ static void placeSection(Section &section) {
// https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm
MemoryLocation location = getStartLocation(section);
if (std::optional<size_t> spaceIdx = getPlacement(section, location); spaceIdx) {
std::deque<FreeSpace> &bankMem =
memory[section.type][location.bank - sectionTypeInfo[section.type].firstBank];
std::deque<FreeSpace> &bankMem = memory[section.type][location.bank - typeInfo.firstBank];
FreeSpace &freeSpace = bankMem[*spaceIdx];
assignSection(section, location);
@@ -308,13 +307,14 @@ static void placeSection(Section &section) {
if (!section.isBankFixed || !section.isAddressFixed) {
// If a section failed to go to several places, nothing we can report
fatal("Unable to place %s", getSectionDescription(section).c_str());
} else if (section.org + section.size > sectTypeEndAddr(section.type) + 1) {
} else if (uint16_t onePastEnd = typeInfo.endAddr() + 1;
section.org + section.size > onePastEnd) {
// If the section just can't fit the bank, report that
fatal(
"Unable to place %s: section runs past end of region ($%04x > $%04x)",
getSectionDescription(section).c_str(),
section.org + section.size,
sectTypeEndAddr(section.type) + 1
onePastEnd
);
} else {
// Otherwise there is overlap with another section
@@ -430,11 +430,12 @@ void assign_AssignSections() {
// Initialize the free space-modelling structs
for (SectionType type : EnumSeq(SECTTYPE_INVALID)) {
memory[type].resize(sectTypeBanks(type));
SectionTypeInfo const &typeInfo = sectionTypeInfo[type];
memory[type].resize(typeInfo.nbBanks());
for (std::deque<FreeSpace> &bankMem : memory[type]) {
bankMem.push_back({
.address = sectionTypeInfo[type].startAddr,
.size = sectionTypeInfo[type].size,
.address = typeInfo.startAddr,
.size = typeInfo.size,
});
}
}
+10 -10
View File
@@ -31,7 +31,7 @@ static void setActiveTypeAndIdx(SectionType type, uint32_t idx) {
}
void layout_SetFloatingSectionType(SectionType type) {
if (sectTypeBanks(type) == 1) {
if (!sectionTypeInfo[type].isBanked()) {
// There is only a single bank anyway, so just set the index to 0.
setActiveTypeAndIdx(type, 0);
} else {
@@ -46,8 +46,8 @@ void layout_SetFloatingSectionType(SectionType type) {
}
void layout_SetSectionType(SectionType type) {
if (sectTypeBanks(type) != 1) {
scriptError("A bank number must be specified for %s", sectionTypeInfo[type].name.c_str());
if (SectionTypeInfo const &typeInfo = sectionTypeInfo[type]; typeInfo.isBanked()) {
scriptError("A bank number must be specified for %s", typeInfo.name.c_str());
// Keep going with a default value for the bank index.
}
@@ -88,22 +88,22 @@ void layout_SetAddr(uint32_t addr) {
return;
}
uint16_t &pc = curAddr[activeType][activeBankIdx];
SectionTypeInfo const &typeInfo = sectionTypeInfo[activeType];
if (addr < pc) {
if (uint16_t &pc = curAddr[activeType][activeBankIdx]; addr < pc) {
scriptError("Cannot decrease the current address (from $%04x to $%04x)", pc, addr);
} else if (addr > sectTypeEndAddr(activeType)) { // Allow "one past the end" sections.
} else if (addr > typeInfo.endAddr()) { // Allow "one past the end" sections.
scriptError(
"Cannot set the current address to $%04" PRIx32 ": %s ends at $%04" PRIx16,
addr,
typeInfo.name.c_str(),
sectTypeEndAddr(activeType)
typeInfo.endAddr()
);
pc = sectTypeEndAddr(activeType);
pc = typeInfo.endAddr();
} else {
pc = addr;
}
isPcFloating = false;
}
@@ -182,7 +182,7 @@ void layout_AlignTo(uint32_t alignment, uint32_t alignOfs) {
", past $%04" PRIx16,
pc,
static_cast<uint16_t>(pc + length),
static_cast<uint16_t>(sectTypeEndAddr(activeType) + 1)
static_cast<uint16_t>(typeInfo.endAddr() + 1)
);
return;
}
@@ -212,7 +212,7 @@ void layout_Pad(uint32_t length) {
"Cannot increase the current address by %u bytes: only %u bytes to $%04" PRIx16,
length,
typeInfo.size - offset,
static_cast<uint16_t>(sectTypeEndAddr(activeType) + 1)
static_cast<uint16_t>(typeInfo.endAddr() + 1)
);
} else {
pc += length;
+5 -8
View File
@@ -71,7 +71,7 @@ void out_AddSection(Section const &section) {
1, // SECTTYPE_OAM
};
uint32_t targetBank = section.bank - sectionTypeInfo[section.type].firstBank;
uint32_t targetBank = section.bank - section.typeInfo().firstBank;
if (targetBank >= maxNbBanks[section.type]) {
fatal(
"Section \"%s\" has an invalid bank range (%" PRIu32 " > %" PRIu32 ")",
@@ -96,7 +96,7 @@ void out_AddSection(Section const &section) {
}
Section const *out_OverlappingSection(Section const &section) {
uint32_t bank = section.bank - sectionTypeInfo[section.type].firstBank;
uint32_t bank = section.bank - section.typeInfo().firstBank;
for (Section const *ptr : sections[section.type][bank].sections) {
if (ptr->org < section.org + section.size && section.org < ptr->org + ptr->size) {
@@ -491,12 +491,10 @@ static void writeMapBank(SortedSections const &sectList, SectionType type, uint3
if (used == 0) {
fputs("\tEMPTY\n", mapFile);
} else {
uint16_t bankEndAddr = sectionTypeInfo[type].startAddr + sectionTypeInfo[type].size;
uint16_t bankEndAddr = sectionTypeInfo[type].endAddr() + 1;
writeEmptySpace(prevEndAddr, bankEndAddr);
uint16_t slack = sectionTypeInfo[type].size - used;
fprintf(mapFile, "\tTOTAL EMPTY: $%04" PRIx16 " byte%s\n", slack, slack == 1 ? "" : "s");
}
}
@@ -513,13 +511,12 @@ static void writeMapSummary() {
continue;
}
// Do not output unused section types
// Skip types which haven't been used at all.
if (nbBanks == 0) {
continue;
}
uint32_t usedTotal = 0;
for (uint32_t bank = 0; bank < nbBanks; ++bank) {
usedTotal += forEachSection(sections[type][bank], [](Section const &) {});
}
@@ -532,7 +529,7 @@ static void writeMapSummary() {
usedTotal == 1 ? "" : "s",
static_cast<size_t>(nbBanks) * sectionTypeInfo[type].size - usedTotal
);
if (sectionTypeInfo[type].firstBank != sectionTypeInfo[type].lastBank) {
if (sectionTypeInfo[type].isBanked()) {
fprintf(mapFile, " in %u bank%s", nbBanks, nbBanks == 1 ? "" : "s");
}
putc('\n', mapFile);
+13 -12
View File
@@ -254,18 +254,20 @@ static void doSanityChecks(Section &section) {
section.isAlignFixed = false;
}
// The section's type is determined now, so we can get its type info
SectionTypeInfo const &typeInfo = section.typeInfo();
// Too large an alignment may not be satisfiable
if (section.isAlignFixed && (section.alignMask & sectionTypeInfo[section.type].startAddr)) {
if (section.isAlignFixed && (section.alignMask & typeInfo.startAddr)) {
error(
"Section \"%s\" has type `%s`, which cannot be aligned to $%04x bytes",
section.name.c_str(),
sectionTypeInfo[section.type].name.c_str(),
typeInfo.name.c_str(),
section.alignMask + 1
);
}
uint32_t minbank = sectionTypeInfo[section.type].firstBank,
maxbank = sectionTypeInfo[section.type].lastBank;
uint32_t minbank = typeInfo.firstBank, maxbank = typeInfo.lastBank;
if (!bankModeError && section.isBankFixed
&& (section.bank < minbank || section.bank > maxbank)) {
@@ -282,12 +284,12 @@ static void doSanityChecks(Section &section) {
}
// Check if section has a chance to be placed
if (section.size > sectionTypeInfo[section.type].size) {
if (section.size > typeInfo.size) {
error(
"Section \"%s\" is bigger than the max size for that type: $%" PRIx16 " > $%" PRIx16,
section.name.c_str(),
section.size,
sectionTypeInfo[section.type].size
typeInfo.size
);
}
@@ -311,24 +313,23 @@ static void doSanityChecks(Section &section) {
}
// Ensure the target address is valid
if (section.org < sectionTypeInfo[section.type].startAddr
|| section.org > sectTypeEndAddr(section.type)) {
if (section.org < typeInfo.startAddr || section.org > typeInfo.endAddr()) {
error(
"Section \"%s\"'s fixed address $%04" PRIx16 " is outside of range [$%04" PRIx16
"; $%04" PRIx16 "]",
section.name.c_str(),
section.org,
sectionTypeInfo[section.type].startAddr,
sectTypeEndAddr(section.type)
typeInfo.startAddr,
typeInfo.endAddr()
);
}
if (section.org + section.size > sectTypeEndAddr(section.type) + 1) {
if (section.org + section.size > typeInfo.endAddr() + 1) {
error(
"Section \"%s\"'s end address $%04x is greater than last address $%04x",
section.name.c_str(),
section.org + section.size,
sectTypeEndAddr(section.type) + 1
typeInfo.endAddr() + 1
);
}
}