----------------------------------------------------------------------
Copyright (C) 1990 by Natrlich!
This file is copyrighted!
Refer to the documentation for details.
----------------------------------------------------------------------
NASM65 --- an Atari 8-Bit Crossassembler for the Atari ST (et al.)
Manual v1.9* for NASM65
Currently not quite up to date
Copyright ½ 1992 by Natrlich!
on sources, binaries and manuals
¯¯ Bang that Bit that doesn't Bang ®®
I n t r o d u c t i o n
NASM65 is a <portable> single-pass cross-assembler that produces 6502
code. NASM65 currently runs on 680x0 Ataris under TOS, on the AMIGA
and apparently under UNIX. It its conceivably portable to MSDOS.
The assembler produces two kinds of output, directly executable code
for the Atari 8-Bit computer (FF FF headers and all that...) or
linkable modules to be used with NLINK65. Instantly executable code
(furtheron referred to as "runnable") is non-relocatable and
non-linkable. The other kind of output are relocatable and linkable
object files. That production mode is further on referred to as
"relocatable". NASM65 is closely compatible to MAC65 from OSS
(now ICD), but not 100%. The differences will be noted later on.
Compatibility worsens somewhat when relocatable output is produced.
(Apple and C64 users, have a peek at XTRCTBIN)
U s a g e
nasm65 [-{rwbqx}][-{tn}][-e number][-o binary][-h includedir] <source>
-t TOS switch, wait for a keypress after running
-w The "what the ...." switch, even though errors occured an output
file is generated.
-r The runnable switch. NASM65 will create an Atari 8-Bit binary
file for direct execution
-h Supply alternate header directory (Default is taken from the
Environment variable >INCLUDE<)
-e Limit the number of errors: 0 = show all
-o Specify alternate output file pathname (or filename)
-b Don't emulate MAC/65 too closely (will improve output in the
runnable mode)
-x List all global variables. Defined globals appear with a '*'
in front.
-q Quiet flag, probably turns up the volume
-n Noisy tokenization. Try it on your ST.
There is no order in which switches or the source file have to appear.
C r e a t i n g r u n n a b l e A T A R I 8 - B i t f i l e s
Type from a shell:
nasm65 -r <source.s65>
That will create a output file {source}.COM
Transfer this file (with NASTY for instance) to a 8-Bit Atari computer
and execute it there.
C r e a t i n g l i n k a b l e m o d u l e s
Type from a shell
nasm65 <source.s65>
That will create a output file {source}.o65, that can then be linked
together with other relocatable output files.
H o w N A S M 6 5 f i n d s i t s f i l e s
Source files:
NASM65 first looks in the current directory for the file you specified
on the command line. After that it tries again by replacing the filename
extension with .S65. If that doesn't work either, NASM65 signals an
error. This means if you type "nasm65 foo" and you have a file FOO and a
file FOO.S65, the file "FOO" will be loaded.
Include files:
If the extension has been omitted and it looks like a filename,
not a pathname, NASM65 will append the default extension .H65 and
insert the default header path at the front.
Else NASM65 looks first in the current directory for the include file.
Afterwards NASM65 replaces the extension with .H65 and it will look
in the directory given either by the environment variable INCLUDE or
by the command option '-h'.
If NASM65 fails again, it will try last to open the file without the
.H65 extension.
S o u r c e c o d e f o r N A S M 6 5
Generally speaking MAC65 style code w i l l work with NASM65. Other
assemblers' source (like SYNASM or MAE) might need to be converted to
NASM65 syntax before assembly [a SED script might be helpful...].
Problems may appear because of the single-pass structure of the
assembler. Conventional assemblers use two passes, one pass collects
all the symbols and if possible assigns values to them. The second pass
actually produces the code. NASM65 tries to do it all in one pass.
Of course there is the problem with forward references f.e.:
...
bne bar
inx
bar clc
...
When the assembler encounters "bne bar" it doesn't yet know, what
value "bar" has and so can't produce proper code for that branch
yet. Only when the bar label is encountered is generation possible.
Therefore NASM65 has some limitations on the code that it can produce.
You will find out about it...
A f e w g o l d e n r u l e s
[Take those marked with a ! really seriously]
1! Don't produce code for zeropage ($00-$FF), be careful of
wraparounds $FFFF-$00 if you assemble ROM-code.
2! Define macros and equates EARLY! the sooner the better.
3. The fewer forward references you use, the less trouble you and
NASM65 will have. Forward references are neccessary only for
¯Branches®, ¯Subroutines® and ¯Data®. Coding like this
lda #$40
sta nmien
nmien = $D40E
is not only in bad style, it's screamingly inefficient and doesn't
work with NASM65 in the module mode.
4! In the "relocatable" mode, all label settings that are not PC-
relative (f.e. `FOO=$D4' but not `FOO: LDA #2') must be
done before the label is used.
<label> = <value>
5! Never put macro definitions after their first invocation.
6. Try to define everything (labels and macros) ahead of its first
usage
7. Put macros and equates, especially if they are used in several
different sources, in common include files. Never mind that
file foo.s65 needs only one of the 100 macro definitions of
"macro.h65" and 10 of the 500 equates of "defines.h65", NASM65 will
be grateful! Be sure to keep PC-relative labels out of the
include files as MUCH AS POSSIBLE. It makes for better style and
also keeps the error count down, when linking your objects.
8. Always remember that MAC65 is a three/two-pass NASM65 is a
single-pass assembler.
9. Always define everything ahead of its usage, except PC-relative
labels like branch, subroutine and data labels.
10. Use local labels as much as possible. Use global labels only for
system equates and subroutines and data that are accessed by out-
side files.
11! If you are into conditional assembly and you like to control that
with a central include file, be sure to use non-PC relative labels
as switches.
e.g.
"header.h65"
errorchecking
"source.s65"
.if .def errorchecking
...
.endif
will **FAIL**, when two files using the same include file are lin-
ked together. Rather use
"header.h65"
errorchecking = 1
"source.s65"
.if .def errorchecking
...
.endif
or even better
.if errorchecking
...
.endif
12! Undefine forward referenced labels in .MACRO definitions. It pays!
13. Apple and C64 users oughta ensure that addresses in their object
files are ascending from start to end. No code like this will
work for you:
*=$4000
clc
bcc foo
*=$30F0
foo rts
T h e " r e l o c a t a b l e " m o d e
The relocatable mode is the default mode, you did not supply a -r
switch on the command line. That means NASM65 will produce an object
file suitably for linking and relocation at runtime. The relocatable
mode imposes some restrictions on your source code.
Forward references can only be made to PC-relative addresses, that
means that all System-equates like (STACK=$100) have to be done before
they are used the first time. This is not really a problem since it is
good style to use a central include file for global symbols that
is read in at the beginning of the source. Since the linker can also
only link PC-relative global symbols (local symbols and not PC-relative
labels are not saved in the object file) NASM65 makes it a necessity.
There is one exception to this rule, see 'Linking Zeropage-labels'.
e.g.
File "sys.h65" :
NMIEN = $D40E
STACK = $100
File "s1.s65":
.include #sys.h65
foo:
lda #$C0
sta NMIEN ;; from sys.h65
jsr bar ;; not in s1.65 or sys.s65 !! -> open reference
bcc foo
rts
File "s2.s65":
.include #sys.h65
bar: ;; here it gets defined. NLINK s1 s2 would
lda STACK ;; produce a file with bar in s1 correctly
clc ;; set to the address of bar in s2
adc STACK+1
rts
The second goal that was set for NASM65 (apart from being a MAC65
compatible cross-assembler) was relocatability and linkability. And
as far as *I* know, no assembler exists that does produce run-time
relocatable 6502 code. The greatest problem with relocating 6502 code
is with source code like this:
lda #>foo ; get 16-Bit address into A an X
ldy #bar-foo ; get length in Y
ldx #<foo
jsr print ; JSR to some routine
bcc out
foo: .byte "F.T.O.E. coming soon.." ; the message to be printed
bar:
Now for you the human, it's quite easy to figure out that the
"lda" and "ldx" belong together, but for the relocating code it's not
so easy. Semantic checking of this kind easily slides into the black
magic dept. of computer science (--> A.I.) and that would be just
overkill.
Ok so there are some limitations in what you can do, here are a
couple of things to know about NASM65.
0. Linkable labels are:
ZEROpage labels declared with ==
All PC-relative global labels
All PC-relative macro labels, except those starting with @
1. Arithmetic with relative addresses is a tricky thing, since
you don't know at assembly time, what the value is. Therefore
many operations don't make sense any more. There are only a few
operations you _can_ use with PC-relative labels. This does not
apply to the runnable mode by the way.
Coming up the only valid operations possible in the relocatable
mode. Refer to the appendix for <words>...
<value> <operation> <value> -> <value>
<operation> <value> -> <value>
<address> '+' <value> -> <address>
<address> '-' <value> -> <address>
<value> '+' <address> -> <address>
<address> '-' <address> -> <value>
'<' <address> -> <saddress> (* careful!! *)
'>' <address> -> <saddress> (* careful!! *)
For example:
bput 1,:header,:l_header,X_IS_READY
:header .byte "Starting off with this little test...",155
:l_header = *-:header
That ain't working...
This will give a warning (not an error, although that might
be changed in the future), because :l_header was assumed to
be an address, but is in fact a value.
bput 1,:header,:e_header-:header,X_IS_READY
:header .byte "Starting off with this little test...",155
:e_header
THAT's the way you do it.
2. An immediate expression that takes either the LSB or the MSB of an
PC-relative address like this
lda #>bar ; grab MSB of `bar'
bar:
lda #<bar ; grab LSB of `bar'
must start off with a '>' (that is "#>foo" or "#>[foo+1]")
or with a '<'. Although in MAC65 "lda #LABEL" and "lda #<LABEL" is
the same, it isn't for NASM65. Actually the same code will be
assembled, but relocatability and linkability will be impaired.
Note that there has been a change in operator precedence from MAC65
concerning the unary '>' and '<' operators. Refer to the table in
the appendix. MAC65 treated "lda #>foo-2" as "lda #[>foo]-2, but
NASM65 treats it as lda #>[foo-2]. This might make recoding of some
old code necessary.
3. .DS works very much different in the relocatable mode than in the
runnable mode (see also "Other Useful Stuff To Know"). Since you
can't use *= anyway, this is not the way to define zeropage labels
or any other non-PC relative labels for that matter. Like
*=$F0 ;;; WRONG
SRC .ds 2
*=$2000
etc.
4. .= works different from the way it does in the runnable mode. MAC/65
allows pass conditional assembly like this:
pass .= pass + 1
.if pass=1
.include ...
.endif
Since NASM65 is single-pass, this isn't a useful technique anymore.
Normally NASM65 would think that 'pass' on the right side of .= is
a forward reference. But in the runnable, for enhanced com-
patibility with MAC/65, pass will get the value of the program
counter.
In the relocatable mode, 'pass' on the right side of .= WILL be
treated as a forward reference, resulting in numerous errors.
L i n k i n g Z e r o p a g e - l a b e l s
There is a way to link zeropage labels with NASM65, so that for
example common vectors can be shared. As you have come to like
it, here is an example to make the point:
"a.s65"
foo == $88 ; declare this 0-page label as linkable
lda #>BAR ; just some stuff to fill up space
sta FOO+1 ; simple expressions are OK
lda #<BAR
sta FOO
jmp FUBAR
bar: .byte $74
"b.s65"
.zext foo ; tell that foo is an external 1 byte address
; that shouldn't be relocated
fubar:
ldy #0 ; Let's use FOO
lda (FOO),y
sta $2C8
rts
NASM65 won't mind some simple arithemtic, as long as you don't use
PC relative addresses. Note that $45 + $120 = $65 and not $165. Don't
try to be overly clever with this feature, keep it simple and stupid
and be happy that this works at all.
What you must not do by the way is this:
.ZEXT FOO ; that's ok
FOOLSB = FOO ; but this and
FOOMSB = FOO + 1 ; that won't work
.ZEXT is more or a less a hack and conflicts with the generality of
the rest of NASM65. Sorry. But doing this right would require
a whole new internal assembler structure.
D i f f e r e n c e s b e t w e e n M A C 6 5 a n d N A S M 6 5
Text after a correctly parsed instruction is assumed to be part of the
comment field by MAC65. NASM65 treats this as garbage. Every comment
has to start with a semicolon ';'.
f.e.
lda #2loser comment w/NASM65
is treated by MAC65 as
lda #2 loser comment w/NASM65
but generates an error with NASM65.
obsolete directives
.PAGE
.TITLE
.SET
.OPT
.TAB
are parsed but nothing will happen.
'>' and '<' (unary) have lower precedence.
MAC65 generates a new binary header at least every 252 bytes (don't
ask me why). You can check with CHKFFFF that actually the same amount
of code (in the runnable mode of course) was generated by NASM65 but
with much less headers. That makes by the way loading of binary files
much faster and decreases overall size.
The include syntax is similiar, but adjusts to your kind of OS. So
you can't expect to assemble instructions like
.include #D3:foo.bar
properly on the ST for instance.
NASM65 currently produces no listing file!
.REF may now be used anywhere in an expression, whereas MAC65
allowed .REF only in .IF expressions.
.SET doesn't work anymore. Compiling with an offset must be (clumsily ?)
simulated by using the linker.
Due to the single-pass nature of NASM65, NASM65 does not do a third
pass over macros like MAC65 does. For example:
.macro bar
jmp foo
foo
.endm
*=$2000
bar
bar
bar
MAC/65 produces: NASM65 produces:
$2000 jmp $2003 jmp $2003
$2003 jmp $2006 jmp $2003
$2006 jmp $2009 jmp $2006
To alleviate this problem rewrite the macro as:
.macro bar
.if .def foo
.undef foo
.endif
jmp foo
foo
.endm
O t h e r u s e f u l s t u f f t o k n o w
When assembling in the runnable mode, NASM defines a label "__RUN"
for you. This way you can with the use of a simple .IF statement
have a file that can be both, assembled as a standalone program and
as a linkable module.
e.g.:
.if .def __RUN
*=$3000
.endif
You have one new directive at your disposal. It's called .ALIGN and
aligns the module on a given boundary (like a page f.i.).
Also NASM always defines the label __NASM65, for conditional assembly
depending on the assembler used for example.
U s i n g r u n t i m e r e l o c a t i o n
The bad news is that the mover isn't quite as smart as the linker
and can't properly move all the code there is. To keep the MOVER happy
you should obey these golden rules:
|R_START means beginning of your code. This is the first assembled
byte of the first object file linked.
|R_END means end of your code. This is the last assembled byte of
the last object file or library. (Excluding the mover)
1. The MOVER fixes all addresses that point into the program space
starting from |R_START - 1 to |R_END, If you somehow managed to
convince NASM65 to assemble |R_START-$100, you will surely lose.
Also bad is coding like this:
start:
jmp *+40
.byte "Fooble"
end:
This probably won't work anyway, but the MOVERs sure won't relocate
it as well.
2. The MOVER needs some information about the program it has to move.
This is done with the aid of two tables. I won't discuss the makeup
of these tables, as it would be too much type work. But you can
keep the size of these tables down, by keeping data and code as
seperate as possible. But this is something you should only consider,
if your program needs 32K file space.
3. Don't expect to get 65C02 insructions relocated correctly. 65C02
compatibility was a last ditch effort on my part. Since the Atari
8-Bit doesn't have a 65C02 this isn't really a problem. Try it out
though, maybe it will even work.
E r r o r s
Yes it can happen to the best of us. Errors in the source code. NASM65
will try to tell you as clearly as possibly in 1000 words or less, where
and why you lost. The form of the message is in most cases, something
like this:
"source filename"[ linenumber in source], <continued>
macroname[ linenumber in macro], ... "Error [error message]"
There are several different error levels
a) normal errors -- f.e. syntax, undefined macro...
b) fatal errors -- f.i. out of memory. file not found...
c) internal errors -- this shouldn't happen
d) serious ....up errors -- NASM65 crashed downright. VERY VERY BAD!
You can fix errors of type 'a' and 'b', they are your problem. Errors
of type 'c' and 'd' are NASM65's problem, there is probably nothing you
can do.
W a r n i n g s
Warnings aren't errors 'cause there is a good chance that the assembler
will actually do what you want to happen. BUT if things go wrong it
isn't a bad idea to look at the warnings.
A p p e n d i x
M e m o r y r e q u i r e m e n t s
NASM65 is memory hungry. Although it does use dynamic memory allocation
instead of fixed tables it needs after its load about 150K space to
work in. For larger files figure about 1/4 MB. There is a real, true,
honest-to-goodness garbage collector coming up in version 3.0 (sorry).
(Well just maybe *NOT*)
S o u r c e C o d e
The lines of source must adhere to some positional restrictions as
you may easily figure out from the schemata below. Just in case you
never saw an assembler before.
Beforehand introducing a few shortcuts
[..] = optional something '..' enclosed in square brackets
^ = Start of line
$ = End of line
. = any number of SPACE or TAB but at least one
_ = any number of SPACE or TAB possibly none
X = any characters except LF possibly none
other characters represent themselves
^_[;X]$
^[label]_;[X]$
^[label].[instruction.[#][_expr]]_[;X]$
^[label].[directive.[stuff][,stuff]*]_[;X]$
^[label].[macroname.[parameter][_,_parameter]*]_[;X]$
^[label].[assignment.[expr]]_[;X]$
Examples:
foo
inx
foo inx
lda foo
foo lda foo
lda #2
foo lda #2 ; this is a comment
.byte 2
foo .byte 2
.byte 2,"FOO"
foo .byte 2,"FOO"
foo POKE foo,3
foo = 34
S p e c i a l s
*
* denotes the program counter or PC, and can be used in expressions
like any other label.
A
Used by ROL ROR LSL LSR to indicate usage of the 6502 A-register.
Therefore you can't use A as a label.
X
Y
Used by indexed or indirect instruction such as LDA (FOO,X) or
STA BAR,Y. Don't use X or Y as labels as well.
I d e n t i f i e r
An identifier is either a label or a macroname. The morphological
structure of an identifier is simply any string of characters that
is taken from this character set [A-Z a-z 0-9 $ @ _ . : ?].
An identifier may not begin with a number. Non macro identifiers should
not begin with a '@' and user identifiers should generally not start
with a '_' (underscore), but this isn't enforced. An identifier must
not just be "A" or "a", "X" or "x", "Y" or "y". Internally all
identifiers are converted to uppercase, so that there is no difference
between "small" and "SMALL". A label that begins with a ':' or '?' is
always a local label.
Label definitions may optionally be directly followed by a ':', which
isn't part of the label. An <equate> is a label that gets its value
by a '=' assignment.
Examples:
A = 45 ;; wrong!, you can't use A as a label name
FOO = 23 ;; OK!
FOO: inx ;; OK global label = "FOO"
Foo:: inx ;; OK global label = "FOO:"
:FoO: inx ;; OK local label = ":FOO"
FoO:: inx ;; WRONG! This is the same label as the one two lines up
?_:_: DEX ;; OK local label = "?_:_"
01234 ;; WRONG! label would start off with a digit
?01234 ;; OK local label = "?01234"
:01234 ;; OK local label = ":01234"
?01234 ;; WRONG! label is already defined (two lines up)
.macro FOO ;; OK. Macros may have the same name as labels!
A s s i g n m e n t s
There are four different possibilities to assign a value to a label.
Note that '^' denotes the beginning of a source line (as above). Also
be aware that some of these <labels> are <equates>. The distinction
is important when you look at macros.
Type A:
^<label> = <expr>
This assigns the value of <expr> to <label>. You can't overload
this label with another assignment.
Examples:
foo = 2 ;; lda #foo would assemble to A9 02
bar = *+foo ;; bar = PC + 2. PC-relative!
NMIEN=$D40E ;; sta NMIEN would assemble to 8D 0E D4
foo = 3 ;; doesn't work, cause foo is already defined!
Type B
^<label> .= <expr>
This is almost the same as <label> = <expr> with the difference
that you can overload <label> again! Using .= with forward references
is possibly dangerous.
Examples:
foo .= 2 ;; lda #foo would assemble to A9 02 <-+
bar .= *+foo ;; bar = PC + 2. PC-relative! |
NMIEN.=$D40E ;; sta NMIEN would assemble to 8D 0E D4 |
foo .= 3 ;; Works fine, cause its a .= assignment -+
Type C
^<label> == <expr>
This is used in conjunction with .ZEXT. Tells the assembler to
include this zeropage! label in the list of linkable symbols.
Examples:
foo == $56 ;; OK!
foo == $456 ;; WRONG! only zeropage allowed
Type D
^<label>
A label that isn't followed by '==', '=' or '.=' takes on the
value of *, the program counter.
Example:
foo jmp foo ;; endless loop!
O p e r a t o r s
[<expr>] Parenthesis (actually brackets)
<expr> + <expr> Addition
<expr> - <expr> Subtraction
- <expr> Minus
<expr> * <expr> Multiplication
<expr> / <expr> Division
<expr> \ <expr> Modulo
These are the normal operators for unsigned 16-Bit values, that you
know from C. And they behave that way too, 'cause NASM65 is written
in C. Note that 16-Bits overflow after 65535 to 0.
Some examples of results to expect
5/3=1 5/2=2 5/1=5 5/2*2=4 4+1-6=65535
4-2+2=4 4-[2+2]=0 4-2*2=0 5\3=1 8\2=0
-1=65535 8+[-1]=7
<expr> .NOT <expr> Boolean negation
<expr> .AND <expr> Boolean AND
<expr> .OR <expr> Boolean OR
<expr> = <expr> Equality
<expr> <> <expr> Inequality
<expr> < <expr> Less than
<expr> > <expr> More than
<expr> >= <expr> More or equal
<expr> <= <expr> Less or equal
These too are quite like C. Everything which isn't 0 is taken to
be 'true'. 0 therefore means 'false'.
.NOT 0 = 1 0 .AND -2 = 0 1 .AND 1 = 1
5 .OR 0 = 1 0 .OR 0 = 0 .NOT 1 .OR .NOT 0 .AND .1 = 0
43 > 43 = 0 43 > -1 = 0 43 > 0 = 1
43 < 43 = 1 43 < -1 = 1 43 < 0 = 0
43 >= 43 = 1 43 >= -1 = 0 43 >= 0 = 1
43 <= 43 = 1 43 <= -1 = 1 43 <= 0 = 0
43 = 43 = 1 43 = -1 = 0 43 = 0 = 0
43 <> 43 = 0 43 <> -1 = 1 43 <> 0 = 1
<expr> & <expr> Bitwise AND
<expr> ! <expr> Bitwise OR
<expr> ^ <expr> Bitwise EOR
These are your regular bitwise operators, what is there to say ?
Some examples just for fun:
$0001 & $FFFE = $0000 $5AF0 & $5555 = $5050
$0001 ! $FFFE = $FFFF $5AF0 ! $5555 = $5FF5
$0001 ^ $FFFE = $FFFF $5AF0 ^ $5555 = $0FA5
.DEF <label> Label defined ?
.REF <label> Label referenced ?
.DEF and .REF can be used to determine, whether a label has already
been defined or whether it has been referenced already. There is
unlike MAC65 no restriction on usage.
Examples:
.if .not .def foobar
.error "Should have included fooble.foobar first!"
.endif
lda #.ref leopold * 6 ;; senseless, but it works!
O p e r a t o r p r e c e d e n c e
Associativity Precedence level Operator Description
- 9 .DEF Special
- 9 .REF Special
L 8 - Unary minus
L 8 .NOT Boolean NOT
L 7 * Multiplication
L 7 / Division
L 7 \ Modulo
L 6 + Addition
L 6 - Subtraction
L 5 ! Bitwise OR
L 5 ^ Bitwise EOR
L 5 & Bitwise AND
L 4 < Most significant byte
L 4 > Least significant byte
- 3 <= Less or equal
- 3 >= Greater or equal
- 3 = Equal
- 3 <> Not equal
- 3 > Greater than
- 3 < Less than
L 2 .AND Boolean AND
L 1 .OR Boolean OR
L 0 , Seperator
D i r e c t i v e s
1. A s s e m b l e r D i r e c t i v e s
.ALIGN <expr>
This is a special directive, that only works in the relocatable
mode and only if no code yet has been generated! The point is
that you sometimes want to align code on a page boundary for
example display lists or display list interrupt routines.
Aligns code to the next boundary given by <expr>.
0x1 == word align (2 bytes)
0x3 == lword align (4 bytes)
0xFF == page align (256 bytes)
f.e.
.align $FF
.CALL <macroname> *** unimplemented, sorry ***
This special directive may only be used IN macro definitions. It
acts like a regular macro call, except that all the parameters of
the macro, that does the call, are passed over to the newly called
macro.
Ex.:
.macro x
.dbyte %1,%2
.endm
.macro y
.call x
.endm
y $0123,$4567
produces, predictably, 01 23 45 67
.END
When NASM65 encounters this directive, the processing of source
code is preempted.
.IF <bexpr>
<lines>
.ELSE
<lines>
.ENDIF
These directives provide the ability to selectively assemble some
parts of the program and to leave some parts out. The use for this
feature lies most importantly in macros as you can see in the
supplied "MACROS.H65" file.
This for example is the macro code, for the "generic" store
absolute instruction. Actually only one of STA STX or STY will
be assembled.
.macro @stt
@0 .= @a
.if %0 = 2
@0 .= %2
.endif
.if @0 = @a
sta %1
.else
.if @0 = @x
stx %1
.else
sty %1
.endif
.endif
.endm
Note that for .IF there has to be an .ENDIF and at most one .ELSE.
.LOCAL
Tells the assembler to "forget" all local labels up to this point.
This means that the following will get you an error with a .LOCAL,
; Start of file
jmp :foo
.local
:foo
; end of file
whereas the second piece of code, will only work with the .LOCAL.
Else you would have a doubly defined label.
; Start of file
:loop dex
bne :loop
.local
:loop inx
bne :loop
; End of file
.INCLUDE #<filename>
Reads in the file specified by <filename> and treats this input as
if it would have appeared in the original file. Technically you first
.INCLUDE is your source!
.ERROR <string>
Creates a user error. This is like any other error that NASM65
generates, but you can supply the error string (required). This may
be useful, when writing .MACROs and you want to check that certain
values are in the required range. This feature isn't really all that
useful as OSS thinks it is. The assembler catches for example
missing parameter errors anyway. MAC65 did too...
.MACRO <macroname>
<lines>
.ENDM
All <lines> are saved in an internal buffer and released upon
invocation of <macroname>. f.e.
LEOPOLD = $1234
lda #0 ;; gets assembled as A9 00
.macro foo ;; start of macro definition called "FOO"
sta LEOPOLD ;; this will not be assembled at this time
.endm ;; end of macro definition. Continue assembly
nop ;; NOP gives an EA
foo ;; Assembles now STA LEOPOLD into 8D 34 12
The interesting thing about macros is that you can pass values to
them. These are accessed with the % placeholder. Lets consider an
example
;; simple POKE … la ATARI BASIC "POKE address,value"
.macro poke
lda #%2 ;; %2 means value from second parameter
sta %1 ;; %1 means value from first parameter
.endm
;; macro invocation
poke $4000,124 ;; will assemble as LDA #124 STA $4000
%0 contains the number of arguments passed to the macro.
You can not only pass values but also strings to a macro. These
are accessed with %$.
f.e:
.macro drop_printable
.byte %$1,155,0 ;; Parameter %1 as string
.endm
drop_printable "Foo" ;; converts to .BYTE "Foo",155,0
Parameters can have these four forms:
%<value> ;; <value> gives index of integer parameter
%(<label>) ;; value of label gives index of integer parameter
%$<value> ;; <value> gives index of string parameter
%$(<label>) ;; value of <label> gives index of string parameter
No forward referencing is allowed with %[$](<label>). The label
you use there must already be defined.
Another example:
.macro foo
which .= %2 ;; use '.=' NOT '=' !!
.byte %1
.byte %$1
.byte %(WHICH)
.byte %$(WHICH)
.endm
MAGIC = $12
foo MAGIC,4,"UNUSED","Hello"
would be expanded to
which .= 4 ;; which has value of 4
.byte $12 ;; MAGIC (=$12) was passed as the first parameter
.byte "MAGIC" ;; Yup! Useless but it works!
.byte 5 ;; String length of "Hello World"
.byte "Hello" ;; String of "Hello"
Type D labels that appear in macro definitions can be reused again.
The next example will not give errors on compilation, since "LEO" is
reset every time foo is called.
.macro foo
leo inx
.endm
foo
foo ;; OK!
foo ;; OK!
"LEO" is visible for code outside the macro after an invocation of
"FOO". Forward references to labels in macros are OK! You should not
put local variables in macros.
.REPT <expr> <macroname> [parameter[,<parameter>]*]
This is a recent addition to NASM65, inspired by the 68000
assemblers. It repeatedly calls a macro (optionally with parameters).
The <expr> contains the number of repetitions.
Ex: REPT 3 LSL.W $3000 ; calls the MACRO `LSL.W' 3 times
.WARNING <string>
Creates a user warning. This is much more useful than the .ERROR
directive. For instance in macros you can explain possible hazards.
Ex: .WARNING "The world comes to an end soon!"
.ZEXT <label>
If you want to link two files together that share zeropage labels
and you don't want to use a central include file to share zero
page symbols, as would be inconvenient for library files that
already exist in assembled form, you need to declare in one file
the zeropage labels as external and in the other file as linkable
zeropage labels. As usual an example will clear up things...
File #1:
.ZEXT src ;; tells NASM65 that src, dst
.ZEXT dst ;; are zeropage addresses.
;; Call with amount to move in X
move: ldy #0 ;; this isn't a very good mover
:loop lda (src),y ;; but this is just for illustrating
sta (src),y ;; a point
iny
dex
bne :loop
rts
File #2:
SRC==$F0 ;; == means declare as linkable zeropage
DST==$F2
ROM=$FF02
RAM=$0610
start ldx #56
lda #<ROM
sta SRC
lda #>ROM
sta SRC+1
lda #<RAM
sta DST
lda #>RAM
sta DST+1
ldx #16
jmp move
brk
When linking the values of SRC and DST of file #1 will be set to
those of file #2.
.ORG <value>
*=<value>
This can only be used in the runnable mode to set the assembly
program counter. f.e:
*=$600
lda #0 ;; useless ditty in PAGE 6
sta $2F4
rts
.org $3000 ;; main program in PAGE $30
jsr $600
nop
*=RUNAD ;; let DOS start program @$3000
.word $3000
Using .ORG in the relocatable mode yields an error.
2. C o d e p r o d u c i n g d i r e c t i v e s
.BYTE [+offset,][[<string>],[<expr>]]* ;; incorrect! guess the meaning
Deposits BYTE values in memory. Strings are treated as arrays
of ATASCII characters. There is no '\0' implicitly appended
after a string like in C.
.SBYTE [+offset,][[<string>],[<expr>]]* ;; Comment as above
Same as above, except that bytes are converted for direct screen
representation. (if you wanted to poke "HELLO WORLD" directly
into screen memory.)
.CBYTE [+offset,][[<string>],[<expr>]]* ;; Comment as above
Same as .BYTE except that the last byte of a <string> is EORed with
$80. This is supposedly useful, when you wan't to check for EOS with
BMI.
.WORD <expr>[,<expr>]* ;; that's correct
Deposits words (LSB MSB) in memory.
.DBYTE <expr>[,<expr>]*
Deposits 16Bit values in MSB LSB order.
.FLOAT <float>[,<float>]*
Deposits floating point exprs into memory. Expressions are not
allowed with floats. This is only kept in NASM65 for MAC65
compatibility.
.DS <expr>
Reserves <expr> bytes of memory. Not that useful in relocatable
mode (see elsewhere). This is quite like writing *=*+<expr>.
.DS is a code producing directive in relocatable mode.
3. O b s o l e t e D i r e c t i v e s
.TITLE <string>
.PAGE <string>
.SET <expr>,<expr>
.OPT [NO]<option>[,[NO]<option>]*
.TAB <expr>
These are all obsolete. The SET directive had some influence on
code generation, but is NOT SUPPORTED anymore.
E r r o r s a n d W a r n i n g s
These are some errors and warnings that may need a bit more
explanation:
Error: "Label still has open references"
This could happen in a case like this:
foo .= s1
lda foo
foo .= s2 ; ERROR
lda foo
s1:
s2:
NASM65 is single pass. On line 1 FOO is set to a forward as of yet
unknown reference. In line 3 the value in FOO is overwritten although,
we didn't yet had a chance to resolve the earlier forward reference.
Warning: "Some non PC-relative labels point into code"
If you used any of these labels to access memory, you might
get into trouble. If you used those labels for benign purposes
such as those from STDDEF, you can ignore those warnings"
"Expression must be preceded by '<' or '>'" [relocatable only]
This occurs when you tried to assemble either .BYTE <expr> or an
immediate instruction like ADC #<expr> and <expr> is PC-relative.
In this case you must specify, whether to use the MSB '<' or the
LSB '>' of the value.
Ex.
.BYTE B8 ;; **ERROR** B8 undefined -> PC-relative fwd ref
.BYTE <B8 ;; OK!
T h i n g s y o u s a w e n c l o s e d i n ' < > '
address : means a PC-relative address like foo in "foo: inx".
bexpr : Boolean expression. 0 is considered to mean 'false' and
everything else means 'true'.
continued: Just means next line should actually stand where you found
continued
equate : This is a label, that has come into existance via a '='
assignment.
expr : Arithmetic expression, like 4 + 5, [2 .AND 4] * [300 & 20]
filename : System dependent character-string, that represents a path
to a file in your filesystem.
f.e. TOS ..\mystuff\n65\foo.h65
UNIX /usr/lib/n65/fo.h65
A filename can contain any characters that are valid for
your filesystem. Note that this will bring in a slight
source incompatibility between systems!
float : Atari's own fun floating point format. 6 Bytes. BCD.
Avoid! E.g.: -3.123E+24, +23.0, 0.1E-1
label : A label is a character string that represents an address or
a value. You define labels by putting them in the first
column of your source code. f.e.
label = 45
- or -
label .= 2
- or -
label lda #2 ;; here label gets the value of *
Labels have the same characterwise restriction as
<macroname>s
lines : zero or more lines of ASCII/ATASCII text.
macroname: Any character string derived from the following character
set [A-Z,a-z,0-9,$,@,_,.]. Cannot start of with a digit!
operation: Either an arithmetic operation ( * + - & etc.) or a
boolean operation (.AND .NOT etc.)
option : Obsolete! Any of the following list
(LIST CLIST OBJ MLIST XREF NUM EJECT)
parameter: a macro parameter. In POKE 2300,23 the numbers 2300 and
23 which are passed to the macro as arguments are called
parameters.
portable : Portability is a relative thing. NASM65 will probably go
belly up on anything with 7-Bit chars or EBCDIC.
saddress : means a short PC-relative address that can't be used
in another expression. For example the least
significant of a PC-relative address is a saddress.
source : The <filename> of the source file.
string : Any number of characters enclosed inbetween >"<.
value : means numbers or non-PC-relative labels like
STACK=$100 or expressions made of the two like
4*5, STACK/4, 2*STACK, STACK-STACK+1...
G l o s s a r y
ACK Acknowledgement
ASCII ASCII != EBCDIC. 7-bit really
Assembler Go back to your wordprocessor, you are reading the wrong
file.
ATASCII Atari extension of ASCII. 8-Bit
BMI .. ..
LDA .... 6502 .... What LDA #<expr> = A9 ..
STA .... mnemos .... else ? STA <word> = 8D .. ..
NOP .. ..
Byte 8 bits unsigned
CR Carriage Return, '\r', ASCII 13
EOS End of string
ICD ? . Just as great as OSS. Hardware mostly though. Bought
OSS.
Linker A program that produces an executable program from one
or more object files and libraries of object files.
LSB Least significant byte of a word -> $12[34]
LSB MSB order would be [34]12
LF Linefeed, '\n', ASCII 10
MAC65 Assembler distributed by OSS.
MSB Most significant byte of a word -> $[12]34
MSB LSB order would be [12]34
OS Operating System
OSS Optimized Systems Software. Makers of great Software for
the Atari 8-Bit. You could buy their stuff eyes closed.
PC Program counter
REF Reference
SPACE Space, ' ', ASCII 32
TAB Tabulator, '\t', ASCII 9
THANX Thanks
TOS Takes up 192K ROM-space in the ST. Contains fragments of
OS-code.
UNIX An OS.
WORD 16 bits 8 of them comprise the LSB the other 8 the MSB
B U G S ( k n o w n )
There is a serious bug in the documentation, which doesn't properly
follow thru with the distinction of <equate> and <label>.
The assembler does not print linenumber and filename, when the
error or warning occurred on the last line.
The assembler does no checking for overflow of it's program
buffer space (assuming that noone would assemble more than
48K in one run anyway). There is a limit imposed on many
data structures in the object file, by virtue of using unsigned
integers instead of lwords. If ANYONE runs into problems please
tell me, changing stuff to LWORDs isn't that big a deal, it just
wastes more filespace.
On UNIX systems all include files must start with a lowercase
character.
A C K S , R E F S & T H A N X (n” special order)
Werner (Ex-Meister) fr moralische Untersttzung
Dinadan for porting this to the AMIGA and finding
some bugs, that escaped me
J. Richter for helping to debug the MSDOS code and lending
me his KONTRON AT for a few days.
Matthias Reichel for making a valiant (and successful) attempt
at porting 2.0 to the PC
Harbison/Steele C - A Reference Manual Second Edition
Poole/McNiff/Cook Your Atari Computer
Chadwick Mapping the Atari
Dripke 6502 Assembler Kurs fr Beginner
OSS MAC/65¿ Manual
Lawrow MAC/65
Wilkinson Atari Basic Source Book (?)
Van Halen (everything 'xcept maybe OU812) read the
Metallica (everything) sources
Megadeth (RIP *GREAT*, SFSG...SW? PS...BWIB? *GREAT*) to
Chris Poland (RTM) find some
Joe Satriani (everything) of
Steve Vai (P&W) the hidden
The Police (RDB TGH) capabilities
David Lee Roth (ALAE *WHOA*) like
Steve Morse (SS *MASTERPIECE*) in the
Suicidal Tendencies (LCR) linker (har har) (is that outdated? nat/92)
Front 242 (*FBF*)
for continous (I mean continous) entertainment