NASM65
Jump to navigation
Jump to search
---------------------------------------------------------------------- Copyright (C) 1990 by NatÂrlich! 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 NatÂrlich! 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) fÂr moralische UnterstÂtzung 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 fÂr 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