Oliver VieBrooks

6asm / 6asm manual

Contents

6asm

A 6502 cross-assembler written in C# / .NET 8. Supports NMOS 6502 official and undocumented opcodes with multi-pass assembly, macro expansion, conditional assembly, and tmpx/ACME/DASM-compatible syntax.

Usage

6asm [options] <input.asm>

Options

Flag Description
-h, --help Show help message
-v, --version Show version
-o, --output FILE Output file name (default: input with .prg extension)
-f, --format FORMAT Output format: bin, hex, srec (default: bin)
-s, --symbols Generate symbol file (.sym)
--symbol-file FILE Explicit symbol file path
--list Generate listing file (.lst)
--list-file FILE Explicit listing file path
--vice Generate VICE monitor symbol file (.lbl)
--vice-file FILE VICE symbol file path
--analyze Suggest peephole optimizations (illegal opcodes, dead code)
-q, --quiet Suppress output messages
--verbose Show detailed pass/symbol information
--max-passes N Maximum assembly passes (default: 10)
-fillbyte=0xNN Fill byte for address gaps (default: 0x00)
--endkeyword Treat END as a directive that stops assembly

Examples

6asm game.asm                         # Assemble to game.prg
6asm -o out.prg game.asm              # Explicit output file
6asm -f hex -s game.asm               # Intel HEX output with symbol file
6asm -fillbyte=0xFF game.asm          # Fill gaps with $FF
6asm --list game.asm                  # Generate listing file

Output Formats

Format Extension Description
bin .prg Raw binary with 2-byte load address header (C64 PRG)
hex .hex Intel HEX
srec .s19 Motorola S-Record
d64 .d64 D64 disk image containing the PRG as a single file
crt .crt CRT cartridge image (8K or 16K normal cartridge)

Assembly Syntax

Line Format

[label[:]]  [mnemonic/directive]  [operand]  [; comment]

Labels

start       lda #0          ; column 1 label (no colon needed)
loop:       inx             ; label with colon (any column)
SCREEN = $0400              ; constant assignment (EQU shorthand)
BORDER      .equ $d020      ; explicit constant
@local      dex             ; local label (scoped)

Number Formats

Prefix Base Example
$ Hexadecimal $FF, $D020
0x Hexadecimal 0xFF, 0x1234
% Binary %10110011, %1010_0011
@ Octal @377
(none) Decimal 255
'c' Character 'A', '\n'

Binary literals accept _ as a visual separator.


Expression Operators

Expressions are evaluated with standard mathematical operator precedence (highest precedence binds tightest).

Precedence Table (lowest to highest)

Level Operators Description
1 = == != <> < > <= >= Comparison (result: 0 or 1)
2 \|\| .OR. Logical OR
3 && .AND. Logical AND
4 \| Bitwise OR
5 ^ .XOR. Bitwise XOR
6 & Bitwise AND
7 << >> Bit shift left/right
8 + - Addition, subtraction
9 * / % .MOD. Multiplication, division, modulo
10 - + ~ ! < > ^ .NOT. Unary: negate, identity, complement, not, lo byte, hi byte, bank byte
11 (primary) Numbers, symbols, (expr), *, .

Special Symbols

Symbol Meaning
* Current program counter (in expressions)
. Current program counter (alternate)

Lo/Hi Byte Operators

    lda #<address       ; low byte of address
    lda #>address       ; high byte of address
    lda #^address       ; bank byte (bits 16-23)

String Escape Sequences

Quoted strings in directives (.text, .byte, .screen, etc.) support the following escapes:

Escape Result
\n Newline ($0A)
\r Carriage return ($0D)
\t Tab ($09)
\0 Null ($00)
\\ Literal backslash
{$XX} Hex byte value (e.g., {$24} emits $)
{name} Named PETSCII control/color code (e.g., {white}, {rvson})

The {$XX} escape allows embedding arbitrary byte values inline within strings. This is useful for characters that are difficult to type or have special meaning in the assembler:

    .screen "@@@2026{$24}02{$24}28@@@"   ; $ signs via hex escape (16 bytes)
    .text "Line1{$0D}Line2"               ; embedded carriage return
    .byte "{$00}"                          ; null byte in a string context

Named PETSCII Codes

For SEQ-file-style text, PETSCII control and color codes can be written by name inside any string (case-insensitive). These are most meaningful in .text / !pet output:

    .text "{clear}{white}HELLO {rvson}{red}WORLD{rvsoff}{return}"

Colors (the 16 C64 colors):

Name(s) Byte Name(s) Byte
{black} $90 {orange} $81
{white} $05 {brown} $95
{red} $1C {lightred} {pink} $96
{cyan} $9F {darkgrey} {grey1} $97
{purple} {magenta} $9C {grey} {grey2} {mediumgrey} $98
{green} $1E {lightgreen} {ltgreen} $99
{blue} $1F {lightblue} {ltblue} $9A
{yellow} $9E {lightgrey} {grey3} $9B

(gray spellings are accepted for every grey.)

Control codes:

Name(s) Byte Name(s) Byte
{clear} {clr} {cls} $93 {down} $11
{home} $13 {up} $91
{rvson} {rvs} $12 {right} $1D
{rvsoff} $92 {left} $9D
{return} {cr} $0D {del} $14
{lower} $0E {insert} {inst} $94
{upper} $8E

An unrecognized {name} is left in the string literally, so existing text is unaffected.


Addressing Modes

All standard NMOS 6502 addressing modes are supported:

Syntax Mode Example
(implied) Implied NOP, RTS
A Accumulator ASL A
#$nn Immediate LDA #$FF
$nn Zero Page LDA $10
$nn,X Zero Page,X LDA $10,X
$nn,Y Zero Page,Y LDX $10,Y
$nnnn Absolute LDA $1000
$nnnn,X Absolute,X LDA $1000,X
$nnnn,Y Absolute,Y LDA $1000,Y
($nnnn) Indirect JMP ($FFFC)
($nn,X) Indexed Indirect LDA ($10,X)
($nn),Y Indirect Indexed LDA ($10),Y
$rr Relative BNE loop

65C02 extensions (when selected via .cpu 65c02):

Syntax Mode Example
($nn) Zero Page Indirect LDA ($10)
($nnnn,X) Indirect Absolute,X JMP ($1000,X)

Zero page and absolute modes are selected automatically based on the operand value. Forward references default to absolute (16-bit) and are optimized to zero page in subsequent passes if possible.


Directives

All directives may be written with or without a leading dot (.byte and BYTE are equivalent).

Origin

    *= $0801            ; set program counter
    .org $C000          ; alternate syntax

Data Definition

Bytes

    .byte $FF, $00, 128         ; emit byte values
    .byte "hello"               ; emit ASCII string as bytes
    .byte <label, >label        ; lo/hi byte of a label

Aliases: BYTE, .BYTE, DC.B, .DC.B, DB, .DB, DFB

Words

    .word $1000, label          ; emit 16-bit values (little-endian)

Aliases: WORD, .WORD, DC.W, .DC.W, DW, .DW, DFW

Long (24-bit)

    .long $123456               ; emit 24-bit value (little-endian)

Aliases: LONG, .LONG, DC.L, .DC.L, DL

32-bit (ACME)

    !32 $12345678               ; emit 32-bit value (little-endian)

Text / Strings

    .text "Trainer"            ; emit PETSCII: prints "Trainer" via jsr $ffd2 (CHROUT)
    .text "Price: {$24}9.99"   ; embed $ via hex escape
    .ascii "raw bytes here"    ; emit raw ASCII bytes (no PETSCII conversion)

.text converts ASCII → PETSCII so the string prints with the intended case when sent to CHROUT ($ffd2): uppercase A-Z → $C1-$DA, lowercase a-z → $41-$5A. Write the string in normal case (.text "Trainer") — no manual case-swapping needed. Use .ascii (or .asc) when you want the literal ASCII bytes with no translation.

Aliases: .text = TEXT, .TEXT (PETSCII). .ascii = .ASCII, ASC, .ASC, DC, .DC (raw ASCII). A custom CMAP overrides both and applies to .text output.

PETSCII Text (ACME)

    !pet "hello"                ; emit PETSCII-encoded text (same as .text)

Uppercase A-Z maps to $C1-$DA, lowercase a-z maps to $41-$5A. The ACME !text, !tx, and !raw pseudo-ops emit raw ASCII bytes (like .ascii).

Screen Codes

    .screen  "HELLO"            ; emit C64 screen codes (not PETSCII)
    .screen  "@@@2026{$24}02{$24}28@@@"  ; hex escapes work here too
    .rscreen "HELLO"            ; reverse-video screen codes (bit 7 set)
    .pscreen "Le Mayday!"       ; PETSCII -> screen codes, case preserved

There are three screen-code directives:

    .pscreen "Le Mayday!"       ; -> 4C 05 20 4D 01 19 04 01 19 21  ("L","e"," ","M"...)
    .pscreen "AB{$e0}c"         ; -> 41 42 E0 03  (A, B, literal $E0, c)

All three also accept a bare comma-separated byte list (.screen 1,2,3), emitting the values directly (.rscreen sets bit 7, .pscreen leaves them as-is).

XOR-Obfuscated Text (.x*)

Each string directive has an .x counterpart that takes an XOR key as its first operand and XORs every emitted byte with it. Handy for lightly obfuscating strings that a runtime routine XORs back with the same key:

    .xtext    $39,"Your Mom"    ; .text bytes, each EOR #$39
    .xascii   $ff,"AB"          ; raw ASCII, each EOR #$FF   -> BE BD
    .xscreen  $80,"HELLO"       ; .screen codes,  each EOR #$80
    .xrscreen $80,"HELLO"       ; .rscreen codes, each EOR #$80
    .xpscreen $80,"Le"          ; .pscreen codes, each EOR #$80  -> CC 85

The key is any expression (e.g. $39, 128, a symbol) and is separated from the text by a comma. All the usual escapes and {name} codes work in the string, and the XOR is applied after the base directive's encoding. Bare byte lists are also supported (.xtext $39,1,2,3). Aliases: XTEXT/.XTEXT, XASCII/.XASCII, XSCREEN/.XSCREEN, XRSCREEN/.XRSCREEN, XPSCREEN/.XPSCREEN.

Space / Reserve

    .ds 256                     ; reserve 256 bytes (filled with fill byte)
    .ds.w 10                    ; reserve 10 words (20 bytes)

Aliases: DS, .DS, RES, .RES, DS.B, DS.W, DS.L

Fill

    .fill 256, $EA              ; fill 256 bytes with $EA

Aliases: FILL, .FILL, !FILL, !FI

Align

    .align 256                  ; align to next 256-byte boundary

Aliases: ALIGN, .ALIGN, !ALIGN

Repeat

    .repeat 8, $FF              ; emit $FF eight times
    .repeat 3, $01, $02, $03   ; emit the sequence 01 02 03 three times (9 bytes)
    .repeat 4, label            ; word-sized labels emit lo-hi pairs

Aliases: REPEAT, .REPEAT, REPT, .REPT

For Loops

Generate data tables or unrolled code with a counter variable:

    .for i = 0, 256
    .byte sin(i * 2 * PI / 256) * 127 + 128
    .endfor

Syntax: .for variable = start, count [, step]

Parameter Description
variable Loop counter name (usable in expressions within the body)
start Initial value
count Number of iterations
step Increment per iteration (default: 1)

The loop variable is available in all expressions within the body, including instruction operands:

    ; Unroll 8 sprite enable bits
    .for n = 0, 8
    lda #1 << n
    sta $d015
    .endfor

Aliases: FOR/.FOR, ENDFOR/.ENDFOR/NEXT/.NEXT

Math Functions

Expressions support built-in math functions for generating lookup tables. All trig functions use radians. Intermediate calculations are done in floating-point; results are rounded to integers for .byte/.word output.

    .byte sin(PI / 4) * 127 + 128      ; sine
    .byte cos(0) * 255                  ; cosine
    .byte sqrt(144)                     ; = 12
    .byte abs(-42)                      ; = 42
    .byte min(10, 20)                   ; = 10
    .byte max(10, 20)                   ; = 20
    .byte pow(2, 8)                     ; = 256
    .byte floor(3.7)                    ; = 3
    .byte ceil(3.2)                     ; = 4
Function Description
sin(x) Sine (x in radians)
cos(x) Cosine
tan(x) Tangent
asin(x) Arc sine
acos(x) Arc cosine
atan(x) Arc tangent
atan2(y,x) Two-argument arc tangent
sqrt(x) Square root
abs(x) Absolute value
floor(x) Round down
ceil(x) Round up
round(x) Round to nearest
int(x) Truncate to integer
log(x) Natural logarithm
log2(x) Base-2 logarithm
exp(x) e^x
pow(x,y) x raised to power y
min(a,b) Minimum of two values
max(a,b) Maximum of two values

Built-in constants: PI (3.14159...), E (2.71828...)

Floating-point literals are supported in expressions: 3.14159, 0.5, etc.

Note: The built-in constant E returns Euler's number (2.71828...) when used as a bare identifier in expressions. If you have a label named E, it will be shadowed by the built-in constant. Use a different label name (e.g., E_ADDR, E_PTR) to avoid this. The constant PI has the same potential for collision but PI is rarely used as a label name.

Bounce (Wave Table)

    .bounce preset, count, min, max, phases

Generates a cosine wave table. Parameters:

Parameter Description
preset Wave preset (1 = cosine)
count Number of table entries
min Minimum output value
max Maximum output value
phases Number of complete wave cycles

Example:

    .bounce 1, 256, 0, 255, 1  ; 256-byte cosine wave, full range, 1 cycle

Aliases: BOUNCE, .BOUNCE

BASIC SYS Line

    *= $0801
    .sysline 10, $2000          ; BASIC: 10 SYS 8192

Generates a complete C64 BASIC line that performs a SYS call:

[next-line ptr lo/hi] [line# lo/hi] $9E(SYS) $20(space) [address as ASCII] $00 $00

The second parameter can be a decimal number, hex value, or label reference.

Aliases: SYSLINE, .SYSLINE

Binary Include

    .binary "sprite.bin"                ; include entire file
    .binary "data.bin", 64              ; skip first 64 bytes
    .binary "data.bin", 64, 128         ; skip 64, include 128 bytes

File paths are resolved relative to the source file's directory.

Aliases: INCBIN, .INCBIN, BINARY, .BINARY, !BINARY, !BIN

Source Include

    .include "routines.asm"         ; relative to current source file
    !src <sprites.asm>              ; ACME angle-bracket syntax
    .append "vectors.asm"           ; as65 syntax

Include paths are searched in order: absolute path, relative to current source file, then each -I include path. Nested includes are supported (max depth 64) with circular include detection.

Use .incdir (DASM) to add search paths at assembly time:

    .incdir "libs/"
    .include "math.asm"             ; found in libs/math.asm

Aliases: INCLUDE/.INCLUDE, !SOURCE/!SRC, APPEND/.APPEND, INCDIR/.INCDIR

Structures

Define named data structures with automatic field offset calculation:

Player  STRUCT
xpos    .byte 0
ypos    .byte 0
speed   .word 0
health  .byte 0
        ENDSTRUCT

        ldx #Player             ; = 5 (total struct size)
        lda $C000+Player.xpos   ; offset 0
        lda $C000+Player.ypos   ; offset 1
        lda $C000+Player.speed  ; offset 2
        lda $C000+Player.health ; offset 4

Inside a STRUCT block, labels define field names and data directives (.byte, .word, .long, .ds) define field sizes. No bytes are emitted; the struct name is defined as a constant equal to the total size, and each field becomes StructName.FieldName equal to its byte offset.

Aliases: STRUCT/.STRUCT, ENDSTRUCT/.ENDSTRUCT/ENDS/.ENDS

Character Mapping

Remap character values for .text output:

        CMAP 'A', 'Z', $01      ; map A-Z to $01-$1A (screen codes)
        .text "HELLO"            ; emits 08 05 0C 0C 0F (CMAP wins over PETSCII)
        CMAP                     ; reset to identity (no mapping)
        .text "HELLO"            ; emits C8 C5 CC CC CF (PETSCII)

CMAP start, end, mapTo remaps all input bytes from start through end so that start maps to mapTo, start+1 maps to mapTo+1, and so on. CMAP with no arguments resets to identity mapping. When a CMAP is active it takes precedence over .text's PETSCII conversion; with no CMAP, .text applies PETSCII and .ascii emits raw bytes.

Aliases: CMAP/.CMAP


Symbols and Constants

EQU / Constants

SCREEN      .equ $0400
BORDER      = $D020
VIC         EQU $D000

Constants are immutable once defined.

SET / Variables

counter     .set 0
counter     .set counter + 1    ; redefinable

Aliases: SET, .SET, !SET


Conditional Assembly

    .if expression
        ; assembled when expression is non-zero
    .else
        ; assembled when expression is zero
    .endif

    .ifdef SYMBOL
        ; assembled when SYMBOL is defined
    .endif

    .ifndef SYMBOL
        ; assembled when SYMBOL is not defined
    .endif

Aliases: IF/.IF/!IF, IFDEF/.IFDEF/!IFDEF, IFNDEF/.IFNDEF/!IFNDEF, ELSE/.ELSE, ENDIF/.ENDIF/EIF/.EIF


Macros

Definition

spritePos .macro
    lda #\1
    sta $D000
    lda #\2
    sta $D001
.endm

Invocation

    #spritePos 100, 150         ; tmpx-style: # prefix
    +spritePos 100, 150         ; ACME-style: + prefix
    spritePos 100, 150          ; also works without prefix

Parameter Substitution

Syntax Style Example
\1, \2, ... tmpx lda #\1
{1}, {2}, ... DASM lda #{1}
\0 or {0} Argument count .byte \0

\0 (or {0}) expands to the number of arguments passed to the macro, enabling variadic macros:

emit .macro
        .byte \0            ; emit argument count first
        .if \0 > 0
            .byte \1
        .endif
        .if \0 > 1
            .byte \2
        .endif
.endm

        #emit 10, 20        ; emits: 02 0A 14
        #emit 42             ; emits: 01 2A

Early Macro Exit

check .macro
        .if \1 == 0
            EXITM           ; stop expanding this macro
        .endif
        sta \1
.endm

EXITM immediately stops expansion of the current macro. Any lines after EXITM in the macro body are skipped. Open .if blocks inside the macro are automatically cleaned up.

Aliases: EXITM/.EXITM

Local Labels in Macros

delay .macro
?loop   dex
        bne ?loop
.endm

Labels prefixed with ? are automatically made unique per macro invocation. The .# suffix is also replaced with a unique counter.

Maximum macro nesting depth: 32 levels.


Scoping

    .scope
        .loop: dex
               bne .loop       ; local to this scope
    .endscope

    .subroutine name
        ; labels are scoped to this subroutine

Aliases: SCOPE/.SCOPE/!ZONE/!ZN, ENDSCOPE/.ENDSCOPE, SUBROUTINE/.SUBROUTINE


Segments

    .segment "code"
    .code                       ; shorthand for code segment
    .data                       ; shorthand for data segment
    .bss                        ; shorthand for BSS segment

Debug Output

    .echo "Value is: ", expression
    .print "Current PC: ", *

Aliases: ECHO/.ECHO, PRINT/.PRINT


Assembler Messages

    !warn "Check this value"        ; emit warning during assembly
    !error "Bad configuration"      ; emit error
    !serious "Fatal problem"        ; emit fatal error and halt

Assertions

    .assert * < $C000, "Code exceeds ROM boundary!"

Aliases: ASSERT/.ASSERT


Processor Selection

    .cpu 6502                   ; NMOS 6502 (default)
    .cpu 65c02                  ; 65C02
    .processor 6502

Aliases: CPU/.CPU/!CPU, PROCESSOR/.PROCESSOR


Supported Instructions

NMOS 6502 (56 official opcodes)

ADC  AND  ASL  BCC  BCS  BEQ  BIT  BMI  BNE  BPL  BRK  BVC  BVS
CLC  CLD  CLI  CLV  CMP  CPX  CPY  DEC  DEX  DEY  EOR  INC  INX
INY  JMP  JSR  LDA  LDX  LDY  LSR  NOP  ORA  PHA  PHP  PLA  PLP
ROL  ROR  RTI  RTS  SBC  SEC  SED  SEI  STA  STX  STY  TAX  TAY
TSX  TXA  TXS  TYA

Undocumented / Illegal Opcodes

Illegal opcodes are enabled by default. All common aliases are recognized:

AHX  ALR  ANC  ANE  ARR  ASR  AXS  DCP  DOP  HLT  ISB  ISC  JAM
KIL  LAS  LAX  LXA  RLA  RRA  SAX  SBX  SHA  SHS  SHX  SHY  SLO
SRE  SXA  SYA  TAS  TOP  XAA

Platform: C64

The following predefined constants are always available for common C64 hardware addresses:

Zero Page: D6510, R6510, TXTTAB, VARTAB, ARYTAB, STREND, FRETOP, MEMSIZ, CURLIN, TXTPTR, FAC, FACSGN, ARG, PNTR, LNMX, TBLX, TIME/TIMEH/TIMEM/TIMEL

VIC-II ($D000): VIC, SP0X..SP7X, SP0Y..SP7Y, MSIGX, SCROLY/CR1, RASTER, SPENA, SCROLX/CR2, VMCSB, VICIRQ, IRQMASK, EXTCOL/BGCOL0..BGCOL3, SPMC0/SPMC1, and more.

SID ($D400): SID, voice frequency/pulse/control/envelope, filter, volume registers.

CIA ($DC00/$DD00): CIA1/CIA2, port/timer/interrupt registers.

KERNAL: CHROUT, CHRIN, GETIN, CLRSCR, SETLFS, SETNAM, OPEN, CLOSE, LOAD, SAVE, STOP, PLOT, IOBASE, SCNKEY, LISTEN, TALK, READST, and more.

BASIC: BASIC_START, BASIC_END, BASIC_COLD, BASIC_WARM

Colors: BLACK, WHITE, RED, CYAN, PURPLE, GREEN, BLUE, YELLOW, ORANGE, BROWN, LIGHT_RED, DARK_GREY, GREY, LIGHT_GREEN, LIGHT_BLUE, LIGHT_GREY


Optimization Control

        NOOPT
        lda $10             ; assembles as AD 10 00 (absolute, 3 bytes)
        OPT
        lda $10             ; assembles as A5 10 (zero page, 2 bytes)

By default, 6asm automatically optimizes absolute addressing to zero page when the operand value fits in one byte. NOOPT disables this optimization — all addresses are assembled as absolute (16-bit). OPT re-enables it. This is useful when you need stable instruction sizes (e.g., self-modifying code).

Aliases: OPT/.OPT, NOOPT/.NOOPT


Cycle Timing

Mark code blocks for cycle counting in the listing file:

        .cycles
loop    inc $d020           ; 6
        lda $d012           ; 4
        cmp #$80            ; 2
        bne loop            ; 2
        .endcycles          ; ;>>> 14 cycles

When --list is used, a Cy column appears showing the base cycle count per instruction, with a total at each .endcycles. Cycle counts are base values (not counting page-crossing or branch-taken penalties).

Raster Budget

Set a cycle budget to get warnings when code exceeds a raster line:

        .rasterbudget 63        ; PAL: 63 cycles per line
        .cycles
        lda #$01                ; 2
        sta $d020               ; 4
        .endcycles              ; ;>>> 6/63 cycles (57 free)

        .rasterbudget 23        ; badline: only 23 cycles
        .cycles
        ; ... tight code here ...
        .endcycles              ; warns if over 23

The listing shows used/budget and whether you're free or over. The assembler emits a warning if a block exceeds the budget.

Use .rasterbudget with no argument to clear the budget.

Aliases: CYCLES/.CYCLES, ENDCYCLES/.ENDCYCLES, RASTERBUDGET/.RASTERBUDGET


Hardware Alignment

Directives that align the program counter to hardware-required boundaries and warn if the following data exceeds the expected block size:

        .spritealign                ; align to 64B boundary
        .for i = 0, 63
        .byte i                     ; 63 bytes of sprite data — fits in 64B block
        .endfor

        .charsetalign               ; align to 2048B boundary
        .binary "charset.bin"       ; warns if > 2048 bytes
Directive Alignment Max Size Use Case
.spritealign 64 bytes 64B Sprite data blocks
.charsetalign 2048 bytes 2048B Character sets
.bitmapalign 8192 bytes 8192B Bitmap graphics
.screenalign 1024 bytes 1024B Screen RAM
.sidalign 256 bytes 256B SID music data

The limit auto-clears on the next *=, .org, or alignment directive.


Bank Configuration

Track the C64 memory bank configuration ($01 register) and warn when code accesses memory regions that aren't visible:

        .bank $37               ; default: all ROM + I/O visible
        lda $d020               ; OK
        jsr $ffd2               ; OK — Kernal visible

        .bank $35               ; I/O + RAM (Kernal banked out)
        lda $d020               ; OK — I/O visible
        jsr $ffd2               ; WARNING — Kernal not mapped

        .bank $34               ; all RAM
        lda $d020               ; WARNING — I/O not visible

        .bank                   ; clear bank tracking
Bank Value LORAM HIRAM CHAREN $A000 $D000 $E000
$37 1 1 1 BASIC ROM I/O Kernal ROM
$36 0 1 1 RAM I/O Kernal ROM
$35 1 0 1 RAM I/O RAM
$34 0 0 0 RAM RAM RAM
$33 1 1 0 BASIC ROM Char ROM Kernal ROM

Aliases: BANK/.BANK


VICE Integration

Symbol File

Generate a VICE monitor symbol file with --vice:

6asm --vice game.asm              # generates game.lbl

Format: al C000 .label — loadable in VICE with ll "game.lbl".

Breakpoints and Watchpoints

Emit debug commands to the VICE symbol file:

        .break                  ; breakpoint at current PC
        .break $0830            ; breakpoint at specific address
        .watch $d020            ; watchpoint on store (default)
        .watchstore $d020       ; explicit store watchpoint
        .watchload $dc00        ; load watchpoint

These appear in the .lbl file as VICE monitor commands:

break $0820
watch store $D020
watch load $DC00

Aliases: BREAK/.BREAK, WATCH/.WATCH, WATCHSTORE/.WATCHSTORE, WATCHLOAD/.WATCHLOAD


Peephole Optimizer

The --analyze flag runs a post-assembly analysis suggesting optimizations:

6asm --analyze --list game.asm

Detects:

Suggestions are printed to console and appended to the listing file with byte/cycle savings estimates.


Listing File

Generate with --list. The listing includes:


Multi-Pass Assembly

6asm uses multi-pass assembly (up to 10 passes by default) to resolve forward references and optimize addressing modes. On each pass:

  1. Forward-referenced labels are resolved as their values become known.
  2. Absolute addresses are optimized to zero page when possible.
  3. Assembly continues until the symbol table stabilizes.

Compatibility

6asm accepts source files written for tmpx (Turbo Macro Pro cross-assembler), DASM, and ACME assembler syntax.

tmpx Compatibility

ACME Compatibility

6asm supports the !-prefixed pseudo-op syntax used by the ACME cross-assembler:

ACME Syntax 6asm Equivalent Notes
!byte, !by, !8, !08 .byte Emit bytes
!word, !wo, !16 .word Emit 16-bit little-endian
!24 .long Emit 24-bit little-endian
!32 (new) Emit 32-bit little-endian
!fill, !fi .fill Fill with count,value
!align .align Alignment
!text, !tx, !raw .ascii Raw ASCII text
!pet .text PETSCII text (case-converted for CHROUT)
!scr .screen Screen code text
!source, !src .include Include source file
!binary, !bin .incbin Include binary file
!if / !ifdef / !ifndef .if / .ifdef / .ifndef Conditional assembly
!set .set Reassignable symbol
!macro .macro Macro definition
!cpu .processor Set target CPU
!warn (new) Emit assembler warning
!error (new) Emit assembler error
!serious (new) Emit fatal error and stop
!eof, !endoffile END Stop processing file
!initmem (new) Set fill byte for gaps
!zone, !zn .scope Scoping / zones
!to (stub) Output file (use CLI -o instead)
!pseudopc (stub) Offset assembly
!convtab, !ct (stub) Character conversion table
!sl, !svl, !sal (stub) Symbol list export
!al, !as, !rl, !rs (stub) 65816 register size

ACME macro invocation uses + prefix: +macroName arg1, arg2

Not yet supported: - { } brace-delimited blocks for conditionals/macros - Anonymous +/- labels

!for note: ACME uses !for .i, 1, 8 { ... } with brace-delimited bodies. 6asm supports .for loops with .endfor block termination instead: .for i = 0, 8 / .endfor. The !for directive is recognized but uses 6asm's .for syntax, not ACME's brace syntax.

ACME Syntax Conflicts

Feature ACME 6asm Resolution
^ operator Power-of Bitwise XOR Kept as XOR — standard across most assemblers
& prefix Octal number Bitwise AND Kept as AND — use @ for octal instead
>>> operator Logical shift right Not supported Use >> (arithmetic shift)
EOR keyword Bitwise XOR Not supported Use ^ or .XOR.

DASM Compatibility

as65 Compatibility


License

MIT