xasm - 6502 cross-assembler
xasm source [options]
xasm is a cross-assembler which generates code for the 6502 processor.
source is the name of the source file. If no filename extension is given, .ASX is appended. The default action (when invoked without options) is to assembly source, writing the result to a file with the .OBX extension.
Source files should be plain ASCII files. Although different line terminators are supported, CR/LF is recommended because it is the standard in the DOS/Windows environment. Lines must be no longer than 256 characters. xasm is not case-sensitive, so you can mix upper- and lower-case for labels and instructions.
xasm is backward compatible with Quick Assembler. If you want to assembly QA sources with xasm, simply convert the text file to CR/LF terminators and replace ATASCII specific characters with their integer representation. You also have to change all OPT directives, but usually you only need to remove them.
A label is a symbol that represents a 32-bit signed integer. You can define a label by putting its name at the beginning of a line (with no spaces before). If you do not use the EQU directive, the label is assigned the current value of the origin counter.
Instructions and directives must be preceded with whitespace. Note that in xasm you can use instruction and directive names as label names. For example
nop
defines a label called nop, whereas
nop
is a 6502 instruction.
Full comment lines must start with a semicolon, a pipe or an asterisk, with optional label definition and spaces before. Here are examples of full comment lines:
; this is a comment * so it is label | and this too
Lines with instructions (and some directives) may be repeated. A single line may be assembled several times, for example:
:4 asl @ table :32*5 dta 5
In lines with instructions or directives, a comment starts after the instruction/directive has been successfully parsed. That is, xasm does not require a special character to start a comment. However, you still can use one, because it is usually required for correct syntax highlighting in text editors.
lda foo ; this is a comment sta bar so it is tax #0 tax requires no operand, so #0 starts a comment
You may put two instructions on the same line. In this case they have the same operand. For example:
eor:sta foo
is equivalent to
eor foo sta foo
Note that
lda:tax #0
is allowed (#0 is a comment for tax).
Expressions are numbers combined with operators and brackets. You should use square brackets, because parentheses are reserved for the indirect addressing.
Numbers are 32-bit signed integers, in the range of -$7fffffff..$7fffffff. A number may be:
Abbreviations of Atari hardware registers are provided to save you the trouble of typing two extra characters (^4e vs $d40e) and to ease porting software between Atari 8-bit computers and the Atari 5200 console. These are very similar machines, one of the biggest differences is different location of hardware registers.
Syntax | Chip | Value in the Atari 8-bit computer mode (opt g-) |
Value in the Atari 5200 game console mode (opt g+) |
---|---|---|---|
^0x | GTIA | $D00x | $C00x |
^1x | GTIA | $D01x | $C01x |
^2x | POKEY | $D20x | $E80x |
^3x | PIA | $D30x | error (there's no PIA chip) |
^4x | ANTIC | $D40x | $D40x |
An op-code is the single-byte op-code of the instruction inside braces. The operand of the instruction is discarded and is necessary only for identifying the addressing mode. The instruction should begin just after the left brace and the right brace should immediately follow the operand or the instruction. You can skip the operand if the addressing mode is fixed. Examples: {lda #}, {jsr}, {bne}, {jmp ()}, {sta a:,x}.
You can use the line repeat counter (#) in the repeated lines. It counts the iterations starting from zero. Examples:
:3 dta # ; generates three bytes: 00, 01, 02. line_lo :192 dta l(screen+40*#) line_hi :192 dta h(screen+40*#) dl :59 dta $4f,a(screen+40*#),0,$4f,a(screen+40*#),0
The follownig binary operators are supported:
The following unary operators are supported:
The operator precedence is following:
first | [] | (brackets) |
+ - ~ < > | (unary) | |
* / % & << >> | (binary) | |
+ - | ^ | (binary) | |
= == <> != < > <= >= | (binary) | |
! | (unary) | |
&& | (binary) | |
last | || | (binary) |
Note that although the operators are similar to those used in C, C++ and Java, their priorities are different than in these languages.
Compare and logical operators assume that zero is false and a non-zero is true. They return 1 for true.
While calculating an expression, signed 32-bit arithmetic is used. When range of 32 bits is exceeded, the 'Arithmetic overflow' error is generated.
five equ 5 here equ *
opt l- listing off opt l+o- listing on, object file off opt f+g+h- useful for Atari 5200 cartridges - raw output format, 5200 hw regs
org $600 org f:$700 table org *+100In the latter example table points to 100 bytes of uninitialized data (label is assigned to * before the ORG directive is executed).
Starting with version 2.6.0, xasm supports code that is relocated in the memory at runtime. Let's say you want your code to be run at the zero page. Typically you can't load it directly into this place, so you load it at a different address and then move at the runtime. xasm differentiates between the address that it used for code generation from the address that is used for generating Atari executable headers. org r: affects only the former one. Example:
org $8000 ldx #code_length-1 mva:rpl code_loaded,x z:code_zpage,x- jmp code_zpage code_loaded org r:$30 code_zpage jmp * ; ... or something more sensible code_length equ *-code_zpage
Note that both * and label definitions use the counter used for code generation. There is no direct access to the other counter, because I think this is not useful. If you really need it, you can always type something like:
where_am_i equ *-code_zpage+code_loaded
dta b(1,2),3,a(1000,-1),l(12345,sin(0,127,256)) dta d"ANTIC"*,c'It''s a string',$9b
icl 'macros.asx' icl 'c:\atari\xasm\fileio'
end
ins 'file'[,offset[,length]]The first byte in a file has the offset of zero.
ins 'picture.raw' ins 'file',-256 insert last 256 bytes of file ins 'file',10,10 insert bytes 10..19 of file
run addris equivalent to:
org $2e0 dta a(addr)Example:
run main
ini showpic
ert *>$c000 ert len1>$ff||len2>$ff
noscr equ 1 widescr equ 1 ift noscr lda #0 eli widescr lda #$23 els lda #$22 eif sta $22fThe above example can be rewritten using the line repeating feature:
noscr equ 1 widescr equ 1 :noscr lda #0 :!noscr&&widescr lda #$23 :!noscr&&!widescr lda #$22 sta $22f
Pseudo-commands are built-in macros.
ldx #0 mva:rne $500,x $600,x+The example code copies memory $500-$5ff to $600-$6ff. Here is the same written with standard 6502 commands only:
ldx #0 loop lda $500,x sta $600,x inx bne loop
lda #40 add:sta $80 scc:inc $81In the above example the word-sized variable $80 is incremented by 40.
jne destis equivalent to:
seq:jmp dest
inw destis equivalent to:
inc dest sne:inc dest+1
mva source dest = lda source : sta dest mvx source dest = ldx source : stx dest mvy source dest = ldy source : sty dest
mv* source dest mv* source+1 dest+1When source is an immediate, an mw* #immed dest will be:
mv* <immed dest mv* >immed dest+1When <immed equals >immed and immed is not forward-referenced, xasm uses an optimization:
mv* <immed dest st* dest+1If possible, MWX and MWY use increment/decrement commands. E.g. mwx #1 dest is assembled as:
ldx #1 stx dest dex stx dest+1
All addressing modes are entered in the standard 6502 convention except for the accumulator addressing mode, which should be marked with the @ character (as in Quick Assembler).
There are two extra immediate addressing modes: < and >, which use the low/high byte of a 16-bit word constant. They are for Quick Assembler compatibility. You can use traditional #< and #>. Note lda >$ff+5 loads 1 (>$104), while lda #>$ff+5 loads 5 (0+5) to the accumulator, because the unary operator > has a higher priority than the binary plus.
In absolute addressing modes, xasm examines the expression and uses zero-page addressing mode if it supposes it's possible. You may override it with a: and z: prefixes.
Examples:
nop asl @ lda >$1234 assembles to lda #$12 lda $100,x lda a:0 generates 16-bit address jmp ($0a) lda ($80),y
There are also pseudo addressing modes, which are similar to pseudo-commands. You may use them just like standard addressing modes in all 6502 commands and pseudo-commands, except for MWA, MWX and MWY:
cmd a,x+ = cmd a,x : inx cmd a,x- = cmd a,x : dex cmd a,y+ = cmd a,y : iny cmd a,y- = cmd a,y : dey cmd (z),y+ = cmd (z),y : iny cmd (z),y- = cmd (z),y : dey cmd (z,0) = ldx #0 : cmd (z,x) cmd (z),0 = ldy #0 : cmd (z),y cmd (z),0+ = ldy #0 : cmd (z),y : iny cmd (z),0- = ldy #0 : cmd (z),y : dey
ift 0 foo equ 1 ift foo eif eif(bug found by Adrian Matoga)
ift 0 :label nop eifreported Label not defined before error for the repeat count
ift 0 label eifreported No ORG specified error for the label definition
Piotr Fusik (fox@scene.pl)
How to configure a text editor for a convenient use of xasm
xasm home page (http://xasm.atari.org)