mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Switch linkdefs from scattered arrays to an array of structs
The info is better organized this way
This commit is contained in:
@@ -79,13 +79,14 @@ enum SectionType {
|
|||||||
SECTTYPE_INVALID
|
SECTTYPE_INVALID
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SectionModifier {
|
// Nont-`const` members may be patched in RGBLINK depending on CLI flags
|
||||||
SECTION_NORMAL,
|
extern struct SectionTypeInfo {
|
||||||
SECTION_UNION,
|
char const *const name;
|
||||||
SECTION_FRAGMENT
|
uint16_t const startAddr;
|
||||||
};
|
uint16_t size;
|
||||||
|
uint32_t const firstBank;
|
||||||
extern char const * const sectionModNames[];
|
uint32_t lastBank;
|
||||||
|
} sectionTypeInfo[SECTTYPE_INVALID];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells whether a section has data in its object file definition,
|
* Tells whether a section has data in its object file definition,
|
||||||
@@ -99,6 +100,32 @@ static inline bool sect_HasData(enum SectionType type)
|
|||||||
return type == SECTTYPE_ROM0 || type == SECTTYPE_ROMX;
|
return type == SECTTYPE_ROM0 || type == SECTTYPE_ROMX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a memory region's end address (last byte), eg. 0x7FFF
|
||||||
|
* @return The address of the last byte in that memory region
|
||||||
|
*/
|
||||||
|
static inline uint16_t endaddr(enum SectionType type)
|
||||||
|
{
|
||||||
|
return sectionTypeInfo[type].startAddr + sectionTypeInfo[type].size - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a memory region's number of banks
|
||||||
|
* @return The number of banks, 1 for regions without banking
|
||||||
|
*/
|
||||||
|
static inline uint32_t nbbanks(enum SectionType type)
|
||||||
|
{
|
||||||
|
return sectionTypeInfo[type].lastBank - sectionTypeInfo[type].firstBank + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SectionModifier {
|
||||||
|
SECTION_NORMAL,
|
||||||
|
SECTION_UNION,
|
||||||
|
SECTION_FRAGMENT
|
||||||
|
};
|
||||||
|
|
||||||
|
extern char const * const sectionModNames[];
|
||||||
|
|
||||||
enum ExportLevel {
|
enum ExportLevel {
|
||||||
SYMTYPE_LOCAL,
|
SYMTYPE_LOCAL,
|
||||||
SYMTYPE_IMPORT,
|
SYMTYPE_IMPORT,
|
||||||
@@ -114,45 +141,4 @@ enum PatchType {
|
|||||||
PATCHTYPE_INVALID
|
PATCHTYPE_INVALID
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BANK_MIN_ROM0 0
|
|
||||||
#define BANK_MAX_ROM0 0
|
|
||||||
#define BANK_MIN_ROMX 1
|
|
||||||
#define BANK_MAX_ROMX 511
|
|
||||||
#define BANK_MIN_VRAM 0
|
|
||||||
#define BANK_MAX_VRAM 1
|
|
||||||
#define BANK_MIN_SRAM 0
|
|
||||||
#define BANK_MAX_SRAM 15
|
|
||||||
#define BANK_MIN_WRAM0 0
|
|
||||||
#define BANK_MAX_WRAM0 0
|
|
||||||
#define BANK_MIN_WRAMX 1
|
|
||||||
#define BANK_MAX_WRAMX 7
|
|
||||||
#define BANK_MIN_OAM 0
|
|
||||||
#define BANK_MAX_OAM 0
|
|
||||||
#define BANK_MIN_HRAM 0
|
|
||||||
#define BANK_MAX_HRAM 0
|
|
||||||
|
|
||||||
extern uint16_t startaddr[];
|
|
||||||
extern uint16_t maxsize[];
|
|
||||||
extern uint32_t bankranges[][2];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes a memory region's end address (last byte), eg. 0x7FFF
|
|
||||||
* @return The address of the last byte in that memory region
|
|
||||||
*/
|
|
||||||
static inline uint16_t endaddr(enum SectionType type)
|
|
||||||
{
|
|
||||||
return startaddr[type] + maxsize[type] - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes a memory region's number of banks
|
|
||||||
* @return The number of banks, 1 for regions without banking
|
|
||||||
*/
|
|
||||||
static inline uint32_t nbbanks(enum SectionType type)
|
|
||||||
{
|
|
||||||
return bankranges[type][1] - bankranges[type][0] + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern char const * const typeNames[SECTTYPE_INVALID];
|
|
||||||
|
|
||||||
#endif /* RGBDS_LINKDEFS_H */
|
#endif /* RGBDS_LINKDEFS_H */
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "asm/warning.h"
|
#include "asm/warning.h"
|
||||||
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "linkdefs.h"
|
||||||
#include "platform.h" // strdup
|
#include "platform.h" // strdup
|
||||||
|
|
||||||
uint8_t fillByte;
|
uint8_t fillByte;
|
||||||
@@ -73,7 +74,7 @@ attr_(warn_unused_result) static bool checkcodesection(void)
|
|||||||
|
|
||||||
attr_(warn_unused_result) static bool checkSectionSize(struct Section const *sect, uint32_t size)
|
attr_(warn_unused_result) static bool checkSectionSize(struct Section const *sect, uint32_t size)
|
||||||
{
|
{
|
||||||
uint32_t maxSize = maxsize[sect->type];
|
uint32_t maxSize = sectionTypeInfo[sect->type].size;
|
||||||
|
|
||||||
// If the new size is reasonable, keep going
|
// If the new size is reasonable, keep going
|
||||||
if (size <= maxSize)
|
if (size <= maxSize)
|
||||||
@@ -232,7 +233,7 @@ static void mergeSections(struct Section *sect, enum SectionType type, uint32_t
|
|||||||
unsigned int nbSectErrors = 0;
|
unsigned int nbSectErrors = 0;
|
||||||
|
|
||||||
if (type != sect->type)
|
if (type != sect->type)
|
||||||
fail("Section already exists but with type %s\n", typeNames[sect->type]);
|
fail("Section already exists but with type %s\n", sectionTypeInfo[sect->type].name);
|
||||||
|
|
||||||
if (sect->modifier != mod) {
|
if (sect->modifier != mod) {
|
||||||
fail("Section already declared as %s section\n", sectionModNames[sect->modifier]);
|
fail("Section already declared as %s section\n", sectionModNames[sect->modifier]);
|
||||||
@@ -299,7 +300,7 @@ static struct Section *createSection(char const *name, enum SectionType type,
|
|||||||
|
|
||||||
/* It is only needed to allocate memory for ROM sections. */
|
/* It is only needed to allocate memory for ROM sections. */
|
||||||
if (sect_HasData(type)) {
|
if (sect_HasData(type)) {
|
||||||
sect->data = malloc(maxsize[type]);
|
sect->data = malloc(sectionTypeInfo[type].size);
|
||||||
if (sect->data == NULL)
|
if (sect->data == NULL)
|
||||||
fatalerror("Not enough memory for section: %s\n", strerror(errno));
|
fatalerror("Not enough memory for section: %s\n", strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
@@ -325,14 +326,13 @@ static struct Section *getSection(char const *name, enum SectionType type, uint3
|
|||||||
if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM
|
if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM
|
||||||
&& type != SECTTYPE_SRAM && type != SECTTYPE_WRAMX)
|
&& type != SECTTYPE_SRAM && type != SECTTYPE_WRAMX)
|
||||||
error("BANK only allowed for ROMX, WRAMX, SRAM, or VRAM sections\n");
|
error("BANK only allowed for ROMX, WRAMX, SRAM, or VRAM sections\n");
|
||||||
else if (bank < bankranges[type][0]
|
else if (bank < sectionTypeInfo[type].firstBank || bank > sectionTypeInfo[type].lastBank)
|
||||||
|| bank > bankranges[type][1])
|
|
||||||
error("%s bank value $%04" PRIx32 " out of range ($%04" PRIx32 " to $%04"
|
error("%s bank value $%04" PRIx32 " out of range ($%04" PRIx32 " to $%04"
|
||||||
PRIx32 ")\n", typeNames[type], bank,
|
PRIx32 ")\n", sectionTypeInfo[type].name, bank,
|
||||||
bankranges[type][0], bankranges[type][1]);
|
sectionTypeInfo[type].firstBank, sectionTypeInfo[type].lastBank);
|
||||||
} else if (nbbanks(type) == 1) {
|
} else if (nbbanks(type) == 1) {
|
||||||
// If the section type only has a single bank, implicitly force it
|
// If the section type only has a single bank, implicitly force it
|
||||||
bank = bankranges[type][0];
|
bank = sectionTypeInfo[type].firstBank;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alignOffset >= 1 << alignment) {
|
if (alignOffset >= 1 << alignment) {
|
||||||
@@ -342,10 +342,10 @@ static struct Section *getSection(char const *name, enum SectionType type, uint3
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (org != (uint32_t)-1) {
|
if (org != (uint32_t)-1) {
|
||||||
if (org < startaddr[type] || org > endaddr(type))
|
if (org < sectionTypeInfo[type].startAddr || org > endaddr(type))
|
||||||
error("Section \"%s\"'s fixed address %#" PRIx32
|
error("Section \"%s\"'s fixed address %#" PRIx32
|
||||||
" is outside of range [%#" PRIx16 "; %#" PRIx16 "]\n",
|
" is outside of range [%#" PRIx16 "; %#" PRIx16 "]\n",
|
||||||
name, org, startaddr[type], endaddr(type));
|
name, org, sectionTypeInfo[type].startAddr, endaddr(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alignment != 0) {
|
if (alignment != 0) {
|
||||||
@@ -361,9 +361,9 @@ static struct Section *getSection(char const *name, enum SectionType type, uint3
|
|||||||
error("Section \"%s\"'s fixed address doesn't match its alignment\n",
|
error("Section \"%s\"'s fixed address doesn't match its alignment\n",
|
||||||
name);
|
name);
|
||||||
alignment = 0; /* Ignore it if it's satisfied */
|
alignment = 0; /* Ignore it if it's satisfied */
|
||||||
} else if (startaddr[type] & mask) {
|
} else if (sectionTypeInfo[type].startAddr & mask) {
|
||||||
error("Section \"%s\"'s alignment cannot be attained in %s\n",
|
error("Section \"%s\"'s alignment cannot be attained in %s\n",
|
||||||
name, typeNames[type]);
|
name, sectionTypeInfo[type].name);
|
||||||
alignment = 0; /* Ignore it if it's unattainable */
|
alignment = 0; /* Ignore it if it's unattainable */
|
||||||
org = 0;
|
org = 0;
|
||||||
} else if (alignment == 16) {
|
} else if (alignment == 16) {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "linkdefs.h"
|
||||||
|
|
||||||
struct MemoryLocation {
|
struct MemoryLocation {
|
||||||
uint16_t address;
|
uint16_t address;
|
||||||
@@ -54,8 +55,8 @@ static void initFreeSpace(void)
|
|||||||
if (!memory[type][bank].next)
|
if (!memory[type][bank].next)
|
||||||
err("Failed to init free space for region %d bank %" PRIu32,
|
err("Failed to init free space for region %d bank %" PRIu32,
|
||||||
type, bank);
|
type, bank);
|
||||||
memory[type][bank].next->address = startaddr[type];
|
memory[type][bank].next->address = sectionTypeInfo[type].startAddr;
|
||||||
memory[type][bank].next->size = maxsize[type];
|
memory[type][bank].next->size = sectionTypeInfo[type].size;
|
||||||
memory[type][bank].next->next = NULL;
|
memory[type][bank].next->next = NULL;
|
||||||
memory[type][bank].next->prev = &memory[type][bank];
|
memory[type][bank].next->prev = &memory[type][bank];
|
||||||
}
|
}
|
||||||
@@ -140,13 +141,13 @@ static struct FreeSpace *getPlacement(struct Section const *section,
|
|||||||
if (curScrambleSRAM > scrambleSRAM)
|
if (curScrambleSRAM > scrambleSRAM)
|
||||||
curScrambleSRAM = 0;
|
curScrambleSRAM = 0;
|
||||||
} else {
|
} else {
|
||||||
location->bank = bankranges[section->type][0];
|
location->bank = sectionTypeInfo[section->type].firstBank;
|
||||||
}
|
}
|
||||||
struct FreeSpace *space;
|
struct FreeSpace *space;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* Switch to the beginning of the next bank */
|
/* Switch to the beginning of the next bank */
|
||||||
#define BANK_INDEX (location->bank - bankranges[section->type][0])
|
#define BANK_INDEX (location->bank - sectionTypeInfo[section->type].firstBank)
|
||||||
space = memory[section->type][BANK_INDEX].next;
|
space = memory[section->type][BANK_INDEX].next;
|
||||||
if (space)
|
if (space)
|
||||||
location->address = space->address;
|
location->address = space->address;
|
||||||
@@ -201,7 +202,7 @@ static struct FreeSpace *getPlacement(struct Section const *section,
|
|||||||
|
|
||||||
/* Try again in the next bank */
|
/* Try again in the next bank */
|
||||||
location->bank++;
|
location->bank++;
|
||||||
if (location->bank > bankranges[section->type][1])
|
if (location->bank > sectionTypeInfo[section->type].lastBank)
|
||||||
return NULL;
|
return NULL;
|
||||||
#undef BANK_INDEX
|
#undef BANK_INDEX
|
||||||
}
|
}
|
||||||
@@ -225,10 +226,10 @@ static void placeSection(struct Section *section)
|
|||||||
*/
|
*/
|
||||||
location.address = section->isAddressFixed
|
location.address = section->isAddressFixed
|
||||||
? section->org
|
? section->org
|
||||||
: startaddr[section->type];
|
: sectionTypeInfo[section->type].startAddr;
|
||||||
location.bank = section->isBankFixed
|
location.bank = section->isBankFixed
|
||||||
? section->bank
|
? section->bank
|
||||||
: bankranges[section->type][0];
|
: sectionTypeInfo[section->type].firstBank;
|
||||||
assignSection(section, &location);
|
assignSection(section, &location);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -314,16 +315,16 @@ static void placeSection(struct Section *section)
|
|||||||
/* If a section failed to go to several places, nothing we can report */
|
/* If a section failed to go to several places, nothing we can report */
|
||||||
if (!section->isBankFixed || !section->isAddressFixed)
|
if (!section->isBankFixed || !section->isAddressFixed)
|
||||||
errx("Unable to place \"%s\" (%s section) %s",
|
errx("Unable to place \"%s\" (%s section) %s",
|
||||||
section->name, typeNames[section->type], where);
|
section->name, sectionTypeInfo[section->type].name, where);
|
||||||
/* If the section just can't fit the bank, report that */
|
/* If the section just can't fit the bank, report that */
|
||||||
else if (section->org + section->size > endaddr(section->type) + 1)
|
else if (section->org + section->size > endaddr(section->type) + 1)
|
||||||
errx("Unable to place \"%s\" (%s section) %s: section runs past end of region ($%04x > $%04x)",
|
errx("Unable to place \"%s\" (%s section) %s: section runs past end of region ($%04x > $%04x)",
|
||||||
section->name, typeNames[section->type], where,
|
section->name, sectionTypeInfo[section->type].name, where,
|
||||||
section->org + section->size, endaddr(section->type) + 1);
|
section->org + section->size, endaddr(section->type) + 1);
|
||||||
/* Otherwise there is overlap with another section */
|
/* Otherwise there is overlap with another section */
|
||||||
else
|
else
|
||||||
errx("Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"",
|
errx("Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"",
|
||||||
section->name, typeNames[section->type], where,
|
section->name, sectionTypeInfo[section->type].name, where,
|
||||||
out_OverlappingSection(section)->name);
|
out_OverlappingSection(section)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -440,13 +440,13 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
/* Patch the size array depending on command-line options */
|
/* Patch the size array depending on command-line options */
|
||||||
if (!is32kMode)
|
if (!is32kMode)
|
||||||
maxsize[SECTTYPE_ROM0] = 0x4000;
|
sectionTypeInfo[SECTTYPE_ROM0].size = 0x4000;
|
||||||
if (!isWRA0Mode)
|
if (!isWRA0Mode)
|
||||||
maxsize[SECTTYPE_WRAM0] = 0x1000;
|
sectionTypeInfo[SECTTYPE_WRAM0].size = 0x1000;
|
||||||
|
|
||||||
/* Patch the bank ranges array depending on command-line options */
|
/* Patch the bank ranges array depending on command-line options */
|
||||||
if (isDmgMode)
|
if (isDmgMode)
|
||||||
bankranges[SECTTYPE_VRAM][1] = BANK_MIN_VRAM;
|
sectionTypeInfo[SECTTYPE_VRAM].lastBank = 0;
|
||||||
|
|
||||||
/* Read all object files first, */
|
/* Read all object files first, */
|
||||||
for (obj_Setup(argc - curArgIndex); curArgIndex < argc; curArgIndex++)
|
for (obj_Setup(argc - curArgIndex); curArgIndex < argc; curArgIndex++)
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ void out_AddSection(struct Section const *section)
|
|||||||
[SECTTYPE_HRAM] = 1
|
[SECTTYPE_HRAM] = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t targetBank = section->bank - bankranges[section->type][0];
|
uint32_t targetBank = section->bank - sectionTypeInfo[section->type].firstBank;
|
||||||
uint32_t minNbBanks = targetBank + 1;
|
uint32_t minNbBanks = targetBank + 1;
|
||||||
|
|
||||||
if (minNbBanks > maxNbBanks[section->type])
|
if (minNbBanks > maxNbBanks[section->type])
|
||||||
@@ -113,7 +113,7 @@ struct Section const *out_OverlappingSection(struct Section const *section)
|
|||||||
{
|
{
|
||||||
struct SortedSections *banks = sections[section->type].banks;
|
struct SortedSections *banks = sections[section->type].banks;
|
||||||
struct SortedSection *ptr =
|
struct SortedSection *ptr =
|
||||||
banks[section->bank - bankranges[section->type][0]].sections;
|
banks[section->bank - sectionTypeInfo[section->type].firstBank].sections;
|
||||||
|
|
||||||
while (ptr) {
|
while (ptr) {
|
||||||
if (ptr->section->org < section->org + section->size
|
if (ptr->section->org < section->org + section->size
|
||||||
@@ -166,7 +166,7 @@ static uint32_t checkOverlaySize(void)
|
|||||||
static void coverOverlayBanks(uint32_t nbOverlayBanks)
|
static void coverOverlayBanks(uint32_t nbOverlayBanks)
|
||||||
{
|
{
|
||||||
/* 2 if is32kMode, 1 otherwise */
|
/* 2 if is32kMode, 1 otherwise */
|
||||||
uint32_t nbRom0Banks = maxsize[SECTTYPE_ROM0] / BANK_SIZE;
|
uint32_t nbRom0Banks = sectionTypeInfo[SECTTYPE_ROM0].size / BANK_SIZE;
|
||||||
/* Discount ROM0 banks to avoid outputting too much */
|
/* Discount ROM0 banks to avoid outputting too much */
|
||||||
uint32_t nbUncoveredBanks = nbOverlayBanks - nbRom0Banks > sections[SECTTYPE_ROMX].nbBanks
|
uint32_t nbUncoveredBanks = nbOverlayBanks - nbRom0Banks > sections[SECTTYPE_ROMX].nbBanks
|
||||||
? nbOverlayBanks - nbRom0Banks
|
? nbOverlayBanks - nbRom0Banks
|
||||||
@@ -247,11 +247,11 @@ static void writeROM(void)
|
|||||||
if (outputFile) {
|
if (outputFile) {
|
||||||
writeBank(sections[SECTTYPE_ROM0].banks ? sections[SECTTYPE_ROM0].banks[0].sections
|
writeBank(sections[SECTTYPE_ROM0].banks ? sections[SECTTYPE_ROM0].banks[0].sections
|
||||||
: NULL,
|
: NULL,
|
||||||
startaddr[SECTTYPE_ROM0], maxsize[SECTTYPE_ROM0]);
|
sectionTypeInfo[SECTTYPE_ROM0].startAddr, sectionTypeInfo[SECTTYPE_ROM0].size);
|
||||||
|
|
||||||
for (uint32_t i = 0 ; i < sections[SECTTYPE_ROMX].nbBanks; i++)
|
for (uint32_t i = 0 ; i < sections[SECTTYPE_ROMX].nbBanks; i++)
|
||||||
writeBank(sections[SECTTYPE_ROMX].banks[i].sections,
|
writeBank(sections[SECTTYPE_ROMX].banks[i].sections,
|
||||||
startaddr[SECTTYPE_ROMX], maxsize[SECTTYPE_ROMX]);
|
sectionTypeInfo[SECTTYPE_ROMX].startAddr, sectionTypeInfo[SECTTYPE_ROMX].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
closeFile(outputFile);
|
closeFile(outputFile);
|
||||||
@@ -345,7 +345,7 @@ static void writeSymBank(struct SortedSections const *bankSections,
|
|||||||
|
|
||||||
qsort(symList, nbSymbols, sizeof(*symList), compareSymbols);
|
qsort(symList, nbSymbols, sizeof(*symList), compareSymbols);
|
||||||
|
|
||||||
uint32_t symBank = bank + bankranges[type][0];
|
uint32_t symBank = bank + sectionTypeInfo[type].firstBank;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < nbSymbols; i++) {
|
for (uint32_t i = 0; i < nbSymbols; i++) {
|
||||||
struct SortedSymbol *sym = &symList[i];
|
struct SortedSymbol *sym = &symList[i];
|
||||||
@@ -371,8 +371,8 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
|
|||||||
struct SortedSection const *section = sectList->sections;
|
struct SortedSection const *section = sectList->sections;
|
||||||
struct SortedSection const *zeroLenSection = sectList->zeroLenSections;
|
struct SortedSection const *zeroLenSection = sectList->zeroLenSections;
|
||||||
|
|
||||||
fprintf(mapFile, "%s bank #%" PRIu32 ":\n", typeNames[type],
|
fprintf(mapFile, "%s bank #%" PRIu32 ":\n", sectionTypeInfo[type].name,
|
||||||
bank + bankranges[type][0]);
|
bank + sectionTypeInfo[type].firstBank);
|
||||||
|
|
||||||
uint16_t used = 0;
|
uint16_t used = 0;
|
||||||
|
|
||||||
@@ -413,7 +413,7 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
|
|||||||
if (used == 0) {
|
if (used == 0) {
|
||||||
fputs(" EMPTY\n\n", mapFile);
|
fputs(" EMPTY\n\n", mapFile);
|
||||||
} else {
|
} else {
|
||||||
uint16_t slack = maxsize[type] - used;
|
uint16_t slack = sectionTypeInfo[type].size - used;
|
||||||
|
|
||||||
fprintf(mapFile, " SLACK: $%04" PRIx16 " byte%s\n\n", slack,
|
fprintf(mapFile, " SLACK: $%04" PRIx16 " byte%s\n\n", slack,
|
||||||
slack == 1 ? "" : "s");
|
slack == 1 ? "" : "s");
|
||||||
@@ -442,7 +442,7 @@ static void writeMapUsed(uint32_t usedMap[MIN_NB_ELMS(SECTTYPE_INVALID)])
|
|||||||
|
|
||||||
if (sections[type].nbBanks > 0) {
|
if (sections[type].nbBanks > 0) {
|
||||||
fprintf(mapFile, " %s: $%04" PRIx32 " byte%s in %" PRIu32 " bank%s\n",
|
fprintf(mapFile, " %s: $%04" PRIx32 " byte%s in %" PRIu32 " bank%s\n",
|
||||||
typeNames[type], usedMap[type], usedMap[type] == 1 ? "" : "s",
|
sectionTypeInfo[type].name, usedMap[type], usedMap[type] == 1 ? "" : "s",
|
||||||
sections[type].nbBanks, sections[type].nbBanks == 1 ? "" : "s");
|
sections[type].nbBanks, sections[type].nbBanks == 1 ? "" : "s");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "link/section.h"
|
#include "link/section.h"
|
||||||
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "linkdefs.h"
|
||||||
|
|
||||||
FILE *linkerScript;
|
FILE *linkerScript;
|
||||||
char *includeFileName;
|
char *includeFileName;
|
||||||
@@ -299,7 +300,7 @@ static struct LinkerScriptToken *nextToken(void)
|
|||||||
if (token.type == TOKEN_INVALID) {
|
if (token.type == TOKEN_INVALID) {
|
||||||
/* Try to match a bank specifier */
|
/* Try to match a bank specifier */
|
||||||
for (enum SectionType type = 0; type < SECTTYPE_INVALID; type++) {
|
for (enum SectionType type = 0; type < SECTTYPE_INVALID; type++) {
|
||||||
if (!strcmp(typeNames[type], str)) {
|
if (!strcmp(sectionTypeInfo[type].name, str)) {
|
||||||
token.type = TOKEN_BANK;
|
token.type = TOKEN_BANK;
|
||||||
token.attr.secttype = type;
|
token.attr.secttype = type;
|
||||||
break;
|
break;
|
||||||
@@ -376,7 +377,7 @@ struct SectionPlacement *script_NextSection(void)
|
|||||||
for (enum SectionType i = 0; i < SECTTYPE_INVALID; i++) {
|
for (enum SectionType i = 0; i < SECTTYPE_INVALID; i++) {
|
||||||
curaddr[i] = malloc(sizeof(*curaddr[i]) * nbbanks(i));
|
curaddr[i] = malloc(sizeof(*curaddr[i]) * nbbanks(i));
|
||||||
for (uint32_t b = 0; b < nbbanks(i); b++)
|
for (uint32_t b = 0; b < nbbanks(i); b++)
|
||||||
curaddr[i][b] = startaddr[i];
|
curaddr[i][b] = sectionTypeInfo[i].startAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
placement.type = SECTTYPE_INVALID;
|
placement.type = SECTTYPE_INVALID;
|
||||||
@@ -394,12 +395,12 @@ struct SectionPlacement *script_NextSection(void)
|
|||||||
if (placement.type != SECTTYPE_INVALID) {
|
if (placement.type != SECTTYPE_INVALID) {
|
||||||
if (curaddr[placement.type][bankID] > endaddr(placement.type) + 1)
|
if (curaddr[placement.type][bankID] > endaddr(placement.type) + 1)
|
||||||
errx("%s(%" PRIu32 "): Sections would extend past the end of %s ($%04" PRIx16 " > $%04" PRIx16 ")",
|
errx("%s(%" PRIu32 "): Sections would extend past the end of %s ($%04" PRIx16 " > $%04" PRIx16 ")",
|
||||||
linkerScriptName, lineNo, typeNames[placement.type],
|
linkerScriptName, lineNo, sectionTypeInfo[placement.type].name,
|
||||||
curaddr[placement.type][bankID], endaddr(placement.type));
|
curaddr[placement.type][bankID], endaddr(placement.type));
|
||||||
if (curaddr[placement.type][bankID] < startaddr[placement.type])
|
if (curaddr[placement.type][bankID] < sectionTypeInfo[placement.type].startAddr)
|
||||||
errx("%s(%" PRIu32 "): PC underflowed ($%04" PRIx16 " < $%04" PRIx16 ")",
|
errx("%s(%" PRIu32 "): PC underflowed ($%04" PRIx16 " < $%04" PRIx16 ")",
|
||||||
linkerScriptName, lineNo,
|
linkerScriptName, lineNo,
|
||||||
curaddr[placement.type][bankID], startaddr[placement.type]);
|
curaddr[placement.type][bankID], sectionTypeInfo[placement.type].startAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (parserState) {
|
switch (parserState) {
|
||||||
@@ -483,17 +484,17 @@ struct SectionPlacement *script_NextSection(void)
|
|||||||
errx("%s(%" PRIu32 "): Didn't specify a bank number",
|
errx("%s(%" PRIu32 "): Didn't specify a bank number",
|
||||||
linkerScriptName, lineNo);
|
linkerScriptName, lineNo);
|
||||||
else if (!hasArg)
|
else if (!hasArg)
|
||||||
arg = bankranges[placement.type][0];
|
arg = sectionTypeInfo[placement.type].firstBank;
|
||||||
else if (arg < bankranges[placement.type][0])
|
else if (arg < sectionTypeInfo[placement.type].firstBank)
|
||||||
errx("%s(%" PRIu32 "): specified bank number is too low (%" PRIu32 " < %" PRIu32 ")",
|
errx("%s(%" PRIu32 "): specified bank number is too low (%" PRIu32 " < %" PRIu32 ")",
|
||||||
linkerScriptName, lineNo,
|
linkerScriptName, lineNo,
|
||||||
arg, bankranges[placement.type][0]);
|
arg, sectionTypeInfo[placement.type].firstBank);
|
||||||
else if (arg > bankranges[placement.type][1])
|
else if (arg > sectionTypeInfo[placement.type].lastBank)
|
||||||
errx("%s(%" PRIu32 "): specified bank number is too high (%" PRIu32 " > %" PRIu32 ")",
|
errx("%s(%" PRIu32 "): specified bank number is too high (%" PRIu32 " > %" PRIu32 ")",
|
||||||
linkerScriptName, lineNo,
|
linkerScriptName, lineNo,
|
||||||
arg, bankranges[placement.type][1]);
|
arg, sectionTypeInfo[placement.type].lastBank);
|
||||||
bank = arg;
|
bank = arg;
|
||||||
bankID = arg - bankranges[placement.type][0];
|
bankID = arg - sectionTypeInfo[placement.type].firstBank;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we read a token we shouldn't have... */
|
/* If we read a token we shouldn't have... */
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
|
#include "linkdefs.h"
|
||||||
|
|
||||||
HashMap sections;
|
HashMap sections;
|
||||||
|
|
||||||
@@ -133,7 +134,7 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
|
|||||||
|
|
||||||
if (target->type != other->type)
|
if (target->type != other->type)
|
||||||
errx("Section \"%s\" is defined with conflicting types %s and %s",
|
errx("Section \"%s\" is defined with conflicting types %s and %s",
|
||||||
other->name, typeNames[target->type], typeNames[other->type]);
|
other->name, sectionTypeInfo[target->type].name, sectionTypeInfo[other->type].name);
|
||||||
|
|
||||||
if (other->isBankFixed) {
|
if (other->isBankFixed) {
|
||||||
if (!target->isBankFixed) {
|
if (!target->isBankFixed) {
|
||||||
@@ -207,7 +208,7 @@ void sect_AddSection(struct Section *section)
|
|||||||
mergeSections(other, section, section->modifier);
|
mergeSections(other, section, section->modifier);
|
||||||
} else if (section->modifier == SECTION_UNION && sect_HasData(section->type)) {
|
} else if (section->modifier == SECTION_UNION && sect_HasData(section->type)) {
|
||||||
errx("Section \"%s\" is of type %s, which cannot be unionized",
|
errx("Section \"%s\" is of type %s, which cannot be unionized",
|
||||||
section->name, typeNames[section->type]);
|
section->name, sectionTypeInfo[section->type].name);
|
||||||
} else {
|
} else {
|
||||||
/* If not, add it */
|
/* If not, add it */
|
||||||
hash_AddElement(sections, section->name, section);
|
hash_AddElement(sections, section->name, section);
|
||||||
@@ -261,11 +262,11 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
|||||||
section->isAlignFixed = false;
|
section->isAlignFixed = false;
|
||||||
|
|
||||||
/* Too large an alignment may not be satisfiable */
|
/* Too large an alignment may not be satisfiable */
|
||||||
if (section->isAlignFixed && (section->alignMask & startaddr[section->type]))
|
if (section->isAlignFixed && (section->alignMask & sectionTypeInfo[section->type].startAddr))
|
||||||
error(NULL, 0, "%s: %s sections cannot be aligned to $%04x bytes",
|
error(NULL, 0, "%s: %s sections cannot be aligned to $%04x bytes",
|
||||||
section->name, typeNames[section->type], section->alignMask + 1);
|
section->name, sectionTypeInfo[section->type].name, section->alignMask + 1);
|
||||||
|
|
||||||
uint32_t minbank = bankranges[section->type][0], maxbank = bankranges[section->type][1];
|
uint32_t minbank = sectionTypeInfo[section->type].firstBank, maxbank = sectionTypeInfo[section->type].lastBank;
|
||||||
|
|
||||||
if (section->isBankFixed && section->bank < minbank && section->bank > maxbank)
|
if (section->isBankFixed && section->bank < minbank && section->bank > maxbank)
|
||||||
error(NULL, 0, minbank == maxbank
|
error(NULL, 0, minbank == maxbank
|
||||||
@@ -274,9 +275,9 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
|||||||
section->name, section->bank, minbank, maxbank);
|
section->name, section->bank, minbank, maxbank);
|
||||||
|
|
||||||
/* Check if section has a chance to be placed */
|
/* Check if section has a chance to be placed */
|
||||||
if (section->size > maxsize[section->type])
|
if (section->size > sectionTypeInfo[section->type].size)
|
||||||
error(NULL, 0, "Section \"%s\" is bigger than the max size for that type: %#" PRIx16 " > %#" PRIx16,
|
error(NULL, 0, "Section \"%s\" is bigger than the max size for that type: %#" PRIx16 " > %#" PRIx16,
|
||||||
section->name, section->size, maxsize[section->type]);
|
section->name, section->size, sectionTypeInfo[section->type].size);
|
||||||
|
|
||||||
/* Translate loose constraints to strong ones when they're equivalent */
|
/* Translate loose constraints to strong ones when they're equivalent */
|
||||||
|
|
||||||
@@ -295,11 +296,11 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure the target address is valid */
|
/* Ensure the target address is valid */
|
||||||
if (section->org < startaddr[section->type]
|
if (section->org < sectionTypeInfo[section->type].startAddr
|
||||||
|| section->org > endaddr(section->type))
|
|| section->org > endaddr(section->type))
|
||||||
error(NULL, 0, "Section \"%s\"'s fixed address %#" PRIx16 " is outside of range [%#"
|
error(NULL, 0, "Section \"%s\"'s fixed address %#" PRIx16 " is outside of range [%#"
|
||||||
PRIx16 "; %#" PRIx16 "]", section->name, section->org,
|
PRIx16 "; %#" PRIx16 "]", section->name, section->org,
|
||||||
startaddr[section->type], endaddr(section->type));
|
sectionTypeInfo[section->type].startAddr, endaddr(section->type));
|
||||||
|
|
||||||
if (section->org + section->size > endaddr(section->type) + 1)
|
if (section->org + section->size > endaddr(section->type) + 1)
|
||||||
error(NULL, 0, "Section \"%s\"'s end address %#x is greater than last address %#x",
|
error(NULL, 0, "Section \"%s\"'s end address %#x is greater than last address %#x",
|
||||||
|
|||||||
101
src/linkdefs.c
101
src/linkdefs.c
@@ -1,48 +1,65 @@
|
|||||||
|
|
||||||
#include "linkdefs.h"
|
#include "linkdefs.h"
|
||||||
|
|
||||||
uint16_t startaddr[] = {
|
// The default values are the most lax, as they are used as-is by RGBASM; only RGBLINK has the full info,
|
||||||
[SECTTYPE_ROM0] = 0x0000,
|
// so RGBASM's job is only to catch unconditional errors earlier.
|
||||||
[SECTTYPE_ROMX] = 0x4000,
|
struct SectionTypeInfo sectionTypeInfo[SECTTYPE_INVALID] = {
|
||||||
[SECTTYPE_VRAM] = 0x8000,
|
[SECTTYPE_ROM0] = {
|
||||||
[SECTTYPE_SRAM] = 0xA000,
|
.name = "ROM0",
|
||||||
[SECTTYPE_WRAM0] = 0xC000,
|
.startAddr = 0x0000,
|
||||||
[SECTTYPE_WRAMX] = 0xD000,
|
.size = 0x8000, // Patched to 0x4000 if !is32kMode
|
||||||
[SECTTYPE_OAM] = 0xFE00,
|
.firstBank = 0,
|
||||||
[SECTTYPE_HRAM] = 0xFF80
|
.lastBank = 0,
|
||||||
};
|
},
|
||||||
|
[SECTTYPE_ROMX] = {
|
||||||
uint16_t maxsize[] = {
|
.name = "ROMX",
|
||||||
[SECTTYPE_ROM0] = 0x8000, // patched to 0x4000 if !is32kMode
|
.startAddr = 0x4000,
|
||||||
[SECTTYPE_ROMX] = 0x4000,
|
.size = 0x4000,
|
||||||
[SECTTYPE_VRAM] = 0x2000,
|
.firstBank = 1,
|
||||||
[SECTTYPE_SRAM] = 0x2000,
|
.lastBank = 65535,
|
||||||
[SECTTYPE_WRAM0] = 0x2000, // patched to 0x1000 if !isWRA0Mode
|
},
|
||||||
[SECTTYPE_WRAMX] = 0x1000,
|
[SECTTYPE_VRAM] = {
|
||||||
[SECTTYPE_OAM] = 0x00A0,
|
.name = "VRAM",
|
||||||
[SECTTYPE_HRAM] = 0x007F
|
.startAddr = 0x8000,
|
||||||
};
|
.size = 0x2000,
|
||||||
|
.firstBank = 0,
|
||||||
uint32_t bankranges[][2] = {
|
.lastBank = 1, // Patched to 0 if isDmgMode
|
||||||
[SECTTYPE_ROM0] = {BANK_MIN_ROM0, BANK_MAX_ROM0},
|
},
|
||||||
[SECTTYPE_ROMX] = {BANK_MIN_ROMX, BANK_MAX_ROMX},
|
[SECTTYPE_SRAM] = {
|
||||||
[SECTTYPE_VRAM] = {BANK_MIN_VRAM, BANK_MAX_VRAM},
|
.name = "SRAM",
|
||||||
[SECTTYPE_SRAM] = {BANK_MIN_SRAM, BANK_MAX_SRAM},
|
.startAddr = 0xA000,
|
||||||
[SECTTYPE_WRAM0] = {BANK_MIN_WRAM0, BANK_MAX_WRAM0},
|
.size = 0x2000,
|
||||||
[SECTTYPE_WRAMX] = {BANK_MIN_WRAMX, BANK_MAX_WRAMX},
|
.firstBank = 0,
|
||||||
[SECTTYPE_OAM] = {BANK_MIN_OAM, BANK_MAX_OAM},
|
.lastBank = 255,
|
||||||
[SECTTYPE_HRAM] = {BANK_MIN_HRAM, BANK_MAX_HRAM}
|
},
|
||||||
};
|
[SECTTYPE_WRAM0] = {
|
||||||
|
.name = "WRAM0",
|
||||||
char const * const typeNames[] = {
|
.startAddr = 0xC000,
|
||||||
[SECTTYPE_ROM0] = "ROM0",
|
.size = 0x2000, // Patched to 0x1000 if !isWRA0Mode
|
||||||
[SECTTYPE_ROMX] = "ROMX",
|
.firstBank = 0,
|
||||||
[SECTTYPE_VRAM] = "VRAM",
|
.lastBank = 0,
|
||||||
[SECTTYPE_SRAM] = "SRAM",
|
},
|
||||||
[SECTTYPE_WRAM0] = "WRAM0",
|
[SECTTYPE_WRAMX] = {
|
||||||
[SECTTYPE_WRAMX] = "WRAMX",
|
.name = "WRAMX",
|
||||||
[SECTTYPE_OAM] = "OAM",
|
.startAddr = 0xD000,
|
||||||
[SECTTYPE_HRAM] = "HRAM"
|
.size = 0x1000,
|
||||||
|
.firstBank = 1,
|
||||||
|
.lastBank = 7,
|
||||||
|
},
|
||||||
|
[SECTTYPE_OAM] = {
|
||||||
|
.name = "OAM",
|
||||||
|
.startAddr = 0xFE00,
|
||||||
|
.size = 0x00A0,
|
||||||
|
.firstBank = 0,
|
||||||
|
.lastBank = 0,
|
||||||
|
},
|
||||||
|
[SECTTYPE_HRAM] = {
|
||||||
|
.name = "HRAM",
|
||||||
|
.startAddr = 0xFF80,
|
||||||
|
.size = 0x007F,
|
||||||
|
.firstBank = 0,
|
||||||
|
.lastBank = 0,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
char const * const sectionModNames[] = {
|
char const * const sectionModNames[] = {
|
||||||
|
|||||||
Reference in New Issue
Block a user