Skip to content

Commit

Permalink
Implement ds align[alignment, offset]
Browse files Browse the repository at this point in the history
  • Loading branch information
Rangi42 committed Oct 28, 2023
1 parent 84f3cb4 commit 13bc757
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 12 deletions.
5 changes: 5 additions & 0 deletions include/asm/lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ int yylex(void);
bool lexer_CaptureRept(struct CaptureBody *capture);
bool lexer_CaptureMacroBody(struct CaptureBody *capture);

struct DsAlignment {
uint8_t alignment;
uint16_t alignOfs;
};

#define INITIAL_DS_ARG_SIZE 2
struct DsArgList {
size_t nbArgs;
Expand Down
1 change: 1 addition & 0 deletions include/asm/section.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ void sect_EndLoadSection(void);
struct Section *sect_GetSymbolSection(void);
uint32_t sect_GetSymbolOffset(void);
uint32_t sect_GetOutputOffset(void);
uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset);
void sect_AlignPC(uint8_t alignment, uint16_t offset);

void sect_StartUnion(void);
Expand Down
26 changes: 23 additions & 3 deletions man/rgbasm.5
Original file line number Diff line number Diff line change
Expand Up @@ -647,8 +647,8 @@ is a shorthand for
.Ic ALIGN Ns Bq Ar align , No 0 ) .
This option can be used with
.Bq Ar addr ,
as long as they don't contradict eachother.
It's also possible to request alignment in the middle of a section, see
as long as they don't contradict each other.
It's also possible to request alignment in the middle of a section; see
.Sx Requesting alignment
below.
.El
Expand Down Expand Up @@ -824,7 +824,7 @@ or
.Ic ROMX .
.El
.Pp
Different declarations of the same unionized section are not appended, but instead overlaid on top of eachother, just like
Different declarations of the same unionized section are not appended, but instead overlaid on top of each other, just like
.Sx Unions .
Similarly, the size of an unionized section is the largest of all its declarations.
.Ss Section fragments
Expand Down Expand Up @@ -1398,6 +1398,16 @@ In ROM sections, it will be filled with the value passed to the
.Fl p
command-line option, except when using overlays with
.Fl O .
.Pp
Instead of a specific number of bytes, you can specify
.Ic DS ALIGN Ns Bq Ar align , offset
to allocate however many bytes are required to align the subsequent data; see
.Sx Requesting alignment
below.
(Note that
.Ic ALIGN Ns Bq Ar align
is a shorthand for
.Ic ALIGN Ns Bq Ar align , No 0 ) .
.Ss Defining constant data in ROM
.Ic DB
defines a list of bytes that will be stored in the final image.
Expand Down Expand Up @@ -2102,6 +2112,16 @@ Note that
.Ic ALIGN Ar align
is a shorthand for
.Ic ALIGN Ar align , No 0 .
.Pp
There may be times when you don't just want to specify an alignment constraint at the current location, but also skip ahead until the constraint can be satisfied. In that case, you can use
.Ic DS ALIGN Ns Bq Ar align , offset
to allocate however many bytes are required to align the subsequent data.
.Pp
If the constraint cannot be met by skipping any amount of space, an error is produced.
Note that
.Ic ALIGN Ns Bq Ar align
is a shorthand for
.Ic ALIGN Ns Bq Ar align , No 0 .
.Sh SEE ALSO
.Xr rgbasm 1 ,
.Xr rgblink 1 ,
Expand Down
36 changes: 36 additions & 0 deletions src/asm/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ enum {
struct SectionSpec sectSpec;
struct MacroArgs *macroArg;
enum AssertionType assertType;
struct DsAlignment dsAlign;
struct DsArgList dsArgs;
struct PurgeArgList purgeArgs;
struct {
Expand Down Expand Up @@ -664,6 +665,7 @@ enum {
%type <sectMod> sectmod
%type <macroArg> macroargs

%type <dsAlign> ds_align
%type <dsArgs> ds_args

%type <purgeArgs> purge_args
Expand Down Expand Up @@ -1169,6 +1171,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 {
Expand Down
29 changes: 20 additions & 9 deletions src/asm/section.c
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,21 @@ 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 the section is undefined, or not fixed and not aligned, no bytes are needed
if (!sect || (sect->org == (uint32_t)-1 && sect->align == 0))
return 0;

uint32_t pcValue = sect->org != (uint32_t)-1 ? sym_GetPCValue() : sect->align != 0
? (sect->alignOfs + curOffset) % (1 << sect->align) : 0;
// We need `(pcValue + return value) % (1 << alignment) == offset
return (offset - pcValue) % (1 << alignment);
}

void sect_AlignPC(uint8_t alignment, uint16_t offset)
{
if (!checksection())
Expand All @@ -489,15 +504,11 @@ void sect_AlignPC(uint8_t alignment, uint16_t offset)
if ((sym_GetPCValue() - 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 {
} else if (sect->align != 0 && (((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;
// We need `(sect->alignOfs + curOffset) % alignSize == offset
sect->alignOfs = (offset - curOffset) % alignSize;
Expand Down
22 changes: 22 additions & 0 deletions test/asm/ds-align.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
SECTION "aligned", ROM0, ALIGN[8]
db 1, 2, 3, 4, 5 ; five
ds align[8, $ff], 6 ; (1 << 8) - five - one = 250 bytes
db 7 ; one
align 8

SECTION "fixed", ROM0[$100]
ds align[2] ; already aligned, 0 bytes
db 8, 9, 10
ds align[4, $e], 11 ; (1 << 4) - three - two = 11 bytes
db 12, 13 ; two
align 4

SECTION "floating", ROM0
db 14, 15 ; two
ds align[4] ; not aligned, 0 bytes
align 4
db 16, 17, 18 ; three
align 4, 3
ds align[5], 19, 20 ; (1 << 5) - three = 29 bytes
db 21 ; one
align 5, 1
Empty file added test/asm/ds-align.err
Empty file.
Empty file added test/asm/ds-align.out
Empty file.

0 comments on commit 13bc757

Please sign in to comment.