ASM8
A
two-pass absolute macro cross-assembler for the 68HC08/HCS08/9S08
ASM8 - Copyright © 2001-2010 by Tony Papadimitriou <tonyp@acm.org>
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. |
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.
§
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.
|
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:
#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