NAME

xasm - 6502 cross-assembler

SYNOPSIS

xasm source [options]

DESCRIPTION

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.

OPTIONS

/c
Enable listing false conditionals. Lines skipped due to a false condition are not listed by default.
/d:label=value
Define a label. label should be a valid label name. value may be any expression (it may use forward references to labels defined in the source file). You may use several /d options to define many labels from the command line.
/e
Enable setting environment variables pointing at the error location. With this option, xasm sets two environment variables: ERRFILE and ERRLINE. They may be used in a batch file to locate the error and set editor's insertion point on it. If there was no error, the variables point at the last issued warning. If no warning occured, they are removed from the environment.
/i
Disable listing included sources. Only main source file will be listed.
/l[:filename]
Enable listing. If no filename is given, the listing is written to source.lst, where source is the name of the source file (without the extension).
/o:filename
Specify object file name. The default is source.obx. You may use the null device (/o:nul) to generate no object file.
/p
Print fully qualified file names in listing and error messages. This option is useful for the Code-Genie editor, which can jump to the error location only if the full path is given.
/q
Suppress info messages. Prevents xasm from printing its name and the summary (how many lines assembled and bytes written). Good if you are building a project from many source files and don't want tons of messages.
/t[:filename]
List label table. If no filename given, the table is appended to the listing.
/u
Warn of unused labels. A warning message will be issued for each label, whose value is never used.

SYNTAX

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

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.

SyntaxChip Value in the Atari 8-bit
computer mode (opt g-)
Value in the Atari 5200
game console mode (opt g+)
^0xGTIA $D00x$C00x
^1xGTIA $D01x$C01x
^2xPOKEY $D20x$E80x
^3xPIA $D30xerror (there's no PIA chip)
^4xANTIC $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.

DIRECTIVES

EQU - assign a value of an expression to the label
Note that a label represents a number, not a text macro.
Examples:
five equ 5
here equ *
OPT - set assembly options
Five options are available:
  • F - fill the space between ORGs with $FF bytes
  • G - Atari 5200 mode for hardware register abbreviations
  • H - generate Atari executable headers
  • L - generate listing
  • O - generate object file
You can turn any of these on or off.
The default (if no OPT specified) is opt f-g-h+l+o+.
Examples:
 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 - change value of the origin counter
You can set some options applied to the new header (if headers are enabled):
  • a: tells xasm to always make a header, even it is unnecessary, like in ORG *.
  • f: works same as a:, but additionally tells to generate a $FF,$FF prefix before the header. xasm adds it at the beginning of the file by default, so use this option only if you want the $FF's somewhere inside.
Examples:
 org $600
 org f:$700
table org *+100
In 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 - define data
There are various data types:
  • integers
    • bytes: b(200) or simply 200
    • words: a(10000)
    • low bytes of words: l(511) defines byte 255
    • high bytes of words: h(511) defines byte 1
    You may enter many expressions in parentheses and combine different types of data in a single line, separating things with commas.
    You may also define a sine lookup table. The syntax is:
    sin(center,amp,size,first,last)
    where:
    • center is a number which is added to every sine value
    • amp is the sine amplitude
    • size is the sine period
    • first,last define range of values in the table. They are optional. The default are 0,size-1.
    Example: dta a(sin(0,1000,256,0,63)) defines a table of 64 words representing a quarter of sine with the amplitude of 1000.
  • real numbers: r(-1.23456e12)
    Real numbers are written in the 6-byte Atari Floating-Point format.
  • text strings
    • ASCII strings: c'Text' or c"Text"
    • ANTIC strings: d'Text' or d"Text"
    A character string consists of any of characters surrounded by quotation marks. Within a string, a single quotation mark character is represented by two succesive quotation marks.
    Placing a * character after a string inverts the highest bit in every byte of the string.
Examples of DTA:
 dta b(1,2),3,a(1000,-1),l(12345,sin(0,127,256))
 dta d"ANTIC"*,c'It''s a string',$9b
ICL - include another source file
Specifies another file to be included in the assembly as if the contents of the referenced file appeared in place of the ICL statement. The included file may contain other ICL statements. The .ASX extension is added if none given.
Examples:
 icl 'macros.asx'
 icl 'c:\atari\xasm\fileio'
END - end assembling file
Remaining part of the file is not assembled. If this statement does not occur, the assembler stops assembling when it encounters the end of the file.
Example:
 end
INS - insert contents of file
Copies every byte of the specified file into the object file and updates the origin counter, as if these bytes were defined with DTA.
You may specify a range of the inserted file. The syntax is following:
 ins 'file'[,offset[,length]]
The first byte in a file has the offset of zero.
If the offset is negative, it is counted from the end of the file.
Examples:
 ins 'picture.raw'
 ins 'file',-256  insert last 256 bytes of file
 ins 'file',10,10 insert bytes 10..19 of file
RUN - generate run address
An Atari executable program should specify a run address. A program may be loaded in many areas of the memory and started from any address.
 run addr
is equivalent to:
 org $2e0
 dta a(addr)
Example:
 run main
INI - generate init address
An Atari executable program may have some routines which are executed during the loading process. There may be many init blocks in one file.
Example:
 ini showpic
ERT - generate an error if an expression is true
Examples:
 ert *>$c000
 ert len1>$ff||len2>$ff
IFT - assemble if expression is true
ELI - else if
ELS - else
EIF - end if
With these directives you can construct fragments which are assembled when a condition is met. Conditional constructions can be nested.
Example:
noscr equ 1
widescr equ 1
 ift noscr
 lda #0
 eli widescr
 lda #$23
 els
 lda #$22
 eif
 sta $22f
The 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

Pseudo-commands are built-in macros.

ADD - addition without carry
If you have ever programmed a 6502, you must have noticed that you had to use a CLC before ADC for every simple addition.
xasm can do it for you. ADD replaces two instructions: CLC and ADC.
SUB - subtraction
It is SEC and SBC.
RCC, RCS, REQ, RMI, RNE, RPL, RVC, RVS - conditional repeat
These are branches to the previous instruction. They take no operand, because the branch target is the address of previously assembled instruction.
Example:
 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
SCC, SCS, SEQ, SMI, SNE, SPL, SVC, SVS - conditional skip
These are branches over the next instructions. No operand is required, because the target is the address of the instruction following the next instruction.
Example:
 lda #40
 add:sta $80
 scc:inc $81
In the above example the word-sized variable $80 is incremented by 40.
JCC, JCS, JEQ, JMI, JNE, JPL, JVC, JVS - conditional jumps
These are a kind of 'long' branches. While standard branches (such as BNE) have range of -128..+127, these jumps have range of all 64 kB.
Example:
 jne dest
is equivalent to:
 seq:jmp dest
INW - increment word
Increments a 16-bit word in the memory.
Example:
 inw dest
is equivalent to:
 inc dest
 sne:inc dest+1
MVA, MVX, MVY - move byte using accumulator, X or Y
Each of these pseudo-commands requires two operands and substitutes two commands:
 mva source dest = lda source : sta dest
 mvx source dest = ldx source : stx dest
 mvy source dest = ldy source : sty dest
MWA, MWX, MWY - move word using accumulator, X or Y
These pseudo-commands require two operands and are combinations of two MV*'s: one to move the low byte, and the other to move the high byte.
You can't use indirect nor pseudo addressing mode with MW*. Destination must be an absolute address (optionally indexed).
When source is also absolute, an mw* source dest will be:
 mv* source  dest
 mv* source+1 dest+1
When source is an immediate, an mw* #immed dest will be:
 mv* <immed dest
 mv* >immed dest+1
When <immed equals >immed and immed is not forward-referenced, xasm uses an optimization:
 mv* <immed dest
 st* dest+1
If possible, MWX and MWY use increment/decrement commands. E.g. mwx #1 dest is assembled as:
 ldx #1
 stx dest
 dex
 stx dest+1

ADDRESSING MODES

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

CHANGES

Version 2.6.1 (2005-05-21)

Version 2.6.0 (2005-02-07)

Version 2.5.2 (2002-10-03)

Version 2.5.1 (2002-08-21)

Version 2.5 (2002-07-08)

Version 2.4.1 (2002-06-27)

Version 2.4 (2002-05-22)

Version 2.3 (2002-02-10)

Version 2.2 (1999-09-10)

Version 2.0 (1998-11-12)

Version 1.2 (1998-08-14)

AUTHOR

Piotr Fusik (fox@scene.pl)

SEE ALSO

How to configure a text editor for a convenient use of xasm

xasm home page (http://xasm.atari.org)