Clarify the `align` statement and offer a helper macro
Rangi42 opened this issue · comments
People have repeatedly thought that align
will add sufficient ds
padding to cause realignment, as in:
align 8
dw 42069
align 8 ; this is an error, not a `ds 254` equivalent
This should be explicitly spelled out in the documentation, and offer a macro that will do what people want (since its internal math is non-trivial):
MACRO realign
ds ((1 << (\1)) - (@ & ((1 << (\1)) - 1))) & ((1 << (\1)) - 1)
align \1
ENDM
That expression, for example, boils down to ds (256 - (@ & 255)) & 255
for realign 8
.
align 8
dw 42069
realign 8 ; ds 254
The major caveat with this macro is that it only works if the section is already aligned enough! That could be worked around using alignof
(if that even exists... does it?), but then it might become too complicated.
Also, I think that align
inside the macro is redundant?
You can't realign without first aligning, so I think that's an acceptable limitation. You get an "Expected constant expression: PC is not constant at assembly time" error if this isn't done.
If somehow the ds
doesn't align properly, the align
will catch it.
You can realign without first sufficiently aligning:
align 7
dw 42069
realign 8 ; Should be `ds 126`, will instead complain about non compile-time expr!
...and the align
won't help much.
Hmm. This is making me think it should be a built-in keyword after all, with the ability to expand the current section's alignment if necessary.
The usual syntax bikeshedding may commence, then.
Users may be at least somewhat likely to have defined realign
for their own purposes as a macro or label, so how about a keyword re@__
? :3
Seriously: since this would be defining some amount of space, dalign
could be appropriate.
Perhaps ds_align
? Since what would be inserted is padding, like ds
(so that's immediately clear), and it ensures PC meets a certain alignment constraint (like align
).
Regarding the syntax, we'd probably want the grammar to be ds_align alignment [, offset [, values...]]
. It's annoying to require the offset when specifying values, but if we're using commas as the arg separator, that's necessary.
I don't like that grammar, because it's really two arg lists, yet they're separated the same as their own items... but it would be a necessary evil to play nice with \#
—though maybe that's moot, because you could(?) shift
the first two args first.
I'm fine with ds_align
like that. And I'd be surprised if anyone ever needs non-padding values
anyway.
Oh, wait: how about align alignment [, offset] ds [values...]
? This avoids introducing any new keywords, has a clear separator between the two arg lists, and is explicit about which arg list is what.
The only downside I see to it, is that the pseudo-ds
syntax there lacks the usual first "size" argument, and also in something like align 8, $80 ds
the ds
may not stand out much? This may be improved by requiring a comma before the ds
, I guess.
Eh, that looks to me like someone forgot to put a newline in their code (and runs the risk of someone actually doing that and silently getting a different effect).
To avoid a new keyword, we could do ds align
or align ds
instead of align_ds
. And to distinguish the argument lists, imitate section
declarations. Thus:
ds align[8]
ds align[8, 2]
ds align[8, 2], $aa, $bb, $cc
Then the align[]
stands in for the usual ds
byte quantity, and reads as "however many are required to align here".
Yeah, that sounds good. I was initially sceptical of requiring the brackets here, but if viewed (and presented) as "instead of a number of bytes, you write where you want to stop", then I think it should make plenty of sense!
Great! Also, just noting that this should do an align
assertion internally, so if it's the only alignment mechanism in the section it would still work. (That would mean, the first time rgbasm sees a ds align[N]
, absent any existing alignment, it would just do ds 0
and then align N
.)