gbdev / rgbds

Rednex Game Boy Development System - An assembly toolchain for the Nintendo Game Boy and Game Boy Color

Home Page:https://rgbds.gbdev.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.)