ref: 35448887afcd54313435ad7e4dd3b9ef0950e7f7
parent: 6ccd386587c671250cf71c5099c0f9b6b0bd507a
author: Anthony J. Bentley <[email protected]>
date: Sun May 19 20:59:15 EDT 2013
Implement VRAM banks.
--- a/include/link/assign.h
+++ b/include/link/assign.h
@@ -7,9 +7,9 @@
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);
--- a/src/asm/gameboy/yaccprt4.y
+++ b/src/asm/gameboy/yaccprt4.y
@@ -17,8 +17,15 @@
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 @@
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");
+ }
}
;
--- a/src/link/assign.c
+++ b/src/link/assign.c
@@ -15,8 +15,10 @@
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 @@
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 @@
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)
{
@@ -135,6 +163,25 @@
}
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)
{
struct sSection *pSection, *r = NULL;
@@ -153,6 +200,27 @@
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 @@
}
if (i == 0) {
+ /* ROM0 bank */
BankFree[i]->nOrg = 0x0000;
if (options & OPT_SMALL) {
BankFree[i]->nSize = 0x8000;
@@ -205,6 +274,7 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
}
AssignCodeSections();
+ AssignVRAMSections();
}
void