Repository navigation
Description
I might submit a PR with support for SDX binaries, but I'd like to know your opinion about the scope first:
- Won't accept anyway, other assemblers can do it.
- Fast Assembler / MADS style
blkandsmbdirectives. Relatively easy with small diff surface, limited to SDX. - Emit llvm-mos-like ELF or obj65 first, add a linker with SDX target. May end up nice, or never finished rabbit hole.
- other?
Everything below this line will be updated as the spec is refined.
Summary
Add support for the SpartaDOS X binary format: relocatable code blocks, allocation blocks, symbol imports and exports, with type-checked relocation.
The work starts by moving object-file generation (block headers, gap filling, the trailer written at the end) out of the assembler core into one class per output format. SpartaDOS X is the first new class. ELF (llvm-mos conventions) and o65 are reserved names in this issue: the syntax, the value typing and the class interface are designed so that they can be added later as new classes only, without touching the directives or the evaluator.
Reference: SpartaDOS X Programming Guide V. 4.50, chapter 2 (file format), 3.4 (program extended area), 3.6 (memory indices), 19.1.3.1 (control byte).
opt 'output=spartadosx'
printf xrf 'PRINTF' ; import a system symbol
gets xrf 'GETS'
bufsz equ 32
rel 'text' ; relocatable block named TEXT, in main memory
hello xdf '@HELLO' ; export this location; @ makes it a shell command
jsr printf
dta c'Type your name: ',0
lda whov
ldx whov+1
ldy #bufsz
jsr gets
bmi quit
jsr printf
dta $9b,c'Hello, %s!',$9b,0
quit rts
whov dta a(who) ; relocated automatically
bss 'bss' ; allocation-only block named BSS
who org *+bufsz
Output settings
Depends on named opt settings (#23), the exact semantics may change.
opt 'output=ataridos' ; Atari DOS executable, $FFFF signature (default; opt h+)
opt 'output=raw' ; plain bytes, no headers (opt f-h-)
opt 'output=rom' ; plain bytes, gaps filled with $FF (opt f+h-)
opt 'output=spartadosx' ; SpartaDOS X executable, $FFFA absolute blocks, sections allowed, no short `opt` syntax
Format capabilities
| raw | rom | ataridos | spartadosx | elf (reserved) | o65 (reserved) | |
|---|---|---|---|---|---|---|
| absolute block signature | none | none | $FFFF |
$FFFA |
n/a | n/a |
| gap filling | legacy f+ |
$FF |
legacy f+ |
never | never | never |
rel/bss names |
error | error | error | any identifier; memory attribute main, extended, program |
ELF section name | text, data, bss, zero |
xrf/xdf names |
error | error | error | ≤8 chars, uppercased, space-padded | any, case kept | any, case kept |
run/ini, org a:/f: |
error | error | yes | yes; run fixed up, ini absolute only |
error | error |
mid-file o± |
yes (warning rule) | yes (warning rule) | yes (warning rule) | error | error | error |
| legacy equivalent | opt f-h- |
opt f+h- |
opt h+ |
none | none | none |
Under spartadosx, a run word gets a fixup when it points into a section. An ini address must be absolute; an address in a section or an imported symbol is an error (see SDX output).
Directives
Four directives, one string operand each: rel/bss open sections, xrf imports a symbol (XREF, $FFFB) and xdf exports one (XDEF, $FFFC). The operand is parsed with the opt rules: comma-separated items, case-insensitive keys, no spaces. The first item is positional; the rest are key or key=value. The operand is always required. As with every xasm directive, the number of operands is fixed, so there's no bare rel or bss.
| Directive | Meaning |
|---|---|
rel 'name[,attr,…]' |
Start a section that carries data, or reopen the section with that name. |
bss 'name[,attr,…]' |
Same, but allocation-only. No data may be emitted; reserve space with org *+n. |
label xrf 'NAME[,attr,…]' |
Import. label becomes a symbol-tagged value 0. |
[label] xdf 'NAME[,attr,…]' |
Export the current location under NAME. The label is optional, as on any line. |
All four are errors under raw, rom and ataridos. A label on a rel/bss line gets the section's current offset: 0 for a new section, the length so far for a reopened one.
Section names. The first item is the section's name. It's the key for reopening the section, in every format. The format parses it:
| Format | Name | Recommended |
|---|---|---|
| spartadosx | an identifier, read with readIdentifier: case-insensitive (Text and TEXT are the same section) |
text for rel, bss for bss, as in elf and o65 |
| elf | an ELF section name; . is allowed, e.g. .text, .rodata, .zp.bss |
.text, .bss |
| o65 | one of text, data, bss, zero |
text, bss |
Section names are a namespace of their own. They can't clash with labels or with xrf/xdf names.
Under spartadosx, each name is one $FFFE block:
- Numbering: blocks are numbered from 1 in the order their names first appear, with at most 7 blocks per file,
relandbsstogether (see "Loader behaviour"). The listing shows the block number on the line that opens the block, so a program that reads theEXTENDED+3table (guide 3.7) can rely on it. - Memory: the attribute
main($00, the default),extended($02) orprogram($04, SDX 4.47+). For example,rel 'drv,extended,align=256'gives control byte$42. - Reopening: it may repeat the attributes or leave them out (
rel 'text'). If it gives them, they must match the first opening. Using one name for both areland absssection is an error. A block that aniniflush has already written out can't be reopened; the error suggests using a new name. - Offsets: a reopened block continues at its current length.
*and labels count from the start of the block, whatever part of the source they are in.
This lets code and data from several included sources go into one text block and one bss block, without the included files knowing anything about block numbers.
Attributes:
| Attribute | On | spartadosx | elf | o65 |
|---|---|---|---|---|
main, extended, program |
rel, bss |
memory index $00, $02, $04; at most one; default main |
error | error |
align=N |
rel, bss |
only 256; sets $40 in the control byte (SDX 4.43+) |
section alignment | header alignment mode |
zp |
rel, bss |
error | zero-page section; implied by a .zp name prefix |
implied by zero; an error elsewhere |
weak |
xrf |
weak import (SDX 4.50+): bit 7 of the 8th name byte | weak undefined | error |
zp |
xrf |
error | 8-bit relocations | zero-segment reference |
weak |
xdf |
error | weak definition | error |
Any other name, attribute or value is an error. The guide (3.6) says SDX memory indices other than $00, $02 and $04 (plus $40) are reserved with undefined behaviour.
Symbol names under spartadosx: 1 to 8 characters. @ is allowed only as the first character. The other characters are the ones allowed in xasm labels. Names are uppercased and padded with spaces.
- An
xdfname exported twice is an error. - Several
xrflabels may import the same name; they share one$FFFBrecord. - An
xrfthat is never referenced writes no record and triggers the unused-label warning (opt u).
Activity
pfusik commentedon Sep 5, 2026
This is all black magic to me and Atariki is down. Educate me. :)
epi commentedon Sep 5, 2026
Binary format description: https://trub.atari8.info/sdx_files/4.41/sdx-programming.pdf
Key features:
MMMG's Fast Assembler was a 90s'-era assembler with a syntax being a superset of QA's, adding:
blkdirective that emits the various types of blocks.symthat declares imported symbols.dta v()for emitting relocatable addresses as dataDocumentation: https://github.com/HolgerJanz/FastAssembler/blob/main/FastAssembler.pdf
Some examples:
https://github.com/HolgerJanz/FastAssembler/blob/main/1.8/EXAMPLES/HI_SDX.ASM
https://github.com/HolgerJanz/FastAssembler/blob/main/1.8/EXAMPLES/TSR.ASM
I don't love that syntax, but:
so I'd vote for using the same syntax anyway.
pfusik commentedon Sep 8, 2026
Please do it! I don't like
blktaking two to four arguments depending on the unquoted first argument, but let's be compatible.epi commentedon Sep 15, 2026
On hold, because:
tgtmay reveal a better way to spell thisepi commentedon Sep 22, 2026
There are a few more things in FA and MADS (syntax and beyond) that make me want to deliberately avoid compatibility with their syntax.
The variable-length lists of unquoted arguments are foreign to xasm syntax.
Support for program extended area (
$04) (introduced in SDX 4.47) and page alignment (| $40) (SDX 4.43) isn't available in FA 1.8, and MADS offers it only via undocumented ELSA-style constant (blk reloc $44)FA doesn't allow allocating data in bss (
blk empty) segments, instead encouraging the weird idiom that assumes the bss would be allocated right after the code segment (which nothing in SDX documentation guarantees, and which is specifically false for page-aligned bss):Weak symbols (ones which the loader allows to be undefined on import instead of aborting, SDX 4.50's addition) aren't supported in FA 1.8, and MADS uses a syntax that's again a bit foreign to xasm (
smb 'FOO'^)All the
blksyntax quirks are modeled after SDX 4.22's file format, and would poorly extend to other relocatables, such as ELF or o65.There are more but I'm tired and I don't feel like explaining all of them.
So I'd reject
blkandsmb '...'^entirely, add a different set of directives, and require explicitly setting a relocatable format to enable them.I'll follow with a proposal in another comment.