diff --git a/include/link/assign.h b/include/link/assign.h index 373103aa..9c522617 100644 --- a/include/link/assign.h +++ b/include/link/assign.h @@ -7,9 +7,9 @@ enum eBankDefine { BANK_HOME = 0, BANK_BSS = 512, BANK_VRAM, - BANK_HRAM + BANK_HRAM = 515 }; -#define MAXBANKS 515 +#define MAXBANKS 516 extern SLONG area_Avail(SLONG bank); extern void AssignSections(void); diff --git a/src/asm/gameboy/yaccprt4.y b/src/asm/gameboy/yaccprt4.y index fd880f4c..061f3397 100644 --- a/src/asm/gameboy/yaccprt4.y +++ b/src/asm/gameboy/yaccprt4.y @@ -17,8 +17,15 @@ section: out_NewAbsSection($2,$4,-1,$8); else yyerror("ROM bank value $%x out of range (1 to $1ff)", $8); - } else - yyerror("BANK only allowed for CODE/DATA"); + } else if ($4 == SECT_VRAM) { + if ($8 >= 0 && $8 <= 1) { + out_NewAbsSection($2, $4, -1, $8); + } else { + yyerror("VRAM bank value $%x out of range (0 to 1)", $8); + } + } else { + yyerror("BANK only allowed for CODE/DATA or VRAM sections"); + } } | T_POP_SECTION string ',' sectiontype '[' const ']' ',' T_OP_BANK '[' const ']' { @@ -27,11 +34,22 @@ section: if( $11>=1 && $11<=0x1ff ) out_NewAbsSection($2,$4,$6,$11); else - yyerror("ROM bank value $%x out of range (1 to $1ff)", 8); + yyerror("ROM bank value $%x out of range (1 to $1ff)", $11); } else yyerror("Address $%x not 16-bit", $6); - } else - yyerror("BANK only allowed for CODE/DATA"); + } else if ($4 == SECT_VRAM) { + if ($6 >= 0 && $6 < 0x10000) { + if ($11 >= 0 && $11 <= 1) { + out_NewAbsSection($2,$4,$6,$11); + } else { + yyerror("VRAM bank value $%x out of range (0 to 1)", $11); + } + } else { + yyerror("Address $%x not 16-bit", $6); + } + } else { + yyerror("BANK only allowed for CODE/DATA or VRAM sections"); + } } ; diff --git a/src/link/assign.c b/src/link/assign.c index 59b75b16..f0b2e4fa 100644 --- a/src/link/assign.c +++ b/src/link/assign.c @@ -15,8 +15,10 @@ struct sFreeArea { struct sFreeArea *BankFree[MAXBANKS]; SLONG MaxAvail[MAXBANKS]; SLONG MaxBankUsed; +SLONG MaxVBankUsed; #define DOMAXBANK(x) {if( (x)>MaxBankUsed ) MaxBankUsed=(x);} +#define DOMAXVBANK(x) {if( (x)>MaxVBankUsed ) MaxVBankUsed=(x);} SLONG area_Avail(SLONG bank) @@ -85,6 +87,19 @@ area_AllocAbs(struct sFreeArea ** ppArea, SLONG org, SLONG size) return (-1); } +SLONG +area_AllocAbsVRAMAnyBank(SLONG org, SLONG size) +{ + if (area_AllocAbs(&BankFree[BANK_VRAM], org, size) == org) { + return BANK_VRAM; + } + if (area_AllocAbs(&BankFree[BANK_VRAM + 1], org, size) == org) { + return BANK_VRAM + 1; + } + + return -1; +} + SLONG area_AllocAbsCODEAnyBank(SLONG org, SLONG size) { @@ -121,6 +136,19 @@ area_Alloc(struct sFreeArea ** ppArea, SLONG size) return (-1); } +SLONG +area_AllocVRAMAnyBank(SLONG size) +{ + SLONG i, org; + + for (i = BANK_VRAM; i <= BANK_VRAM + 1; i += 1) { + if ((org = area_Alloc(&BankFree[i], size)) != -1) + return ((i << 16) | org); + } + + return (-1); +} + SLONG area_AllocCODEAnyBank(SLONG size) { @@ -134,6 +162,25 @@ area_AllocCODEAnyBank(SLONG size) return (-1); } +struct sSection * +FindLargestVRAM(void) +{ + struct sSection *pSection, *r = NULL; + SLONG nLargest = 0; + + pSection = pSections; + while (pSection) { + if (pSection->oAssigned == 0 && pSection->Type == SECT_VRAM) { + if (pSection->nByteSize > nLargest) { + nLargest = pSection->nByteSize; + r = pSection; + } + } + pSection = pSection->pNext; + } + return (r); +} + struct sSection * FindLargestCode(void) { @@ -153,6 +200,27 @@ FindLargestCode(void) return (r); } +void +AssignVRAMSections(void) +{ + struct sSection *pSection; + + while ((pSection = FindLargestVRAM())) { + SLONG org; + + if ((org = area_AllocVRAMAnyBank(pSection->nByteSize)) != -1) { + pSection->nOrg = org & 0xFFFF; + pSection->nBank = org >> 16; + pSection->oAssigned = 1; + DOMAXVBANK(pSection->nBank); + } else { + fprintf(stderr, + "Unable to place VRAM section anywhere\n"); + exit(1); + } + } +} + void AssignCodeSections(void) { @@ -196,6 +264,7 @@ AssignSections(void) } if (i == 0) { + /* ROM0 bank */ BankFree[i]->nOrg = 0x0000; if (options & OPT_SMALL) { BankFree[i]->nSize = 0x8000; @@ -205,6 +274,7 @@ AssignSections(void) MaxAvail[i] = 0x4000; } } else if (i >= 1 && i <= 511) { + /* Swappable ROM bank */ BankFree[i]->nOrg = 0x4000; /* * Now, this shouldn't really be necessary... but for @@ -218,14 +288,17 @@ AssignSections(void) MaxAvail[i] = 0x4000; } } else if (i == BANK_BSS) { + /* WRAM */ BankFree[i]->nOrg = 0xC000; BankFree[i]->nSize = 0x2000; MaxAvail[i] = 0x2000; - } else if (i == BANK_VRAM) { + } else if (i == BANK_VRAM || i == BANK_VRAM + 1) { + /* Swappable VRAM bank */ BankFree[i]->nOrg = 0x8000; BankFree[i]->nSize = 0x2000; MaxAvail[i] = 0x2000; } else if (i == BANK_HRAM) { + /* HRAM */ BankFree[i]->nOrg = 0xFF80; BankFree[i]->nSize = 0x007F; MaxAvail[i] = 0x007F; @@ -272,16 +345,57 @@ AssignSections(void) pSection->nBank = BANK_HRAM; break; case SECT_VRAM: - if (area_AllocAbs - (&BankFree[BANK_VRAM], pSection->nOrg, - pSection->nByteSize) != pSection->nOrg) { - fprintf(stderr, "Unable to load fixed " - "VRAM section at $%lX\n", - pSection->nOrg); - exit(1); + if (pSection->nBank == -1) { + /* + * User doesn't care which bank. + * Therefore he must here be specifying + * position within the bank. + * Defer until later. + */ + ; + } else { + /* + * User specified which bank to use. + * Does he also care about position + * within the bank? + */ + if (pSection->nOrg == -1) { + /* + * Nope, any position will do + * Again, we'll do that later + * + */ + ; + } else { + /* + * Bank and position within the + * bank are hardcoded. + */ + + if (pSection->nBank >= 0 + && pSection->nBank <= 1) { + pSection->nBank += + BANK_VRAM; + if (area_AllocAbs + (&BankFree + [pSection->nBank], + pSection->nOrg, + pSection->nByteSize) + != pSection->nOrg) { + fprintf(stderr, +"Unable to load fixed VRAM section at $%lX in bank $%02lX\n", pSection->nOrg, pSection->nBank - BANK_VRAM); + exit(1); + } + DOMAXVBANK(pSection-> + nBank); + pSection->oAssigned = 1; + } else { + fprintf(stderr, +"Unable to load fixed VRAM section at $%lX in bank $%02lX\n", pSection->nOrg, pSection->nBank - BANK_VRAM); + exit(1); + } + } } - pSection->oAssigned = 1; - pSection->nBank = BANK_VRAM; break; case SECT_HOME: if (area_AllocAbs @@ -378,6 +492,24 @@ AssignSections(void) fprintf(stderr, "Unable to load fixed CODE/DATA section into bank $%02lX\n", pSection->nBank); exit(1); } + } else if (pSection->oAssigned == 0 + && pSection->Type == SECT_VRAM + && pSection->nOrg == -1 && pSection->nBank != -1) { + pSection->nBank += BANK_VRAM; + /* User wants to have a say... and he's pissed */ + if (pSection->nBank >= BANK_VRAM && pSection->nBank <= BANK_VRAM + 1) { + if ((pSection->nOrg = + area_Alloc(&BankFree[pSection->nBank], + pSection->nByteSize)) == -1) { + fprintf(stderr, "Unable to load fixed VRAM section into bank $%02lX\n", pSection->nBank - BANK_VRAM); + exit(1); + } + pSection->oAssigned = 1; + DOMAXBANK(pSection->nBank); + } else { + fprintf(stderr, "Unable to load fixed VRAM section into bank $%02lX\n", pSection->nBank - BANK_VRAM); + exit(1); + } } pSection = pSection->pNext; } @@ -403,6 +535,20 @@ AssignSections(void) } pSection->oAssigned = 1; DOMAXBANK(pSection->nBank); + } else if (pSection->oAssigned == 0 + && pSection->Type == SECT_VRAM + && pSection->nOrg != -1 && pSection->nBank == -1) { + /* User wants to have a say... and he's back with a + * vengeance */ + if ((pSection->nBank = + area_AllocAbsVRAMAnyBank(pSection->nOrg, + pSection->nByteSize)) == + -1) { + fprintf(stderr, "Unable to load fixed VRAM section at $%lX into any bank\n", pSection->nOrg); + exit(1); + } + pSection->oAssigned = 1; + DOMAXVBANK(pSection->nBank); } pSection = pSection->pNext; } @@ -438,14 +584,6 @@ AssignSections(void) pSection->oAssigned = 1; break; case SECT_VRAM: - if ((pSection->nOrg = - area_Alloc(&BankFree[BANK_VRAM], - pSection->nByteSize)) == -1) { - fprintf(stderr, "VRAM section too large\n"); - exit(1); - } - pSection->nBank = BANK_VRAM; - pSection->oAssigned = 1; break; case SECT_HOME: if ((pSection->nOrg = @@ -469,6 +607,7 @@ AssignSections(void) } AssignCodeSections(); + AssignVRAMSections(); } void