Implement byte alignment in section assingment

Yay, more refactoring of the section assignment… This version of the linker will allocate sections by their alignment, and then by their size (largest first, in both cases).

In future, this may be improved by using dense packing (as suggested by #83).
This commit is contained in:
Ben10do
2017-02-19 22:43:45 +00:00
parent e4cbf773f6
commit 1b05c43b97

View File

@@ -46,7 +46,7 @@ const struct sSectionAttributes SECT_ATTRIBUTES[] = {
case SECT_WRAMX: DOMAXWBANK(y); break; \ case SECT_WRAMX: DOMAXWBANK(y); break; \
case SECT_SRAM: DOMAXSBANK(y); break; \ case SECT_SRAM: DOMAXSBANK(y); break; \
case SECT_VRAM: DOMAXVBANK(y); break; \ case SECT_VRAM: DOMAXVBANK(y); break; \
default: errx(1, "DOMAXBANK used with invalid parameters"); break; }} default: break; }}
#define DOMAXRBANK(x) {if( (x)>MaxBankUsed ) MaxBankUsed=(x);} #define DOMAXRBANK(x) {if( (x)>MaxBankUsed ) MaxBankUsed=(x);}
#define DOMAXWBANK(x) {if( (x)>MaxWBankUsed ) MaxWBankUsed=(x);} #define DOMAXWBANK(x) {if( (x)>MaxWBankUsed ) MaxWBankUsed=(x);}
#define DOMAXSBANK(x) {if( (x)>MaxSBankUsed ) MaxSBankUsed=(x);} #define DOMAXSBANK(x) {if( (x)>MaxSBankUsed ) MaxSBankUsed=(x);}
@@ -77,6 +77,40 @@ area_Avail(SLONG bank)
return (r); return (r);
} }
SLONG
area_doAlloc(struct sFreeArea *pArea, SLONG org, SLONG size)
{
if (org >= pArea->nOrg && (org + size) <= (pArea->nOrg + pArea->nSize)) {
if (org == pArea->nOrg) {
pArea->nOrg += size;
pArea->nSize -= size;
return org;
} else {
if ((org + size) == (pArea->nOrg + pArea->nSize)) {
pArea->nSize -= size;
return org;
} else {
struct sFreeArea *pNewArea;
if ((pNewArea = malloc(sizeof(struct sFreeArea))) != NULL) {
*pNewArea = *pArea;
pNewArea->pPrev = pArea;
pArea->pNext = pNewArea;
pArea->nSize = org - pArea->nOrg;
pNewArea->nOrg = org + size;
pNewArea->nSize -= size + pArea->nSize;
return org;
} else {
err(1, NULL);
}
}
}
}
return -1;
}
SLONG SLONG
area_AllocAbs(struct sFreeArea ** ppArea, SLONG org, SLONG size) area_AllocAbs(struct sFreeArea ** ppArea, SLONG org, SLONG size)
{ {
@@ -84,39 +118,11 @@ area_AllocAbs(struct sFreeArea ** ppArea, SLONG org, SLONG size)
pArea = *ppArea; pArea = *ppArea;
while (pArea) { while (pArea) {
if (org >= pArea->nOrg SLONG result = area_doAlloc(pArea, org, size);
&& (org + size - 1) <= (pArea->nOrg + pArea->nSize - 1)) { if (result != -1) {
if (org == pArea->nOrg) { return result;
pArea->nOrg += size;
pArea->nSize -= size;
return 0;
} else {
if ((org + size - 1) ==
(pArea->nOrg + pArea->nSize - 1)) {
pArea->nSize -= size;
return 0;
} else {
struct sFreeArea *pNewArea;
if ((pNewArea =
malloc(sizeof(struct sFreeArea)))
!= NULL) {
*pNewArea = *pArea;
pNewArea->pPrev = pArea;
pArea->pNext = pNewArea;
pArea->nSize =
org - pArea->nOrg;
pNewArea->nOrg = org + size;
pNewArea->nSize -=
size + pArea->nSize;
return 0;
} else {
err(1, NULL);
}
}
}
} }
ppArea = &(pArea->pNext); ppArea = &(pArea->pNext);
pArea = *ppArea; pArea = *ppArea;
} }
@@ -142,37 +148,41 @@ area_AllocAbsAnyBank(SLONG org, SLONG size, enum eSectionType type)
} }
SLONG SLONG
area_Alloc(struct sFreeArea ** ppArea, SLONG size) area_Alloc(struct sFreeArea ** ppArea, SLONG size, SLONG alignment) {
{
struct sFreeArea *pArea; struct sFreeArea *pArea;
if (alignment < 1) {
alignment = 1;
}
pArea = *ppArea; pArea = *ppArea;
while (pArea) { while (pArea) {
if (size <= pArea->nSize) { SLONG org = pArea->nOrg;
SLONG r; if (org % alignment) {
org += alignment;
r = pArea->nOrg;
pArea->nOrg += size;
pArea->nSize -= size;
return (r);
} }
org -= org % alignment;
SLONG result = area_doAlloc(pArea, org, size);
if (result != -1) {
return result;
}
ppArea = &(pArea->pNext); ppArea = &(pArea->pNext);
pArea = *ppArea; pArea = *ppArea;
} }
return (-1); return -1;
} }
SLONG SLONG
area_AllocAnyBank(SLONG size, enum eSectionType type) { area_AllocAnyBank(SLONG size, SLONG alignment, enum eSectionType type) {
ensureSectionTypeIsValid(type); ensureSectionTypeIsValid(type);
SLONG startBank = SECT_ATTRIBUTES[type].bank; SLONG startBank = SECT_ATTRIBUTES[type].bank;
SLONG bankCount = SECT_ATTRIBUTES[type].bankCount; SLONG bankCount = SECT_ATTRIBUTES[type].bankCount;
for (int i = 0; i < bankCount; i++) { for (int i = 0; i < bankCount; i++) {
SLONG org = area_Alloc(&BankFree[startBank + i], size); SLONG org = area_Alloc(&BankFree[startBank + i], size, alignment);
if (org != -1) { if (org != -1) {
return ((startBank + i) << 16) | org; return ((startBank + i) << 16) | org;
} }
@@ -182,45 +192,27 @@ area_AllocAnyBank(SLONG size, enum eSectionType type) {
} }
struct sSection * struct sSection *
FindLargestSection(enum eSectionType type) FindLargestSection(enum eSectionType type, bool bankFixed)
{ {
struct sSection *pSection, *r = NULL; struct sSection *pSection, *r = NULL;
SLONG nLargest = 0; SLONG nLargest = 0;
SLONG nLargestAlignment = 0;
pSection = pSections; pSection = pSections;
while (pSection) { while (pSection) {
if (pSection->oAssigned == 0 && pSection->Type == type) { if (pSection->oAssigned == 0 && pSection->Type == type && (bankFixed ^ (pSection->nBank == -1))) {
if (pSection->nByteSize > nLargest) { if (pSection->nAlign > nLargestAlignment || (pSection->nAlign == nLargestAlignment && pSection->nByteSize > nLargest)) {
nLargest = pSection->nByteSize; nLargest = pSection->nByteSize;
nLargestAlignment = pSection->nAlign;
r = pSection; r = pSection;
} }
} }
pSection = pSection->pNext; pSection = pSection->pNext;
} }
return r; return r;
} }
void
AssignBankedSections(enum eSectionType type)
{
ensureSectionTypeIsValid(type);
struct sSection *pSection;
while ((pSection = FindLargestSection(type))) {
SLONG org;
if ((org = area_AllocAnyBank(pSection->nByteSize, type)) != -1) {
pSection->nOrg = org & 0xFFFF;
pSection->nBank = org >> 16;
pSection->oAssigned = 1;
DOMAXBANK(pSection->Type, pSection->nBank);
} else {
errx(1, "Unable to place %s section anywhere",
SECT_ATTRIBUTES[type].name);
}
}
}
bool bool
VerifyAndSetBank(struct sSection *pSection) VerifyAndSetBank(struct sSection *pSection)
@@ -237,6 +229,47 @@ VerifyAndSetBank(struct sSection *pSection)
} }
} }
void
AssignFixedBankSections(enum eSectionType type)
{
ensureSectionTypeIsValid(type);
struct sSection *pSection;
while ((pSection = FindLargestSection(type, true))) {
if (VerifyAndSetBank(pSection) &&
(pSection->nOrg = area_Alloc(&BankFree[pSection->nBank], pSection->nByteSize, pSection->nAlign)) != -1) {
pSection->oAssigned = 1;
DOMAXBANK(pSection->Type, pSection->nBank);
} else {
errx(1, "Unable to load fixed %s section into bank $%02lX",
SECT_ATTRIBUTES[pSection->Type].name, pSection->nBank);
}
}
}
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) {
pSection->nOrg = org & 0xFFFF;
pSection->nBank = org >> 16;
pSection->oAssigned = 1;
DOMAXBANK(pSection->Type, pSection->nBank);
} else {
errx(1, "Unable to place %s section anywhere",
SECT_ATTRIBUTES[type].name);
}
}
}
void void
AssignSections(void) AssignSections(void)
{ {
@@ -353,35 +386,11 @@ AssignSections(void)
} }
/* /*
* Next, let's assign all the bankfixed ONLY ROMX sections... * Next, let's assign all the bankfixed ONLY sections...
* *
*/ */
for (enum eSectionType i = SECT_MIN; i <= SECT_MAX; i++) {
pSection = pSections; AssignFixedBankSections(i);
while (pSection) {
if (pSection->oAssigned == 0
&& pSection->nOrg == -1 && pSection->nBank != -1) {
switch (pSection->Type) {
case SECT_ROMX:
case SECT_SRAM:
case SECT_VRAM:
case SECT_WRAMX:
if (VerifyAndSetBank(pSection) &&
(pSection->nOrg = area_Alloc(&BankFree[pSection->nBank], pSection->nByteSize)) != -1) {
pSection->oAssigned = 1;
DOMAXBANK(pSection->Type, pSection->nBank);
} else {
errx(1, "Unable to load fixed %s section into bank $%02lX",
SECT_ATTRIBUTES[pSection->Type].name, pSection->nBank);
}
break;
default: // Handle other sections later
break;
}
}
pSection = pSection->pNext;
} }
/* /*
@@ -421,41 +430,9 @@ AssignSections(void)
* sections * sections
* *
*/ */
for (enum eSectionType i = SECT_MIN; i <= SECT_MAX; i++) {
pSection = pSections; AssignFloatingBankSections(i);
while (pSection) {
if (pSection->oAssigned == 0) {
switch (pSection->Type) {
case SECT_WRAM0:
case SECT_HRAM:
case SECT_ROM0:
pSection->nBank = SECT_ATTRIBUTES[pSection->Type].bank;
if ((pSection->nOrg =
area_Alloc(&BankFree[pSection->nBank],
pSection->nByteSize)) == -1) {
errx(1, "%s section too large", SECT_ATTRIBUTES[pSection->Type].name);
}
pSection->oAssigned = 1;
break;
case SECT_SRAM:
case SECT_VRAM:
case SECT_WRAMX:
case SECT_ROMX:
break;
default:
errx(1, "(INTERNAL) Unknown section type!");
break;
}
}
pSection = pSection->pNext;
} }
AssignBankedSections(SECT_ROMX);
AssignBankedSections(SECT_VRAM);
AssignBankedSections(SECT_WRAMX);
AssignBankedSections(SECT_SRAM);
} }
void void