You could shorten the source, and make it easier to follow, by replacing each occurrence with a macro call: you might set up a suitable macro with the statements ADDTWO MACRO LDA VAR CLC ADC #2 STA VAR ENDM Then, instead of writing the four lines of code, simply write one line ADDTWO The Assembler will expand the macro definition, and will automatically generate the four lines for you. 9.1 Using macro parameters Although this is useful in itself, the macro as shown above is rather limited. It couldn't, for instance, be used to add 2 to the variable COUNT instead of VAR. In order to provide this sort of flexibility, you can pass information to macros as "parameters". You could re-write the macro above to read 42 USING THE 65C02 ASSEMBLER ADDTWO MACRO LDA @P1 CLC ADC #2 STA @P1 ENDM Here we have replaced the occurrences of VAR by the string "@P1". Now, when the Assembler expands the macro, it will replace all occurrences of "@P1" with parameter number 1 of the macro call. To add 2 to VAR, you would then write ADDTWO VAR and to add 2 to COUNT, you would write ADDTWO COUNT You can supply up to 9 parameters when you call a macro, and they are indicated in the body of the macro by @P1, @P2, @P3 and so on. (Note that you can also specify the parameters as @1, @2, @3 and so on, omitting the "P". This is adequate for existing code; however, for new programs you should use the "@P1" form, as this is necessary when you come to use the Macro Programming Language) 9.2 Specifying macro parameters You can specify anything you want as parameters to macros. A macro can have up to 9 parameters, separated by a comma and optional spaces. A macro with 3 parameters could be called with lines like CHECK 1,FRED,27 CHECK 1 , FRED , 27 and so on. Normally, the Assembler will remove leading and trailing spaces from each parameter. If you require leading or trailing spaces, or if the parameter has to include a comma, you will need to specify it as a string, delimited by single- or double-quote characters. Thus, a macro call might look like THING 'Here, is a comma' and "@P1" will be replaced in the macro body with the characters Here, is a comma Note that the string delimiters are not taken as part of the parameter proper. 43 USING THE 65C02 ASSEMBLER 9.3 Nesting macros You can call macros from within macros, up to a depth of 5. If you attempt to nest deeper than that the Assembler will flag an error. 9.4 Redefining opcodes and directives The Assembler allows you to set up macros to redefine any opcode or directive. For example, you might want to redefine the JSR (Jump-to-Subroutine) opcode to automatically save the registers before entering the subroutine. You could do this by declaring a macro called JSR thus: JSR MACRO PHA TXA PHA TYA PHA JSR @P1 ENDM Now, whenever the Assembler comes across a line with JSR in the opcode field, it will expand the macro JSR rather than obeying the opcode. It will plant the code to save the registers, and then will come to the line JSR @P1 in the macro. Here, because it is already in a macro, the Assembler will not use the macro JSR. Instead it will assemble the opcode JSR, planting the code to enter the subroutine. 9.5 Labels within macros Suppose you wish to write a macro that includes a branch of some sort. You might write the macro definition as: 44 USING THE 65C02 ASSEMBLER THING MACRO LDA @P1 BEQ ZERO EOR #$FF ZERO STA @P2 ENDM The first time the macro is called, it plants the code bytes, and defines the label ZERO as the destination of the BEQ instruction. On a subsequent call, though, the macro will produce the same code, and will attempt to define the value of ZERO again. This of course will fail, since it already exists from the first macro call. The Assembler provides a way round this problem, by giving you a way of generating unique labels. Every time a macro is called, the Assembler sets up what you can regard as a special parameter on your behalf, which contains a string that is different for every macro call. This string is substituted, in the same way as ordinary parameters, by writing "@$MC" in the line. Thus, the above macro could be changed to be: THING MACRO LDA @P1 BEQ ZERO@$MC EOR #$FF ZERO@$MC STA @P1 ENDM Then, on the first macro call, every occurrence of ZERO@$MC might be changed to ZERO1X1. On the next call, they become ZERO2X1, so that there is no clash between the macros. 45 USING THE 65C02 ASSEMBLER 10. THE MACRO PROGRAMMING LANGUAGE A very powerful feature of the Assembler is its Macro Programming Language. This allows you considerable control in how macros are expanded - you can construct loops, manipulate macro parameters and perform several other functions that allow you to build macros of great power. Although this facility is mostly intended for use within macros, many of its facilities can also be used outside macros to great effect, as this section will explain. The Macro Programming Language's facilities build on two source language features known as Assembly Time Variables and Sequence Symbols. 10.1 Sequence Symbols These are "place markers" within your source files or within macros that the Macro Programming Language uses in loops. Using directives such as AGO and AIF, you can make the Assembler move up or down within a file or a macro, letting you repeatedly assemble some parts of the source or totally omit others. Sequence Symbols are very similar to the labels that are part of the source proper, and they can contain the same characters. To distinguish them, Sequence Symbols always begin within a "%" sign in the first character of the line. The Sequence Symbol should be the only thing on the line: if you do put anything else there the Assembler will ignore it. To take an example of how Sequence Symbols could be used, suppose your source file contained the lines AGO %SKIP ASC 'These lines will never ' ASC 'get assembled' %SKIP ASC 'But this one will' The Assembler will encounter the AGO directive, and will then ignore everything in the source file until it finds the Sequence Symbol %SKIP. It will then resume its normal processing. Although this example will actually work, the technique isn't greatly useful, as ignoring source lines can be done just as easily with the IF..ELSE..FI construction. However, AGO (and the various conditional skips such as AIF) also allows you to go backwards in the 46 USING THE 65C02 ASSEMBLER source or macro - there is no other way of achieving this. The Sequence Symbols used in any file or macro are quite independent of those in any other; thus you can safely use ones of the same name in every file and macro, if you wish. 10.2 Assembly Time Variables Assembly Time Variables, or ATVs, are string variables that the Assembler itself uses while assembling your source files. As it reads the program source (either from a file or from the definition of a macro) the Assembler continually looks for references to ATVs. These are replaced - before the line is assembled - with the contents of the ATV, thus allowing you to vary the source that is actually processed. You can use ATVs in many ways. For example, the first line of a source might set an ATV string to hold the version number of the program you are assembling; the Assembler will then automatically replace every reference to that name with the string. Some ATVs are created by the Assembler itself, and let you incorporate such things as the name of the source file into the source itself. The main use, though, is in controlling loops within macros and within source files. 10.2.1 Creating Assembly Time Variables ATVs have names similar to the variables that form part of the source proper, and you can manipulate them with various directives. 10.2.1.1 Local and Global ATVs There are two types of ATV: local and global ones. a. Global ATVs exist for the whole of the assembly, and can be used anywhere. They are created and manipulated with the ASTR, ASET, ASTRIP and ALEN directives, which you can use even inside macros - the ATVs they create will continue to exist after the macro finishes. b. Local ATVs are created and manipulated by the MSTR, MSET, MSTRIP and MLEN directives. These directives can only be used inside macros, and the ATVs thy create can be used only within the same macro - they cease to exist at the end of the macro expansion. You would use these, for example, in controlling loops within a macro. In fact, you have already seen local ATVs in use in section 47 USING THE 65C02 ASSEMBLER 9.1 on "Simple Macros". Whenever you invoke a macro, the Assembler creates local ATVs with names P1, P2, P3 and so on, each holding one of the parameters you supplied on the macro call. For example, the source line NAME ASET 'OSWRCH' will set up an ATV called NAME, whose contents are the string 'OSWRCH'. Since the ASET directive has been used, the ATV is global, and can be used anywhere in the assembly. You can create local and global ATVs of the same name if you wish. However, if you wish to refer to the local ATV, you should be careful to always use the "M" form of the directives. The "A" forms will always create global ATVs, even if local ones of the same name already exist. 10.2.1.2 String and Numeric Values All ATVs are stored by the Assembler as printable character strings. However, in many cases you will find you use them as counters for controlling loops: to make this easy, the Assembler will automatically convert ATVs from numbers to strings whenever necessary. The rule used is quite simple. When processing ASET or MSET directives the Assembler examines the first character of the operand field. If it is a string delimiter, the operand is taken as a string and is not evaluated. If it is any other character, the Assembler treats the operand as a numeric expression, evaluates it, and converts the result into a string for storage. Thus, the line COUNT ASET 15+3 will set up the ATV COUNT, containing the string "18", but COUNT ASET '15+3' sets up the string "15+3". The operand can be any expression, provided it does not contain any forward references: thus COUNT ASET ADDRESS+10 sets COUNT to hold the string form of the result of adding 10 to the address label ADDRESS. 48 USING THE 65C02 ASSEMBLER If you use expressions that mix numeric and character literal values, some caution is needed to make sure that the Assembler does what you want: for example, VALUE ASET 'A'+3 would produce an error, rather than adding 3 to the code for the character 'A'. This is because the Assembler, seeing the operand field beginning with a "'" character, will treat the operand field as a string and find that it is invalid. To overcome this, you may be able to re-order the operand expression: thus you could write the above example as VALUE ASET 3+'A' Now the Assembler will treat the operand field as a numeric expression, since it does not begin with a string delimiter. In some cases, though (particularly in macros where you may not know beforehand what the expression may look like) it may not be possible to re-order things safely. Here you can simply put a dummy number in front of the expression: thus VALUE ASET 0+'A'+'B' would add the character values 'A' and 'B', the leading "0" character forcing the Assembler to treat the operand as a numeric expression. The ALEN and MLEN directives similarly convert from number to string for you. Here the operand must be a string: for example, SIZE ALEN 'A short string' sets SIZE to hold the string "14" - the length of the operand string, converted from a number into a string. 10.2.1.3 String slicing The ASET and MSET directives also allow to you to "slice" strings, or extract characters from inside them. You perform this by adding some parameters in the operand field: for example SLICE ASET 'abcdefghij',3,2 will set SLICE to hold the string "cd". The second operand parameter specifies the position of the first character to be sliced out (the string starts at character 1), and the third parameter specifies the number of characters to be sliced. If you omit the third parameter, exactly one character is sliced: thus 49 USING THE 65C02 ASSEMBLER SLICE ASET 'abcdefghij',3 will set SLICE to hold the string "c". Occasionally, string manipulations such as slicing may result in strings that have leading or trailing spaces, and you may not be able to tell beforehand how many. The ASTRIP and MSTRIP directives remove all leading and trailing spaces, so that NEW ASTRIP ' abcd ' would set the string NEW to be "abcd". 10.2.1.4 Efficient use of memory The strings contained by ATVs are held by the Assembler in the symbol table, and so compete for memory with other symbols. You can change the contents of an ATV to a string of different length as often as you wish: however, every time the string becomes longer the Assembler will allocate a new block of memory for it. The previous block cannot be used again, so continually increasing the size of an ATV can be extremely wasteful of memory. To overcome this, the ASTR and MSTR directives let you pre-declare a block of memory big enough to hold the maximum size string you will use. For example, NAME ASTR 50 sets up a block long enough to hold a 50-byte string without the need to get more memory. The minimum amount of memory the Assembler will allocate is 5 bytes: this is enough to hold the largest possible numeric value, so that loop counters will not cause memory wastage as their values grow - you need not use ASTR and MSTR for them. 10.2.2 Simple Substitution of Assembly Time Variables Once you have set up ATVs, you can use them to create variable source lines. We have already come across this concept in section 9.1 on "Simple Macros", in the discussion of macro parameter substitution. There, we saw that if the source of the macro contained the line LDA #@P1 the Assembler would replace "@P1" with whatever you had specified as 50 USING THE 65C02 ASSEMBLER the first parameter of the macro when you called it. ATVs are substituted into source lines in exactly the same way, and as we saw, macro parameters are in fact local ATVs. The rule the Assembler uses is quite simple: whenever it detects an "@" sign in the source (other than in a comment line) it expects an ATV name to follow. The "@" and the name itself are replaced by the contents of the ATV before the line is assembled. For example, you might keep the version number of a program in a small, quickly-editable file that is INCLUDEd into the source at the start of an assembly. This might contain the line VERSION ASET "3.45" which sets the ATV VERSION to hold the string "3.45". Then, at any point in the source where you needed to insert the version number (such as in a screen message) you could write, for example TITLE ASC "SuperGame @VERSION" The Assembler would replace "@VERSION" with "3.45" before it assembled the line, so the string actually planted would be "SuperGame 3.45" This technique lets you keep the version number in one easily-alterable place, and lets the Assembler take care of putting the up-to-date value (or parts of the value) into the source at the appropriate places. There are some more complex uses of ATV substitution, and we shall discuss these later in section 10.3 on "Writing Complex Macros". Some useful points to note on substitution are: a. If you want the "@" character to appear in the line the Assembler processes, your source must contain two of them. Thus, if the line you really want to assemble is ASC 'VAT @ 15%' write it in the source file as ASC 'VAT @@ 15%' b. Once the Assembler finds an "@" character in the source, it assumes that what follows is an ATV name. The end of this name is assumed to be the first non-alphanumeric character that it meets, or the end of the line. In almost all cases, this will cause no 51 USING THE 65C02 ASSEMBLER difficulty, but occasionally will, usually in complex macros. As an example, suppose you had declared at ATV called EXPR, holding the string "10+". A subsequent source line might then read LDA #@EXPR3 and the intention is for this to be transformed into LDA #10+3 In this case, though, the substitution will fail, as the Assembler will look for an ATV called EXPR3. To force it to do as you want, write the source line as LDA #@EXPR/3 The "/" character enables the Assembler to detect the end of the ATV name, so it will look for EXPR as it should. The "/" will be discarded, so that the resulting line will be LDA #10+3 as intended. If you need a "/" character in the resulting line, write it as "//". There is another techniques you might use in these circumstances. The Assembler does not regard spaces as significant in numeric expressions, so that you could write LDA #@EXPR 3 to achieve the same result. c. No ATV substitution is performed in comment lines, in lines containing Sequence Symbols, or in the definition of macros (i.e. between the MACRO and ENDM directives). Apart from these, though, substitutions can be made at any place in a line - you can substitute for labels, opcodes, operands or any parts of them. 10.3 Writing Complex Macros 10.3.1 Programming macro loops Mostly, you will use the Macro Programming Language to program macro loops, controlled by various conditions. 52 USING THE 65C02 ASSEMBLER 10.3.1.1 Simple loops controlled by counter The simplest form of loop is one which is executed a fixed number of times, and needs only a counter to control it. As an example, suppose that we need a macro to plant a number of bytes containing $FF with the DFB directive, the number being specified by the first parameter. (There are much easier ways of doing this than with a macro, of course - this only shows a general technique). The macro definition might then be: PLANT MACRO COUNT MSET 0 %LOOP DFB $FF COUNT MSET @COUNT+1 AIF @COUNT<@P1,%LOOP ENDM To see how this works, we can examine each line in turn, assuming that the macro was called with a line PLANT 7 Line 1 : This is the macro definition line. Line 2 : This line sets up a local ATV called COUNT, and gives it a string value of "0". Line 3 : This is a Sequence Symbol marking the top of the loop. Note that there is nothing else on the line with it. Line 4 : This is the DFB line that plants the $FF byte required. Line 5 : This line increments the value of COUNT. As the Assembler reads the line, it encounters "@COUNT", which it replaces with the current string value of the ATV. Thus the first time this line is encountered, the Assembler will generate COUNT MSET 0+1 The second time, it generates COUNT MSET 1+1 and so on. Line 6 : This tests whether the Assembler is to loop round once more. As with line 4, the Assembler will replace 53 USING THE 65C02 ASSEMBLER "@COUNT" with the current value of the ATV. "@P1" is, of course, replaced by the first parameter of the macro. The first time round, the line processed is AIF 0<7,%LOOP which is true, so the Assembler skips backwards in the macro to line 4 and resumes processing from there. 10.3.1.2 Loops accessing macro parameters Another frequently-needed form of loop is one in which all the parameters of the macro are accessed in turn. Suppose, for example, you need to write a macro THINGS, whose parameters are all numbers. Each number is to be planted in a byte in the object file with a DFB directive: to make THINGS interesting, the number of parameters must be variable. Such a macro is fairly simple to write, but uses an ATV substitution technique that can, at first sight, be somewhat daunting. If the job were simply to plant the value of parameter 1, the line in the macro that does it would simply be DFB @P1 However, we need to access each parameter in turn: the Assembler must somehow be made to see "@P1" the first time round the loop, "@P2" in the second, and so on. Effectively, then, we need a substitution technique that lets us have a variable ATV name: i.e. one that first substitutes the number ("1", "2", "3" etc) then substitutes for the ATV name so formed. The Assembler can do this easily, since ATV substitution operates in a hierarchic fashion. For example, suppose that a source line contains @(P@COUNT) somewhere. On seeing the first "@" character, the Assembler prepares to substitute an ATV. It finds, though, that the next character is a "(", so that it now expects a bracketed expression rather than an ATV name. It notes where it has got to in the source line, and explores within the brackets. Now, though, it stores the characters it finds (rather than passing them on to be assembled), and expects to end up with a valid ATV name by the time it gets to the ")" character. It notes the "P", then finds the second "@". This makes it try again to 54 USING THE 65C02 ASSEMBLER substitute an ATV, and this time it finds a real ATV called COUNT, which we shall suppose contains the string "1". After "COUNT" it finds the ")" ending the bracketed expression; thus, within the brackets the string it has built is now "P1". Having ended the bracketed expression, the Assembler goes back to where it was.The "(P@COUNT)" has provided the string "P1", and this now is a valid ATV name. So it proceeds to substitute the value of ATV P1, the first macro parameter, as we intended. To see how we might use this technique, we can consider a definition of THINGS: THINGS MACRO COUNT MSET 1 %LOOP AIF '@(P@COUNT)'='',%ALL.DONE DFB @(P@COUNT) COUNT MSET @COUNT+1 AIF @COUNT<10,%LOOP %ALL.DONE ENDM To see how this works, we can examine each line in turn. Line 1 : This is the macro definition line. Line 2 : This line sets up a local ATV called COUNT, and gives it a string value of "1". Line 3 : This is a Sequence Symbol marking the top of the loop. Line 4 : Since the number of parameters must be variable, we need to test whether we've processed them all. You can see the substitution technique discussed above in use here to check if the next parameter is null - any parameters that you don't supply in a macro call are strings of zero size. If the parameter is null, the Assembler skips forwards in the macro until it gets to the Sequence Symbol %ALL.DONE. Line 5 : This is the DFB line that plants the current macro parameter as a byte. Line 6 : This line increments the value of COUNT, as in the previous example. Line 7 : This tests whether the Assembler is to loop round once more. The final macro parameter is P9, so once COUNT reaches 10 the macro is finished. Line 8 : This is the Sequence Symbol that line 4 skips to if it 55 USING THE 65C02 ASSEMBLER finds a null parameter. Thus, if the macro was called with a line THINGS 1,$FE,FRED-1 the loop would be traversed three times, and the lines actually assembled would be DFB 1 DFB $FE DFB FRED-1 The technique of hierarchical substitution, though most often used to access macro parameters in turn, can be used in many other applications: you can nest substitutions to as deep as you are likely to need, so that you might write something as horrendous looking as LDA #@(XX@(COUNT@PTR)B) if you really needed to. 10.3.2 Changing macro parameters Macro parameters are in fact local ATVs with names P1, P2, P3 and so on. This means that you can change them within a macro as you wish. One example of this might be to allow the use of default macro parameters (although section 10.3.3 below shows an automatic way to do this). Suppose that a macro parameter should be a number, whose default value is 1. You could define it as: TEST MACRO AIF '@P1'#'',%NEXT P1 MSET 1 %NEXT LDA #@P1 ENDM Within this example, we have: Line 1 : The macro definition line. Line 2 : This tests if parameter 1 has been supplied. If so, it will not be a null string, so the Assembler skips to %NEXT. 56 USING THE 65C02 ASSEMBLER Line 3 : This line sets parameter 1 to the default value. Line 4 : This is the Sequence Symbol skipped to if the parameter is not defaulted. Line 5 : This line actually uses the parameter. It will assemble correctly even if the parameter was not given, since in that case line 3 will have set it up to be the default value. 10.3.3 Setting default macro parameters The example above showed one way of establishing a default value of a macro parameter, but in fact the Assembler gives you an automatic and easy way of doing this with the DEFPARS directive. The effect of this directive, which you can issue at any time inside a macro, is to set the values of any of the macro parameters P1, P2, P3 and so on, unless they are already defined. For example, you might call a macro with a line FRED 1,,3 where you have defined parameters 1 and 3, but not parameter 2. If the macro now executes, say, DEFPARS 100,200,300 the Assembler will check the parameters in turn. Parameters 1 and 3 are already defined, so the "100" and "300" values are not used. Parameter 2, though, is not yet defined, so it is set to "200" from this point on. If you wished, say, to establish a default for only some of the parameters of a macro, simply specify only those parameters in the DEFPARS directive and default the others. Thus DEFPARS ,,,44 sets a default for parameter 4, but has no effect whatsoever on parameters 1, 2, 3, 5, 6, 7, 8 and 9. 10.3.4 Listing control for macros If you write complex macros with lots of loops, you will find that the Assembler actually executes a large number of lines that just contain the AIF, MSET directives, etc. This can swamp the 57 USING THE 65C02 ASSEMBLER listing, and make it hard to see the actual directives that plant data or code (as well as using up a large amount of paper). To overcome this, list level 2 will not list directives such as MSET, AIF, etc, unless they contain errors. In order to see all the lines of a macro expansion, use list level 3. (Note that outside macros, ASET and other similar directives will list at level 2). 10.3.5 Exiting a macro prematurely You may sometimes need to exit a macro as a result of a test. Depending on circumstances, you may be able to use AIF or AGO to skip to the physical end of the macro; however, you can also use the MEXIT directive. This exits the macro immediately, wherever in the macro body it is encountered. 10.3.6 Comment lines within macros You can include comment lines within the definitions of macros, just as in normal code. For example, a short macro might be defined as TEST MACRO * * Adjust value in PTR0 * INC PTR0 ENDM The three comment lines will be stored in the macro definition, and (if the listing level is set to 2 or higher) will be listed whenever you call the macro. This lets you output comments to describe the actions of the macro. The disadvantage of this technique is that the comment lines are stored in their entirety in memory when the macro is defined, giving you correspondingly less space for the symbol table. When you come to writing complex macros making great use of ATV's and loops, you will find it most advantageous to include liberal amounts of comment. In order that these comments, which purely document how the macro works rather than the code it generates, shouldn't use memory, comment lines beginning with "!" are not stored. Thus, you could write a macro as TEST MACRO ! ! See if first parameter is null ! 58 USING THE 65C02 ASSEMBLER AIF '@P1'#'',%NEXT ! ! It is null, so reset it to "1" ! P1 MSET 1 %NEXT ! ! Parameter 1 now definitely has a value, ! so we can use it ! LDA #@P1 ENDM The lines beginning "!" will appear in the listing when you define the macro, but will not be stored and will not appear when the macro is called. 10.4 System ATVs The Assembler provides a number of read-only ATVs that you can substitute. They provide information on the Assembler and the environment that you can use to control assembly. Each system ATV name starts with a "$" character: they are $CLST The current code listing level. $DEFCLST The default code listing level. $DEFLST The default listing level. $FLEVEL "1" if the current file is an INCLUDE file; "0" if it is not. $FS The number of the filing system in use, as returned by OSARGS with A=0, Y=0. The Acorn DFS returns "4", Econet returns "5" and ADFS returns "8". $LINE The number of the current source line. $LST The current listing level. $MC The macro call counter, used to generate unique labels within macros (see section 9.5) $MLEVEL The current macro nesting level. If not in a macro, the value is "0". $OBJECT The name of the current object file, which may include leading or trailing spaces. 59 USING THE 65C02 ASSEMBLER $OS The version of the MOS in use, as returned by OSBYTE with A=0. $OSHWM The primary OSHWM value of the machine running the Assembler. $PLENGTH The current page depth used in the assembly listing, as set by the PAGE directive. $PWIDTH The current line width of the asembly listing, as set by the PAGE directive. $PRINTING Indicates whether the assembly listing is being sent to the screen or to a printer or file. The value returned is "0" if the listing is being sent to the screen, and "-1" if it is being sent to a printer or a file. $SOURCE The name of the current source file, which may include leading or trailing spaces. $TIME The currently-set timestamp string, which may include leading or trailing spaces. $TTL The currently-set page title string, which may include leading or trailing spaces. $VERSION The version of the Assembler in use. This is returned as a numeric string, so that version 1.60 sets the string to be "160". For example, the line ORG @$OSHWM could be used to set the base address of the code to the OSHWM value of the machine being used, without the need to know what that value was. 60 USING THE 65C02 ASSEMBLER Appendix 1 : OPCODES AND ADDRESSING MODES The Assembler supports all the opcodes of the 6502 and 65C02 processor families, using standard MOSTEK mnemonics. For descriptions of the opcodes, see for example "The Advanced User Guide for the BBC Micro" (for 6502-compatible opcodes) and the "Master Reference Manual Part 2" (both 6502- and 65C02-compatible opcodes, although it describes the BBC BASIC Assembler syntax which cannot be used with this Assembler.) The 6502-compatible opcode mnemonics available are: ADC AND ASL BCC BCS BEQ BIT BMI BNE BPL BRK BVC BVS CLC CLD CLI CLV CMP CPX CPY DEC DEX DEY EOR INC INX INY JMP JSR LDA LDX LDY LSR NOP ORA PHA PHP PLA PLP ROL ROR RTI RTS SBC SEC SED SEI STA STX STY TAX TAY TSX TXS TYA The 65C02-only mnemonics are: BRA DEA INA PHX PHY PLX PLY STZ TRB TSB The opcode CLR can be used as a synonym for STZ. The addressing modes common to both the 6502 and 65C02 processors are: Mode Syntax Implied op Accumulator op A or op Immediate op #expr8 Low byte op #>expr High byte op # Example: AGO %LOOP AIF Skips to a Sequence Symbol if a condition is true. Syntax: AIF , or AIF , If is false assembly continues in the next line. Example: AIF 'FREDA'>'FRED',%LOOP AIFDEF Skips to a Sequence Symbol if a symbol has been defined. Syntax: AIFDEF , Example: AIFDEF RAM.CODE,%DOING.RAM AIFNDEF Skips to a Sequence Symbol if a symbol has not been defined. The syntax is as for AIFDEF. ALEN Sets a global ATV to the length of the operand string. Syntax: