diff --git a/include/asm/section.h b/include/asm/section.h index 3fb4d035..8e4f49e6 100644 --- a/include/asm/section.h +++ b/include/asm/section.h @@ -44,6 +44,7 @@ void out_EndLoadSection(void); struct Section *sect_GetSymbolSection(void); uint32_t sect_GetOutputOffset(void); +void sect_AlignPC(uint8_t alignment, uint16_t offset); void out_AbsByte(uint8_t b); void out_AbsByteGroup(uint8_t const *s, int32_t length); diff --git a/src/asm/asmy.y b/src/asm/asmy.y index b42a17ad..0d8db329 100644 --- a/src/asm/asmy.y +++ b/src/asm/asmy.y @@ -774,6 +774,26 @@ simple_pseudoop : include | popo | pusho | opt + | align +; + +align : T_OP_ALIGN uconst { + if ($2 > 16) + yyerror("Alignment must be between 0 and 16, not %u", + $2); + else + sect_AlignPC($2, 0); + } + | T_OP_ALIGN uconst ',' uconst { + if ($2 > 16) + yyerror("Alignment must be between 0 and 16, not %u", + $2); + else if ($4 >= 1 << $2) + yyerror("Offset must be between 0 and %u, not %u", + (1 << $2) - 1, $4); + else + sect_AlignPC($2, $4); + } ; opt : T_POP_OPT { diff --git a/src/asm/section.c b/src/asm/section.c index 11653ff0..30a9b4be 100644 --- a/src/asm/section.c +++ b/src/asm/section.c @@ -354,6 +354,28 @@ uint32_t sect_GetOutputOffset(void) return curOffset + loadOffset; } +void sect_AlignPC(uint8_t alignment, uint16_t offset) +{ + struct Section *sect = sect_GetSymbolSection(); + + if (sect->nOrg != -1) { + if ((sym_GetValue(pPCSymbol) - offset) % (1 << alignment)) + yyerror("Section's fixed address fails required alignment (PC = $%04x)", + sym_GetValue(pPCSymbol)); + } else if (sect->nAlign != 0) { + if ((((sect->alignOfs + curOffset) % (1 << sect->nAlign)) - offset) % (1 << alignment)) { + yyerror("Section's alignment fails required alignment (offset from section start = $%04x)", + curOffset); + } else if (alignment > sect->nAlign) { + sect->nAlign = alignment; + sect->alignOfs = (offset - curOffset) % (1 << alignment); + } + } else { + sect->nAlign = alignment; + sect->alignOfs = offset; + } +} + static inline void growSection(uint32_t growth) { curOffset += growth; diff --git a/test/asm/align-pc.asm b/test/asm/align-pc.asm new file mode 100644 index 00000000..b197d81d --- /dev/null +++ b/test/asm/align-pc.asm @@ -0,0 +1,22 @@ +SECTION "fixed org", SRAM[$BEAD] + ds 42 + static_assert @ == $BED7 + align 5,$17 + + +; Should land at $0001 +SECTION "align", ROM0,ALIGN[1,1] + db 69 + align 1 ; This wants to go at $0000, $0002, $0004... + + +; Should land at $0003 +SECTION "under-aligned", ROM0,ALIGN[1,1] + dw $BEEF + align 2,1 ; This wants to go at $0001, $0005, $0009... + + +; Should land at $0005 +SECTION "forced align", ROM0 + dw $DEAD + align 2,3 ; This wants to go at $0003, $0007, $000B... diff --git a/test/asm/align-pc.err b/test/asm/align-pc.err new file mode 100644 index 00000000..e69de29b diff --git a/test/asm/align-pc.out b/test/asm/align-pc.out new file mode 100644 index 00000000..e69de29b diff --git a/test/asm/align-pc.out.bin b/test/asm/align-pc.out.bin new file mode 100644 index 00000000..e69de29b