Using it

Reading a binary back

asm198x disasm turns bytes into source. It works for every dialect, and it writes in that dialect’s own syntax — so what comes out is something you can feed back in.

A worked example

* = $c000
screen = $0400
fill:
        lda #$51
        ldx #$00
loop:   sta screen,x
        inx
        bne loop
        rts

Assembled, then read back with asm198x disasm -d acme --org 0xc000 fill.a.bin:

        *= $C000
        LDA #$51
        LDX #$00
        STA $0400,X
        INX
        BNE $C004
        RTS

Labels and symbol names are gone, because they were never in the file — screen and loop lived in the assembler, not in the bytes. What survives is what the CPU sees.

--org is not cosmetic

A flat binary is bytes and nothing else: it carries no record of where it was meant to live. --org supplies that, and it changes what the listing says:

        *= $0000
        LDA #$51
        LDX #$00
        STA $0400,X
        INX
        BNE $0004
        RTS

The instructions are identical — the same bytes decode the same way — but the BNE target moved. A branch encodes a relative displacement, so its printed destination depends entirely on where you say the code starts. Read a C64 program at $0000 and every branch target in it is wrong by $C000.

Absolute operands do not move: STA $0400,X reads the same either way, because $0400 is in the instruction. It is the relative ones that need you to be right.

Bytes that are not instructions

Data does not announce itself. The disassembler decodes what it can and emits the rest as data, in the dialect’s syntax:

* = $c000
        lda #$51
        !byte $ff
        !byte $02
        rts
        *= $C000
        LDA #$51
        !byte $FF
        !byte $02
        RTS

$FF is not a 6502 opcode, so it comes out as !byte. That is a disassembly rather than a failure — but it is also the tell that you are reading a table, a sprite or a string as though it were code. If a run of !byte appears where you expected instructions, the origin is probably right and the boundary is wrong.

It reassembles

Feeding the listing back to the assembler produces the byte-for-byte original. That is what makes the output worth trusting, not just reading:

asm198x --dialect acme fill.a -o original.bin
asm198x disasm --dialect acme --org 0xc000 original.bin > back.a
asm198x --dialect acme back.a -o again.bin
cmp original.bin again.bin && echo identical

The same round trip runs in the conformance suite against the reference assemblers, which is where the disassembler’s correctness is established — see Why asm198x.

Picking the CPU

disasm takes the CPU from --dialect: a 6502 dialect disassembles as 6502, and anything else defaults to Z80. Pass -d when the default is wrong, or --cpu to name a chip directly with no dialect at all.