Skip to content

assembler: cleanup, robustness, ATmega2560, .rept, data sections#9

Merged
begeistert merged 6 commits into
mainfrom
improve/assembler-cleanup-and-features
Jun 24, 2026
Merged

assembler: cleanup, robustness, ATmega2560, .rept, data sections#9
begeistert merged 6 commits into
mainfrom
improve/assembler-cleanup-and-features

Conversation

@begeistert

Copy link
Copy Markdown
Collaborator

Follow-up improvements after the RCALL/front-end fixes (#8). Stacked on #8 — base is fix/assembler-rcall-and-gcc-frontend; retarget to main once #8 merges.

Each item was validated with the same clean-room harness (our assembler vs avr-as/avr-gcc -Os -S, assembled and linked).

Maintainability

  • Removed ~1000 lines of dead, unwired code. PR AVR assembler: fix opcode bugs, add avr-as directive support, expression evaluator, and architectural improvements #6 added parallel encoder/directive modules that were never called — the live engine is still the legacy OpTable + inline directives in Assembler.cs. That duplication is what let the RCALL bug exist in one path while looking correct in another. Deleted Encoders/{Branch,Arithmetic,LoadStore,BitManip,Misc}Encoders.cs, DirectiveProcessor.cs, AssemblerContext.cs (0 external refs). This also consolidates register parsing onto a single path.

Robustness / DX

  • 1-based error line numbers. Diagnostics used the 0-based line index while the line table is 1-based — every message was off by one. Fixed all sites.
  • TryAssemble / AssembleOrThrow. Callers no longer have to distinguish "empty output" from "errors" via a side property; AssembleOrThrow raises AssemblerException carrying the messages.

Features

  • ATmega2560 device definition (178 symbols: ports A–L, USART0–3, timers 0–5, SPI/TWI/ADC/EEPROM, interrupts, clock/power). Addresses extracted verbatim from avr-libc <avr/iom2560.h>; extended-I/O accesses verified byte-identical to avr-as -mmcu=atmega2560.
  • . location-counter arithmetic (.+N / .-N) in relative branches — matches avr-as.
  • .rept N / .endr repeat blocks; composes with the existing \name / @n macro parameters.
  • Data segment (.data/.bss/.dseg/.section, .comm/.lcomm, .skip/.space/.zero). Data-segment labels get sequential SRAM addresses (allocator base 0x100) so lds/sts resolve global-data references. Addresses are self-consistent but not avr-gcc's linker-assigned ones.

Latent bugs found & fixed (surfaced by deferring LDS/STS for data forward-refs)

  • ElementSize concatenated a resolved 4-byte pair into a string, so a deferred 4-byte instruction (CALL/JMP/LDS/STS) as the last line was misread as 2 bytes.
  • _currentSymbolTable was nulled at the end of pass one, so forward-referenced address expressions (lds rN, sym+1) could not resolve in pass two. Restored at pass-two start.

Validation

All six avr-gcc -Os -S sample programs (GPIO, loops, arithmetic, functions, switch, bit ops, and a global-pointer program) assemble. 500 tests pass (+~30 new), no regressions.

Intentionally out of scope

  • libgcc relocations (call __mulhisi3, …): requires a real linker and the libgcc objects, which a flat code-image assembler for a simulator can't run anyway.

🤖 Generated with Claude Code

begeistert and others added 6 commits June 24, 2026 02:18
PR #6 introduced parallel encoder/directive modules but never wired them
into the live assembly path, which is still the legacy OpTable plus inline
directive handling in Assembler.cs. The duplication is what allowed the
RCALL offset bug to be correct in BranchEncoders.cs yet wrong in the live
OpTable.

Removed (0 external references, verified by grep across src/ and tests/):
- Encoders/{Branch,Arithmetic,LoadStore,BitManip,Misc}Encoders.cs
- DirectiveProcessor.cs
- AssemblerContext.cs

Kept (live): EncoderHelpers.cs (register parsing), Tokenizer.cs,
AssemblerIr.cs (SymbolTable/LabelTable/LineTablePassOne).

484 tests pass, no behaviour change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hrow

- Error messages used the 0-based line index (`Line {idx}`) while the line
  table is 1-based, so every diagnostic was off by one. All sites now report
  1-based line numbers. Updated the one test that pinned the old value.
- Add TryAssemble(input, out bytes, out errors) and AssembleOrThrow(input)
  so callers no longer have to distinguish "empty output" from "errors" by
  inspecting a side property. AssembleOrThrow raises AssemblerException, which
  carries the collected messages (snapshotted, not the live list).

Adds 5 tests. 488 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The simulator models the ATmega2560 (Arduino Mega) but `.device` only knew
ATmega328P and ATtiny85. Adds a full ATmega2560 register map (178 symbols:
ports A-L, USART0-3, timers 0-5, SPI, TWI, ADC, EEPROM, external/pin-change
interrupts, clock/power control) plus RAMEND/FLASHEND/E2END.

Addresses extracted verbatim from avr-libc <avr/iom2560.h> / iomxx0_1.h,
using the same convention as the existing definitions: low I/O (data < 0x60)
stored as the I/O address, extended I/O (>= 0x60) as the data-space address.
Extended-I/O accesses (sts UDR3/PORTL, lds TWBR) were verified byte-identical
to avr-as -mmcu=atmega2560.

Adds 4 tests. 492 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The tokenizer now emits a bare '.' as a current-PC token (reusing the Dollar
kind the expression evaluator already resolves), so relative branches accept
`.+N` / `.-N` operands. Verified byte-identical to avr-as: `rjmp .+2` => 01c0,
`rjmp .-2` => ffcf, `rcall .+4` => 02d0. Dotted directives/labels (.L2) are
unaffected (still tokenized as before).

Adds a test. 493 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GNU `.rept <count> ... .endr` blocks are recorded like a macro body and
injected <count> times. Composes with the existing \name / @n macro
parameter substitution (verified: a .rept around a \reg macro expands
correctly and matches avr-as for plain bodies). A stray .endr is reported
as an error. Note: \name and @n macro parameters were already supported;
this adds the repeat construct.

Adds 3 tests. 496 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… fixes

Adds a minimal SRAM data segment so avr-gcc programs that reference global
data assemble:
- .dseg/.data/.bss/.section .data|.bss switch to a data segment; .cseg/.text
  switch back. Labels in the data segment, and .comm/.lcomm NAME,SIZE, get
  sequential SRAM addresses from a simple allocator (base 0x100). Data
  directives (.byte/.word/...) and .skip/.space/.zero reserve space without
  emitting code. lds/sts then resolve these symbols.
  Addresses are self-consistent but are NOT avr-gcc's linker-assigned ones.

To support data symbols defined after their use (avr-gcc emits .data last),
LDS/STS now defer to pass two like CALL/JMP. Doing so surfaced two latent
bugs, both fixed here:
- ElementSize concatenated a resolved 4-byte KeyValuePair into a string, so a
  deferred 4-byte instruction as the LAST line was misread as 2 bytes
  (affected CALL/JMP too). Now keeps the pair.
- _currentSymbolTable was nulled at the end of pass one, so forward-referenced
  address *expressions* (`lds rN, sym+1`) could not resolve in pass two. It is
  now restored at the start of pass two.

Validated: all six avr-gcc -Os -S sample programs (including a global-pointer
one) now assemble. Adds 4 tests. 500 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying avr8sharp-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: e148ed9
Status: ✅  Deploy successful!
Preview URL: https://788d7193.avr8sharp-docs.pages.dev
Branch Preview URL: https://improve-assembler-cleanup-an.avr8sharp-docs.pages.dev

View logs

@begeistert begeistert changed the base branch from fix/assembler-rcall-and-gcc-frontend to main June 24, 2026 08:48
@begeistert begeistert merged commit c1d0440 into main Jun 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant