X-Assembler version 2.5.2


TABLE OF CONTENTS


INTRODUCTION

The X-Assembler is a cross-assembler, which generates code for the 6502 processor. It has been designed to be easy to use for Quick Assembler programmers, therefore its syntax is an extension of QA's.

Changes

Version 2.5.2

Version 2.5.1

Version 2.5

Version 2.4.1

Version 2.4

Version 2.3

Version 2.2

Version 2.0

Version 1.2


USAGE

System requirements

Source code requirements

Converting Quick Assembler files

Because of possible editor-associated problems you had better convert an Atari text file to a regular PC text file, i.e. EOLs from $9b to $0d/$0a and ATASCII specific characters to their integer representation.
You have to change all OPT directives, but usually you only need to remove them.

Assembling a source program

The common syntax of invoking command line is following:
XASM source [options]
source is the name of source file. If no extension is given, the .ASX is implied.

Default action on invoking without options is to compile writing to a file with the .OBX extension.

Assembling options

Following options are supported:
/c
Enable listing false conditionals.
By default lines skipped due to false condition are not listed.

/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 to the error location.
With this option, X-Asm sets two environment variables: ERRFILE and ERRLINE. They may be used in a batch file to locate error and set editor's insertion point on it. For example, you may create following batch file:
XASM %1 /e
IF NOT ERRORLEVEL 1 GOTO ok
NCE +%ERRLINE% %ERRFILE%
:ok
NCE stands for Norton Classic Editor.

If there was no error, variables point to the last issued warning. If no warning occured, they are removed from the environment.

Note: NCE is an old editor for DOS. To learn about integration with modern text editors for Windows read this.

/i
Disable listing included source. Only main source file will be listed.

/l[:filename]
Enable generating listing. If no filename given, listing is written to source.lst (where source is the name of the source file (without extension).

/n
Check source and object file modification time and assemble only if source is newer than object file. X-Asm does NOT check included nor inserted files but only main source, so be careful with this option.

Note: Much more powerful for this purpose is GNU make utility. In DOS and Windows you may use its DJGPP port (available from http://www.delorie.com/djgpp).

/o:filename
Specify object file name. 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 (see
here), which can jump to the error location only if full path is given.

/q
Suppress info messages.
Prevents X-Asm from printing "X-Assembler 2.5.2 by Fox/Taquart" 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.

/s
Disable converting spaces to tabs in listing.
Using tabs makes listing file shorter. Tab stops are assumed to be every 8 characters.

/t[:filename]
List label table.
If no filename given, the table is written at the end of listing or to source.tab.

/u
Warn of unused labels.
A warning message will be issued for each label, which value is never used.

If source is incorrect, X-Asm stops on first encountered error.

Exit codes

Meaning of exit codes returned by X-Asm:
3 = bad parameters, assembling not started
2 = error occured
1 = warning(s) only
0 = no errors, no warnings

Listing structure

A line of listing contains:

Label table structure

A line of label table contains:

SYNTAX

Fields

Source code is line-oriented. Every line of source consists of fields. Same sequence of characters used in different fields has completely different meaning. Fields are separated with one or more blank characters. There can't be any space within a field, except for strings and comments.

There are following types of fields:

Every line of source must match one of two general forms: In the first form, both fields are optional. Blank lines are ignored of course. Comment must here start with one of these characters: ; | or * (semicolon, pipe or asterisk). Any information in the line following such character is ignored.

In the latter form, you must use a minimum of an instruction field. It depends on the instruction, how many operands it takes. Every instruction takes constant number of operands, therefore there's no need to use a special character at the start of a comment, because after succesfully taking operands, X-Asm discards the remaining part of line. However, general purpose text editors may highlight the comments only if a special delimiter is used, and for that reason, the semicolon is recommended to start a comment.

Label field

This field is optional. It must start at first character in line, without any blank characters before. The purpose of using label field is to define a label.
Label is a symbol representing an integer of range -$ffff..$ffff.
Name of a label may contain letters, digits and underscores (_). Digit can not be label's first character. Name of a label may be as long as you want and all the characters are meaningful. In Quick Assembler only 6 leading characters were recognized and some sources may not compile under X-Asm for this reason.
Defining a label without using EQU makes it equal to current value of the origin counter.
Labels can't be redefined.

Repeat count

Repeating means here assembling single line several times as if there were several identical lines. Note it is not just duplicating bytes written to the object file.
Repeat count, which can be any valid expression, has to be preceded with a colon.
Examples:
:4 asl @
:2 dta a(*)
In the latter example each DTA has different operand value.
If repeat count equals zero, remaining part of line is not assembled. This allows compact single-line conditional assembly.

Instruction field

If this is the first field in a line, the line must start with at least one blank character. Instruction field consists of one or two instructions. The latter case is called instructions pairing, because a pair of instructions have shared operand. You separate instructions with a colon.
Example:
 adc:sta $80
is equivalent to
 adc $80
 sta $80
Note that
 lda:tax $80
is correct, because $80 is a comment for TAX.

Single instruction always consists of 3 letters. It may be:

  1. a 6502 command - standard mnemonics are used
  2. a directive
  3. a pseudo-command

Operand field

Some instructions don't need any operand, other need two operands.
6502 commands require operand with proper
addressing mode.

Comment

Comment in a statement does not start from any special character like ; for example. Comment field is implied when appropriate number of operands was taken.


Expressions

Expressions are numbers combined with operators and brackets. You should use square brackets, because parentheses are reserved for 6502 indirect addressing.

Numbers

Numbers are 32-bit signed integers, in the range of -$7fffffff..$7fffffff. A number may be:

  • a decimal number
-12345
  • a hexadecimal number
$abcd
  • a binary number
%10100101
  • an ASCII character
'a' or "a"
  • the origin counter value
*
  • a hardware register
^4e

An abbreviation of Atari hardware register is provided to save you trouble of typing two extra characters (^4e vs $d40e) and to support porting software between Atari 8-bit computers and Atari 5200 console. These are very similar machines, one of biggest differences is different location of hardware registers.

Syntax Chip  Value in Atari 8-bit
computer mode (OPT G-
Value in 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
(x is a hexadecimal digit).

  • an op-code
{lda #0}
Single-byte op-code of the instruction inside braces (e.g. value of {nop} is $ea). Operand is discarded and is necessary only for identifying addressing mode. Instruction should begin just after the left brace and the right brace should immediately follow the operand or the command.
You can skip the operand, if the addressing mode is fixed. Examples:
{lda #}, {jsr}, {bne}, {jmp ()}, {sta a:,x}.

Operators

Binary operators:

+ Addition
- Subtraction
* Multiplication
/ Division
% Remainder
& Bitwise and
| Bitwise or
^ Bitwise xor
<< Arithmetic shift left
>> Arithmetic shift right
= Equal
== Equal (same as =)
<> Not equal
!= Not equal (same as <>)
< Less than
> Greater than
<= Less or equal
>= Greater or equal
&& Logical and
|| Logical or

Unary operators:

+Plus (does nothing)
-Minus (changes sign)
~Bitwise not (complements all bits)
!Logical not (changes true to false and vice versa)
<Low (extracts low byte)
>High (extracts high byte)

Operator precedence:

first[](brackets)
+ - ~ < >(unary)
* / % & << >>(binary)
+ - | ^(binary)
= == <> != < > <= >=(binary)
!(unary)
&&(binary)
last ||(binary)

Note that although the operators are similar to these 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 expression, signed 32-bit arithmetic is used. When range of 32 bits is exceeded, 'Arithmetic overflow' error is generated.


Directives

EQU - assign a value of an expression to the label
Note that label represents a number, not a text macro.
Examples:
five equ 5
here equ *
OPT - set assembly options
Five options are available: You can turn any of these on or off.
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 X-Asm 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. X-Asm 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 ORG directive is executed).

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 single line, separating things with commas.
    You may also define a sine lookup table. Syntax is:
    sin(centre,amp,size,first,last)
    where:
    • centre 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. Default are 0,size-1.
    Example: dta a(sin(0,1000,256,0,63)) defines table of 64 words representing a quarter of sine with amplitude of 1000.

  • real numbers: r(-1.23456e12)
    Real numbers are written in 6-byte Atari Floating-Point format. You can't combine reals with operators, as you can integers.

  • 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 high bit in every byte of 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, assembler stops assembling when encounters end of file.
Example:
 end
INS - insert contents of file
Copies every byte of specified file into the object file and updates the origin counter, as if these bytes were defined with DTA.
You may specify range of inserted file. Syntax is following:
 ins 'file'[,offset[,length]]
First byte in file has offset 0.
If offset is negative, it is counted from the end of 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
The Atari executable program should have a run address specified. A program may be loaded in many areas of memory and started from any address.
 run addr
is equivalent to:
 org $2e0
 dta a(addr)
Examples:
 run start
 run main
INI - generate init address
The Atari executable program may have some routines which are executed during loading process. There may be many init blocks in one file.
Examples:
 ini init
 ini showpic
ERT - generate error if 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
Above example can be rewritten using 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. They are not unofficial instructions, so they work on typical 6502.

ADD - addition without carry
If you have ever programmed 6502, you must have noticed that you had to use a CLC before ADC for every simple addition.
X-Asm 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 instruction following the next instruction.
Example:
 lda #40
 add:sta $80
 scc:inc $81
In the above example word-size variable $80 is incremented by 40.
Nor conditional repeat nor skip pseudo-commands require operand, thus they can be paired with any other command.

JCC, JCS, JEQ, JMI, JNE, JPL, JVC, JVS - conditional jumps
These are a kind of 'long' branches. While standard branches (BNE, BEQ) 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 low byte, and the other to move high byte.
You can't use indirect nor pseudo addressing mode with MW*. Destination must be absolute address (optionally indexed).
When source is also absolute, a mw* source dest will be:
 mv* source   dest
 mv* source+1 dest+1
When source is an immediate, a mw* #immed dest will be:
 mv* <immed dest
 mv* >immed dest+1
When <immed equals >immed and immed is not forward-referenced, X-Asm uses optimization:
 mv* <immed dest
 st* dest+1
If possible, MWX and MWY use increment/decrement commands. E.g. mwx #1 dest is assembled as:
 mvx #1 dest
 dex
 stx dest+1

Addressing modes

All addressing modes are entered in standard convention except the accumulator addressing mode, which should be marked with a @ character (as in Quick Assembler).

There are two extra immediate addressing modes: < and >, which use low/high byte of 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 accumulator, because unary operator > has higher priority than the binary plus.

In absolute addressing modes, X-Asm 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

FAQ

Note: All the following things, which may be odd for you, are familiar to Quick Assembler users. If you have other questions/problems,
contact me.


Back