1
0
mirror of https://github.com/pfusik/xasm.git synced 2024-12-22 00:29:15 +00:00
xasm/xasm.htm
2013-01-07 12:07:27 +01:00

509 lines
18 KiB
HTML

<HTML>
<HEAD>
<TITLE>X-Assembler 2.0 Manual</TITLE>
</HEAD>
<BODY BACKGROUND="6502PROC.GIF">
<CENTER>
<H1>X-Assembler version 2.0</H1>
coded by Fox/Taquart
<HR>
</CENTER>
<H2>INTRODUCTION</H2>
The X-Assembler is an assembler, which generates code for the 6502 processor.
It is 99% compatible with Quick Assembler on 8-bit Atari.
<BR>
<H3>System requirements</H3>
<UL>
<LI> a PC compatible computer with 386 or better CPU
<LI> a MS-DOS compatible OS
<LI> a numeric coprocessor for generating sinus tables.
Your CPU probably has a built-in coprocessor.
</UL>
<BR>
<H3>Creating a source program</H3>
Source file should be standard text file with IBM-style EOLs: CR/LF. You can
use any text editor on PC to prepare your source code.
Single line of source should not be longer than 256 characters.
There is no limitation on the length of the file.
Source may contain tabulators - there are treated as spaces.
Assembler is NOT case-sensitive.
<BR>
<H3>Converting Quick Assembler files</H3>
You must convert Atari text file into PC text file (EOL's from $9b to $0d/$0a),
ATASCII 0-31 and 128-255 characters should be replaced with standard ASCII
characters, using QAsm expressions.<BR>
You also have to change all OPT directives, but usually you needn't them
at all.
<BR>
<H3>Assembling a source program</H3>
Syntax (parameters in brackets are optional):<BR>
<PRE>XASM source [options]
</PRE><TT>'source'</TT> is name of source file.
If no extension given, the .ASX is added by default.<P>
Options are:
<DL>
<DT><TT>/c</TT>
<DD>Enable listing false conditionals.
<DT><TT>/i</TT>
<DD>Disable listing included source.
<DT><TT>/l[:fname]</TT>
<DD>Enable generating listing. If no <TT>fname</TT> given, listing is written to source.lst.
<DT><TT>/o:fname</TT>
<DD>Specify object name. Default is <TT>source.obx</TT>.
<DT><TT>/s</TT>
<DD>Disable converting spaces to tabs. Using tabs makes listing file shorter.<BR>
Tab stops are assumed to be every 8 characters.
<DT><TT>/t[:fname]</TT>
<DD>List label table. If no fname given, table is written at the end of listing.
</DL>
If source is incorrect, X-Asm displays ONLY FIRST encountered error.<P>
Errorlevels returned by X-Asm:<BR>
3 = bad parameters, assembling not started<BR>
2 = error occured<BR>
1 = warning(s) only<BR>
0 = no errors, no warnings<BR>
<H3>Listing structure</H3>
Line of listing includes:
<UL>
<LI> decimal number of line of source file (if source is different than in
previous listed line, appropriate message line is generated)
<LI> hexadecimal origin
<LI> hexadecimal bytes written to object file
Listed are also generated headers. A <TT>xxxx-yyyy&GT;</TT> in place of origin is
a generated header: <TT>$xxxx</TT> is the first and <TT>$yyyy</TT> is the last byte of block.
A <TT>FFFF&GT;</TT> represents two $ff bytes written as a header prefix.<P>
A plus sign placed after hex numbers stands for more bytes written to object
in this line, not listed through lack of space.
<LI> remaining part of listing line is a copy of source
</UL>
<H3>Label table structure</H3>
Line of label table includes:
<UL>
<LI> some info of label:<BR>
<TT>n</TT> - label not used<BR>
<TT>2</TT> - label value known in pass 2 only (label definition uses forward reference
and thus you can't do forward references to that label)
<LI> hex value of label
<LI> name of label
</UL>
<HR>
<H2>X-ASM LANGUAGE STRUCTURE</H2>
Lines of source code may be:
<UL>
<LI> empty lines - ignored, of course
<LI> comments - ignored, too
<LI> statements - not ignored :-)
</UL>
Comment lines must have one of the following characters in the FIRST column
of the line: <TT>* ; |</TT>
<H3>Numbers</H3>
Numbers are 32-bit signed integers, in the range of -$7fffffff..$7fffffff.
A number can be:
<UL>
<LI> a decimal number <TT>-12345</TT>
<LI> a hexadedecimal number <TT>$abcd</TT>
<LI> a binary number <TT>%10100101</TT>
<LI> a character <TT>'a'</TT> or <TT>"a"</TT> (new in 2.0!)
<LI> a hardware register <TT>^31</TT>
<LI> an origin counter <TT>*</TT>
</UL>
I think only 'a hardware register' should be explained. It is a short way
of accessing Atari hardware registers:<P>
<TT>^0x</TT> means <TT>$d00x</TT><BR>
<TT>^1x</TT> means <TT>$d01x</TT><BR>
<TT>^2x</TT> means <TT>$d20x</TT><BR>
<TT>^3x</TT> means <TT>$d30x</TT><BR>
<TT>^4x</TT> means <TT>$d40x</TT><BR>
where x is a hexadecimal digit.
<H3>Expressions</H3>
Expressions are numbers combined with operators and brackets.
You should use square brackets, because parentheses are reserved
for 6502 indirect addressing. Currently there are 19 operators:<P>
<TT>+ </TT>Addition<BR>
<TT>- </TT>Subtraction<BR>
<TT>* </TT>Multiplication<BR>
<TT>/ </TT>Division<BR>
<TT>% </TT>Remainder<BR>
<TT>& </TT>Bitwise and<BR>
<TT>| </TT>Bitwise or<BR>
<TT>^ </TT>Bitwise xor<BR>
<TT>&LT;&LT; </TT>Arithmetic shift left<BR>
<TT>&GT;&GT; </TT>Arithmetic shift right<BR>
<TT>= </TT>Equal<BR>
<TT>&LT;&GT; </TT>Not equal<BR>
<TT>!= </TT>Not equal (same as &LT;&GT;)<BR>
<TT>&LT; </TT>Less than<BR>
<TT>&GT; </TT>Greater than<BR>
<TT>&LT;= </TT>Less or equal<BR>
<TT>&GT;= </TT>Greater or equal<BR>
<TT>&& </TT>Logical and<BR>
<TT>|| </TT>Logical or<P>
Operator precedence:
<PRE>
first []
* / % & &LT;&LT; &GT;&GT;
+ - | ^
= &LT;&GT; != &LT; &GT; &LT;= &GT;=
&&
last ||
</PRE>
Compare and logical operators assume that zero is false and non-zero is true.
They return -1 for true.<P>
When calculating expression, 32-bit arithmetic is used. When range of 32 bits
is exceeded, <TT>'Arithmetic overflow'</TT> error is generated.<P>
If result of expression has improper size, <TT>'Value out of range'</TT> error occurs.<P>
Note difference beetwen X-Asm 2.0 and QAsm/X-Asm 1.2: in older assemblers,
which used 16-bit arithmetic, a <TT>LDA 0-1</TT> was correct (<TT>LDA $ffff</TT>), but X-Asm 2.0
encounters an error: address can't be negative.<P>
X-Asm recognizes now signed bytes: <TT>LDA #-1</TT> is OK.
<H3>Statements</H3>
A statement is divided into fields: a label field, an operation field,
one or two operand fields, and a comment field. There should be at least
one space between every two fields and there can't be any space within a field
excluding strings.
<H4>Label field</H4>
This field is optional. It is required only by the <TT>EQU</TT> directive.
Specyfying this field definies a label. Defined label represents an integer
of range -$ffff..$ffff.<P>
Name of label must begin in column 1 and can contain letters, digits
and underscores (<TT>_</TT>). Digit can't be label's first character. Name of label
can be as long as you want and all the characters are meaningful.<P>
In Quick Assembler only 6 leading characters were recognized
and some programs may not compile well under X-Asm for this reason.<P>
Defining a label without using <TT>EQU</TT> makes it equal to current value
of the origin counter. Label can't be redefined.
<H4>Operation field</H4>
Operation field is the only field which is always required.
You have to put one or more spaces or tab characters between label
and operation field. If no label is defined, line must start with a blank
character. Operation field is always 3 letters long. It can be:
<OL TYPE=a>
<LI><I> a 6502 processor command</I>
<LI><I> a compiler directive</I>
<LI><I> a pseudo-command</I>
</OL>
<OL TYPE=a>
<LI><I> 6502 command</I><BR>
One of 56 well known processor commands.<BR><BR>
<LI><I> compiler directive</I><BR>
One of the following:
<DL>
<DT><TT><B>EQU</B></TT> - assign a value of expression to the label
<DD>Note that label represents a number, not a text macro.<P>
Examples:
<PRE>five equ 5
ten equ five+five
</PRE>
<DT><TT><B>OPT</B></TT> - set assembling options
<DD>Currently there are two options: listing generating and headers generating.
You can turn any of these on or off.<P>
Examples:
<PRE> opt l- listing off
opt h- headers off
opt l+h- listing on, headers off
</PRE>
Remember not to put a space between options:
<PRE> opt l+ h-
</PRE>
is actually
<PRE> opt l+
</PRE>
because h- is a comment.<P>
Default (if no opt specified) is <TT>opt l+h+</TT>.<P>
<DT><TT><B>ORG</B></TT> - set new origin counter
<DD>Examples:
<PRE> org $600 code will be located starting from $0600
table org *+100 'table' points to 100 bytes of uninitialized data
</PRE>
New! You can set some options applied to new header (if headers are on):
<PRE> org $600
rts
org a:$601
</PRE>
'a:' tells X-Asm to always make a header, even it is unnecessary (as in above).
So by default X-Asm 2.0 does not generate unnecessary headers, distinct from
QAsm and X-Asm 1.2.
<PRE> org f:$700
</PRE>
'f:' works same as 'a:', but additionally tells to generate a $ff,$ff prefix
before header. X-Asm adds it to the first header in file by default, so use
this option only if you want the $ff's somewhere inside.<P>
<DT><TT><B>DTA</B></TT> - define data
<DD>You may define:
<UL>
<LI> numbers
<UL>
<LI> bytes: <TT>b(200)</TT>
<LI> words: <TT>a(10000)</TT>
<LI> low bytes of words: <TT>l(511)</TT> defines byte 255
<LI> high bytes of words: <TT>h(511)</TT> defines byte 1
You may enter many expressions in parentheses and combine different types
of data in single line.<P>
You may also define a sinus table. Enter this expression:<BR>
<TT>sin(centre,amp,size,first,last)</TT><BR>
where:
<UL>
<LI> centre is a number which is added to every value of sinus
<LI> amp is the amplitude of sinus
<LI> size is the period of sinus
<LI> first,last define range of values in the table.
They are optional. Default are 0,size-1.
</UL>
Example: <TT>dta a(sin(0,1000,256,0,63))</TT> defines table of 64 words representing
a quarter of sinus with amplitude of 1000.
<LI> real numbers: <TT>r(-1.23456e12)</TT><BR>
Real numbers are written in 6-byte Atari Floating-Point format. You can't
combine reals with operators, as you can integers.<P>
</UL>
<LI> text strings
<UL>
<LI> ASCII strings: <TT>c'Text'</TT> or <TT>c"Text"</TT>
<LI> ANTIC strings: <TT>d'Text'</TT> or <TT>d"It's something new!"</TT>
</UL>
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.<P>
Placing a '*' character after a string inverts bit 7 in every byte of string.<P>
</UL>
Examples of <TT>DTA</TT>:
<PRE>
dta b(2,5),a(1000,-1),l(12345,sin(0,127,256))
dta d"ANTIC"*,c'It''s a string',b(155)
</PRE>
<DT><TT><B>ICL</B></TT> - include another source file
<DD>Specifies another file to be included in the assembly as if the contests of
the referenced file appeared in place of the <TT>ICL</TT> statement. The included file
may contain other <TT>ICL</TT> statements.<P>
Examples:
<PRE>
icl 'macros.asx'
icl 'c:\atari\xasm\fileio.asx'
</PRE>
<DT><TT><B>END</B></TT> - end assembling of file
<DD>Remaining part of the file is not assembled. If this statement does not occur,
assembler stops assembling when encounters end of file.<BR>
Example:
<PRE>
end
</PRE>
<DT><TT><B>INS</B></TT> - insert contents of file
<DD>Copies every byte of specified file into object file and moves origin counter,
as if these bytes were defined with <TT>DTA</TT>.<P>
Examples:
<PRE>
ins 'picture.raw'
ins 'tables.dat'
</PRE>
New! You may specify range of inserted file. Syntax is:
<PRE>
ins 'file'[,offset[,length]]
</PRE>
First byte in file has offset 0.<P>
If offset is negative, it is counted from the end of file.
<PRE>
ins 'file',-256 inserts last 256 bytes of file
ins 'file',10,10 inserts bytes 10..19 of file
</PRE>
<DT><TT><B>RUN</B></TT> - generate run address
<DD>The Atari executable program should have run address specified. Remember that
a program may be loaded in many areas of memory and started from any address.
<PRE> run addr
</PRE>
is equivalent to:
<PRE> org $2e0
dta a(addr)
</PRE>
Examples:
<PRE> run start
run program
</PRE>
<DT><TT><B>INI</B></TT> - generate init address
<DD>The Atari executable program may have some routines which are executed during
loading process. There may be many init blocks in one file.
Examples:
<PRE> ini init
ini showpic
</PRE>
<DT><TT><B>ERT</B></TT> - generate error if expression is true
<DD>Examples:
<PRE> ert *&GT;$c000
ert len1&GT;$ff||len2&GT;$ff
</PRE>
<DT><TT><B>IFT</B></TT> - assemble if expression is true<BR>
<TT><B>ELS</B></TT> - else<BR>
<TT><B>EIF</B></TT> - end if<BR>
<DD>Example:
<PRE>noscr equ 1
ift noscr
lda #0
els
lda #$22
eif
sta $22f
</PRE>
</DL>
<LI><I> pseudo-command</I><BR>
It is something like built-in macro. It replaces two or more standard
processor commands. Note that it is not an illegal instruction and works
on typical 6502.
<DL>
<DT><TT><B>ADD</B></TT> - addition without carry
<DD>If you ever programmed 6502, you must have noticed that you had to use a <TT>CLC</TT>
before <TT>ADC</TT> for every simple addition.<BR>
X-Asm can do it for you. <TT>ADD</TT> simply replaces two instructions: <TT>CLC</TT> and <TT>ADC</TT>.<P>
<DT><TT><B>SUB</B></TT> - subtraction
<DD>It is <TT>SEC</TT> and <TT>SBC</TT>.<P>
<DT><TT><B>JNE, JEQ, JCC, JCS, JPL, JMI, JVC, JVS</B></TT> - conditional jumps
<DD>They are a kind of 'long' branches. While standard branches (<TT>BNE, BEQ</TT>) have
range of -128..+127, these jumps have range of all 64 kB.<P>
For example: a <TT>JNE DEST</TT> is replaced with:
<PRE> beq *+5
jmp dest
</PRE>
<DT><TT><B>INW</B></TT> - increment word
<DD>It is a 16-bit memory increment command. An <TT>INW DEST</TT> will be replaced by:
<PRE> inc dest
bne _skip
inc dest+1
_skip equ *
</PRE>
The <TT>_skip</TT> label is not declared of course.<P>
<DT><TT><B>MVA, MVX, MVY</B></TT> - move byte using accumulator, X or Y
<DD>These pseudo-commands require two operands.
<PRE> mva source dest = lda source : sta dest
mvx source dest = ldx source : stx dest
mvy source dest = ldy source : sty dest
</PRE>
<DT><TT><B>MWA, MWX, MWY</B></TT> - move word using accumulator, X or Y
<DD>Also require two operands. They are something like combination of two <TT>MV*</TT>'s:
one to move low byte, and the other to move high byte.<P>
You can't use indirect nor pseudo addressing modes with <TT>MW*</TT>.<P>
Destination must be absolute address (indexed or not).<P>
When source is also absolute, a <TT>MW* SOURCE DEST</TT> will be:
<PRE> mv* source dest
mv* source+1 dest+1
</PRE>
When source is immediate, a <TT>MW* #IMMED</TT> dest will be
<PRE> mv* &LT;immed dest
mv* &GT;immed dest+1
</PRE>
but when &LT;IMMED = &GT;IMMED and IMMED is not forward-referenced,
X-Asm uses optimization:
<PRE> mv* &LT;immed dest
st* dest+1
</PRE>
</DL>
</OL>
<H4>Operand</H4>
It depends on the operation field. Some statements don't need an operand
or need two operands.<P>
6502 commands require operand depending on the addressing mode.
Addressing modes should be entered in standard convention except
the accumulator addressing mode, which should be marked with a <TT>@</TT> character
(as in Quick Assembler).<P>
There are two extra immediate addressing modes: &LT; and &GT;, which use low/high
byte of word is used rather than byte value.<P>
In absolute addressing modes, X-Asm examines expression and uses zero-page
addressing mode if it thinks it is possible to do it. You may override it
with <TT>a:</TT> and <TT>z:</TT> prefixes.<P>
Examples:
<PRE>
nop
asl @
lda &GT;$1234 assembles to lda #$12
lda $100,x
lda a:0 generates 16-bit address
jmp ($0a)
lda ($80),y
</PRE>
New! X-Asm 2.0 brings pseudo addressing modes. They are similar to
pseudo-commands and you may use them as standard addressing modes
in all 6502 commands and pseudo-commands, excluding <TT>MW*</TT>:
<PRE> 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
</PRE>
<H3>Problems</H3>
These notes may help you solve problems:
<UL>
<LI> No spaces are allowed within a field.
<PRE>label equ 1 + 2
</PRE>
causes label to be equal 1 (<TT>+ 2</TT> is treated as a comment).<P>
<LI> <TT>&LT;</TT> and <TT>&GT;</TT> represent addressing modes rather than LOW and HIGH operators.<P>
You specify <TT>lda &LT;table</TT>, not <TT>lda #&LT;table</TT> like in most 6502 assemblers.<P>
<LI> Label definition does not include a colon
<PRE>label: lda ^4b ERROR - colon after label name
</PRE>
<LI> Exactly one run address should be specified<P>
Remember that unlike in other assemblers
<PRE> end start
</PRE>
does not tell the assembler that <TT>start</TT> is the run address (it is a comment).
You must specify the run address with <TT>RUN</TT> directive.<P>
<LI> X-Asm reads source twice (in pass 1 and pass 2)<BR>
This allows forward references, but not too complex.<P>
Keep in mind that assembler should know all the values in second pass.<P>
Example:
<PRE>two equ one+one This value is known in 2nd pass only
one equ 1 This value is known as early as in 1st pass
</PRE>
These values can be fixed in 2 passes.<P>
But if you insert following statement as first line:
<PRE>three equ one+two
</PRE>
X-Asm will generate an error because it doesn't know the value of <TT>three</TT> in
second pass.<BR>
(sorry for v1.2 users: <TT>EQU</TT> forward reference didn't work at all).<P>
<LI> X-Asm displays only first error<BR>
When you correct one error don't be surpised if you get another one.<P>
<LI> If you encounter X-Asm works improperly, please <A HREF=mailto:pfusik@elka.pw.edu.pl>let me know</A>.
</UL>
</BODY>
</HTML>