diff --git a/include/link/mylink.h b/include/link/mylink.h index 0d3c9c52..c315e724 100644 --- a/include/link/mylink.h +++ b/include/link/mylink.h @@ -10,6 +10,7 @@ extern SLONG options; #define OPT_SMALL 0x01 #define OPT_SMART_C_LINK 0x02 +#define OPT_OVERLAY 0x04 enum eRpnData { RPN_ADD = 0, diff --git a/include/link/output.h b/include/link/output.h index 7256a92c..06147cff 100644 --- a/include/link/output.h +++ b/include/link/output.h @@ -2,6 +2,7 @@ #define RGBDS_LINK_OUTPUT_H void out_Setname(char *tzOutputfile); +void out_SetOverlayname(char *tzOverlayfile); void Output(void); #endif diff --git a/src/link/assign.c b/src/link/assign.c index 18326cb7..2c46987f 100644 --- a/src/link/assign.c +++ b/src/link/assign.c @@ -258,13 +258,16 @@ void AssignFloatingBankSections(enum eSectionType type) { ensureSectionTypeIsValid(type); - + struct sSection *pSection; while ((pSection = FindLargestSection(type, false))) { SLONG org; if ((org = area_AllocAnyBank(pSection->nByteSize, pSection->nAlign, type)) != -1) { + if (options & OPT_OVERLAY) { + errx(1, "All sections must be fixed when using overlay"); + } pSection->nOrg = org & 0xFFFF; pSection->nBank = org >> 16; pSection->oAssigned = 1; @@ -421,6 +424,9 @@ AssignSections(void) while (pSection) { if (pSection->oAssigned == 0 && pSection->nOrg != -1 && pSection->nBank == -1) { + if (options & OPT_OVERLAY) { + errx(1, "All sections must be fixed when using overlay"); + } switch (pSection->Type) { case SECT_ROMX: case SECT_VRAM: diff --git a/src/link/main.c b/src/link/main.c index 8eda44a8..ab87d9cb 100644 --- a/src/link/main.c +++ b/src/link/main.c @@ -35,8 +35,8 @@ static void usage(void) { printf( -"usage: rgblink [-t] [-m mapfile] [-n symfile] [-o outfile] [-p pad_value]\n" -" [-s symbol] file [...]\n"); +"usage: rgblink [-t] [-m mapfile] [-n symfile] [-O overlay] [-o outfile] \n" +" [-p pad_value] [-s symbol] file [...]\n"); exit(1); } @@ -56,7 +56,7 @@ main(int argc, char *argv[]) progname = argv[0]; - while ((ch = getopt(argc, argv, "m:n:o:p:s:t")) != -1) { + while ((ch = getopt(argc, argv, "m:n:o:O:p:s:t")) != -1) { switch (ch) { case 'm': SetMapfileName(optarg); @@ -67,6 +67,10 @@ main(int argc, char *argv[]) case 'o': out_Setname(optarg); break; + case 'O': + out_SetOverlayname(optarg); + options |= OPT_OVERLAY; + break; case 'p': fillchar = strtoul(optarg, &ep, 0); if (optarg[0] == '\0' || *ep != '\0') { diff --git a/src/link/output.c b/src/link/output.c index 95feb6de..e1fa1207 100644 --- a/src/link/output.c +++ b/src/link/output.c @@ -8,9 +8,12 @@ #include "link/assign.h" char *tzOutname; +char *tzOverlayname = NULL; + +SLONG MaxOverlayBank; void -writehome(FILE * f) +writehome(FILE * f, FILE * f_overlay) { struct sSection *pSect; UBYTE *mem; @@ -18,15 +21,20 @@ writehome(FILE * f) mem = malloc(MaxAvail[BANK_ROM0]); if (!mem) return; - - memset(mem, fillchar, MaxAvail[BANK_ROM0]); + + if (f_overlay != NULL) { + fseek(f_overlay, 0L, SEEK_SET); + fread(mem, 1, MaxAvail[BANK_ROM0], f_overlay); + } else { + memset(mem, fillchar, MaxAvail[BANK_ROM0]); + } MapfileInitBank(0); pSect = pSections; while (pSect) { if (pSect->Type == SECT_ROM0) { memcpy(mem + pSect->nOrg, pSect->pData, - pSect->nByteSize); + pSect->nByteSize); MapfileWriteSection(pSect); } pSect = pSect->pNext; @@ -39,7 +47,7 @@ writehome(FILE * f) } void -writebank(FILE * f, SLONG bank) +writebank(FILE * f, FILE * f_overlay, SLONG bank) { struct sSection *pSect; UBYTE *mem; @@ -48,14 +56,19 @@ writebank(FILE * f, SLONG bank) if (!mem) return; - memset(mem, fillchar, MaxAvail[bank]); + if (f_overlay != NULL && bank <= MaxOverlayBank) { + fseek(f_overlay, bank*0x4000, SEEK_SET); + fread(mem, 1, MaxAvail[bank], f_overlay); + } else { + memset(mem, fillchar, MaxAvail[bank]); + } MapfileInitBank(bank); pSect = pSections; while (pSect) { if (pSect->Type == SECT_ROMX && pSect->nBank == bank) { memcpy(mem + pSect->nOrg - 0x4000, pSect->pData, - pSect->nByteSize); + pSect->nByteSize); MapfileWriteSection(pSect); } pSect = pSect->pNext; @@ -73,18 +86,52 @@ out_Setname(char *tzOutputfile) tzOutname = tzOutputfile; } +void +out_SetOverlayname(char *tzOverlayfile) +{ + tzOverlayname = tzOverlayfile; +} + + void Output(void) { SLONG i; FILE *f; + FILE *f_overlay = NULL; + if ((f = fopen(tzOutname, "wb"))) { - writehome(f); + if (tzOverlayname) { + f_overlay = fopen(tzOverlayname, "rb"); + if (!f_overlay) { + fprintf(stderr, "Failed to open overlay file %s\n", tzOverlayname); + exit(1); + } + fseek(f_overlay, 0, SEEK_END); + if (ftell(f_overlay) % 0x4000 != 0) { + fprintf(stderr, "Overlay file must be aligned to 0x4000 bytes\n"); + exit(1); + } + MaxOverlayBank = (ftell(f_overlay) / 0x4000) - 1; + if (MaxOverlayBank < 1) { + fprintf(stderr, "Overlay file be at least 0x8000 bytes\n"); + exit(1); + } + if (MaxOverlayBank > MaxBankUsed) { + MaxBankUsed = MaxOverlayBank; + } + } + + writehome(f, f_overlay); for (i = 1; i <= MaxBankUsed; i += 1) - writebank(f, i); + writebank(f, f_overlay, i); fclose(f); + + if (tzOverlayname) { + fclose(f_overlay); + } } for (i = BANK_WRAM0; i < MAXBANKS; i++) { struct sSection *pSect; diff --git a/src/link/rgblink.1 b/src/link/rgblink.1 index f4a22729..d6a6975a 100644 --- a/src/link/rgblink.1 +++ b/src/link/rgblink.1 @@ -9,6 +9,7 @@ .Op Fl t .Op Fl m Ar mapfile .Op Fl n Ar symfile +.Op Fl O Ar overlayfile .Op Fl o Ar outfile .Op Fl p Ar pad_value .Op Fl s Ar symbol @@ -32,6 +33,10 @@ The arguments are as follows: Write a mapfile to the given filename. .It Fl n Ar symfile Write a symbol file to the given filename. +.It Fl O Ar overlayfile +The ROM image to overlay sections over. +When an overlay ROM is provided, all sections must be fixed. +This may be used to patch an existing binray. .It Fl o Ar outfile Write ROM image to the given filename. .It Fl p Ar pad_value