ASM8

A two-pass absolute macro cross-assembler for the 68HC08/HCS08/9S08

 

 

Quick Reference Guide

ASM8 - Copyright © 2001-2010 by Tony Papadimitriou <tonyp@acm.org>

Latest Update: September 4, 2010 for ASM8 v6.10


Command-Line Syntax and Options

 

ASM8 [-option [...]] [[@]filespec [...]] [>errfile]

 

·        option(s) may appear before, in between or after filespec(s).

·        option(s) apply to all files assembled, regardless of command line placement.

·        Text file(s) containing list(s) of files to be processed may be specified by naming the text file on the command line, prefixed with a «@» character.  These text files may not contain command line options.

·        filespec(s) may include wildcard characters (?,*).  Wildcards are not allowed in filespec(s) that are prefixed with a «@» but are allowed in filespecs inside @files.

·        If the file extension for a source filespec is omitted, the extension «.ASM» is assumed (see description of the –R.ext option below).

·        Assembler errors may be redirected to errfile using standard DOS output redirection syntax.  This capability may be used in conjunction with, or as an alternative to the –E+ option.  Currently, error redirection is only possible with the DOS version.

·        All shaded areas are pertinent to the MMU enabled versions (Win32/Linux only).

·        Any label can hold a value that is 32-bit long.  Even though the CPU cannot understand numbers larger than 16-bit for data or addressing (MMU not withstanding), the ability to have 32-bit labels allows keeping constants that are larger than 16-bit for use in later constant calculations.  Decimal numbers are signed; the largest number is +/-2147483647.  Hex or binary numbers are unsigned and can go up to the full 32-bit value (2^32-1).  For example, a symbol holding the crystal frequency of operation can be expressed with Hz detail to be used later to derive other constant values (such as bps rates or cycle-based delays). The 32-bit capability is NOT available in the DOS version.

·        The assembler will set the DOS ERRORLEVEL variable when it terminates as indicated:
0          No error, assembly of last file was successful
1            System error (hardware I/O failure, out of disk space, etc.), or
-W option failure
2            Error(s) generated (or Escape pressed) during assembly of last file
3            Warning(s) generated during assembly of last file
4            Assembler was not started (help screen displayed,
-W option used with success)

 

Option

Default

Description

 

 

 

-C[±]

-C-

Label case sensitivity: + = case sensitive (See also #CASEON/#CASEOFF)

-Dlabel [:expr]

 

Use up to ten times to define symbols for use with conditional assembly (IFDEF and IFNDEF directives).  Symbols are always uppercase (regardless of -C option).  If they are not followed by a value (or expression) they assume the value zero.  Expression is limited to 19 characters.  Character constants should not contain spaces, and they are converted to uppercase.  Cannot be saved with -W.

-E[±]

-E-

Generate *.ERR file (one for each file assembled).  *.ERR files are not generated for file(s) that do not contain errors.

-EH[±]

-EH+

If –E+ is in effect, hide (do not display) error messages on screen.

-EXP[±]

-EXP-

When on, an .EXP file is created containing all symbols defined with an EXP rather than an EQU pseudo-opcode.  The resulting file can be used as an #INCLUDE file for other programs.  This allows for automatic creation of include files with global exported symbols.

-HCS[±]

-HCS-

When on, the assembler understands the extended HCS08 instruction set.  The cycle counts in the listing also reflect the HCS08 core.  To check the current status of this switch look at the help screen’s second line from top.  The software will say it’s either a MC68HC08 or a MC68HCS08 assembler based on this setting.  See also the directives #HCSON, #HCSOFF, #IFHCS, and #IFNHCS

-Ix

 

Define default INCLUDE directory root.  Relative path files not found relative to the main file, will be tried next relative to this directory.  This switch does not affect absolute path file definitions.  Affects both the INCLUDE and the IF(N)EXISTS directives.

-J[±]

-J+

Effective only while the MMU is disabled: When on, CALL/RTC instructions are treated as if they were JSR/RTS instructions, respectively.  When off, CALL/RTC instructions produce errors.  Makes it possible to write common library functions using CALL/RTC instead of JSR/RTS and have them used in all MCUs, regardless if they have an MMU or not.  See also the directives #JUMP, and #CALL

-L[±]

-L+

Create a *.LST file (one for each file assembled).

-LC[±]

-LC+

List any conditional directives fully (the directives only, not the contents in between), even when they are False.

-LS[±]

-LS-

Create a *.SYM symbol list (one for each file assembled).  May be useful for debuggers that do not support the P&E map file format.

-LSx

-LSS

x may be either S (default) for simple SYM file, E for EM11/Shadow11 SYM compatible format (possibly not useful for HC08), or N for NoICE SYM format.

-M[±]

-M+

Create a *.MAP (one for each file assembled).  *.MAP files created may be used with debuggers that support the P&E source-level map file format.

-MMU[±]

-MMU-

Enable the MMU features (e.g., CALL/RTC instructions, 24-bit addresses and expressions).  See also the directives #MMU, #NOMMU, #IFMMU, and #IFNOMMU

-MTx

-MTP

Specifies type of MAP file to be generated (if –M+ in effect):

-MTA : Generate parsable ASCII map file

-MTP : Generate P&E-style map file

-O[±]

-O+

Enables these three warnings:  ‘S19 overlap’, ‘Violation of MEMORY directive’, and ‘Violation of VARIABLE directive’.

-P[±]

-P+

When on it tells the assembler to stop after Pass 1 if there were any errors.  Provides for faster overall assembly process and less confusion by irrelevant side errors of Pass 2.  Warnings do not affect this.

-Q[±]

-Q-

Specifies quiet run (no output) when redirecting to an error file (DOS only).  Useful for IDEs that call ASM8 and don’t want to have their display messed up.

Beginning with v1.29, this option can also be used to suppress all output from #Message directives.

-Rn

-R74

Specifies maximum length of S-record files.  The length count n includes all characters in an S-record, including the leading «S» and record type, but not the CR/LF line terminator.  Minimum value is 12 while maximum is 250.

-R.ext

-R.ASM

Specifies the default extension to assume for source files specified on the command line, which do not directly specify an extension.

-REL[±]

-REL+

Allows generation of  «BRA/BSR instead of JMP/JSR» optimization warnings when enabled.  (See also OPTRELON/OPTRELOFF)

-RTS[±]

-RTS-

Allows generation of  «JSR followed by RTS» subroutine call optimization warnings when enabled. (See also OPTRTSON/OPTRTSOFF)

-S[±]

-S+

Generate *.S19 object file (one for each file assembled).

-S2[±]

-S2-

Force the generation of S2 records (24-bit addresses) even for 16-bit addresses.  Although 24-bit addresses are enabled, no MMU features are enabled.  Useful mostly for forcing 16-bit addresses to appear as 24-bit (with leading byte as $00) so that S19 loaders can use that as the PPAGE value.  See also #S1 and #S2

-SH[±]

-SH-

Include dummy «S0» record (header) in object file (only if –S+).

-SP[±]

-SP-

When enabled, the operand part of an instruction is stripped of spaces before parsing.  In this case, possible comments must begin with semi-colon.  (See also SPACESON/SPACESOFF)

-T[±]

-T-

Makes all errors look like Borland errors (useful to fool certain IDEs).

-Tn

-T8

Specifies tab field width to use in *.LST files.   Tab characters embedded in the source file are converted to spaces in the listing file such that columns are aligned to 1 + every nth character.

-Ux

 

Define default OUTPUT directory.  If this option is defined, all produced files will end up in this directory, regardless of where the source file is located.  When this option is undefined (no path given), produced files will end up in the same directory as the primary source file.

Not available in the DOS version.

-X[±]

-X+

Allow recognition of extra, non-68HC08-standard mnemonics and simulated index modes in source files. (See also EXTRAON/EXTRAOFF)

-Z[±]

-Z-

Convert the paged addresses (PAGE:ADDR16) to linear (extended) address in the produced S19 file(s).  In effect, all addresses within the ranges $xx8000-$xxBFFF are converted to their linear format.  The code or listing is not affected at all.

This is useful for S19 loaders that expect addresses in linear format, instead of paged format.

Warning: The ambiguous case of $8000-$BFFF is treated as PAGE0, which is converted to linear addresses: $000000-$003FFF.  If you want to place something at PAGE2, position it (ORG) at $028000, which will convert to linear address $008000.

-WRN[±]

-WRN+

Enables or disables the display of all warnings.  When enabled, only warnings that aren’t disabled individually will be generated. When disabled, it overrides local warning options (such as -REL and -RTS).

-W

(none)

Write options specified on command line to the ASM8 executable.  The user-specified options become the default values used by ASM8 in subsequent invocations.  Filespec(s) on the command line are ignored.  Assembly of source files does not take place if this option is specified.

 

 


Source File Pseudo-Opcodes (Pseudo-Instructions)

All shaded areas are pertinent to the MMU enabled versions (Win32/Linux only).

Pseudo-Op

Description

 

 

DB string|expr[,...]

Define Byte(s).  expr may be a constant numeric, a label reference, an expression, or a string.  DB encodes a single byte in the object file at the current location counter for each expr encountered (using the LSB of the result) or one byte for each character in strings.

DS blocksize

Define Storage.  The assembler’s location counter is incremented by blocksize. Forward references not allowed.  No code is generated.

DW expr[,...]

Define Word(s).  expr may be a constant numeric, a label or an expression.  expr is always interpreted as a word (16-bit) quantity, and is stored in the object file at the current location counter, high byte followed by low byte.

END [expr]

Provided for compatibility.  The END directive cannot be used to terminate assembly; ASM8 always processes the source file to the end of file.  If expr is specified, the word result of the final END directive is encoded in the S9 record of the object file.

If the expr specified is 24-bit (bits 23-16, collectively, are non-zero), which is possible only when the MMU option is enabled, the 24-bit result is encoded in the S8 record of the object file (no S9 record is produced in that case).

ENDM

Ends definition of a macro.

label EQU expr

Assigns the value of expr to label. See also EXP and SET

label EXP expr

Assigns the value of expr to label.  This is similar to EQU but with the following difference: Labels defined thus will be included in the .EXP file as regular SETs. This effectively allows exporting symbols for use from other source files.  It makes it possible to give only object code to others along with the produced .EXP file so that they can «link» the object to their source.

FAR expr[,...]

Define 24-bit word(s) when the MMU is enabled.  expr may be a constant numeric, a label or an expression.  expr is always interpreted as a 24-bit quantity, and is stored in the object file at the current location counter in big-endian order.

If, however, the MMU option is disabled, FAR is treated as DW.

FCB string|expr[,...]

Form Constant Byte(s).  Same as DB.

FCC string|expr[,...]

Form Constant Character(s).  Same as DB.

FCS string|expr[,...]

Form Constant String.  Similar to FCC, but automatically appends a terminating null (0) byte to the end of the string defined (for ASCIZ strings).

FDB expr[,...]

Form Double Byte(s).  Same as DW.

LONG expr[,...]

Form 32-bit long word(s).  expr may be a constant numeric, a label or an expression.  expr is always interpreted as a 32-bit quantity, and is stored in the object file at the current location counter in big-endian order.

Not available in the DOS version.

MacroName MACRO comments

Begins definition of a macro.

  • Macros must be defined anytime before they are invoked, and they can be invoked until the end of the current assembly (for global macros), end of current file (for local macros), or until a #DROP directive undefines them, in either global or local case.
  • Macros are invoked using the @MacroName[,parm separator] syntax, by default (see #MACRO, #@MACRO and #MCF directives).  Note: You can also use the %macro call syntax to force the macro counters (:MINDEX, :INDEX, :LOOP) to reset, as if you had dropped and recreated the macro.
  • The macro name may be followed by a comma and any non-alphabetic single character (if more characters found, only the first matters).  If this parameter override option is found, then the character right after the comma will act as a one-time parameter delimiter (just for this macro call.  The #PARMS defined delimiter will not be affected.)  If the character is a space, it does not require yet another space as field separator.
  • The macro may refer to yet undefined labels or macros, as the code or definitions inside it are not parsed until the macro is actually used, if at all.
  • Local macro names start with the ? symbol (like normal local labels).
  • The special local macro named ? (just a single question-mark) is to be used ad-hoc.  This one special macro name is automatically dropped (without warning) at each new redefinition.  It’s useful for quickly defining a temporary macro to be used immediately afterwards, and considered discarded later.

§         Parameters are passed during invocation in the operand field separated by commas (or whatever delimiter you have defined with the #PARMS directive, or the special one-time parm separator.)

§         To use a null parameter, just put two delimiters next to each other (e.g., @MACRO PARM1,,PARM3).  Note: This will work for any delimiter except for space; two or more consecutive spaces – outside a string, of course – are seen by the assembler as one space in the parameter field.  Space delimiters can only be used with sequential parameters without gaps in between (which is good for the majority of cases, but not for all).  If you must know, this is because the assembler trims multiple spaces between fields to locate the operand field.  If spaces were allowed to separate null parameters, it would also have to count the spaces from the macro name to the parameter field less one that is required to separate the two fields and possibly less one more that could be used with a “space” parameter override, and since the null parameters could be first in the list of parameters, this would be very confusing, and hard to get it to work correctly (especially since you can’t easily count spaces) while also maintaing the desired code formatting.  So, when calling a macro with non-trailing null parameters, make sure the parameter separator is NOT a space (either by default or by override) or you will get incorrect macro expansions.

  • Macro-only labels must include the string $$$ anywhere inside their name (except at the very beginning), e.g. Loop$$$
  • Parameter text replaces placeholders anywhere within the body of the macro (label, operation, operand, comment fields) without regard to context.  Parameter placeholders are ~0~ thru ~9~ (where ~0~ is reserved for the macro name itself, and ~1~ thru ~9~ for actual parameters.)
  • The body of a macro may contain embedded expressions (in any field, even comments) of the form {<expr>}, like one can do with strings, where <expr> is any valid expression, normally including some parameter placeholder(s).  Expressions are evaluated last, after expansion of parameter placeholders.
  • To accommodate indexed mode within any one parameter (provided the macro is called with a non-comma parameter separator), you can use the following variations of the placeholders: ~n,~ and ~,n~ (where n is the number 1 thru 9) and the comma position (either after or before the number) defines whether we want the part before the index (excluding the comma), or the index itself (including the comma), respectively.  For example, the instruction lda ~1,~+1~,1~ will expand correctly whether parm ~1~ contains an index or not.  (Using the simpler lda ~1~+1 will not expand with the intended behavior, as the +1 will follow the index, and not the offset before the index.)  If no index is within the parameter, ~n,~ is the same as ~n~ while ~,n~ is null.  The assembler will pick anything following a possible comma within a parameter as being an index (so you could get creative and use the feature for other purposes also).
  • The special placeholder ~#~ returns either a null string or the character # if the first parameter’s (~1~) first character is a # (possibly, indicating immediate mode use).  With conditional assembly (e.g., #IFPARM ~#~) one can treat the ~1~ parameter differently, assuming immediate mode.
  • Similarly, the placeholder ~#n~ (where n is a number from 1 thru 9, zero also accepted but it is pointless) returns the parameter part after a possible # sign, if one is present.  This allows to get an immediate mode type parameter in a form (stripped of the # symbol) that can be used in expressions (for example, in an #IF directive expression).
  • Since one may often call a macro with a non-comma delimiter (such as when a parameter contains a comma in an indexed operand – e.g. 1,sp), a possible chained macro call passing this parameter to another macro, or to self while looping, must use the same parameter delimiter that was used to call the original macro, or else the parameter may not be passed on correctly, or not even as a single parameter.  Using the default (a comma) is problematic in those cases.  To solve this problem, two equivalent special placeholders have been introduced.  One is the ASCII code 149 [•] (e.g., use the ALT-7 method for entry in Win-PCs), and the other is the two-character sequence \, (a backslash followed by a comma) which should work in all environments.  Either of these placeholders will be replaced by the same delimiter as the one used for the most recent macro call (either by default or by override), unless there is a new explicit one-time delimiter override (@macro,char format).
  • The special placeholder ~label~ (case-insensitive) returns the actual text of a label appearing in the label column of the last macro invocation (after expanding possible label embedded {<expr>}).  This can be used with ‘function-like’ macros that need to set a label to a specific value (without having to pass the name of the label as a regular parameter).  If no label is used in the same line as the macro invocation, then it returns a null (empty) string.  If, however, no label is used with a chained macro invocation (a macro invocation occuring from inside a macro) then the text is not changed from the original macro’s.  This way, a macro can chain to itself (for looping) and still have the ~label~ placeholder expand correctly.
  • The placeholder ~@~ is an alias for the full list of placeholders separated by • (starting from ~1~).   Useful if you want to pass all parameters to another macro.  The sequence produced by ~@~ is: ~1~•~2~•~3~•~4~•~5~•~6~•~7~•~8~•~9~
  • The placeholder ~@@~ is an alias for the full list of placeholders separated by • but starting from ~2~.  Useful if you want to pass the remaining parameters to the same macro when looping (assuming each loop only processing the first parameter, until that becomes null).  The sequence produced by ~@@~ is: ~2~•~3~•~4~•~5~•~6~•~7~•~8~•~9~
  • Trailing commas due to macro expansion of null parameters are automatically removed.
  • Order of placeholder expansion is: ~label~, ~#~, ~#n~, ~n~ (where n = 0..9, in that order), \,, and .
  • During macro invocation, any parameter text may contain embedded {<expr>}, like one can do with strings, where <expr> is any expression, possibly including some parameter placeholder(s).
  • Macros cannot #INCLUDE files.
  • Macros cannot define other macros.
  • Macros cannot temporarily invoke other macros.  (No nesting.)
  • Macros, however, can chain to self or other macros (with no return).  This allows, among other things, for creating loops, making macros very powerful.
  • To break out of an endless macro loop, press [ESC].
  • Macro labels may be case-sensitive (depending on #CaseOn/Off directives) when defined, but are always case-insensitive when invoked (like normal opcode names).
  • Virtually unlimited number of macro definitions (memory permitting.)
  • Virtually unlimited size of each macro (memory permitting.)
  • Unlimited number of macro invocations (all internal macro counters are 32-bit).

MEXIT

Causes early exit from a macro expansion.  (Normally, used with conditionals.)

label NEXP symbol[,expr]

Assigns the current value of symbol to label as if with EXP.  Then, it increments the value of symbol by one (as if with SET) or, if the optional expression is present, by the value of that expression.  Useful for defining a series of symbols based on a common starting value.  Note: symbol is a single label and not an expression.  See also NEXT, SETN

label NEXT symbol[,expr]

Assigns the current value of symbol to label as if with EQU.  Then, it increments the value of symbol by one (as if with SET) or, if the optional expression is present, by the value of that expression.  Useful for defining a series of symbols based on a common starting value.  Note: symbol is a single label and not an expression. See also NEXP, SETN

ORG expr

Sets the assembler’s location counter for the active segment.  Code generated after this directive will be assembled starting at the location specified by expr.

RMB blocksize

Reserve Memory Byte(s).  Same as DS.

label SET expr

Assigns the value of expr to label even if label is already defined with a different value.

This is similar to EQU but allows making multiple re-definitions.  The value set will be used until another SET pseudo-instruction or to the end of the assembly process.

Warning: Careless, or simply wrong use of this directive can lead to multiple side errors or warnings (please note this is a two-pass assembler).  Using a forward SET defined symbol may lead to problems, as the value used will be the one from the last SET definition, which is not necessarily the one we want.

Correct behavior is guaranteed if any symbols re-defined with SET are used only after each new re-definition, otherwise, the first reference in Pass 2 will use the value from the last re-definition in Pass 1.

Example of wrong use:

1.             lda  #Value  ;we expect 123, actual is 234

2. Value       equ  123

               ...

3.             lda  #Value  ;we expect 234, actual is 123

4. Value       set  234

Value in line 1 will be 234 (the last known value from Pass 1) while Value in line 3 will be 123 (most recent value in current Pass 2).

 

Example of correct use:

1. Value       equ  123

2.             lda  #Value  ;we expect 123, actual is 123

               ...

3. Value       set  234

4.             lda  #Value  ;we expect 234, actual is 234

See also EXP and EQU

label SETN symbol[,expr]

Assigns the current value of symbol to label as if with SET.  Then, it increments the value of symbol by one (as if with SET) or, if the optional expression is present, by the value of that expression.  Useful for (re-)defining a series of symbols based on a common starting value.  Note: symbol is a single label and not an expression.  See also NEXP, NEXT


Source File Processing Directives

 

·        All processing directives must be prefixed with a $ or # character.  ASM8 will recognize either character as the start of a processing directive.

·        If a directive has a corresponding command-line option, the directive in the source file will override the command line directive at the point in which the source file directive is encountered.

·        [text] will be trimmed of duplicate spaces.  To have more than one consecutive spaces display, use the Alt-255 character, as many times as needed.

·        All shaded areas are pertinent to the MMU enabled versions (Win32/Linux only).

 

Directive

Description

 

 

#AIS symbol

#AIS checks the current value of the :SP internal variable against the most recent AIS instruction’s value, and issues a warning if the two numbers do NOT differ by the exact value in the symbol (note: a plain symbol, not an expression), indicating a possible stack frame definition error (assuming correct placement of the relevant directives).

 

The warning also shows the correct AIS instruction that is required to correct the problem.
 
This directive makes it very easy to correct the numeric value in AIS instructions to match the following stack frame definition (normally made using the internal :: symbol in the various #SPAUTO modes, and the next/setn method for defining records/structures. )  This is useful to prevent having to define the stack frame before the AIS instruction using a one-based starting offset just so you can use a label with AIS and then having to re-define it for dynamic assignment of offsets based on the current :SP.

 

The associated :AIS symbol returns the difference between the current :SP and the value saved during the most recent AIS instruction.  This can be used to de-allocate just the number of stack bytes that are still left on the stack between the two points in your source (inclusive of the previous AIS instruction).  This is only meant for use in #SPAUTO modes which automatically adjusts the current value of the :SP internal symbol.

 

#PUSH and #PULL will save/restore the value of this setting.

 
Example use:

 

                    #spauto

 

Subroutine          ais       #-4                 ;local data

 

?                   set       ::

?Parm1              setn      ?,2

?Parm2              setn      ?,2

 

                    #ais      ?                   ;check frame definition

 

#CALL

Effective only while the MMU is disabled: When active, CALL/RTC instructions are NOT treated as if they were JSR/RTS instructions, but they issue errors instead.  See also the directives #JUMP, #MMU, #NOMMU

Equivalent to the –J- command line option.

#CASEOFF

When #CASEOFF is in effect, all symbol references that follow are converted to uppercase internally before they are searched for or placed in the symbol table.

Equivalent to the –C- command line option.

#CASEON

When #CASEON is in effect, symbol references are NOT internally converted to uppercase before they are searched for or placed in the symbol table.

Equivalent to the –C+ command line option.

#CRC expr

The two CRCs (user and S19) maintained by the assembler are 16-bit each, and they are updated only during PASS2 by each produced user code/data byte that is put into the S19 file.  The starting CRC value for both CRCs is zero.

 

With this directive you can alter the user CRC value at any time (either before the very first byte of code/data to produce a different CRC for the same firmware, or several times in between to skip certain volatile sections, for example).

 

The computed CRCs are available by accessing the internal symbols :CRC and :S19CRC

 

The formula used for the 16-bit CRC calculation is very simple to be easily implemented even in tiny bootloaders:

 

16BitCRC := 16BitCRC + 16BitAddress*8BitData

 

:S19CRC is mostly useful with the END directive (END :S19CRC) as it is not affected by the #CRC directive.  An S19 loader can check the overall integrity of the S19 file.

 

:CRC, on the other hand, is mostly useful for checking code after it has been loaded into the MCU, at each reset, for example.

 

Please note that for both CRCs all $00 bytes do not affect the calculation while, for the user CRC only (:CRC), all $FF bytes are intentionally skipped.  This allows for the CRC in an S19 file (which does not necessarily fill a contiguous block of memory) to match the CRC computed by the MCU over a complete block of memory without the MCU bootloader knowing in advance the actual addresses used within that block, provided any unused bytes are in the erased state.

As a side effect, however, any $00->$FF or $FF->$00 alterations in the file cannot be detected with the user CRC.

#CYCLES [expr]

Sets the internal :CYCLES to zero (if expression is missing) or any arbitrary value.  This can also be used inside macros to restore the cycle counter of surrounding code, if the macro cycles should be counted in a special way, or not at all.

#DATA

Activation of the DATA segment.  Default starting value is $FE00.

#DROP macro[,macro]*

Undefines one or more macros.  If a macro is not currently defined, a warning will be issued (to protect from possible typing errors).

 

If used from inside a macro, and that macro is dropped, the macro will terminate at that point.  The rest of the macro will not be processed.

 

The special macro named ? (just a single question-mark) is to be used ad-hoc, and it is automatically dropped (without warning) at each new redefinition.  You may also drop it with #DROP but only need to do so if you want to force errors in later use of the macro, so you can easily locate them.

#EEPROM

Activation of the EEPROM segment.  Default starting value is $0000.

#EJECT

See #PAGE

#ELSE

When used in conjunction with conditional assembly directives (#IF, #IF[N]DEF, $IF[N]Z, #IFMAIN, #IFINCLUDED, etc.), code following the #ELSE directive is assembled if the conditional it is paired with evaluates to a not-true result.

#ENDIF

Marks the end of a conditional-assembly block.

Conditional assembly statements may be nested if they are properly blocked with #ENDIF directives.

#ERROR [text]

When encountered in the source, the assembler issues an error message in the same form as internally-generated errors, using the text specified, prefixed with «USER: »

#EXTRAOFF

Disables recognition of ASM8’s extended instruction set for source lines that follow this directive.

Equivalent to the –X- command line option.

#EXTRAON

Enables recognition of ASM8’s extended instruction set for source lines that follow this directive.

Equivalent to the –X+ command line option.

#FATAL [text]

Similar to the #ERROR directive, but generates an assembler fatal error message and terminates the assembler (possible further files in the list will not be processed).

#HCSOFF

Disables the HCS08 instruction set mode.  See also #IFHCS #IFNHCS #HCSON

Equivalent to the –HCS- command line option.

#HCSON

Enables the HCS08 instruction set mode.  See also #IFHCS #IFNHCS #HCSOFF

Equivalent to the –HCS+ command line option.

#HOMEDIR path

Makes the specified path the current home directory.  Although this cannot affect where any output files will go, it does make a difference on where any following relative #INCLUDE files will be searched.  Relative file path specifications will now be relative to the directory specified by the #HOMEDIR directive, including any relative #INCLUDE references in nested include files.

#IF expr1 cond expr2

Evaluates expr1 and expr2 (which may be any valid ASM8 expression) and compares them using the specified cond conditional operator.  If the condition is true, the code following the #IF operator is assembled, up to its matching #ELSE or #ENDIF directive.

Cond may be any one of:  <  <=  =  >=  >  <>

The condition is always evaluated using unsigned arithmetic.

If a symbol referenced in expr1 or expr2 is not defined, the statement will always evaluate as false.

#IFDEF expr

Attempts to evaluate expr, and if successful, assembles the code that follows, up to the matching #ELSE or #ENDIF directive.  This directive is used to test if a specified symbol has been defined.  Symbol(s) referenced in expr must be defined before the directive for the result to evaluate true (e.g., forward references will evaluate as false). #IFDEF without an expr following will always evaluate to False.

#IFEXISTS fpath

Checks for the existence of the file specified by fpath (using the same rules as those used for #INCLUDE directives) and assembles the code that follows if the specified fpath exists.

#IFHCS

Assembles the following code if the assembler is in the extended HCS08 instruction set mode.  See also #IFNHCS #HCSON #HCSOFF

#IFINCLUDED

Assembles the code which follows if the file containing this directive is a file used in an INCLUDE directive of a higher-level file (regardless of nesting level).  See also #IFMAIN

#IFMAIN

Assembles the code that follows if the file containing this directive is the main (primary) file being assembled.  See also #IFINCLUDED.

#IFMDEF macro

#IFNOMDEF macro

#IFMDEF checks if the specified macro exists, and if so, assembles the code that follows, up to the matching #ELSE or #ENDIF directive.  This directive is used to test if the specified macro has been defined.  #IFNOMDEF does the opposite check.

#IFMMU

Assembles the code that follows if the MMU option is enabled.  See also the directives #MMU, #NOMMU, and #IFNOMMU

#IFNOMMU

Assembles the code that follows if the MMU option is disabled.  See also the directives #MMU, #NOMMU, and #IFMMU

#IFPARM text [= text2]

#IFNOPARM text [= text2]

Normally used inside a macro.  If text is non-blank, assembles the code that follows, up to the matching #ELSE or #ENDIF directive.  This directive is used to test if a specified macro parameter has been defined.  #IFPARM without text following (after macro expansion) will always evaluate to False. text is usually a parameter placeholder (e.g,. ~1~).

You can also make a case-insensitive comparison of the parameter to a specific text2 string (with or without quotes, depending on your intent) by separating the two text strings with an ‘equals’ (=) sign.  For example, #IFPARM ~1~ = * tests if parameter one is a plain asterisk (normally used to indicate the current location pointer.)

#IFNOPARM performs the opposite test.

#IFSPAUTO

Assembles the code that follows, up to the matching #ELSE or #ENDIF directive, if the assembler is currently in #SPAUTO (automatic SP adjustment) mode.  See also #SPAUTO #SP

#INCLUDE fpath

INCLUDEs the specified fpath file in the assembly stream, as if the contents of the file were physically present in the source at the point where the #INCLUDE directive is encountered.  INCLUDEs may be nested, up to 100 levels (the main source file counts as one level).  Relative fpath specifications are always referenced to the directory in which the main source file resides, including any relative #INCLUDE fpath references in nested include files.

 

Note: ASM8 will only generate a standard error (not an assembly-terminating fatal error) if a file specified in a #INCLUDE directive is not found.  The #IFEXISTS and #IFNEXISTS directives may be used in conjunction with #FATAL if termination of assembly is desired under such conditions.

#IFNDEF expr

Evaluates expr and assembles the code that follows if the expression could NOT be evaluated, usually as the result of a reference to an undefined symbol.  This directive is the functional opposite of the #IFDEF directive.

#IFNEXISTS fpath

The opposite of #IFEXISTS; code following this directive is assembled if the specified fpath does NOT exist.  The -Ix directory will be used also to determine if a file exists or not.

#IFNHCS

Assembles the following code if the assembler is in the regular HC08 instruction set mode.  See also #IFHCS #HCSON #HCSOFF

#IFNZ expr

Evaluates expr and assembles the code that follows if the expression evaluates to a non-zero value.  #IFNZ always evaluates to false if expr references undefined or forward-defined symbols.

#IFTOS expr

If top-of-stack evaluates expr+:SP (+:SP is implied) and assembles the code that follows if the expression is equal to one (when in #SP[AUTO] modes), or zero (when in #SP1 mode), i.e., expression points to top-of-stack in all modes.  #IFTOS always evaluates to false if expr references undefined or forward-defined symbols.

Useful mostly in #SP[AUTO] modes.

#IFZ expr

Evaluates expr and assembles the code that follows if the expression is equal to zero.  #IFZ always evaluates to false if expr references undefined or forward-defined symbols.

#JUMP

Effective only while the MMU is disabled: When active, CALL/RTC instructions are treated as if they were JSR/RTS instructions, respectively.  Makes it possible to write common library functions using CALL/RTC instead of JSR/RTS to be used in any MCU, regardless if an MMU is available/used or not.  See also the directives #CALL, #MMU, #NOMMU

Equivalent to the –J+ command line option.

#LISTOFF

#NOLIST

Turns off generation of source and object data in the *.LST file for all lines which follow this directive.  Useful for excluding the contents of #INCLUDE files in the *.LST file.

#LISTON

#LIST

Enables generation of source and object data in the *.LST file for the source code following this directive.  Has no effect if list file generation is disabled (-L- command line option in effect).

#MACRO

#MCF

#@MACRO

 

#MACRO tells the assembler to treat unknown assembly language operations as possible macros.  Normal instructions (including the built-in macro instructions) have priority over macros, so macros named the same as active built-in operations can only be called with the @ prefix.

In effect, when in this mode, the assembler automatically adds the @ symbol if an unknown operation is found to be a macro name.  In this mode, one can invoke macros either way, with or without the @ prefix, but instructions have priority over same name macros.

Note: To avoid problems, all macros should internally use the @macro syntax so they can be properly expanded regardless of mode.

#MCF (“Macros Come First”) is similar to #MACRO (i.e., no @ prefix is required for calling macros) but in this case macros have priority over same name instructions but only when called from outside any macros.  Macro chaining (i.e., jumping to a macro from inside a macro) is still only possible using the @ prefix when a macro name collides with an active instruction name.   So, using this mode is 100% compatible with macros written before this mode was introduced and does not require editing macros to use the !instruction format mentioned next.

If you’re in #MCF mode, and you want to temporarily give priority to a real instruction (without changing to #Macro or #@Macro mode), you must prefix it with a ! (exclamation point.)

The #MCF mode is most useful when you want to override the functionality of any internal instruction with something more involved (a macro), as for example, when porting code from another CPU with similar instructions but different functionality (e.g. LDX in 68HC11 is a word operation, and it may compile without errors in the 68HC[S]08 but with incorrect operation as it will not affect the full HX register).

I do not recommend casual use of this mode as it may make the source code totally misleading (if instructions which are now possibly macros aren’t what they seem but something completely different.)

#@MACRO turns off this option.  This is the default setting when a new assembly begins.  In this mode, you can only invoke macros with the @ prefix.  This is the recommended mode for most normal applications.

#MLISTOFF

#NOMLIST

 

Turns off generation of source and object data in the *.LST file for all macro body lines which follow this directive.  Useful for excluding the body of macros in the *.LST file.

#MLISTON

#MLIST

Enables generation of source and object data in the *.LST file for all macro body lines following this directive.  Has no effect if list file generation is disabled (-L- command line option in effect).  This is the default setting.

#MAPOFF

Suppresses generation of source-line information in the *.MAP file for the code following this directive.  Symbols which are defined following this directive are still included in the *.MAP file.

#MAPON

Enables generation of source-line information in the *.MAP file for the code following this directive.  #MAPON is the default state when assembly is started when map file generation is enabled (-M+ command line option).

#MEMORY addr1 [addr2]

Maps a memory location (or range, if addr2 is also supplied) of object code and/or data areas as valid.  Use multiple directives to specify additional ranges.  Any code or data that falls outside the given range(s) will produce a warning (if the -O option is enabled) for each violating byte.  Very useful for segmented memory devices, etc.  Addr1 and addr2 may be specified in any order.  The range defined will always be between the smaller and the higher values.  See also #VARIABLE

#MESSAGE [text]

Displays text on screen during the first pass of assembly when this directive is encountered in the source.  Messages are not written to the error file.  They are meant to inform the user of the options used or conditional path taken.

#MMU

Enable the MMU features (e.g., CALL/RTC instructions, 24-bit addresses and expressions).  See also the directives #NOMMU, #IFMMU, and #IFNOMMU

Equivalent to the –MMU+ command line option.

#NOMMU

Disable the MMU features (e.g., CALL/RTC instructions, 24-bit addresses and expressions).  See also the directives #MMU, #IFMMU, and #IFNOMMU

Equivalent to the –MMU- command line option.

#NOWARN

Turns warnings off.  Equivalent to the –WRN- command line option.  See also #WARN

#OPTRELOFF

Disable «BRA/BSR instead of JMP/JSR» optimization warnings.

Equivalent to the –REL- command line option.

#OPTRELON

Enable warning generation when an absolute branch or subroutine call (JMP or JSR) is encountered that could be successfully implemented using the relative form of the same instruction (BRA or BSR).  This option is on by default.

Equivalent to the –REL+ command line option.

#OPTRTSOFF

Disable RTS-after-JSR/BSR optimization warning (default).

Equivalent to the –RTS- command line option.

#OPTRTSON

Enable warning generation when a subroutine call (JSR or BSR) is immediately followed by a RTS.  This option is off by default.  Command-line option -RTS+ does the same thing.

#PARMS [char|SPACE]

Allows changing the delimiter used to separate macro parameters when invoking the macro.  If char is defined the new delimiter will be the same as char.  If there is no character following the directive, the default parameter delimiter (a comma) will be used.

To use a regular space as a parameter separator, the [char] part of the command should be the special keyword SPACE (case-insensitive).

#PSP

#PSP (stands for Preserve SP) simply keeps a copy of the current :SP value to be used later by the :PSP internal symbol.

 

The :PSP symbol returns the difference between the then current :SP and the value saved with this directive.  This can be used to de-allocate just the number of stack bytes that were pushed in between.  This is only meant for use in #SPAUTO mode, which automatically adjusts the current value of the :SP internal symbol.

 

#PUSH and #PULL will save/restore the value of this setting.

#S19FLUSH

Forces the immediate termination of an S-record line when encountered, rather than waiting for the record to reach the size specified by the –Rn command line directive.  This directive may be used to make identification of the end of code blocks easier when viewing the *.S19 file.

#S1

#S2

#S2 forces the generation of S2 records (24-bit addresses) even for 16-bit addresses.  (#S1 reverts to normal, which produces S1 or S2 records based on address.)  Although 24-bit addresses are enabled, no MMU features are enabled.  Useful mostly for forcing 16-bit addresses to appear as 24-bit (with leading byte as $00) so that S19 loaders can use that as the PPAGE value.

Equivalent to the –S2- and -S2+ command line options.

#SP [expr]

#SP1 [expr]

#SPAUTO [expr]

#SPADD [expr]

#SP1 automatically adds one to all SP indexed offsets.  It does this without affecting the current value of the :SP internal symbol.

 

#SP without any expression cancels #SP1 and #SPAUTO modes (reverts to default/normal operation).

 

#SP followed by any expression (including a zero value) sets the :SP offset to the value of that expression but does not affect the current #SPAUTO mode.

 

#SPADD adds a [signed] number to the current value of the :SP offset (regardless of mode).  It does not reset the :SPCHECK variable, as with #SPAUTO.

 

When #SP1 is enabled, all SP indexed instructions use the same (zero-based) offsets as their corresponding X indexed instructions right after a TSX instruction.  This allows using the same [named or numeric] offsets for both addressing modes to access the same memory location(s)!

 

If the optional signed expression is present, its value will be added, also.  This makes it easier to adjust for any stack depth changes, such as for subroutines or in-line stack changes.

 

#SPAUTO will automatically adjust the offset based on the instructions used.  All push and pull instructions (including the extra ones) as well as all AIS instructions will automatically adjust the offset by as many bytes as required by each instruction.  Use the #SP directive (without any parameter offset, not even zero) to turn off the #SPAUTO mode and zero the SP offset (or, use #SPAUTO with the special #OFF# parameter to turn off the #SPAUTO mode without changing the current SP offset.)

 

Manual alterations of the stack size, however (such as when you push an extra byte per loop iteration) cannot be automatically detected as the assembler will not follow your code’s logic.  In those cases, you’ll have to adjust the offset ‘manually’ using #SPADD and an appropriate offset, like so:

 

#SPADD LOOPCOUNT-1

 

#PUSH and #PULL will save/restore the current setting of all modes of this option.

 

The assembler always starts in plain #SP mode (no offsets).

 

See also internal symbols :SP and :SP1 and the simulated indexed modes ,ASP and ,LSP

#SPCHECK

#SPCHECK checks the current value of the :SP internal symbol against the last used #SPAUTO value (found in :SPCHECK internal symbol), and issues a warning if the two numbers do NOT match, indicating a possible unbalanced stack situation (assuming correct placement of the relevant directives).

 

The current difference between :SP and :SPCHECK is found in :SPFREE (eg., use with AIS #:SPFREE)

 

The warning also shows the number of bytes by which the stack is off.  This can be used as a first-line of defense against unbalanced stack coding errors, especially in situations where there is heavy manipulation of the stack, and a visual inspection may prove confusing.  Positive numbers indicate the stack contains so many extra bytes.  Negative numbers indicate the stack is missing so many bytes.

 

Hint: If you do not wish to use the #SPAUTO function for a particular section of code (or anywhere in your program) you can still temporarily place the #SPAUTO directive at the beginning of a code section to check, and the #SPCHECK at the end of the same code section, until you verify there are no related compilation warnings.  Then you can remove the two directives (possibly even with the use of conditional directives), and continue with other coding work.

 

See also #SPAUTO

#X [expr]

When #X is enabled (i.e., followed by a non-zero signed offset), all X indexed instructions will have that offset value automatically added to them (on top of whatever offset is actually specified with the instruction).  This has a lot of potential uses, such as pointer adjustments (after TSX), or anytime the same constant needs to be added to a series of X-indexed instructions within a block of code.

 

#PUSH and #PULL will save/restore the current setting of this option.

 

The assembler always starts in plain #X mode (no offsets).

 

See also internal symbol :X and the simulated indexed mode ,AX

#UNDEF symbol[,symbol]*

Undefines one or more symbols.  If a symbol is not currently defined, a warning will be issued (to protect from possible typing errors).

Careless, or simply wrong use of this directive can lead to multiple side errors or warnings (please note this is a two-pass assembler).

If you simply want to redefine the value of a symbol, prefer using the SET pseudo-op, rather than using #UNDEF followed by a repeated symbol definition.

#UNDEF can be used, for example, to completely remove unrelated or conflicting conditionals.

#PAGE

Outputs a Form Feed (ASCII 12) character followed by a Carriage Return (ASCII 13) in the *.LST file just before displaying the line that contains this directive.

#PUSH

Pushes on an internal stack the current segment and the current settings of the following options: MAPx, LISTx, CASEx, EXTRAx, SPACESx, OPTRELx, OPTRTSx, WARN, NOWARN, HCSx, MMU, JUMP, CALL, S1, S2, SP1, SP, SPAUTO, X, TRACEx, MACRO, @MACRO, MCF, various SP-based offsets (eg., :AIS) , MLISTx and TABSIZE.  Useful in included files that want to change any of these options without affecting parent files.  See also #PULL

#PULL

Pulls from an internal stack the last pushed segment and settings of the following options: MAPx, LISTx, CASEx, EXTRAx, SPACESx, OPTRELx, OPTRTSx, WARN, NOWARN, HCSx, MMU, JUMP, CALL, S1, S2, SP1, SP, SPAUTO, X, TRACEx, MACRO, @MACRO, MCF, various SP-based offsets (eg., :AIS) , MLISTx and TABSIZE.  Useful in included files that want to change any of these options without affecting parent files.  You can use PULL even if haven’t used PUSH; no action will take place.  See also #PUSH

#RAM

Activation of the RAM segment. Default starting value is $0080.

#ROM

Activation of the ROM segment. Default starting value is $F600.  This is the default segment if none is specified.

#SEGn

Activation of the SEGn segment (n is a number from 0 through 9).  Default starting value for all ten segments is $0000.

#TABSIZE n

Specifies the field width of tab stops used in the source file.  Proper use of this directive ensures that the *.LST files generated by ASM8 are formatted in the same way as your source files appear in your text editor.  This directive overrides the setting of the –Tn command line option for the source file(s) in which it is encountered.

#TRACEON

#TRACEOFF

#TRACEON enables generation of source-line information in the *.MAP file for any code found in the body of macros following this directive.  The map info is generated in such a way that while tracing the debugger will display the actual source of the macro.  This can be used globally (to affect all macro invocations), inside a specific macro (to debug that one macro), or around a specific macro invocation (to debug that one macro call.)

#TRACEOFF turns this option off making macros appear as a single line in the debugger.  #TRACEOFF is the default state when assembly is started.

#VARIABLE addr1 [addr2]

Maps a location (or range, if addr2 is also supplied) of variable allocation area (normally in RAM) as valid.  Use multiple directives to specify additional ranges.  Any RMB or DS definitions that fall (fully or partially) outside the given range(s) will produce a warning (if the -O option is enabled) for each such definition.  Addr1 and addr2 may be specified in any order.  The range defined will always be between the smaller and the higher values.  See also #MEMORY

#VECTORS

Activation of the VECTORS segment. Default starting value is $FFC0.

#WARN

Turns warnings on.  Equivalent to the -WRN+ command line option.  See also #NOWARN

#WARNING [text]

Similar to the #ERROR directive, but generates an assembler warning message instead of an error message.

#XRAM

Activation of the XRAM segment.  Default starting value is $2000.

#XROM

Activation of the XROM segment.  Default starting value is $EC00.

 


Note: [text] in directives and all strings may contain expressions enclosed in curly brackets, e.g. {expr}.  The expression may not contain spaces (regardless of the –SP option state, or #SPACESON directive.  An optional format modifier (case-insensitive) within parentheses after the expression can force the display in the specified format.  (D) for default/decimal, (H) for hex, (S) for signed decimal, (1) thru (4) (or, thru (9) for the 32-bit versions) for the corresponding number of decimal places after division by 10n where n is a number from 1 to 4 (or 9), and (X) for eXpanded.  If no format modifier is used, (D) is assumed.  Some examples using this feature:

 

ROM EQU $F000

#Message ROM is at {ROM}

will display:

ROM is at 61440

 

Adding a format modifier will have the following effect:

 

#Message ROM is at {ROM(x)}

will display:

ROM is at 61440 [$F000]

 

#Message ROM is at {ROM(d)}

will display:

ROM is at 61440

 

#Message ROM is at {ROM(h)}

will display:

ROM is at $F000

 

#Message ROM is at {ROM(s)}

will display:

ROM is at -4096

 

It can also be used in strings, like so:

 

VERSION equ 101 ;Firmware version as x.xx

MsgVersion fcs ‘Firmware v{VERSION(2)}’,LF

is equivalent to

MsgVersion fcs ‘Firmware v1.01’,LF

 

but it will automatically adjust the MsgVersion string each time the symbol VERSION changes value.  No need to re-adjust all relevant messages manually.  The potential uses of this capability are only limited by imagination.

 

An expression that cannot be evaluated (due to forward references or undefined symbols) will display as three question marks (???) when used in directives, but no error or warning message will be issued.  When used in strings, however, errors will be displayed as usual.

 

To prevent an expression evaluation in directives, enclose the [text] that contains the curly brackets within quotes.

 

To prevent an expression evaluation in strings, break the string into two so that both curly brackets are not part of the same string, e.g.:

 

instead of fcc ‘{Hello}’ which tries to evaluate the symbol Hello use: fcc ‘{‘,’Hello}’.

 


Internally defined symbols

 

Some special internal symbols are defined by the assembler.  All such symbols begin with a colon (:) character.  Currently, the following internal symbols are defined:

 

§         :: returns the current (dynamically assigned) stack offset.  Very useful mostly in #SPAUTO mode so that you can assign labels to stack contents as they are created.  (Same as 1-:SP in #SP[AUTO] modes, or 0-:SP if in #SP1 [sub-]mode.)  Note: Beginning with v5.70 if any push instruction is followed by a label, that label will be SET to the current :: value (must be in #ExtraOn mode).

§         :SP returns the current offset of the #SP or #SP1 directives.  This value is the basis for several other internal symbols.

§         :SPX returns :SP-1 when in #SP[AUTO] modes and :SP-0 when in #SP1 [sub-]mode.  Useful with #X as in #X :SPX.  Alternatively (and preferably), you may use the ,SPX simulated indexed mode, which does not depend on the :SPX value, and which is actually X-indexed mode but stack-relative to the most recent TSX instruction, and possible subsequent AIX instructions. (Note: there are many ways to alter the contents of the HX index register; the assembler cannot automatically account for all those possibilities; use #X expr where needed to manually adjust the offset, and use the plain X-indexed mode).  This feature provides a very simple way of optimizing any ,SP relative instruction to ,X relative (by simply appending an X to ,SP making it ,SPX and using TSX anywhere before these instructions.  All offsets are automatically adjusted.)

§         :SPCHECK returns the actual offset used with the most recent #SPAUTO directive.

§         :SPFREE returns the current stack depth change (same as :SP-:SPCHECK).  For example, you may use it with the AIS instruction to free so many bytes of stack.    (The symbol :SP alone will not work for this purpose – releasing remaining stack bytes – unless #SPAUTO is used with a zero offset, while :SPFREE works, regardless of the initial offset.)

§         :AIS returns the current stack depth change since and including the last stack-increasing AIS instruction (not the #AIS directive).  For example, you may use it with a new [normally, stack-reducing] AIS instruction to free so many bytes of stack.  :AIS is updated automatically after each stack-increasing AIS instruction, i.e., a negative AIS instruction with an actual instruction operand of $80 to $FF, losing whatever previous value was in :AIS, and it can be used to free whatever stack bytes remain since the last stack-increasing AIS instruction (used like so:, AIS #:AIS).  #SP, #SPAUTO, and #SP1 reset the :AIS symbol to zero or the value of the parameter used with the corresponding directive until the next AIS instruction.

§         :PSP returns the current stack depth change since the last #PSP directive.  For example, you may use it with the AIS instruction to free so many bytes of stack.  Unlike :SPFREE which is related to the automatically updated :SPCHECK during any #SPAUTO directive, :PSP is only updated manually with the #PSP directive, and can be used locally (eg., around a sub-routine call) to free the number of stack bytes for only a specific section of code (eg., whatever parameters were pushed on the stack for use by the sub-routine).

§         :SP1 returns the current offset of the #SP or #SP1 directives (like :SP), but also adds one only if we’re currently in the #SP1 mode.  This value is always the true effective offset for both #SP and #SP1 modes.

§         :AB returns the number of Address Bytes (useful for stack offsets).  2 for normal, 3 for MMU

§         :X returns the current offset of the #X directive.

§         :YEAR returns the year at assembly time (e.g., 2010)  Hint: Use :YEAR\100 for two-digit year.

§         :MONTH returns the month at assembly time (e.g., 9)

§         :DATE returns the date at assembly time (e.g., 4)

§         :CRC returns the current value of the running user CRC

§         :S19CRC returns the current value of the running S19 CRC.

§         :PAGE_START returns the page window’s starting address.

§         :PAGE_END returns the page window’s ending address.

§         :CYCLES returns the current value of the cycles counter, and then it is reset to zero.

§         :TOTALMACROCALLS returns the current value of the total macro invocations.  Use it for display, or even to restrict macro use (e.g., #IFNZ :TOTALMACROCALLS … #ERROR No macros allowed for this application … #ENDIF).

§         :MACRONEST returns the current value of the macro (chain) ‘loop level’ regardless if calling the same, or a different macro (think of it as the ‘nesting level’).  A value of zero is returned if used outside any macros.  First level is number 1.  Each time the top-level macro is called, the number is reset to 1.  Each time the same or a different macro is called from within the current macro, the number is incremented by 1.  The macro (chain) can also initialize itself during, say, count one.

§         :MACROLOOP (or, simply, :LOOP) is similar to :MACRONEST but it returns the current value of the macro ‘loop level’ only for the current macro.  A value of zero is returned if used outside any macros.  First level is number 1.  Each time the macro is called from outside any macros, or from a different macro, the number is reset to 1.  Each time the macro calls itself, the number is incremented by 1.  This can be used as an automatic loop counter.  The macro can also initialize itself during, say, count one.  This differs from :MACRONEST in that chained macro calls will restart this counter for each new macro.  This counter is also reset with a %macro syntax call.

§         :MACROINDEX (or :MINDEX) returns the current value of the current macro’s number of invocations.  A value of zero is returned if used outside any macros.  First call of each macro is number 1.  If the specific macro is dropped and re-created, the number is reset (it is, afterall, a new macro).  An example use is to create different labels at each invocation (not to be confused with automatic $$$ label generation, which assumes values based on :TOTALMACROCALLS and cannot be guaranteed to take sequential values between consecutive calls of the exact same macro since other macros may have increased the counter in between), or instruction offsets (e.g., with the special ad-hoc macro named “?”), etc.  This counter is also reset with a %macro syntax call.

§         :INDEX returns the next value of the current macro’s internal user index.  A value of zero is returned if used outside any macros.  First use in each macro is number 1.  If the specific macro is dropped and re-created, the number is reset (it is, afterall, a new macro).  Its use is similar to :MACROINDEX but there is a significant difference.  :INDEX is only updated each time it is accessed, regardless of how many times the macro is actually called.  So, if used inside a conditional block of code, it will only be incremented when that part is expanded.  Note: Because of the auto-increment on access, if you want to use the same value more than once in the same macro invocation, you must first assign the value to some label, and then use the label, instead.  This counter is also reset with a %macro syntax call.

 

Notes about :SP and :SP1:

 

:SP returns the current automatic SP offset (the same for both #SP and #SP1 modes).  It will NOT account for the extra ‘plus one’ of the #SP1 mode, however.  Use it to adjust the current SP offset manually, or to work with labels that are dependent on the current #SP or #SP1 mode; for example, the current level labels while a one-based or zero-based offset is in effect.  The local labels will still need to be in the same (zero or one) base, however.  You can also use the simulated indexed mode ,LSP (Local SP) to get the same effect.

 

:SP1, on the other hand, returns the current automatic SP offset just like :SP but which will be ‘plus one’ if we’re currently in #SP1 mode.  This is always the true difference between automatic and actual stack offset, regardless of mode.  You may also use the simulated indexed mode, ,ASP (Absolute SP) to get the same effect.

 

For example, use ,ASP (or –:SP1) to cancel out all offsets for dealing with absolute numbers:

 

#sp1       SomeValue

...

?LocalA                     equ       1

pshx

cmp       1-:sp1,sp              ;absolute offset

cmp       ?LocalA-:sp1,sp       ;absolute offset

cmp       ?LocalA,asp              ;absolute offset

pulx

 

All three CMP instructions above will compare against the stacked value from the immediately preceding PSHX instruction, regardless if the directive earlier is #SP or #SP1, and regardless of the presence or value of the optional parameter SomeValue.  It is equivalent to CMP 1,sp when #SP mode is off, and you can use it regardless of the current #SP mode and offset, and even if the #SP directive is never used, use it to lock the offsets (so that possible future #SP/#SP1 automatic offsets in related code will not affect these lines).

 

This feature is most useful when a section of code is under #SP control (say, because most instructions refer to the parent routine’s stack frame, and coding becomes simpler and more readable under #SP control) but you temporarily want to access local stack without any automatic offsets.  That way, you don’t have to turn off #SP/#SP1 mode just for one instruction, or so.

 

To switch from zero-based label [or numeric] offsets to one-based (normal) stack offsets, without changing the current stack depth (automatic SP offset), you must do this:

 

#sp               :sp

 

Similarly, to switch back to zero-based offsets without changing the current automatic SP offset (current stack depth), you must do this:

 

#sp1               :sp

 

You can also use the :sp internal symbol to adjust X-indexed offsets after a TSX to refer to higher stack levels (say, a parent routine).  For example:

 

MyOffset                           equ           0                    ;zero-based offset

 

ais              #-1                     ;allocate temp space

...

tsx

sta              MyOffset,x              ;save to local stack

bsr              Sub

...

#sp1              2                     ;account for RTS (zero-based)

 

Sub                                tsx

lda              MyOffset,sp              ;gets A from parent stack

lda              MyOffset+:sp,x              ;(equivalent to above)

 

Examine the assembler listing on the following page to see the corresponding produced offsets for each case.


    1      0000                 ?                   equ       0

    2                          

    3      F600                                     org       *

    4                          

    5                                              ;#sp                           ; default mode, no offsets

    6                          

    7 F600:9EE6 01         [ 4]                     lda       1-:sp,sp            ; SP/SP1 relative offset

    8 F603:9EE6 01         [ 4]                     lda       1,lsp               ; SP/SP1 relative offset

    9 F606:9EE6 01         [ 4]                     lda       1-:sp1,sp           ; absolute offset

   10 F609:9EE6 01         [ 4]                     lda       1,asp               ; absolute offset

   11 F60C:9EE6 00         [ 4]                     lda       ?,sp

   12                          

   13                                               #sp1                          ; zero-based offset mode

   14                          

   15 F60F:9EE6 02         [ 4]                     lda       1-:sp,sp            ; SP/SP1 relative offset

   16 F612:9EE6 02         [ 4]                     lda       1,lsp               ; SP/SP1 relative offset

   17 F615:9EE6 01         [ 4]                     lda       1-:sp1,sp           ; absolute offset

   18 F618:9EE6 01         [ 4]                     lda       1,asp               ; absolute offset

   19 F61B:9EE6 01         [ 4]                     lda       ?,sp

   20                          

   21                                               #sp       10                  ; one-based plus 10

   22                          

   23 F61E:9EE6 01         [ 4]                     lda       1-:sp,sp            ; SP/SP1 relative offset

   24 F621:9EE6 01         [ 4]                     lda       1,lsp               ; SP/SP1 relative offset

   25 F624:9EE6 01         [ 4]                     lda       1-:sp1,sp           ; absolute offset

   26 F627:9EE6 01         [ 4]                     lda       1,asp               ; absolute offset

   27 F62A:9EE6 0A         [ 4]                     lda       ?,sp

   28                          

   29                                               #sp1      :sp                 ; zero-based plus :SP (10)

   30                          

   31 F62D:9EE6 02         [ 4]                     lda       1-:sp,sp            ; SP/SP1 relative offset

   32 F630:9EE6 02         [ 4]                     lda       1,lsp               ; SP/SP1 relative offset

   33 F633:9EE6 01         [ 4]                     lda       1-:sp1,sp           ; absolute offset

   34 F636:9EE6 01         [ 4]                     lda       1,asp               ; absolute offset

   35 F639:9EE6 0B         [ 4]                     lda       ?,sp

 

Notes about :AIS:

 

:AIS returns the number of stack bytes still allocated since the most recent stack-increasing AIS instruction (normally useful only in #SP[AUTO] modes).  Example usage:

 

                    #spauto                       ;auto mode and zero offset

 

                    push                          ;protect all registers

 

                    ais       #-5                 ;(negative AIS marks the current :SP)

                    ...

                    ais       #2                  ;de-allocate some locals (no marking)

                    ...

                    ais       #:ais               ;deallocate however many bytes (3 in this case)

                                                  ;still left on stack since negative AIS

                    pull                          ;restore all registers

                    rts

 

                    #sp                           ;cancel auto mode and offsets