Allow specifying offset in addition to alignment

This commit is contained in:
ISSOtm
2020-04-08 00:40:41 +02:00
parent e82ad21704
commit b0ec8468e6
16 changed files with 154 additions and 44 deletions

View File

@@ -22,7 +22,8 @@ struct Section {
uint32_t size; uint32_t size;
uint32_t nOrg; uint32_t nOrg;
uint32_t nBank; uint32_t nBank;
uint32_t nAlign; uint8_t nAlign;
uint16_t alignOfs;
struct Section *pNext; struct Section *pNext;
struct Patch *pPatches; struct Patch *pPatches;
uint8_t *tData; uint8_t *tData;
@@ -30,7 +31,8 @@ struct Section {
struct SectionSpec { struct SectionSpec {
uint32_t bank; uint32_t bank;
uint32_t alignment; uint8_t alignment;
uint16_t alignOfs;
}; };
struct Section *out_FindSectionByName(const char *pzName); struct Section *out_FindSectionByName(const char *pzName);

View File

@@ -50,6 +50,7 @@ struct Section {
uint32_t bank; uint32_t bank;
bool isAlignFixed; bool isAlignFixed;
uint16_t alignMask; uint16_t alignMask;
uint16_t alignOfs;
uint8_t *data; /* Array of size `size`*/ uint8_t *data; /* Array of size `size`*/
uint32_t nbPatches; uint32_t nbPatches;
struct Patch *patches; struct Patch *patches;

View File

@@ -1425,6 +1425,7 @@ section : T_POP_SECTION sectunion string ',' sectiontype sectorg sectattrs {
sectunion : /* empty */ { $$ = false; } sectunion : /* empty */ { $$ = false; }
| T_POP_UNION { $$ = true; } | T_POP_UNION { $$ = true; }
;
sectiontype : T_SECT_WRAM0 { $$ = SECTTYPE_WRAM0; } sectiontype : T_SECT_WRAM0 { $$ = SECTTYPE_WRAM0; }
| T_SECT_VRAM { $$ = SECTTYPE_VRAM; } | T_SECT_VRAM { $$ = SECTTYPE_VRAM; }
@@ -1449,15 +1450,29 @@ sectorg : /* empty */ { $$ = -1; }
sectattrs : /* empty */ { sectattrs : /* empty */ {
$$.alignment = 0; $$.alignment = 0;
$$.alignOfs = 0;
$$.bank = -1; $$.bank = -1;
} }
| sectattrs ',' T_OP_ALIGN '[' uconst ']' { | sectattrs ',' T_OP_ALIGN '[' uconst ']' {
if ($5 < 0 || $5 > 16) if ($5 > 16)
yyerror("Alignment must be between 0 and 16 bits, not %u", yyerror("Alignment must be between 0 and 16, not %u",
$5); $5);
else else
$$.alignment = $5; $$.alignment = $5;
} }
| sectattrs ',' T_OP_ALIGN '[' uconst ',' uconst ']' {
if ($5 > 16) {
yyerror("Alignment must be between 0 and 16, not %u",
$5);
} else {
$$.alignment = $5;
if ($7 >= 1 << $$.alignment)
yyerror("Alignment offset must not be greater than alignment (%u < %u)",
$7, 1 << $$.alignment);
else
$$.alignOfs = $7;
}
}
| sectattrs ',' T_OP_BANK '[' uconst ']' { | sectattrs ',' T_OP_BANK '[' uconst ']' {
/* We cannot check the validity of this now */ /* We cannot check the validity of this now */
$$.bank = $5; $$.bank = $5;

View File

@@ -181,6 +181,7 @@ static void writesection(struct Section const *pSect, FILE *f)
fputlong(pSect->nOrg, f); fputlong(pSect->nOrg, f);
fputlong(pSect->nBank, f); fputlong(pSect->nBank, f);
fputc(pSect->nAlign, f); fputc(pSect->nAlign, f);
fputlong(pSect->alignOfs, f);
if (sect_HasData(pSect->nType)) { if (sect_HasData(pSect->nType)) {
fwrite(pSect->tData, 1, pSect->size, f); fwrite(pSect->tData, 1, pSect->size, f);

View File

@@ -85,9 +85,14 @@ struct Section *out_FindSectionByName(const char *pzName)
* Find a section by name and type. If it doesn't exist, create it * Find a section by name and type. If it doesn't exist, create it
*/ */
static struct Section *getSection(char const *pzName, enum SectionType type, static struct Section *getSection(char const *pzName, enum SectionType type,
uint32_t org, uint32_t bank, uint32_t org, struct SectionSpec const *attrs,
uint8_t alignment, bool isUnion) bool isUnion)
{ {
#define mask(align) ((1 << (align)) - 1)
uint32_t bank = attrs->bank;
uint8_t alignment = attrs->alignment;
uint16_t alignOffset = attrs->alignOfs;
if (bank != -1) { if (bank != -1) {
if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM
&& type != SECTTYPE_SRAM && type != SECTTYPE_WRAMX) && type != SECTTYPE_SRAM && type != SECTTYPE_WRAMX)
@@ -99,12 +104,18 @@ static struct Section *getSection(char const *pzName, enum SectionType type,
bankranges[type][0], bankranges[type][1]); bankranges[type][0], bankranges[type][1]);
} }
if (alignOffset >= 1 << alignment) {
yyerror("Alignment offset must not be greater than alignment (%u < %u)",
alignOffset, 1 << alignment);
alignOffset = 0;
}
if (alignment != 0) { if (alignment != 0) {
/* It doesn't make sense to have both set */ /* It doesn't make sense to have both alignment and org set */
uint32_t mask = (1 << alignment) - 1; uint32_t mask = mask(alignment);
if (org != -1) { if (org != -1) {
if (org & mask) if ((org - alignOffset) & mask)
yyerror("Section \"%s\"'s fixed address doesn't match its alignment", yyerror("Section \"%s\"'s fixed address doesn't match its alignment",
pzName); pzName);
alignment = 0; /* Ignore it if it's satisfied */ alignment = 0; /* Ignore it if it's satisfied */
@@ -153,32 +164,41 @@ static struct Section *getSection(char const *pzName, enum SectionType type,
if (sect_HasData(type)) if (sect_HasData(type))
fail("Cannot declare ROM sections as UNION"); fail("Cannot declare ROM sections as UNION");
if (org != -1) { if (org != -1) {
/* If neither is fixed, they must be the same */ /* If both are fixed, they must be the same */
if (pSect->nOrg != -1 && pSect->nOrg != org) if (pSect->nOrg != -1 && pSect->nOrg != org)
fail("Section \"%s\" already declared as fixed at different address $%x", fail("Section \"%s\" already declared as fixed at different address $%x",
pSect->pzName, pSect->nOrg); pSect->pzName, pSect->nOrg);
else if (pSect->nAlign != 0 else if (pSect->nAlign != 0
&& (((1 << pSect->nAlign) - 1) & org)) && (mask(pSect->nAlign)
fail("Section \"%s\" already declared as aligned to %u bytes", & (org - pSect->alignOfs)))
pSect->pzName, 1 << pSect->nAlign); fail("Section \"%s\" already declared as aligned to %u bytes (offset %u)",
pSect->pzName, 1 << pSect->nAlign,
pSect->alignOfs);
else else
/* Otherwise, just override */ /* Otherwise, just override */
pSect->nOrg = org; pSect->nOrg = org;
} else if (alignment != 0) { } else if (alignment != 0) {
/* Make sure any fixed address is compatible */ /* Make sure any fixed address is compatible */
if (pSect->nOrg != -1) { if (pSect->nOrg != -1) {
uint32_t mask = alignment - 1; if ((pSect->nOrg - alignOffset)
& mask(alignment))
if (pSect->nOrg & mask)
fail("Section \"%s\" already declared as fixed at incompatible address $%x", fail("Section \"%s\" already declared as fixed at incompatible address $%x",
pSect->pzName, pSect->pzName,
pSect->nOrg); pSect->nOrg);
/* Check if alignment offsets are compatible */
} else if ((alignOffset & mask(pSect->nAlign))
!= (pSect->alignOfs
& mask(alignment))) {
fail("Section \"%s\" already declared with incompatible %u-byte alignment (offset %u)",
pSect->pzName, pSect->nAlign,
pSect->alignOfs);
} else if (alignment > pSect->nAlign) { } else if (alignment > pSect->nAlign) {
/* /*
* If the section is not fixed, * If the section is not fixed,
* its alignment is the largest of both * its alignment is the largest of both
*/ */
pSect->nAlign = alignment; pSect->nAlign = alignment;
pSect->alignOfs = alignOffset;
} }
} }
/* If the section's bank is unspecified, override it */ /* If the section's bank is unspecified, override it */
@@ -239,6 +259,7 @@ static struct Section *getSection(char const *pzName, enum SectionType type,
pSect->nOrg = org; pSect->nOrg = org;
pSect->nBank = bank; pSect->nBank = bank;
pSect->nAlign = alignment; pSect->nAlign = alignment;
pSect->alignOfs = alignOffset;
pSect->pNext = pSectionList; pSect->pNext = pSectionList;
pSect->pPatches = NULL; pSect->pPatches = NULL;
@@ -261,6 +282,7 @@ static struct Section *getSection(char const *pzName, enum SectionType type,
pSectionList = pSect; pSectionList = pSect;
return pSect; return pSect;
#undef mask
} }
/* /*
@@ -280,13 +302,12 @@ static void setSection(struct Section *pSect)
* Set the current section by name and type * Set the current section by name and type
*/ */
void out_NewSection(char const *pzName, uint32_t type, uint32_t org, void out_NewSection(char const *pzName, uint32_t type, uint32_t org,
struct SectionSpec const *attributes, bool isUnion) struct SectionSpec const *attribs, bool isUnion)
{ {
if (currentLoadSection) if (currentLoadSection)
fatalerror("Cannot change the section within a `LOAD` block"); fatalerror("Cannot change the section within a `LOAD` block");
struct Section *pSect = getSection(pzName, type, org, attributes->bank, struct Section *pSect = getSection(pzName, type, org, attribs, isUnion);
attributes->alignment, isUnion);
setSection(pSect); setSection(pSect);
curOffset = isUnion ? 0 : pSect->size; curOffset = isUnion ? 0 : pSect->size;
@@ -297,15 +318,14 @@ void out_NewSection(char const *pzName, uint32_t type, uint32_t org,
* Set the current section by name and type * Set the current section by name and type
*/ */
void out_SetLoadSection(char const *name, uint32_t type, uint32_t org, void out_SetLoadSection(char const *name, uint32_t type, uint32_t org,
struct SectionSpec const *attributes) struct SectionSpec const *attribs)
{ {
checkcodesection(); checkcodesection();
if (currentLoadSection) if (currentLoadSection)
fatalerror("`LOAD` blocks cannot be nested"); fatalerror("`LOAD` blocks cannot be nested");
struct Section *pSect = getSection(name, type, org, attributes->bank, struct Section *pSect = getSection(name, type, org, attribs, false);
attributes->alignment, false);
loadOffset = curOffset; loadOffset = curOffset;
curOffset = 0; /* curOffset -= loadOffset; */ curOffset = 0; /* curOffset -= loadOffset; */

View File

@@ -132,7 +132,8 @@ static bool isLocationSuitable(struct Section const *section,
if (section->isAddressFixed && section->org != location->address) if (section->isAddressFixed && section->org != location->address)
return false; return false;
if (section->isAlignFixed && location->address & section->alignMask) if (section->isAlignFixed
&& ((location->address - section->alignOfs) & section->alignMask))
return false; return false;
if (location->address < freeSpace->address) if (location->address < freeSpace->address)
@@ -183,8 +184,13 @@ static struct FreeSpace *getPlacement(struct Section const *section,
space = NULL; space = NULL;
} else if (section->isAlignFixed) { } else if (section->isAlignFixed) {
/* Move to next aligned location */ /* Move to next aligned location */
/* Move back to alignment boundary */
location->address -= section->alignOfs;
/* Ensure we're there (e.g. on first check) */
location->address &= ~section->alignMask; location->address &= ~section->alignMask;
location->address += section->alignMask + 1; /* Go to next align boundary and add offset */
location->address += section->alignMask + 1
+ section->alignOfs;
} else { } else {
/* Any location is fine, so, next free block */ /* Any location is fine, so, next free block */
space = space->next; space = space->next;
@@ -309,8 +315,8 @@ static void placeSection(struct Section *section)
if (section->isAddressFixed) if (section->isAddressFixed)
snprintf(where, 64, "at address $%04x", section->org); snprintf(where, 64, "at address $%04x", section->org);
else if (section->isAlignFixed) else if (section->isAlignFixed)
snprintf(where, 64, "with align mask %x", snprintf(where, 64, "with align mask %x and offset %u",
~section->alignMask); ~section->alignMask, section->alignOfs);
else else
strcpy(where, "anywhere"); strcpy(where, "anywhere");
} }

View File

@@ -255,7 +255,7 @@ static void readSection(FILE *file, struct Section *section,
char const *fileName, struct Section *fileSections[]) char const *fileName, struct Section *fileSections[])
{ {
int32_t tmp; int32_t tmp;
uint8_t type; uint8_t byte;
tryReadstr(section->name, file, "%s: Cannot read section name: %s", tryReadstr(section->name, file, "%s: Cannot read section name: %s",
fileName); fileName);
@@ -265,24 +265,34 @@ static void readSection(FILE *file, struct Section *section,
errx(1, "\"%s\"'s section size (%d) is invalid", section->name, errx(1, "\"%s\"'s section size (%d) is invalid", section->name,
tmp); tmp);
section->size = tmp; section->size = tmp;
tryGetc(type, file, "%s: Cannot read \"%s\"'s type: %s", tryGetc(byte, file, "%s: Cannot read \"%s\"'s type: %s",
fileName, section->name); fileName, section->name);
section->type = type & 0x7F; section->type = byte & 0x7F;
section->isUnion = type >> 7; section->isUnion = byte >> 7;
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s org: %s", tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s org: %s",
fileName, section->name); fileName, section->name);
section->isAddressFixed = tmp >= 0; section->isAddressFixed = tmp >= 0;
if (tmp > UINT16_MAX) if (tmp > UINT16_MAX) {
errx(1, "\"%s\"'s org' is too large (%d)", section->name, tmp); error("\"%s\"'s org is too large (%d)", section->name, tmp);
tmp = UINT16_MAX;
}
section->org = tmp; section->org = tmp;
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s bank: %s", tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s bank: %s",
fileName, section->name); fileName, section->name);
section->isBankFixed = tmp >= 0; section->isBankFixed = tmp >= 0;
section->bank = tmp; section->bank = tmp;
tryGetc(tmp, file, "%s: Cannot read \"%s\"'s alignment: %s", tryGetc(byte, file, "%s: Cannot read \"%s\"'s alignment: %s",
fileName, section->name); fileName, section->name);
section->isAlignFixed = tmp != 0; section->isAlignFixed = byte != 0;
section->alignMask = (1 << tmp) - 1; section->alignMask = (1 << byte) - 1;
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s alignment offset: %s",
fileName, section->name);
if (tmp > UINT16_MAX) {
error("\"%s\"'s alignment offset is too large (%d)",
section->name, tmp);
tmp = UINT16_MAX;
}
section->alignOfs = tmp;
if (sect_HasData(section->type)) { if (sect_HasData(section->type)) {
/* Ensure we never allocate 0 bytes */ /* Ensure we never allocate 0 bytes */

View File

@@ -48,21 +48,28 @@ static void mergeSections(struct Section *target, struct Section *other)
errx(1, "Section \"%s\" is defined with conflicting addresses $%x and $%x", errx(1, "Section \"%s\" is defined with conflicting addresses $%x and $%x",
other->name, target->org, other->org); other->name, target->org, other->org);
} else if (target->isAlignFixed) { } else if (target->isAlignFixed) {
if (other->org & target->alignMask) if ((other->org - target->alignOfs) & target->alignMask)
errx(1, "Section \"%s\" is defined with conflicting %u-byte alignment and address $%x", errx(1, "Section \"%s\" is defined with conflicting %u-byte alignment (offset %u) and address $%x",
other->name, target->alignMask + 1, other->name, target->alignMask + 1,
other->org); target->alignOfs, other->org);
} }
target->isAddressFixed = true; target->isAddressFixed = true;
target->org = other->org; target->org = other->org;
} else if (other->isAlignFixed) { } else if (other->isAlignFixed) {
if (target->isAddressFixed) { if (target->isAddressFixed) {
if (target->org & other->alignMask) if ((target->org - other->alignOfs) & other->alignMask)
errx(1, "Section \"%s\" is defined with conflicting address $%x and %u-byte alignment", errx(1, "Section \"%s\" is defined with conflicting address $%x and %u-byte alignment (offset %u)",
other->name, target->org, other->name, target->org,
other->alignMask + 1); other->alignMask + 1, other->alignOfs);
} else if (target->isAlignFixed
&& (other->alignMask & target->alignOfs)
!= (target->alignMask & other->alignOfs)) {
errx(1, "Section \"%s\" is defined with conflicting %u-byte alignment (offset %u) and %u-byte alignment (offset %u)",
other->name, target->alignMask + 1,
target->alignOfs, other->alignMask + 1,
other->alignOfs);
} else if (!target->isAlignFixed } else if (!target->isAlignFixed
|| other->alignMask > target->alignMask) { || (other->alignMask > target->alignMask)) {
target->isAlignFixed = true; target->isAlignFixed = true;
target->alignMask = other->alignMask; target->alignMask = other->alignMask;
} }

View File

@@ -94,6 +94,9 @@ REPT NumberOfSections
BYTE Align ; Alignment of this section, as N bits. 0 when not specified. BYTE Align ; Alignment of this section, as N bits. 0 when not specified.
LONG Ofs ; Offset relative to the alignment specified above.
; Must be below 1 << Align.
IF (Type == ROMX) || (Type == ROM0) ; Sections that can contain data. IF (Type == ROMX) || (Type == ROM0) ; Sections that can contain data.
BYTE Data[Size] ; Raw data of the section. BYTE Data[Size] ; Raw data of the section.

View File

@@ -1,6 +1,6 @@
error: Section "conflicting alignment" is defined with conflicting 4-byte alignment and address $cafe error: Section "conflicting alignment" is defined with conflicting 4-byte alignment (offset 0) and address $cafe
--- ---
ERROR: -(18): ERROR: -(18):
Section "conflicting alignment" already declared as aligned to 4 bytes Section "conflicting alignment" already declared as aligned to 4 bytes (offset 0)
ERROR: -(18): ERROR: -(18):
Cannot create section "conflicting alignment" (1 errors) Cannot create section "conflicting alignment" (1 errors)

View File

@@ -0,0 +1,10 @@
IF !DEF(SECOND)
ATTRS equs ",ALIGN[3,7]"
ELSE
ATTRS equs ",ALIGN[4,14]"
ENDC
SECTION UNION "conflicting alignment", WRAM0 ATTRS
db
PURGE ATTRS

View File

@@ -0,0 +1,6 @@
error: Section "conflicting alignment" is defined with conflicting 8-byte alignment (offset 7) and 16-byte alignment (offset 14)
---
ERROR: -(18):
Section "conflicting alignment" already declared with incompatible 3-byte alignment (offset 7)
ERROR: -(18):
Cannot create section "conflicting alignment" (1 errors)

View File

@@ -0,0 +1,10 @@
IF !DEF(SECOND)
ATTRS equs ",ALIGN[3,7]"
ELSE
ATTRS equs ",ALIGN[3,6]"
ENDC
SECTION UNION "conflicting alignment", WRAM0 ATTRS
db
PURGE ATTRS

View File

@@ -0,0 +1,6 @@
error: Section "conflicting alignment" is defined with conflicting 8-byte alignment (offset 7) and 8-byte alignment (offset 6)
---
ERROR: -(18):
Section "conflicting alignment" already declared with incompatible 3-byte alignment (offset 7)
ERROR: -(18):
Cannot create section "conflicting alignment" (1 errors)

View File

@@ -11,6 +11,11 @@ SECTION UNION "c", HRAM[$FFC0]
ds 5 ds 5
c1:: c1::
SECTION UNION "d", SRAM,ALIGN[8,$BA]
d1::
SECTION UNION "e", SRAM[$BABE]
SECTION "output 1", ROM0 SECTION "output 1", ROM0
dw a1,a2 ; $C00A, $C02A dw a1,a2 ; $C00A, $C02A
@@ -19,3 +24,4 @@ SECTION "output 1", ROM0
SECTION "output 3", ROM0 SECTION "output 3", ROM0
db BANK(banked) db BANK(banked)
dw d1,d2 ; $ABBA, $BBBA

View File

@@ -12,6 +12,13 @@ b1: ; Same but in different sections now
ds 5 ds 5
c2:: c2::
SECTION UNION "d", SRAM,ALIGN[12,$BBA]
ds $1000
d2::
SECTION UNION "e", SRAM,ALIGN[8,$BE]
SECTION "output 2", ROM0 SECTION "output 2", ROM0
dw a1,a2 dw a1,a2
dw b1,b2 dw b1,b2