Group extern RGBLINK variables in an Options struct, like RGBGFX

This commit is contained in:
Rangi42
2025-07-21 18:12:40 -04:00
parent 0cd60ea1e6
commit d652212857
6 changed files with 110 additions and 118 deletions

View File

@@ -11,27 +11,31 @@
#include "linkdefs.hpp" #include "linkdefs.hpp"
// Variables related to CLI options struct Options {
extern bool isDmgMode; bool isDmgMode; // -d
extern char const *linkerScriptName; char const *linkerScriptName; // -l
extern char const *mapFileName; char const *mapFileName; // -m
extern bool noSymInMap; bool noSymInMap; // -M
extern char const *symFileName; char const *symFileName; // -n
extern char const *overlayFileName; char const *overlayFileName; // -O
extern char const *outputFileName; char const *outputFileName; // -o
extern uint8_t padValue; uint8_t padValue; // -p
extern bool hasPadValue; bool hasPadValue = false;
extern uint16_t scrambleROMX; // Setting these three to 0 disables the functionality
extern uint8_t scrambleWRAMX; uint16_t scrambleROMX = 0; // -S
extern uint8_t scrambleSRAM; uint8_t scrambleWRAMX = 0;
extern bool is32kMode; uint8_t scrambleSRAM = 0;
extern bool beVerbose; bool is32kMode; // -t
extern bool isWRAM0Mode; bool beVerbose; // -v
extern bool disablePadding; bool isWRAM0Mode; // -w
bool disablePadding; // -x
};
extern Options options;
#define verbosePrint(...) \ #define verbosePrint(...) \
do { \ do { \
if (beVerbose) { \ if (options.beVerbose) { \
fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, __VA_ARGS__); \
} \ } \
} while (0) } while (0)

View File

@@ -96,19 +96,19 @@ static ssize_t getPlacement(Section const &section, MemoryLocation &location) {
// Determine which bank we should start searching in // Determine which bank we should start searching in
if (section.isBankFixed) { if (section.isBankFixed) {
location.bank = section.bank; location.bank = section.bank;
} else if (scrambleROMX && section.type == SECTTYPE_ROMX) { } else if (options.scrambleROMX && section.type == SECTTYPE_ROMX) {
if (curScrambleROM < 1) { if (curScrambleROM < 1) {
curScrambleROM = scrambleROMX; curScrambleROM = options.scrambleROMX;
} }
location.bank = curScrambleROM--; location.bank = curScrambleROM--;
} else if (scrambleWRAMX && section.type == SECTTYPE_WRAMX) { } else if (options.scrambleWRAMX && section.type == SECTTYPE_WRAMX) {
if (curScrambleWRAM < 1) { if (curScrambleWRAM < 1) {
curScrambleWRAM = scrambleWRAMX; curScrambleWRAM = options.scrambleWRAMX;
} }
location.bank = curScrambleWRAM--; location.bank = curScrambleWRAM--;
} else if (scrambleSRAM && section.type == SECTTYPE_SRAM) { } else if (options.scrambleSRAM && section.type == SECTTYPE_SRAM) {
if (curScrambleSRAM < 0) { if (curScrambleSRAM < 0) {
curScrambleSRAM = scrambleSRAM; curScrambleSRAM = options.scrambleSRAM;
} }
location.bank = curScrambleSRAM--; location.bank = curScrambleSRAM--;
} else { } else {
@@ -172,28 +172,30 @@ static ssize_t getPlacement(Section const &section, MemoryLocation &location) {
// available. Otherwise, try in ascending order. // available. Otherwise, try in ascending order.
if (section.isBankFixed) { if (section.isBankFixed) {
return -1; return -1;
} else if (scrambleROMX && section.type == SECTTYPE_ROMX && location.bank <= scrambleROMX) { } else if (options.scrambleROMX && section.type == SECTTYPE_ROMX
&& location.bank <= options.scrambleROMX) {
if (location.bank > typeInfo.firstBank) { if (location.bank > typeInfo.firstBank) {
--location.bank; --location.bank;
} else if (scrambleROMX < typeInfo.lastBank) { } else if (options.scrambleROMX < typeInfo.lastBank) {
location.bank = scrambleROMX + 1; location.bank = options.scrambleROMX + 1;
} else { } else {
return -1; return -1;
} }
} else if (scrambleWRAMX && section.type == SECTTYPE_WRAMX } else if (options.scrambleWRAMX && section.type == SECTTYPE_WRAMX
&& location.bank <= scrambleWRAMX) { && location.bank <= options.scrambleWRAMX) {
if (location.bank > typeInfo.firstBank) { if (location.bank > typeInfo.firstBank) {
--location.bank; --location.bank;
} else if (scrambleWRAMX < typeInfo.lastBank) { } else if (options.scrambleWRAMX < typeInfo.lastBank) {
location.bank = scrambleWRAMX + 1; location.bank = options.scrambleWRAMX + 1;
} else { } else {
return -1; return -1;
} }
} else if (scrambleSRAM && section.type == SECTTYPE_SRAM && location.bank <= scrambleSRAM) { } else if (options.scrambleSRAM && section.type == SECTTYPE_SRAM
&& location.bank <= options.scrambleSRAM) {
if (location.bank > typeInfo.firstBank) { if (location.bank > typeInfo.firstBank) {
--location.bank; --location.bank;
} else if (scrambleSRAM < typeInfo.lastBank) { } else if (options.scrambleSRAM < typeInfo.lastBank) {
location.bank = scrambleSRAM + 1; location.bank = options.scrambleSRAM + 1;
} else { } else {
return -1; return -1;
} }
@@ -388,7 +390,7 @@ void assign_AssignSections() {
// Overlaying requires only fully-constrained sections // Overlaying requires only fully-constrained sections
verbosePrint("Assigning other sections...\n"); verbosePrint("Assigning other sections...\n");
if (overlayFileName) { if (options.overlayFileName) {
fputs("FATAL: All sections must be fixed when using an overlay file", stderr); fputs("FATAL: All sections must be fixed when using an overlay file", stderr);
uint8_t nbSections = 0; uint8_t nbSections = 0;
for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED; constraints >= 0; for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED; constraints >= 0;

View File

@@ -25,23 +25,7 @@
#include "link/symbol.hpp" #include "link/symbol.hpp"
#include "link/warning.hpp" #include "link/warning.hpp"
bool isDmgMode; // -d Options options;
char const *linkerScriptName; // -l
char const *mapFileName; // -m
bool noSymInMap; // -M
char const *symFileName; // -n
char const *overlayFileName; // -O
char const *outputFileName; // -o
uint8_t padValue; // -p
bool hasPadValue = false;
// Setting these three to 0 disables the functionality
uint16_t scrambleROMX = 0; // -S
uint8_t scrambleWRAMX = 0;
uint8_t scrambleSRAM = 0;
bool is32kMode; // -t
bool beVerbose; // -v
bool isWRAM0Mode; // -w
bool disablePadding; // -x
FILE *linkerScript; FILE *linkerScript;
@@ -243,20 +227,20 @@ static void parseScrambleSpec(char const *spec) {
switch (region) { switch (region) {
case SCRAMBLE_ROMX: case SCRAMBLE_ROMX:
scrambleROMX = limit; options.scrambleROMX = limit;
break; break;
case SCRAMBLE_SRAM: case SCRAMBLE_SRAM:
scrambleSRAM = limit; options.scrambleSRAM = limit;
break; break;
case SCRAMBLE_WRAMX: case SCRAMBLE_WRAMX:
scrambleWRAMX = limit; options.scrambleWRAMX = limit;
break; break;
case SCRAMBLE_UNK: // The error has already been reported, do nothing case SCRAMBLE_UNK: // The error has already been reported, do nothing
break; break;
} }
} else if (region == SCRAMBLE_WRAMX) { } else if (region == SCRAMBLE_WRAMX) {
// Only WRAMX can be implied, since ROMX and SRAM size may vary // Only WRAMX can be implied, since ROMX and SRAM size may vary
scrambleWRAMX = 7; options.scrambleWRAMX = 7;
} else { } else {
argErr('S', "Cannot imply limit for region \"%.*s\"", regionNameFmtLen, regionName); argErr('S', "Cannot imply limit for region \"%.*s\"", regionNameFmtLen, regionName);
} }
@@ -279,8 +263,8 @@ int main(int argc, char *argv[]) {
for (int ch; (ch = musl_getopt_long_only(argc, argv, optstring, longopts, nullptr)) != -1;) { for (int ch; (ch = musl_getopt_long_only(argc, argv, optstring, longopts, nullptr)) != -1;) {
switch (ch) { switch (ch) {
case 'd': case 'd':
isDmgMode = true; options.isDmgMode = true;
isWRAM0Mode = true; options.isWRAM0Mode = true;
break; break;
case 'h': case 'h':
// LCOV_EXCL_START // LCOV_EXCL_START
@@ -288,37 +272,37 @@ int main(int argc, char *argv[]) {
exit(0); exit(0);
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
case 'l': case 'l':
if (linkerScriptName) { if (options.linkerScriptName) {
warnx("Overriding linker script %s", linkerScriptName); warnx("Overriding linker script %s", options.linkerScriptName);
} }
linkerScriptName = musl_optarg; options.linkerScriptName = musl_optarg;
break; break;
case 'M': case 'M':
noSymInMap = true; options.noSymInMap = true;
break; break;
case 'm': case 'm':
if (mapFileName) { if (options.mapFileName) {
warnx("Overriding map file %s", mapFileName); warnx("Overriding map file %s", options.mapFileName);
} }
mapFileName = musl_optarg; options.mapFileName = musl_optarg;
break; break;
case 'n': case 'n':
if (symFileName) { if (options.symFileName) {
warnx("Overriding sym file %s", symFileName); warnx("Overriding sym file %s", options.symFileName);
} }
symFileName = musl_optarg; options.symFileName = musl_optarg;
break; break;
case 'O': case 'O':
if (overlayFileName) { if (options.overlayFileName) {
warnx("Overriding overlay file %s", overlayFileName); warnx("Overriding overlay file %s", options.overlayFileName);
} }
overlayFileName = musl_optarg; options.overlayFileName = musl_optarg;
break; break;
case 'o': case 'o':
if (outputFileName) { if (options.outputFileName) {
warnx("Overriding output file %s", outputFileName); warnx("Overriding output file %s", options.outputFileName);
} }
outputFileName = musl_optarg; options.outputFileName = musl_optarg;
break; break;
case 'p': { case 'p': {
char *endptr; char *endptr;
@@ -328,15 +312,15 @@ int main(int argc, char *argv[]) {
argErr('p', "Argument for 'p' must be a byte (between 0 and 0xFF)"); argErr('p', "Argument for 'p' must be a byte (between 0 and 0xFF)");
value = 0xFF; value = 0xFF;
} }
padValue = value; options.padValue = value;
hasPadValue = true; options.hasPadValue = true;
break; break;
} }
case 'S': case 'S':
parseScrambleSpec(musl_optarg); parseScrambleSpec(musl_optarg);
break; break;
case 't': case 't':
is32kMode = true; options.is32kMode = true;
break; break;
case 'V': case 'V':
// LCOV_EXCL_START // LCOV_EXCL_START
@@ -345,19 +329,19 @@ int main(int argc, char *argv[]) {
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
case 'v': case 'v':
// LCOV_EXCL_START // LCOV_EXCL_START
beVerbose = true; options.beVerbose = true;
break; break;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
case 'W': case 'W':
warnings.processWarningFlag(musl_optarg); warnings.processWarningFlag(musl_optarg);
break; break;
case 'w': case 'w':
isWRAM0Mode = true; options.isWRAM0Mode = true;
break; break;
case 'x': case 'x':
disablePadding = true; options.disablePadding = true;
// implies tiny mode // implies tiny mode
is32kMode = true; options.is32kMode = true;
break; break;
default: default:
// LCOV_EXCL_START // LCOV_EXCL_START
@@ -375,15 +359,15 @@ 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 (!options.is32kMode) {
sectionTypeInfo[SECTTYPE_ROM0].size = 0x4000; sectionTypeInfo[SECTTYPE_ROM0].size = 0x4000;
} }
if (!isWRAM0Mode) { if (!options.isWRAM0Mode) {
sectionTypeInfo[SECTTYPE_WRAM0].size = 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 (options.isDmgMode) {
sectionTypeInfo[SECTTYPE_VRAM].lastBank = 0; sectionTypeInfo[SECTTYPE_VRAM].lastBank = 0;
} }
@@ -393,10 +377,10 @@ int main(int argc, char *argv[]) {
} }
// apply the linker script's modifications, // apply the linker script's modifications,
if (linkerScriptName) { if (options.linkerScriptName) {
verbosePrint("Reading linker script...\n"); verbosePrint("Reading linker script...\n");
script_ProcessScript(linkerScriptName); script_ProcessScript();
// If the linker script produced any errors, some sections may be in an invalid state // If the linker script produced any errors, some sections may be in an invalid state
requireZeroErrors(); requireZeroErrors();

View File

@@ -125,7 +125,7 @@ static uint32_t checkOverlaySize() {
if (overlaySize % BANK_SIZE) { if (overlaySize % BANK_SIZE) {
warnx("Overlay file does not have a size multiple of 0x4000"); warnx("Overlay file does not have a size multiple of 0x4000");
} else if (is32kMode && overlaySize != 0x8000) { } else if (options.is32kMode && overlaySize != 0x8000) {
warnx("Overlay is not exactly 0x8000 bytes large"); warnx("Overlay is not exactly 0x8000 bytes large");
} else if (overlaySize < 0x8000) { } else if (overlaySize < 0x8000) {
warnx("Overlay is less than 0x8000 bytes large"); warnx("Overlay is less than 0x8000 bytes large");
@@ -138,7 +138,7 @@ static uint32_t checkOverlaySize() {
// This ensures that `writeROM` will output each bank, even if some are not // This ensures that `writeROM` will output each bank, even if some are not
// covered by any sections. // covered by any sections.
static void coverOverlayBanks(uint32_t nbOverlayBanks) { static void coverOverlayBanks(uint32_t nbOverlayBanks) {
// 2 if is32kMode, 1 otherwise // 2 if options.is32kMode, 1 otherwise
uint32_t nbRom0Banks = sectionTypeInfo[SECTTYPE_ROM0].size / 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].size() uint32_t nbUncoveredBanks = nbOverlayBanks - nbRom0Banks > sections[SECTTYPE_ROMX].size()
@@ -159,13 +159,13 @@ static uint8_t getNextFillByte() {
return c; return c;
} }
if (static bool warned = false; !hasPadValue && !warned) { if (static bool warned = false; !options.hasPadValue && !warned) {
warnx("Output is larger than overlay file, but no padding value was specified"); warnx("Output is larger than overlay file, but no padding value was specified");
warned = true; warned = true;
} }
} }
return padValue; return options.padValue;
} }
static void static void
@@ -193,7 +193,7 @@ static void
} }
} }
if (!disablePadding) { if (!options.disablePadding) {
while (offset < size) { while (offset < size) {
putc(getNextFillByte(), outputFile); putc(getNextFillByte(), outputFile);
++offset; ++offset;
@@ -202,16 +202,16 @@ static void
} }
static void writeROM() { static void writeROM() {
if (outputFileName) { if (options.outputFileName) {
if (strcmp(outputFileName, "-")) { if (strcmp(options.outputFileName, "-")) {
outputFile = fopen(outputFileName, "wb"); outputFile = fopen(options.outputFileName, "wb");
} else { } else {
outputFileName = "<stdout>"; options.outputFileName = "<stdout>";
(void)setmode(STDOUT_FILENO, O_BINARY); (void)setmode(STDOUT_FILENO, O_BINARY);
outputFile = stdout; outputFile = stdout;
} }
if (!outputFile) { if (!outputFile) {
fatal("Failed to open output file \"%s\": %s", outputFileName, strerror(errno)); fatal("Failed to open output file \"%s\": %s", options.outputFileName, strerror(errno));
} }
} }
Defer closeOutputFile{[&] { Defer closeOutputFile{[&] {
@@ -220,16 +220,18 @@ static void writeROM() {
} }
}}; }};
if (overlayFileName) { if (options.overlayFileName) {
if (strcmp(overlayFileName, "-")) { if (strcmp(options.overlayFileName, "-")) {
overlayFile = fopen(overlayFileName, "rb"); overlayFile = fopen(options.overlayFileName, "rb");
} else { } else {
overlayFileName = "<stdin>"; options.overlayFileName = "<stdin>";
(void)setmode(STDIN_FILENO, O_BINARY); (void)setmode(STDIN_FILENO, O_BINARY);
overlayFile = stdin; overlayFile = stdin;
} }
if (!overlayFile) { if (!overlayFile) {
fatal("Failed to open overlay file \"%s\": %s", overlayFileName, strerror(errno)); fatal(
"Failed to open overlay file \"%s\": %s", options.overlayFileName, strerror(errno)
);
} }
} }
Defer closeOverlayFile{[&] { Defer closeOverlayFile{[&] {
@@ -471,7 +473,7 @@ static void writeMapBank(SortedSections const &sectList, SectionType type, uint3
writeSectionName(sect.name, mapFile); writeSectionName(sect.name, mapFile);
fputs("\"]\n", mapFile); fputs("\"]\n", mapFile);
if (!noSymInMap) { if (!options.noSymInMap) {
// Also print symbols in the following "pieces" // Also print symbols in the following "pieces"
writeMapSymbols(&sect); writeMapSymbols(&sect);
} }
@@ -529,19 +531,19 @@ static void writeMapSummary() {
} }
static void writeSym() { static void writeSym() {
if (!symFileName) { if (!options.symFileName) {
return; return;
} }
if (strcmp(symFileName, "-")) { if (strcmp(options.symFileName, "-")) {
symFile = fopen(symFileName, "w"); symFile = fopen(options.symFileName, "w");
} else { } else {
symFileName = "<stdout>"; options.symFileName = "<stdout>";
(void)setmode(STDOUT_FILENO, O_TEXT); // May have been set to O_BINARY previously (void)setmode(STDOUT_FILENO, O_TEXT); // May have been set to O_BINARY previously
symFile = stdout; symFile = stdout;
} }
if (!symFile) { if (!symFile) {
fatal("Failed to open sym file \"%s\": %s", symFileName, strerror(errno)); fatal("Failed to open sym file \"%s\": %s", options.symFileName, strerror(errno));
} }
Defer closeSymFile{[&] { fclose(symFile); }}; Defer closeSymFile{[&] { fclose(symFile); }};
@@ -579,19 +581,19 @@ static void writeSym() {
} }
static void writeMap() { static void writeMap() {
if (!mapFileName) { if (!options.mapFileName) {
return; return;
} }
if (strcmp(mapFileName, "-")) { if (strcmp(options.mapFileName, "-")) {
mapFile = fopen(mapFileName, "w"); mapFile = fopen(options.mapFileName, "w");
} else { } else {
mapFileName = "<stdout>"; options.mapFileName = "<stdout>";
(void)setmode(STDOUT_FILENO, O_TEXT); // May have been set to O_BINARY previously (void)setmode(STDOUT_FILENO, O_TEXT); // May have been set to O_BINARY previously
mapFile = stdout; mapFile = stdout;
} }
if (!mapFile) { if (!mapFile) {
fatal("Failed to open map file \"%s\": %s", mapFileName, strerror(errno)); fatal("Failed to open map file \"%s\": %s", options.mapFileName, strerror(errno));
} }
Defer closeMapFile{[&] { fclose(mapFile); }}; Defer closeMapFile{[&] { fclose(mapFile); }};

View File

@@ -10,7 +10,7 @@
#include "linkdefs.hpp" #include "linkdefs.hpp"
void script_ProcessScript(char const *path); void script_ProcessScript();
} }
%code { %code {
@@ -828,12 +828,12 @@ static void placeSection(std::string const &name, bool isOptional) {
/******************** External API ********************/ /******************** External API ********************/
void script_ProcessScript(char const *path) { void script_ProcessScript() {
activeType = SECTTYPE_INVALID; activeType = SECTTYPE_INVALID;
lexerStack.clear(); lexerStack.clear();
atEof = false; atEof = false;
LexerStackEntry &newContext = lexerStack.emplace_back(std::string(path)); LexerStackEntry &newContext = lexerStack.emplace_back(std::string(options.linkerScriptName));
if (!newContext.file.open(newContext.path, std::ios_base::in)) { if (!newContext.file.open(newContext.path, std::ios_base::in)) {
error("Failed to open linker script \"%s\"", newContext.path.c_str()); error("Failed to open linker script \"%s\"", newContext.path.c_str());

View File

@@ -247,7 +247,7 @@ static void doSanityChecks(Section &section) {
return; return;
} }
if (is32kMode && section.type == SECTTYPE_ROMX) { if (options.is32kMode && section.type == SECTTYPE_ROMX) {
if (section.isBankFixed && section.bank != 1) { if (section.isBankFixed && section.bank != 1) {
error( error(
"Section \"%s\" has type ROMX, which must be in bank 1 (if any) with option `-t`", "Section \"%s\" has type ROMX, which must be in bank 1 (if any) with option `-t`",
@@ -257,7 +257,7 @@ static void doSanityChecks(Section &section) {
section.type = SECTTYPE_ROM0; section.type = SECTTYPE_ROM0;
} }
} }
if (isWRAM0Mode && section.type == SECTTYPE_WRAMX) { if (options.isWRAM0Mode && section.type == SECTTYPE_WRAMX) {
if (section.isBankFixed && section.bank != 1) { if (section.isBankFixed && section.bank != 1) {
error( error(
"Section \"%s\" has type WRAMX, which must be in bank 1 with options `-w` or `-d`", "Section \"%s\" has type WRAMX, which must be in bank 1 with options `-w` or `-d`",
@@ -267,7 +267,7 @@ static void doSanityChecks(Section &section) {
section.type = SECTTYPE_WRAM0; section.type = SECTTYPE_WRAM0;
} }
} }
if (isDmgMode && section.type == SECTTYPE_VRAM && section.bank == 1) { if (options.isDmgMode && section.type == SECTTYPE_VRAM && section.bank == 1) {
error( error(
"Section \"%s\" has type VRAM, which must be in bank 0 with option `-d`", "Section \"%s\" has type VRAM, which must be in bank 0 with option `-d`",
section.name.c_str() section.name.c_str()