mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-22 11:12:07 +00:00
Implement ds align[alignment, offset] (#1181)
This commit is contained in:
@@ -503,6 +503,7 @@ enum {
|
||||
struct SectionSpec sectSpec;
|
||||
struct MacroArgs *macroArg;
|
||||
enum AssertionType assertType;
|
||||
struct DsAlignment dsAlign;
|
||||
struct DsArgList dsArgs;
|
||||
struct PurgeArgList purgeArgs;
|
||||
struct {
|
||||
@@ -660,6 +661,7 @@ enum {
|
||||
%type <sectMod> sectmod
|
||||
%type <macroArg> macroargs
|
||||
|
||||
%type <dsAlign> ds_align
|
||||
%type <dsArgs> ds_args
|
||||
|
||||
%type <purgeArgs> purge_args
|
||||
@@ -1194,6 +1196,40 @@ ds : T_POP_DS uconst { sect_Skip($2, true); }
|
||||
sect_RelBytes($2, $4.args, $4.nbArgs);
|
||||
freeDsArgList(&$4);
|
||||
}
|
||||
| T_POP_DS ds_align trailing_comma {
|
||||
uint32_t n = sect_GetAlignBytes($2.alignment, $2.alignOfs);
|
||||
|
||||
sect_Skip(n, true);
|
||||
sect_AlignPC($2.alignment, $2.alignOfs);
|
||||
}
|
||||
| T_POP_DS ds_align T_COMMA ds_args trailing_comma {
|
||||
uint32_t n = sect_GetAlignBytes($2.alignment, $2.alignOfs);
|
||||
|
||||
sect_RelBytes(n, $4.args, $4.nbArgs);
|
||||
sect_AlignPC($2.alignment, $2.alignOfs);
|
||||
freeDsArgList(&$4);
|
||||
}
|
||||
;
|
||||
|
||||
ds_align : T_OP_ALIGN T_LBRACK uconst T_RBRACK {
|
||||
if ($3 > 16) {
|
||||
error("Alignment must be between 0 and 16, not %u\n", $3);
|
||||
} else {
|
||||
$$.alignment = $3;
|
||||
$$.alignOfs = 0;
|
||||
}
|
||||
}
|
||||
| T_OP_ALIGN T_LBRACK uconst T_COMMA uconst T_RBRACK {
|
||||
if ($3 > 16) {
|
||||
error("Alignment must be between 0 and 16, not %u\n", $3);
|
||||
} else if ($5 >= 1 << $3) {
|
||||
error("Offset must be between 0 and %u, not %u\n",
|
||||
(1 << $3) - 1, $5);
|
||||
} else {
|
||||
$$.alignment = $3;
|
||||
$$.alignOfs = $5;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
ds_args : reloc_8bit {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
@@ -471,6 +472,27 @@ uint32_t sect_GetOutputOffset(void)
|
||||
return curOffset + loadOffset;
|
||||
}
|
||||
|
||||
// Returns how many bytes need outputting for the specified alignment and offset to succeed
|
||||
uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset)
|
||||
{
|
||||
struct Section *sect = sect_GetSymbolSection();
|
||||
if (!sect)
|
||||
return 0;
|
||||
|
||||
bool isFixed = sect->org != (uint32_t)-1;
|
||||
|
||||
// If the section is not aligned, no bytes are needed
|
||||
// (fixed sections count as being maximally aligned for this purpose)
|
||||
uint8_t curAlignment = isFixed ? 16 : sect->align;
|
||||
if (curAlignment == 0)
|
||||
return 0;
|
||||
|
||||
// We need `(pcValue + curOffset + return value) % (1 << alignment) == offset`
|
||||
uint16_t pcValue = isFixed ? sect->org : sect->alignOfs;
|
||||
return static_cast<uint16_t>(offset - curOffset - pcValue)
|
||||
% (1u << std::min(alignment, curAlignment));
|
||||
}
|
||||
|
||||
void sect_AlignPC(uint8_t alignment, uint16_t offset)
|
||||
{
|
||||
if (!checksection())
|
||||
@@ -480,20 +502,16 @@ void sect_AlignPC(uint8_t alignment, uint16_t offset)
|
||||
uint16_t alignSize = 1 << alignment; // Size of an aligned "block"
|
||||
|
||||
if (sect->org != (uint32_t)-1) {
|
||||
if ((sym_GetPCValue() - offset) % alignSize)
|
||||
if ((sect->org + curOffset - offset) % alignSize)
|
||||
error("Section's fixed address fails required alignment (PC = $%04" PRIx32
|
||||
")\n", sym_GetPCValue());
|
||||
} else if (sect->align != 0) {
|
||||
if ((((sect->alignOfs + curOffset) % (1 << sect->align)) - offset) % alignSize) {
|
||||
error("Section's alignment fails required alignment (offset from section start = $%04"
|
||||
PRIx32 ")\n", curOffset);
|
||||
} else if (alignment > sect->align) {
|
||||
sect->align = alignment;
|
||||
sect->alignOfs = (offset - curOffset) % alignSize;
|
||||
}
|
||||
} else {
|
||||
")\n", sect->org + curOffset);
|
||||
} else if (sect->align != 0 && (((sect->alignOfs + curOffset) % (1u << sect->align))
|
||||
- offset) % alignSize) {
|
||||
error("Section's alignment fails required alignment (offset from section start = $%04"
|
||||
PRIx32 ")\n", curOffset);
|
||||
} else if (alignment > sect->align) {
|
||||
sect->align = alignment;
|
||||
// We need `(sect->alignOfs + curOffset) % alignSize == offset
|
||||
// We need `(sect->alignOfs + curOffset) % alignSize == offset`
|
||||
sect->alignOfs = (offset - curOffset) % alignSize;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user