This chapter contains the following sections:
Overview
mppxa
Introduction
mppxa Invocation
Detailed Description of Macro Preprocessor Options
INCLUDE Files
Creating and Calling Macros
Creating Parameterless Macros
Creating Macros with Parameters
Local Symbols in Macros
The Macro Preprocessor's Built-In Functions
Comment, Escape and Bracket Functions
Comment Function
Escape Function
Bracket Function
METACHAR Function
Numbers and Expressions in mppxa
SET Function
EVAL Function
Logical Expressions and String Comparisons in mppxa
Control Flow Functions and Conditional Assembly
IF Function
WHILE Function
REPEAT Function
EXIT Function
String Manipulation Functions
LEN Function
SUBSTR Function
MATCH Function
Console I/O Functions
Advanced mppxa Concepts
Macro Delimiters
Implied Blank Delimiters
Identifier Delimiters
Literal Delimiters
Literal vs. Normal Mode
Algorithm for Evaluating Macro Calls
prxa
Preparing the Demo Files
Displaying Parts of an Object File
Option -h, display general file info
Option -s, display section info
Option -c, display call graph
Option -e, display external part
Option -g, display global type information
Option -d, display debug information
Option -i, display the section images
Option -il4, produce disassembly
View an Object at Lower Level
Object Layers
The Level Option -ln
The Verbose Option -vn
The following utilities are supplied with the Cross-Assembler for the XA processor family which can be useful at various stages during program development.
arxa An IEEE archiver. This is a librarian facility, which can be used to create and maintain object libraries.
ccxa A control program for the XA tool chain.
mkxa A utility program to maintain, update, and reconstruct groups of programs.
mppxa A macro preprocessor with a syntax compatible with Intel's macro processing language (MPL).
prxa An IEEE object reader that views the contents of files which have been created by a tool from the TASKING XA tool chain.
When you use a UNIX shell (Bourne shell,
C-shell), arguments containing special characters (such as '( )' and '?') must be enclosed
with "" or escaped. The -? option
(in the C-shell) becomes: "-?"
or -\?.
The utilities are explained on the following pages.
arxa IEEE archiver and library maintainer
arxa key_option [option]...
library [object_file]...
arxa -V
arxa -? ( UNIX C-shell : "
-?" or -\? )
With arxa you can combine separate object modules in a library file. The linker optionally includes modules from a library when a specific module resolves an external symbol definition in one of the modules that has been read before. The library maintainer arxa is a program to build library files and it offers the possibility to replace, extract or remove modules from an existing library.
key_option one of the main options indicating the action arxa has to take. Key options may appear in any order, at any place.
option optional sub-options as explained on the next pages.
library is the library file.
object_file is an object module to be added, extracted, replaced or removed from the library.
You may specify options with or without a leading '-'. Options may occur in random order. You may also combine options. So -xv is allowed. -V and -? however, must be the only option on the command line.
-d Delete the named object modules from the library.
-m Move the named object modules to the end of the library, or to another position as specified by one of the positioning options.
-p Print the named object modules in the library on standard output.
-r Replace the named object modules in the library if they exist. If they are not in the library, add them. If no names are given, only those object modules are replaced for which a file with the same name is found in the current directory. New modules are placed at the end.
-t Print a table of contents of the library. If no names are given, all object modules in the library are printed. If names are given, only those object modules are tabled.
-x Extract the named object modules from the library. If no names are given, all modules are extracted from the library. In neither case does x alter the library.
-? Display an explanation of options at stdout.
-V Display version information at stderr.
-a posname
Append or move new object modules after existing module posname. This option can only be used in combination
with the m or r option.
-b posname
Insert or move new object modules before existing module posname. This option can only be used in combination
with the m or r option.
-c Create the library file without notification if the library does not exist.
-f file Read options from file file. '-' means stdin.
-o Reset the last-modified date to the date recorded in the library. It can only be used in combination with the x option.
-s Print a list of symbols. This option must be combined with -t.
-s1 Print a list of symbols. Each symbol is preceded by the library name and the name of the object file. This option must be combined with -t.
-u Replace only those object modules with the last-modified date later than the library file. It can only be used in combination with the r option.
-v Verbose. Under the verbose option, arxa gives a module-by-module description of the making of a new library file from the old library and the constituent modules. It can only be used in combination with the d, m, r, or x option.
-wn Set warning level n.
1. Create library clib.a consisting of the modules startup.obj, and calc.obj :
arxa cr clib.a startup.obj calc.obj
2. Extract all modules form library clib.a :
arxa x clib.a
3. Print a list of symbols from library clib.a :
arxa ts clib.a
startup.obj symbols: _start _copytable calc.obj symbols: _entry
4. Print a list of symbols from library clib.a in a different form:
arxa ts1 clib.a
clib.a:startup.obj:_start clib.a:startup.obj:_copytable clib.a:calc.obj:_entry
5. Delete module calc.obj from library clib.lib :
arxa d clib.a calc.obj
ccxa control program for the XA tool chain
ccxa [ [option]... [control] ... [file]... ]...
ccxa -V
ccxa -? ( UNIX C-shell : "
-?" or -\? )
The control program ccxa facilitates the invocation of the various components of the XA family tool chain from a single command line. The control program accepts source files and options on the command line in random order.
Options are preceded by a '-' (minus sign). The input file can have one of the extensions explained below.
The control program recognizes the following argument types:
Normally, a control program tries to compile and assemble all source files to object files, followed by a link and locate phase which produces an absolute output file. There are however, options to suppress the assembler, linker or locator stage. The control program produces unique filenames for intermediate steps in the compilation process, which are removed afterwards. If the compiler and assembler are called subsequently, the control program prevents preprocessing of the compiler generated assembly file. Normally, assembly input files are preprocessed first.
-? Display a short explanation of options at stdout.
-Ccpu Use special function register definitions for cpu.
-M{t|s|c|m|l}
Specify the memory model to be used:
-V The copyright header containing the version number is displayed, after which the control program terminates.
-Wa
arg
-Wcarg
-Wcparg
-Wlkarg
-Wlcarg
-Wmarg
-Wplarg With these options you can pass a command line argument directly to the macro preprocessor (-Wm), assembler (-Wa), C compiler (-Wc), C++ compiler (-Wcp), C++ pre-linker (-Wpl), linker (-Wlk) or locator (-Wlc). These options may be used to pass some options that are not recognized by the control program, to the appropriate program. The argument may be either directly appended to the option, or follow the option as a separate argument of the control program.
-al Generate an absolute list file for each module in the application.
-c++ Specify that files with the extension .c are considered to be C++ files instead of C files. So, the C++ compiler is called prior to the C compiler. This option also forces the linker to link C++ libraries.
-c
-cc
-cl
-cs Normally, the control program invokes all stages to build an absolute file from the given input files. With these options it is possible to skip the C compiler, assembler, linker or locator stage. With the -cc option the control program stops after compilation of the C++ files and retains the resulting .c files. With the -cs option the control program stops after the compilation of the C source files (.c) and after preprocessing the assembly source files (.asm), and retains the resulting .src files. With the -c option the control program stops after the assembler, with as output one or more object files (.obj). With the -cl option the control program stops after the link stage, with as output a linker object file (.out).
-f file Read command line arguments from file. The filename "-" may be used to denote standard input. To get around the limits on the size of the command line, it is possible to use command files. These command files contain the options that could not be part of the real command line. Command files can also be generated on the fly, for example by the make utility.
1. It is possible to have multiple arguments on the same line in the command file.
2. To include whitespace in the argument, surround the argument with either single or double quotes.
3. If single or double quotes are to be used inside a quoted argument, we have to go by the following rules:
a. If the embedded quotes are only single or double quotes, use the opposite quote around the argument. Thus, if a argument should contain a double quote, surround the argument with single quotes.
b. If both types of quotes are used, we have to split the argument in such a way that each embedded quote is surrounded by the opposite type of quote.
Example:
"This has a single quote ' embedded"
or
'This has a double quote " embedded'
or
'This has a double quote " and \ a single quote '"' embedded"
4. Some operating systems impose limits on the length of lines within a text file. To circumvent this limitation it is possible to use continuation lines. These lines end with a backslash and newline. In a quoted argument, continuation lines will be appended without stripping any whitespace on the next line. For non-quoted arguments, all whitespace on the next line will be stripped.
Example:
"This is a continuation \ line" -> "This is a continuation line" control(file1(mode,type),\ file2(type)) -> control(file1(mode,type),file2(type))
5. It is possible to nest command line files up to 25 levels.
-fptrap Use floating point library with trap handling (libfptt.a, libfpst.a, libfpmt.a or libfplt.a). Without this option a floating point library is selected which uses no trapping.
-g[f|l|n]... Enable symbolic debug information (unless -gn used). With -gn you disable all debug, including type checking. With -gl you disable lifetime information for all types. If you use -gf, high level language type information is also emitted for types which are not referenced by variables. Therefore, this sub-option is not recommended.
-ieee
-ihex
-srec
-tiof With these options you can specify the locator output format of the absolute file. The output file can be an IEEE-695 file (.abs), Intel Hex file (.hex), Motorola S-record file (.sre) or TIOF-695 file (.abs). The default output is IEEE-695 (.abs).
-nolib With this option the control program does not supply the standard libraries to the linker. Normally the control program supplies the default C and run time libraries to the linker. Which libraries are needed is derived from the compiler options.
-o file Normally, this option is passed to the locator to specify the output file name. When you use the -cl option to suppress the locating phase, the -o option is passed to the linker. When you use the -c option to suppress the linking phase, the -o option is passed to the assembler, provided that only one source file is specified. When you use the -cs option to suppress the assembly phase, the -o option is passed to the compiler. The argument may be either directly appended to the option, or follow the option as a separate argument of the control program.
-tmp With this option the control program creates intermediate files in the current directory. They are not removed automatically. Normally, the control program generates temporary files for intermediate translation results, such as compiler generated assembly files, object files and the linker output file. If the next phase in the translation process completes successfully, these intermediate files will be removed.
-v When you use the -v option, the invocations of the individual programs are displayed on standard output, preceded by a '+' character.
-v0 This option has the same effect as the -v option, with the exception that only the invocations are displayed, but the programs are not started.
-wc++ Enable C and assembler warnings for C++ files. The assembler and C compiler may generate warnings on C output of the C++ compiler. By default these warnings are suppressed.
The control program uses the following environment variables:
TMPDIR This variable may be used to specify a directory, which the control program should use to create temporary files. When this environment variable is not set, temporary files are created in the directory "/tmp" on UNIX systems, and in the current directory on other operating systems.
CCXAOPT This environment variable may be used to pass extra options and/or arguments to each invocation of the control program ccxa. The control program processes the arguments from this variable before the command line arguments.
CCXABIN When this variable is set, the control program prepends the directory specified by this variable to the names of the tools invoked.
mkxa maintain, update, and reconstruct groups of programs
mkxa [option]... [target]...
[macro=value]...
mkxa -V
mkxa -? ( UNIX C-shell: "-?" or -\? )
mkxa takes a file of dependencies (a 'makefile') and decides what commands have to be executed to bring the files up-to-date. These commands are either executed directly from mkxa or written to the standard output without executing them.
If no target is specified on the command line, mkxa uses the first target defined in the first makefile.
Long filenames are supported when they are surrounded
by double quotes ("). It is also allowed to use spaces in directory names
and file names.
-? Show invocation syntax.
-D Display the text of the makefiles as read in.
-DD Display the text of the makefiles and 'mkxa.mk'.
-G dirname
Change to the directory specified with dirname before reading a makefile. This makes it possible to build an application in another directory than the current working directory.
-K Do not remove temporary files.
-S Undo the effect of the -k option. Stop processing when a non-zero exit status is returned by a command.
-V Display version information at stderr.
-W target Execute as if this target has a modification time of "right now". This is the "What If" option.
-d Display the reasons why mkxa chooses to rebuild a target. All dependencies which are newer are displayed.
-dd Display the dependency checks in more detail. Dependencies which are older are displayed as well as newer.
-e Let environment variables override macro definitions from makefiles. Normally, makefile macros override environment variables. Command line macro definitions always override both environment variables and makefile macros definitions.
-f file Use the specified file instead of 'makefile'. A - as the makefile argument denotes the standard input.
-i Ignore error codes returned by commands. This is equivalent to the special target .IGNORE:.
-k When a nonzero error status is returned by a command, abandon work on the current target, but continue with other branches that do not depend on this target.
-m file Read command line information from file. If file is a '-', the information is read from standard input.
-n Perform a dry run. Print commands, but do not execute them. Even lines beginning with an @ are printed. However, if a command line is an invocation of mkxa, that line is always executed.
-q Question mode. mkxa returns a zero or non-zero status code, depending on whether or not the target file is up to date.
-r Do not read in the default file 'mkxa.mk'.
-s Silent mode. Do not print command lines before executing them. This is equivalent to the special target .SILENT:.
-t Touch the target files, bringing them up to date, rather than performing the rules to reconstruct them.
-w Redirect warnings and errors to standard output. Without, mkxa and the commands it executes use standard error for this purpose.
macro=value
Macro definition. This definition remains fixed for the mkxa invocation. It overrides any regular definitions for the specified macro within the makefiles and from the environment. It is inherited by subordinate mkxa's
but act as an environment variable for these. That is, depending on the -e setting, it may be overridden by a makefile definition.
The first makefile read is 'mkxa.mk', which is looked for at the following places (in this order):
- in the current working directory
- in the directory pointed to by the HOME environment variable
- in the etc directory relative to the directory where mkxa is located
Example (PC):
Example (UNIX):
It typically contains predefined macros and implicit rules.
The default name of the makefile is 'makefile' in the current directory. If this file is not found on a UNIX system, the file 'Makefile' is then used as the default. Alternate makefiles can be specified using one or more -f options on the command line. Multiple -f options act as if all the makefiles were concatenated in a left-to-right order.
The makefile(s) may contain a mixture of comment lines, macro definitions, include lines, and target lines. Lines may be continued across input lines by escaping the NEWLINE with a backslash (\). If a line must end with a backslash then an empty macro should be appended. Anything after a "#" is considered to be a comment, and is stripped from the line, including spaces immediately before the "#". If the "#" is inside a quoted string, it is not treated as a comment. Completely blank lines are ignored.
An include line is used to include the text of another makefile. It consists of the word "include" left justified, followed by spaces, and followed by the name of the file that is to be included at this line. Macros in the name of the included file are expanded before the file is included. Include files may be nested.
An export line is used for exporting a macro definition to the environment of any command executed by mkxa. Such a line starts with the word "export", followed by one or more spaces and the name of the macro to be exported. Macros are exported at the moment an export line is read. This implies that references to forward macro definitions are equivalent to undefined macros.
Lines containing ifdef, ifndef, else or endif are used for conditional processing of the makefile. They are used in the following way:
ifdef macroname if-lines else else-lines endif
The if-lines and else-lines may contain any number of lines or text of any kind, even other ifdef, ifndef, else and endif lines, or no lines at all. The else line may be omitted, along with the else-lines following it.
First the macroname after the if command is checked for definition. If the macro is defined then the if-lines are interpreted and the else-lines are discarded (if present). Otherwise the if-lines are discarded; and if there is an else line, the else-lines are interpreted; but if there is no else line, then no lines are interpreted.
When using the ifndef line instead of ifdef, the macro is tested for not being defined. These conditional lines can be nested up to 6 levels deep.
Macros have the form `WORD = text and more text'. The WORD need not be uppercase, but this is an accepted standard. Spaces around the equal sign are not significant. Later lines which contain $(WORD) or ${WORD} will have this replaced by `text and more text'. If the macro name is a single character, the parentheses are optional. Note that the expansion is done recursively, so the body of a macro may contain other macro invocations. The right side of a macro definition is expanded when the macro is actually used, not at the point of definition.
Example:
FOOD = $(EAT) and $(DRINK) EAT = meat and/or vegetables DRINK = water export FOOD
`$(FOOD)' becomes `meat and/or vegetables and water' and the environment variable FOOD is set accordingly by the export line. However, when a macro definition contains a direct reference to the macro being defined then those instances are expanded at the point of definition. This is the only case when the right side of a macro definition is (partially) expanded. For example, the line
DRINK = $(DRINK) or beer
after the export line affects `$(FOOD)' just as the line
DRINK = water or beer
would do. However, the environment variable FOOD will only be updated when it is exported again.
You are advised not to use the double quotes (") for
long filename support in macros, otherwise this might result in a concatination of two macros with double quotes (") in between.
MAKE This normally has the value mkxa. Any line which invokes MAKE temporarily overrides the -n option, just for the duration of the one line. This allows nested invocations of MAKE to be tested with the -n option.
MAKEFLAGS
This macro has the set of options provided to mkxa
as its value. If this is set as an environment variable, the set of options is processed before any command line options. This macro may be explicitly passed to nested mkxa's, but
it is also available to these invocations as an environment variable. The -f and -d flags are
not recorded in this macro.
PRODDIR This macro expands the name of the directory where mkxa is installed without the last path component. The resulting directory name will be the root directory of the installed XA package, unless mkxa is installed somewhere else. This macro can be used to refer to files belonging to the product, for example a library source file.
Example:
DOPRINT = $(PRODDIR)/lib/src/_doprint.c
When mkxa is installed in the directory /cxa/bin this line expands to:
DOPRINT = /cxa/lib/src/_doprint.c
SHELLCMD
This contains the default list of commands which are local to the SHELL. If a rule is an invocation of one of these commands, a SHELL is automatically spawned to handle it.
TMP_CCPROG
This macro contains the name of the control program. If this macro and the TMP_CCOPT macro are set and the command line argument list for the control program exceeds 127 characters then mkxa will create a temporary file
filled with the command line arguments. mkxa will call the control program with the temporary file as command input file. This macro is only known by the PC version of mkxa.
TMP_CCOPT
This macro contains the option for the control program which tells the control program to read a file as command arguments. This macro is only known by the PC version of mkxa.
Example:
TMP_CCPROG = ccxa TMP_CCOPT = -f
$ This macro translates to a dollar sign. Thus you can use "$$" in the makefile to represent a single "$".
There are several dynamically maintained macros that are useful as abbreviations within rules. It is best not to define them explicitly.
$* The basename of the current target.
$< The name of the current dependency file.
$@ The name of the current target.
$? The names of dependents which are younger than the target.
$! The names of all dependents.
The $< and $* macros are normally used for implicit rules. They may be unreliable when used within explicit target command lines. All macros may be suffixed with F to specify the Filename components (e.g. ${*F}, ${@F}). Likewise, the macros $*, $< and $@ may be suffixed by D to specify the directory component.
The result of the $* macro is always without double quotes
("), regardless of the original target having double quotes (") around
it or not.
The result of using the suffix F (Filename component) or D (Directory component) is also always without double quotes ("), regardless of
the original contents having double quotes (") around it or not.
A function not only expands but also performs a certain operation. Functions syntactically look like macros but have embedded spaces in the macro name, e.g. '$(match arg1 arg2 arg3 )'. All functions are built-in and currently there are five of them: match, separate, protect, exist and nexist.
The match function yields all arguments which match a certain suffix:
$(match .obj prog.obj sub.obj mylib.a)
will yield
prog.obj sub.obj
The separate function concatenates its arguments using the first argument as the separator. If the first argument is enclosed in double quotes then '\n' is interpreted as a newline character, '\t' is interpreted as a tab, '\ooo' is interpreted as an octal value (where, ooo is one to three octal digits), and spaces are taken literally. For example:
$(separate "\n" prog.obj sub.obj)
will result in
prog.obj sub.obj
Function arguments may be macros or functions themselves. So,
$(separate "\n" $(match .obj $!))
will yield all object files the current target depends on, separated by a newline string.
The protect function adds one level of quoting. This function has one argument which can contain white space. If the argument contains any white space, single quotes, double quotes, or backslashes, it is enclosed in double quotes. In addition, any double quote or backslash is escaped with a backslash.
Example:
echo $(protect I'll show you the "protect" function)
will yield
echo "I'll show you the \"protect\" function"
The exist function expands to its second argument if the first argument is an existing file or directory.
Example:
$(exist test.c ccxa test.c)
When the file test.c exists it will yield:
ccxa test.c
When the file test.c does not exist nothing is expanded.
The nexist function is the opposite of the exist function. It expands to its second argument if the first argument is not an existing file or directory.
Example:
$(nexist test.src ccxa test.c)
A target entry in the makefile has the following format:
target ... : [dependency ...] [; rule] [rule] ...
Any line which does not have leading white space (other than macro definitions) is a 'target' line. Target lines consist of one or more filenames (or macros which expand into same) called targets, followed by a colon (:). The ':' is followed by a list of dependent files. The dependency list may be terminated with a semicolon (;) which may be followed by a rule or shell command.
Special allowance is made on MS-DOS for the colons which are needed to specify files on other drives, so for example, the following will work as intended:
c:foo.obj : a:foo.c
If a target is named in more than one target line, the dependencies are added to form the target's complete dependency list.
The dependents are the ones from which a target is constructed. They in turn may be targets of other dependents. In general, for a particular target file, each of its dependent files is 'made', to make sure that each is up to date with respect to it's dependents.
The modification time of the target is compared to the modification times of each dependent file. If the target is older, one or more of the dependents have changed, so the target must be constructed. Of course, this checking is done recursively, so that all dependents of dependents of dependents of ... are up-to-date.
To reconstruct a target, mkxa expands macros and functions, strips off initial white space, and either executes the rules directly, or passes each to a shell or COMMAND.COM for execution.
For target lines, macros and functions are expanded on input. All other lines have expansion delayed until absolutely required (i.e. macros and functions in rules are dynamic).
.DEFAULT:
The rule for this target is used to process a target when there is no other entry for it, and no implicit rule for building it. mkxa ignores all dependencies for this target.
.DONE: This target and its dependencies are processed after all other targets are built.
.IGNORE: Non-zero error codes returned from commands are ignored. Encountering this in a makefile is the same as specifying -i on the command line.
.INIT: This target and its dependencies are processed before any other targets are processed.
.SILENT: Commands are not echoed before executing them. Encountering this in a makefile is the same as specifying -s on the command line.
.SUFFIXES:
The suffixes list for selecting implicit rules. Specifying this target with dependents adds these to the end of the suffixes list. Specifying it with no dependents clears the list.
.PRECIOUS:
Dependency files mentioned for this target are not removed. Normally, mkxa removes a target file if a command
in its construction rule returned an error or when target construction is interrupted.
A line in a makefile that starts with a TAB or SPACE is a shell line or rule. This line is associated with the most recently preceding dependency line. A sequence of these may be associated with a single dependency line. When a target is out of date with respect to a dependent, the sequence of commands is executed. Shell lines may have any combination of the following characters to the left of the command:
@ will not echo the command line, except if -n is used.
- mkxa will ignore the exit code of the command, i.e. the ERRORLEVEL of MS-DOS. Without this, mkxa terminates when a non-zero exit code is returned.
+ mkxa will use a shell or COMMAND.COM to execute the command.
If the '+' is not attached to a shell line, but the command is a DOS command or if redirection is used (<, |, >), the shell line is passed to COMMAND.COM anyway. For UNIX, redirection, backquote (`) parentheses and variables force the use of a shell.
You can force mkxa to execute multiple command lines in one shell environment. This is accomplished with the token combination ';\'.
Example:
cd c:\cxa\bin ;\ cxa -V
The ';' must always directly be followed by the '\' token. Whitespace is not removed when it is at the end of the previous command line or when it is in front of the next command line. The use of the
';' as an operator for a command (like a semicolon ';' separated list with
each item on one line) and the '\' as a layout tool is not supported, unless
they are separated with whitespace.
mkxa can generate inline temporary files. If a line contains '<<WORD' then all subsequent lines up to a line starting with WORD, are placed in a temporary file. Next, '<<WORD' is replaced with the name of the temporary file.
No whitespace is allowed between '<<' and 'WORD'.
Example:
lkxa -o $@ -f <<EOF $(separate "\n" $(match .obj $!)) $(separate "\n" $(match .a $!)) $(LKFLAGS) EOF
The three lines between the tags (EOF) are written to a temporary file (e.g. "\tmp\mk2"), and the command line is rewritten as "lkxa -o $@ -f \tmp\mk2".
Implicit rules are intimately tied to the .SUFFIXES: special target. Each entry in the .SUFFIXES: list defines an extension to a filename which may be used to build another file. The implicit rules then define how to actually build one file from another. These files are related, in that they must share a common basename, but have different extensions.
If a file that is being made does not have an explicit target line, an implicit rule is looked for. Each entry in the .SUFFIXES: list is combined with the extension of the target, to get the name of an implicit target. If this target exists, it gives the rules used to transform a file with the dependent extension to the target file. Any dependents of the implicit target are ignored.
If a file that is being made has an explicit target, but no rules, a similar search is made for implicit rules. Each entry in the .SUFFIXES: list is combined with the extension of the target, to get the name of an implicit target. If such a target exists, then the list of dependents is searched for a file with the correct extension, and the implicit rules are invoked to create the target.
This makefile says that prog.out depends on two files prog.obj and sub.obj, and that they in turn depend on their corresponding source files (prog.c and sub.c) along with the common file inc.h.
LIB = -ls prog.out: prog.obj sub.obj lkxa prog.obj sub.obj $(LIB) -o prog.out prog.obj: prog.c inc.h cxa prog.c asxa prog.src sub.obj: sub.c inc.h cxa sub.c asxa sub.src
The following makefile uses implicit rules (from mkxa.mk) to perform the same job.
LDFLAGS = -ls prog.out prog.obj sub.obj prog.obj: prog.c inc.h sub.obj: sub.c inc.h
makefile Description of dependencies and rules.
Makefile Alternative to makefile, for UNIX.
mkxa.mk Default dependencies and rules.
mkxa returns an exit status of 1 when it halts as a result of an error. Otherwise it returns an exit status of 0.
It is recommended that you use the internal preprocessor of the assembler asxa. Preprocessor mppxa is supplied for those who need a Intel MPL compatible preprocessor syntax.
The macro preprocessor, mppxa, is a string manipulation tool which allows you to write repeatedly used sections of code once and then insert that code at several places in your program. mppxa also handles conditional assembly, assembly-time loops, console I/O and recursion.
The macro preprocessor is implemented as a separate program which saves both time and space in an assembler, particularly for those programs that do not use macros and thus need not run the macro preprocessor. mppxa is compatible with Intel's syntax and semantics for the 8051 macro processing language (MPL). A user of macros must submit his source input to the macro preprocessor. The macro preprocessor produces one output file which can then be used as an input file to the XA Cross-assembler.
The macro preprocessor regards its input file as a stream of characters, not as a sequence of statements like the assembler does. The macro preprocessor scans the input (source) file looking for macro calls. A macro-call is a request to the macro preprocessor to replace the call pattern of a built-in or user-defined macro with its return value.
As soon as a macro call is encountered, the macro preprocessor expands the call to its return value. The return value of a macro is the text that replaces the macro call. This value is then placed in a temporary file, and the macro preprocessor continues. The return value of some macros is the null string, i.e., a character string containing no characters. So, when these macros are called, the call is replaced by the null string on the output file, and the assembler will never see any evidence of its presence. This is of course particularly useful for conditional assembly.
This chapter documents mppxa in several parts. First the invocation of mppxa is described. The following sections describe how to define and use your own macros, describe the syntax of the macro processing language and describe the macro preprocessor's built-in functions. This chapter also contains a section that is devoted to the advanced concepts of mppxa.
The first five sections give enough information to begin using the macro preprocessor. However, sometimes a more exact understanding of mppxa's operation is needed. The advanced concepts section should fill those needs.
At macro time, symbols, labels, predefined assembler
symbols, EQU, and SET symbols, and the location counter are not known. The macro preprocessor does not recognize the assembly language. Similarly, at assembly time, no information about macro symbols is known.
The command line invocation line of mppxa is:
The input-file is an assembly source-file containing user-defined macros. You must give a complete filename (no default file extension is taken).
The output file is an assembly source file in which all user-defined macros are replaced. This file is the input file for asxa. It has the default file extension of .src.
Invocation with -V only displays a version header.
Option | Description | ||||||
-? | Display invocation syntax | ||||||
-Dmacro=def |
Define preprocessor macro
-Idirectory |
Look in directory for include files |
-V |
Display version header only |
-o filename |
Specify name of output file | |
Table 11-1: mppxa options
-?
Display an explanation of options at stdout.
mppxa -?
-Dmacro=def
The macro you want to define and optionally its definition.
Define macro as in 'define' Any number of symbols can be defined.
mppxa -DPI=3.1416 test.asm
-Idirectory
The name of the directory to search for include file(s).
Change the algorithm for searching $INCLUDE files whose names do not have an absolute pathname to look in directory. Thus, $INCLUDE files are searched for first in the directory of the file containing the $INCLUDE line, then in directories named in -I options in left-to-right order.
mppxa -I/proj/include test.asm
-o filename
An output filename.
Basename of assembly source file with .src suffix.
Use filename as output filename of the macro preprocessor instead of the basename of the assembly source file with the .src extension.
To create the assembly file myfile.src instead of test.src, enter:
mppxa test.asm -o myfile.src
-V
With this option you can display the version header of the macro preprocessor. This option must be the only argument of mppxa. Other options are ignored. mppxa exits after displaying the version header.
mppxa -V
XA macro preprocessor va.b rc SN00000000-015 (c) year TASKING, Inc.
If the macro preprocessor encounters a $INCLUDE statement in the input file, preprocessing will continue by scanning the specified file until an end-of-file or another INCLUDE is encountered.
$INCLUDE(file)
$IC(file)
$<spaces><eol># 1 "file"
The '$' must be in column 1 for the macro preprocessor to recognize it for processing at macro time. In the output file the INCLUDE(file) part of the INCLUDE call is replaced by spaces (because the assembler also recognizes the '$' character but does not recognize INCLUDE as a control). Also a line containing # 1 "file" is put in the output file.
As soon as the macro preprocessor encounters an end-of-file in the include file, input is resumed where it left off, namely at the next line after the latest INCLUDE call (which due to nesting does not necessarily mean returning to the original input file). Nesting of include files is allowed up to 32 files.
If the macro preprocessor after recognizing the '$' character does not find an INCLUDE before it encounters an end-of-line, due to misspelling or simple because the '$' is followed by a control only recognized by the assembler, no macro-time error is reported and scanned characters are simply passed to the output file.
Each control line (i.e. a line starting with '$') may not contain more than one INCLUDE call.
; source lines . $include( mysrc.inc ) ; include the contents of ; file mysrc.inc . ; other source lines .
Macro calls differ between user-defined macros and so-called built-in functions. All characters in bold typeface in the syntax descriptions of the following sections are constituents of the macro syntax. Italic tokens represent place holders for user-specific declarations.
The macro preprocessor scans through the input source, one character at a time, looking for a special character called the METACHARACTER, the percent sign '%' initially. This metacharacter must precede a macro-call. Until the macro preprocessor finds a metacharacter, it does not process text. It simply passes the text from the input file to the output file.
Since mppxa only processes macro calls, it is necessary to call a macro in order to create other macros, the so-called "user-defined macros". The built-in function DEFINE creates macros. Built-in functions are a predefined part of the macro language, so they may be called without prior definition. The general syntax for DEFINE is shown below.
DEFINE is the most important mppxa built-in function. This section is devoted to describing this built-in function. Each of the symbols in the syntax above (macro-name, parameter-list, local-list and macro-body) are described in detail on the pages that follow. In some cases, we have abbreviated this general syntax to emphasize certain concepts.
When you create a parameterless macro, there are two parts to a DEFINE call: the macro-name and the macro-body. The macro-name defines the name used when the macro is called; the macro-body defines the return value of the call.
The '%' character signals a macro call. The '*' is the optional literal character. When you define a macro using the literal character '*', as shown above, macro calls contained in the body of the macro are not expanded until the macro is called. The exact use of the literal character is discussed in the advanced concept section. When you define a parameterless macro, the macro-name is a macro identifier that follows the '%' character in the source line. The rules for macro identifier are:
- The identifier must begin with an upper or lowercase alphabetic character (A,B,...,Z or a,b,...,z), or a special character ( a question mark '?' or an underscore character '_').
- The remaining characters may be alphabetic, special or decimal digits (0,1,2,...,9).
- Only the first 31 characters of a macro identifier are recognized as the unique identifier name. Upper and lower case characters are not distinguished in a macro identifier.
The macro-body is usually the return value of the macro call. However, the macro-body may contain calls to other macros. If so, the return value is actually the fully expanded macro-body, including the return values of the call to other macros. The macro call is re-expanded each time it is called.
%*DEFINE (String_1) (An) %*DEFINE (String_2) (ele) %*DEFINE (String_3) (phant) %*DEFINE (String_4) (shopping) %DEFINE (String_5) (goes %String_4) %DEFINE (Part_1) (%String_1 %String_2%String_3)
The macro-body must consist of a balanced-text string, i.e. you must have balanced parentheses within the macro-body. In other words, each left parenthesis must have a succeeding right parenthesis, and each right parenthesis must have a preceding left parenthesis.
The possible placement of the macro-body and the parenthesis are both represented in the above examples. The beginning of the macro-body is determined by the syntactical end of the left parenthesis, where tabs (08H), blanks and the first new line (0AH) are also part of the macro-body.
The macro-body of String_1 starts with the 'A' of "An"
The macro-body of String_3 starts with the 'p' of "phant"
The macro-body of String_4 starts with the '(08H)'
of "(08H)shopping".
The end of macro-body is determined by the right parenthesis.
The macro-body of String_4 is "(08H)shopping"
The macro-body of String_5 is "goes (0AH)
(08H)shopping"
The expanded value of DEFINE is the null string, but the macro body is stored internally for later use. User-defined macros may invoke themselves within their bodies. This property is called 'recursion'. Any macro which calls itself must terminate eventually or the macro preprocessor may enter an infinite loop.
Once a macro has been created, it may be redefined by a second call to DEFINE.
To call a macro, you use the '%' character followed by the name of the macro (the literal character '*' is only admissible for defined macros whose call is passed to a macro as a an actual parameter; example: %M1(%*M2)). The macro preprocessor removes the call and inserts the return value of the call. If the macro-body contains any call to other macros, they are replaced with their return values.
%Part_1 %String_5 --> An elephant goes shopping
Once a macro has been created, it may be redefined by a second call to DEFINE. Note, however that a macro should not redefine itself within its body (see Advanced mppxa Concepts).
The examples below show several macro definitions. Their return values are also shown.
Macro definition at the top of the program:
%*DEFINE (MOVE) ( MOV R3H, [R1] MOV [R2], R3H )
The macro call as it appears in the program:
MOV R1, #1 ----%MOVE
The program as it appears after the macro preprocessor made the following expansion, where the first expanded line is preceded by the four blanks preceding the call (the sign - indicates the preceding blanks):
MOV R1, #1 ---- MOV R3H, [R1] MOV [R2], R3H
Macro definition at the top of the program:
%*DEFINE (ADD5) ( MOV R0, #5 MOV R5, [R2] ADD R5, R0 )
The macro call as it appears in the original program body:
MOV R5, #2 %ADD5
The program after the macro expansion:
MOV R5, #2 MOV R0, #5 MOV R5, [R2] ADD R5, R0
Macro definition at the top of the program:
%*DEFINE (MOVE_AND_ADD) ( %MOVE %ADD5 )
The macro call as it appears in the body of the program:
MOV R1, #1 %MOVE_AND_ADD
The program after the macro expansion:
MOV R1, #1 MOV R3H, [R1] MOV [R2], R3H MOV R0, #5 MOV R5, [R2] ADD R5, R0
If the only function of the macro preprocessor was to perform simple string replacement, then it would not be very useful for most of the programming tasks. Each time we wanted to change even the simplest part of the macro's return value we would have to redefine the macro.
Parameters in macro calls allow more general-purpose macros. Parameters leave holes in a macro-body that are filled in when you call the macro. This permits you to design a single macro that produces code for typical programming operations. The term 'parameters' refers to both the formal parameters that are specified when the macro is defined (the holes, and the actual parameters or arguments that are specified when the macro is called (the fill-ins).
The syntax for defining macros with parameters is very similar to the syntax for macros without parameters.
The macro-name must be a valid identifier.
The parameter-list is a list of macro identifiers separated by macro delimiters. These identifiers comprise the formal parameters used in the macro. The macro identifier for each parameter in the list must be unique, but they may be the same as other formal argument names to other macros since they have no existence outside the macro definition. They may also be the same as the names of other user macros or of macro functions. Note, however that in this case the macro or function cannot be used within the macro-body, since its name would be recognized as a parameter instead. To reference a formal argument within the macro-body, use its name preceded by the metacharacter.
Typically, the macro delimiters are parentheses and commas. When using these delimiters, you would enclose the parameter-list in parentheses and separate each formal parameter with a comma. When you define a macro using parentheses and commas as delimiters, you must use those same delimiters, when you call that macro.
The example below shows the definition of a macro with three parameters: SOURCE, DEST and COUNT. The macro produces code to copy any number of words from one part of memory to another.
%*DEFINE (MOVE_ADD_GEN(SOURCE,DEST,COUNT)) ( MOV R1, #%SOURCE MOV R0, #%DEST MOV R6, #%COUNT MOV R3H, [R1] MOV [R0], R3H ADDS R1, #1 ADDS R0, #1 DJNZ R6, ($-4) )
To call a macro with parameters, you must use the metacharacter followed by the macro's name as with parameterless macros. However, a list of the actual parameters must follow. These actual parameters have to be enclosed within parentheses and separated from each other by commas. The actual parameters may optionally contain calls to other macros.
A simple call to a macro defined above might be:
%MOVE_ADD_GEN( 10, 24, 8 )
The above macro call produces the following code:
MOV R1, #10 MOV R0, #24 MOV R6, #8 MOV R3H, [R1] MOV [R0], R3H ADDS R1, #1 ADDS R0, #1 DJNZ R6, ($-4)
If we used a fixed label instead of the offset ($-4) in the previous example, the macro using the fixed label can only be called once, since a second call to the macro causes a conflict in the label definitions at assembly time. The label can be made a parameter and a different symbol name can be specified each time the macro is called.
A preferable way to ensure a unique label for each macro call is to put the label in a local-list. The local-list construct allows you to use macro identifiers to specify assembly-time symbols. Each use of a LOCAL symbol in a macro guarantees that the symbol will be replaced by a unique assembly-time symbol each time the symbol is called.
The macro preprocessor increments a counter once for each symbol used in the list every time your program calls a macro that uses the LOCAL construct. Symbols in the local-list, when used in the macro-body, receive a two to five digit suffix that is the hexadecimal value of the counter. The first time you call a macro that uses the LOCAL construct, the suffix is '00'.
The syntax for the LOCAL construct in the DEFINE function is shown below. (This is the complete syntax for the built-in function DEFINE):
The local-list is a list of valid macro identifiers separated by spaces. Since these macro identifiers are not parameters, the LOCAL construct in a macro has no effect on a macro call.
To reference local symbols in the macro-body, they must be preceded by the metacharacter. The symbol LOCAL is not reserved; a user symbol or macro may have this name.
The next example shows a macro definition that uses a LOCAL list.
%*DEFINE (MOVE_ADD_GEN(SOURCE,DEST,COUNT)) LOCAL LAB ( MOV R1, #%SOURCE MOV R0, #%DEST MOV R6, #%COUNT %LAB: MOV R3H, [R1] MOV [R0], R3H ADDS R1, #1 ADDS R0, #1 DJNZ R6, %LAB )
A simple call to a macro defined above might be:
%MOVE_ADD_GEN( 50, 100, 24 )
The above macro call might produce the following code (if this is he eleventh call to a macro using a LOCAL list):
MOV R1, #50 MOV R0, #100 MOV R6, #24 LAB0A: MOV R3H, [R1] MOV [R0], R3H ADDS R1, #1 ADDS R0, #1 DJNZ R6, LAB0A
Since macro identifiers follow the same rules as asxa, any macro identifier can be used in a local-list. However, if
long identifier names are used, they should be restricted to 29 characters. Otherwise, the label
suffix may cause the identifier to exceed 31 characters and these would be truncated.
The assembler supports numeric labels. The numbers 1 through 255 can be used as labels. They must be followed by a colon, when defined. To reference such a numeric label, you must put an n (next) or p (previous) immediately after the label. This is required because the same label number may be used repeatedly. Thus it is possible to use numeric labels in macros. The following example shows the use of a previous referenced numeric label (label followed by the character 'p') as a substitute for the LOCAL list example.
%*DEFINE (MOVE_ADD_GEN(SOURCE,DEST,COUNT)) ( MOV R1, #%SOURCE MOV R0, #%DEST MOV R6, #%COUNT 1: MOV R3H, [R1] MOV [R0], R3H ADDS R1, #1 ADDS R0, #1 DJNZ R6, 1p )
After the following calls,
%MOVE_ADD_GEN( 50, 100, 24 ) %MOVE_ADD_GEN( 60, 200, 48 )
the preprocessor produces the following code:
MOV R1, #50 MOV R0, #100 MOV R6, #24 1: MOV R3H, [R1] MOV [R0], R3H ADDS R1, #1 ADDS R0, #1 DJNZ R6, 1p MOV R1, #60 MOV R0, #200 MOV R6, #48 1: MOV R3H, [R1] MOV [R0], R3H ADDS R1, #1 ADDS R0, #1 DJNZ R6, 1p
The assembler accepts the duplicate numerical labels and translates them to the corresponding address offsets in a segment.
The macro preprocessor has several built-in or predefined macro functions. These built-in functions perform many useful operations that are difficult or impossible to produce in a user-defined macro.
We have already discussed one of these built-in functions, DEFINE. DEFINE creates user-defined macros. DEFINE does this by adding an entry in the macro preprocessor's tables of macro definitions. Each entry in the tables includes the macro-name of the macro, its parameter-list, its local-list and its macro-body. Entries for the built-in functions are present when the macro preprocessor begins operation.
Other built-in functions perform numerical and logical expression evaluation, affect control flow of the macro preprocessor, manipulate character strings, and perform console I/O.
The following sections deal with the following:
Comment, escape , bracket ('...', '..., n..., (...) )METACHAR
Metachar function ( METACHAR)
Expressions processed by mppxa
Calculating functions ( SET , EVAL )
Controlling functions ( IF , WHILE , REPEAT , EXIT )
String-processing functions ( LEN , SUBSTR , MATCH )
String-comparing functions (EQS, NES, LTS, LES, GTS, GES)
Input/Output functions ( IN, OUT)
The macro processing language can be very subtle, and the operation of macros written in a straightforward manner may not be immediately obvious. Therefore, it is often necessary to comment macro definitions.
or
The comment function always evaluates to the null string. Two terminating characters are recognized: the apostrophe ' and the end-of-line (line-feed character, ASCII 0AH). The second form of the call allows macro definitions to be spread over several lines, while avoiding any unwanted end-of-lines in the return value. In either form of the comment function, the text or comment is not evaluated for macro calls.
%*DEFINE (MOVE_ADD_GEN(SOURCE,DEST,COUNT)) LOCAL LAB ( MOV R1, #%SOURCE %'This is the source address' MOV R0, #%DEST %'This is the destination' MOV R6, #%COUNT %'%COUNT must be a constant' %LAB: %'This is a local label. %'End of line is inside the comment! MOV R3H, [R1] MOV [R0], R3H ADDS R1, #1 ADDS R0, #1 DJNZ R6, %LAB )
Call the above macro:
%MOVE_ADD_GEN( 50, 100, 24 )
Return value from above call:
MOV R1, #50 MOV R0, #100 MOV R6, #24 LAB0A: MOV R3H, [R1] MOV [R0], R3H ADDS R1, #1 ADDS R0, #1 DJNZ R6, LAB0A
Note that the comments that were terminated with the end-of-line removed the end-of-line character along with the rest of the comment.
The metacharacter is not recognized as flagging a call to the macro preprocessor when it appears in the comment function.
Sometimes it is necessary to prevent the macro preprocessor from processing text. The escape function and the bracket function perform such tasks.
The escape function prevents the macro preprocessor from processing a text string of n characters long, where n is a decimal digit from 0 to 9. The escape function is useful for inserting a metacharacter as text, adding a comma as part of an argument, or placing a single parenthesis in a character string that requires balanced parentheses.
Before Macro Expansion After Macro Expansion ;Average of 20%1% ->;Average of 20% %DTCALL(JAN 21%1, 1992, -> JAN 21, 1992 JUN 12%1, 1992) -> JUN 12, 1992 %MYCALL(1%1) Option 1, -> 1) Option 1 2%1) Option 2, -> 2) Option 2 3%1) Option 2) -> 3) Option 3
The first example add a literal '%' in the text. The second example keeps the date as one actual parameter adding a literal ','. The third example adds a literal right parenthesis ')' to each parameter.
The bracket function is the other built-in function that inhibits the macro preprocessor from expanding text.
The bracket function inhibits all macro preprocessor expansion of the text contained within the parentheses. However, the escape function, the comment function, and the parameter substitution are still recognized. Since there is no restriction for the length of the text within the bracket function, it is usually easier to use than the escape function.
The literal character '*' is not accepted in connection with the three functions described in this subsection.
%*DEFINE (DW(LIST,NAME)) ( %NAME DW %LIST)
The macro DW expands DW statements, where the variable NAME represents the first parameter and the expression LIST represents the second parameter.
The following expansion should be obtained by the call:
PHONE DW 198H, 3DH, 0F0H
If the call in the following form:
%DW(198H, 3DH, 0F0H, PHONE)
occurs, the macro preprocessor would interpret the first argument (198H) as NAME and everything after the first comma as the second parameter, since the first comma would be interpreted as the delimiter separating the macro parameters.
In order to change this method of interpretation, all tokens that are to be combined for an individual parameter must be identified as a parameter string and set in a bracket function:
%DW(%(198H, 3DH, 0F0H), PHONE)
This way the bracket function prevents the string '198H, 3DH, 0F0H' from being evaluated as separate parameters.
The METACHAR function can be used to redefine the metacharacter (initially: '%')
Although the balanced-text string may be any number of characters long, only the first character in the string is taken to be the new metacharacter. Macro calls in the balanced-text string are still recognized and corresponding actions that will not lead to any direct expansion on the output file will be performed. So, for example a SET macro call inside the balanced-text string will be performed.
Characters that may not be used as a metacharacter are:
a blank, letter, digit, left or right parenthesis, or asterisk.
The following example is catastrophic !!!
%METACHAR( & )
This examples defines the space character as the new metacharacter, since it is the first character in the balanced-text strings!
Many built-in functions recognize and evaluate numerical expressions in their arguments. mppxa uses the same rules for representing numbers as asxa (see chapter Operands and Expressions for detailed information):
- Numbers may be represented in the formats binary (B suffix), octal (O or Q suffix), decimal (D or no suffix), and hexadecimal (H suffix).
- Internal representation of numbers is 16-bits (00H to 0FFFFH); the processor does not recognize or output real or long integer numbers.
- The following operators are recognized by the macro preprocessor (in descending precedence):
The symbolic forms of the relational operators (i.e.,
<, >, =, <>, >=, <=) are not recognized by the macro preprocessor.
The macro preprocessor cannot access the assembler's symbol table. The values of labels, location counter, EQU and SET symbols are not known during macro time expression evaluation. Any attempt to use assembly time symbols in a macro time expression generates an error. Macro time symbols can be defined, however, with the predefined macro, SET.
SET assigns the value of the numeric expression to the identifier, macro-variable, and stores the macro-variable in the macro time symbol table, macro-variable must follow the same syntax convention used for other macro identifiers. Expansion of a macro-variable always results in hexadecimal format.
The SET macro call affects the macro time symbol table only; when SET is encountered, the macro preprocessor replaces it with the null string. Symbols defined by SET can be redefined by a second SET call, or defined as a macro by a DEFINE call The SET function is thanks to the necessary compatibility with Intel the only predefined macro function which may be redefined. Such a redefinition of the SET function must however be strongly dissuaded, because as a consequence, the original functionality will be lost for the rest of the program, i.e., macro-time symbols can no longer be defined.
%SET(COUNT,0) -> null string %SET(OFFSET,16) -> null string MOV R1, #%COUNT + %OFFSET -> MOV R1,#0H + 10H MOV R2, #%COUNT -> MOV R2,#0H
SET can also be used to redefine symbols in the macro time table:
%SET(COUNT,%COUNT + %OFFSET) -> null string %SET(OFFSET,%OFFSET * 2) -> null string MOV R1, #%COUNT + %OFFSET -> MOV R1,#10H + 20H MOV R2, #%COUNT -> MOV R2,#10H
The built-in function EVAL accepts an expression as its argument and returns the expression's value in hexadecimal.
The expression argument must be a legal macro-time expression. The return value from EVAL is built according to asxa's rules for representing hexadecimal numbers. The trailing character is always the hexadecimal suffix (H). The expanded value is at most 16 bits and negative numbers are shown in two's complement form. If the leading digit of the return-value is 'A', 'B', 'C', 'D', 'E' or 'F', it is preceded by a 0.
COUNT SET %EVAL(33H + 15H + 0f00H) -> COUNT SET 0f48H MOV R1, #%EVAL(10H - ((13+6) *2 ) +7) -> MOV R1, #0fff1H %SET( NUM1, 44) -> null string %SET( NUM2, 25) -> null string MOV R1, #%EVAL( %NUM1 LE %NUM2 ) -> MOV R1, #00H
Several built-in functions return a logical value when they are called. Like relational operators that compare numbers and return TRUE or FALSE ('0fffH' or '00H') respectively, these built-in functions compare character strings. If the function evaluates to 'TRUE', then it returns the character string '0ffffH'. If the function evaluates to 'FALSE', then it returns '00H'.
The built-in functions that return a logical value compare two balanced-text arguments and return a logical value based on that comparison. The list of string comparison functions below shows the syntax and describes the type of comparison made for each. Both arguments may contain macro calls.
%EQS(arg1,arg2 ) TRUE if both arguments are identical; equal
%NES(arg1,arg2 ) TRUE if arguments are different in any way; not equal
%LTS(arg1 ,arg2) TRUE if first argument has a lower value than second argument; less than
%LES(arg1,arg2 ) TRUE if first argument has a lower value than second argument or if both arguments are identical; less than or equal
%GTS(arg1,arg2 ) TRUE if first argument has a higher value than second argument; greater than
%GES(arg1,arg2 ) TRUE if first argument has a higher value than second argument, or if both arguments are identical; greater than or equal
Before these functions perform a comparison, both strings are completely expanded. Then the ASCII value of the first character in the first string is compared to the ASCII value of the first character in the second string. If they differ, then the string with the higher ASCII value is to be considered to be greater. If the first characters are the same, the process continues with the second character in each string, and so on. Only two string s of equal length that contain the same characters in the same order are equal.
Before Macro Expansion After Macro Expansion
%EQS(ABC,ABC) 0ffffH (TRUE).
The character strings are identical.
%EQS(ABC, ABC) 00H (FALSE).
The space after the comma is part of
the second argument
%LTS(CBA,cba) 0ffffH (TRUE).
The lower case characters have a
higher ASCII value than upper case.
%GES(ABC,ABC) 00H (FALSE).
The space at the end of the second
string makes the second string greater
than the first one.
%GTS(16,111H) 0ffffH (TRUE).
ASCII '6' is greater than ASCII '1'.
The strings to the string comparison macros have to follow the rules of the balanced-text described earlier.
%MATCH(NEXT,LIST)(CAT,DOG_MOUSE) %EQS(%NEXT,CAT) -> 0ffffH (TRUE) %EQS(DOG,%SUBSTR(%LIST,1,3)) -> 0ffffH (TRUE)
Some built-in functions expect logical expressions in their arguments. Logical expressions follow the same rules as numeric expressions. The difference is in how the macro interprets the 16-bit value that the expression represents. Once the expression has been evaluated to a 16-bit value, mppxa uses only the low-order bit to determine whether the expression is TRUE or FALSE. If the low-order bit is one, the expression is TRUE. If the low-order bit is zero the expression is FALSE.
Typically, the relational operators (EQ, NE, LE, LT, GE, or GT) or the string comparison functions (EQS, NES, LES LTS, GES, or GTS) are used to specify a logical value. Since these operators and functions always evaluate to 0FFFFH or 00H, internal determination is not necessary.
The IF built-in function evaluates a logical expression, and based on that expression, expands or withholds its text arguments.
The IF function allows a user to decide at macro time whether to assemble certain code or not (conditional assembly). So, the assembler never has to see any code which is not to be assembled.
The IF function first evaluates the expression. If it is TRUE, then the succeeding balanced-text1 is expanded; if it is FALSE and the optional ELSE clause is included in the call, then the balanced-text2 is expanded. If the expression results to FALSE and the ELSE clause is not included, the IF call returns the null string. The macro call must be terminated by FI.
IF calls can be nested. The ELSE clause refers to the most recent IF call that is still open (not terminated by FI). FI terminates the most recent IF call that is still open. The level of macro nesting is limited to 300.
This is a simple example of the IF call with no ELSE clause:
%SET( VALUE, 0F0H ) %IF( %VALUE GE 0FFH ) THEN (MOV R1, #%VALUE) FI
This is a simple form of the IF call with an ELSE clause:
%IF( %EQS(ADD,%OPERATION)) THEN (ADD R6, #03H) ELSE (SUB R6, #03H) FI
This is an example of three nested IF calls:
%IF( %EQS(%OPER,ADD)) THEN ( ADD R1, #03H )ELSE (%IF( %EQS(%OPER,SUB)) THEN ( SUB R1, #03H )ELSE (%IF( %EQS(%OPER,MUL)) THEN ( MOV R1, #03 JMP MUL_LAB )ELSE ( MOV R1, #DATUM JMP DIV_LAB )FI )FI )FI
Demonstrating conditional assembly:
%SET(DEBUG,1) %IF(%DEBUG) THEN ( MOV R1, #%DEBUG JMP DEBUG )FI MOV R1, R2 . . .
This expands to:
MOV R1, #%DEBUG JMP DEBUG MOV R1, R2
%SET can be changed to:
%SET(DEBUG,0)
to turn off the debug code.
The IF macro is useful for implementing one kind of conditional assembly including or excluding lines of code in the source file. However, in many cases this is not enough. Often you may wish to perform macro operations until a certain condition is met. The built-in function WHILE provides this facility.
The WHILE function evaluates the expression. If it results to TRUE, the balanced-text is expanded WHILE expands to the null string. Once the balanced-text has been expanded, the logical argument is retested and if it is still TRUE, the balanced-text is expanded again. This continues until the logical argument proves FALSE.
Since the macro continues processing until the expression is FALSE, the balanced-text should modify the expression, or else WHILE may never terminate.
A call to built-in function EXIT always terminates a WHILE macro. EXIT is described below.
The following example shows the common use of the WHILE macro:
%SET(COUNTER,7) %WHILE( %COUNTER GT 0 ) ( MOV R2, #%COUNTER MOV [R1], R2 ADD R1, #2 %SET(COUNTER, %COUNTER - 1) )
This example uses the SET macro and a macro-time symbol to count the iterations of the WHILE macro.
mppxa offers another built-in function that performs the counting loop automatically. The built-in function REPEAT expands its balanced-text a specified number of times.
Unlike the IF and WHILE macros, REPEAT uses the expression for a numerical value that specifies the number of times the balanced-text should be expanded. The expression is evaluated once when the macro is first called, then the specified number of iterations is performed.
A call to built-in function EXIT always terminates a REPEAT macro. EXIT is described in the next section.
Lab: MOV R3H, #8 MOV R2, #0FFFFH %REPEAT( 8 ) ( MOV [R2], R3H ADD [R1], R3H )
The built-in function EXIT terminates expansion of the most recently called user defined macro. It is most commonly used to avoid infinite loops (e.g. a recursive user defined macro that never terminates). It allows several exit points in the same macro.
This use of EXIT terminates a recursive macro when an odd number of bytes have been added.
%*DEFINE (MEM_ADD_MEM(SOURCE,DEST,BYTES)) ( %IF( %BYTES LE 0 )THEN ( %EXIT ) FI ADD R3H, %SOURCE ADDC R3H, %DEST MOV %DEST, R3H %IF( %BYTES EQ 1 ) THEN ( %EXIT ) FI MOV R3H, %SOURCE+1 ADDC R3H, %DEST+1 MOV %DEST+1, R3H IF (%BYTES GT 2) THEN ( %MEM_ADD_MEM(%SOURCE+2,%DEST+2,%BYTES-2)) FI )
The above example adds two pairs of bytes and stores results in DEST. As long as there is a pair of bytes to be added, the macro MEM_ADD_MEM is expanded. When BYTES reaches a value of 1 or 0, the macro is exited.
This EXIT is a simple jump out of a recursive loop:
%*DEFINE (BODY) ( MOV R3H,%MVAR %SET(MVAR, %MVAR + 1 ) ) %*DEFINE (UNTIL(CONDITION,EXE_BODY)) ( %EXE_BODY %IF( %CONDITION ) THEN ( %EXIT ) ELSE ( %UNTIL( %CONDITION, %EXE_BODY ) )FI ) %SET(MVAR,0) %UNTIL( %MVAR GT 3, %*BODY )
The macro language contains three functions that perform common string manipulation functions, namely, the LEN, SUBSTR and MATCH function.
The built-in function LEN takes a character string argument and returns the length of the character string in hexadecimal format (the same format as EVAL).
Before Macro Expansion After Macro Expansion %LEN(ABNCDEFGHIJKLMOPQRSTUVWXYZ) -> 1bH %LEN(A,B,C) -> 05H %LEN() -> 00H %MATCH(STR1,STR2) (Cheese,Mouse) %LEN(%STR1) -> 06H %LEN(%SUBSTR(%STR2, 1, 3 )) -> 03H
The built-in function SUBSTR returns a substring of its text argument. The macro takes three arguments: a string from which the substring is to be extracted and two numeric arguments.
balanced-text as described earlier. It may contain a macro call.
expression1 specifies the starting character of the substring.
expression2 specifies the number of characters to be included in the substring.
If expression1 is zero or greater than the length of the argument string, SUBSTR returns the null string.
If expression2 is zero, then SUBSTR returns the null string. If it is greater than the remaining length of the string, then all characters from the start character of the substring to the end of the string are included.
The examples below several calls to SUBSTR and the value returned:
Before Macro Expansion After Macro Expansion %SUBSTR(ABCDEFG, 5, 1 ) -> E %SUBSTR(ABCDEFG, 5, 100 ) -> EFG %SUBSTR(123(56)890, 4, 4 ) -> (56) %SUBSTR(ABCDEFG, 8, 1 ) -> null %SUBSTR(ABCDEFG, 3, 0 ) -> null
The MATCH function primarily serves to define macro identifiers. The MATCH function searches a character string for a delimiter character and assigns the substrings on either side of the delimiter to the macro identifiers.
balanced-text as described earlier. It may contain a macro call.
macro-id1 and macro-id2 may be any valid mppxa identifier.
delimiter is the first character to follow macro-id1. You can use a space or a comma or any other delimiter. See the Advanced mppxa Concepts section for more information on delimiters.
MATCH searches the balanced-text for the first delimiter. When it is found, all characters to the left of it are assigned to macro-id1 and all characters to the right are assigned to macro-id2. If the delimiter is not found, the entire balanced-text is assigned to macro-id1 and the null string is assigned to macro-id2.
%MATCH(MS1,MS2) (ABC,DEF) -> MS1=ABC MS2=DEF %MATCH(MS3,MS4) (GH,%MS1) -> MS3=GH MS4=ABC %MATCH(MS5,MS6) (%LEN(%MS1)) -> MS5=03H MS6=null
You can use the MATCH function for processing string lists as shown in the next example.
%MATCH(NEXT,LIST)(10H,20H,30H) %WHILE(%LEN(%NEXT)) ( MOV R3H, %NEXT ADD R3H, #2 MOV %NEXT, R3H %MATCH(NEXT,LIST)(%LIST) )
Produces the following code:
First iteration of WHILE:
MOV R3H, 10H ADD R3H, #2 MOV 10H, R3H
Second iteration of WHILE:
MOV R3H, 20H ADD R3H, #2 MOV 20H, R3H
Third iteration of WHILE:
MOV R3H, 30H ADD R3H, #2 MOV 30H, R3H
Two built-in functions, IN and OUT, perform console l/O. They are line-oriented. IN outputs the character '>' as a prompt to the console, and returns the next line typed at the console including the line terminator. OUT outputs a string to the console; the return value of OUT is the null string.
The results of an IN call (of the input) is interpreted as a macro-string. IN can also be used everywhere, where a macro-string is allowed.
%OUT(ENTER NUMBER OF PROCESSORS IN SYSTEM) %SET(PROC_COUNT,%IN) %OUT(ENTER THIS PROCESSOR'S ADDRESS) ADDRESS SET %IN %OUT(ENTER BAUD RATE) %SET(BAUD,%IN)
The following lines would be displayed on the console:
ENTER NUMBER OF PROCESSORS IN SYSTEM > user response ENTER THIS PROCESSOR'S ADDRESS > user response ENTER BAUD RATE > user response
For most programming problems, mppxa as described above, is sufficient. However, in some cases, a more complete description of the macro preprocessor's function is necessary. It is impossible to describe all of the obscurities of the macro preprocessor in a single chapter. Specific questions to mppxa can easily be answered by simple tests following the given rules.
Delimiters are used in the function DEFINE to separate the macro-name from the optional parameter-list and to separate different parameters in this parameter-list. In the MATCH function a delimiter is used to define a separator, which is used as kind of terminator in the corresponding balanced-text argument. The most commonly used delimiters are characters like parentheses and commas, but the macro language permits almost any character or group of characters to be used as a delimiter.
Regardless of the type of delimiter used to define a macro, once it has been defined, only the delimiters used in the definition can be used in the macro call. Macros defined with parentheses and commas require parentheses and commas in the macro call. Macros defined with spaces (or any other delimiter), require that delimiter when called.
Macro delimiters can be divided into three classes: implied blank delimiters, identifier delimiters, and literal delimiters.
Implied blank delimiters are the easist to use and contribute the most readability and flexibility to macro definitions. An implied blank delimiter is one or more spaces, tabs or new lines (a carriage-return/linefeed pair) in any order. To define a macro that uses the implied blank delimiter, simply place one or more spaces, tabs, or new lines surrounding the parameter list and separating the formal parameters.
When you call the macro defined with the implied blank delimiter, each delimiter will match a series of spaces, tabs, or new lines. Each parameter in the call begins with the first non-blank character, and ends when a blank character is found.
%*DEFINE(WORDS FIRST SECOND)(TEXT: %FIRST %SECOND)
All of the following calls are valid:
Before Macro Expansion After Macro Expansion %WORDS hello world -> TEXT: hello world %WORDS one two -> TEXT: one two %WORDS well done -> TEXT: well done
Identifier delimiters are legal macro identifiers designated as delimiters. To define a macro that uses an identifier delimiter in its call pattern, you must prefix the delimiter with the commercial at symbol '@'. You must separate the identifier delimiter from the macro identifiers by a blank character.
When calling a macro defined with identifier delimiters, an implied blank delimiter is required to precede the identifier delimiter, but none is required to follow the identifier delimiter.
%*DEFINE(ADD M1 @TO M2 @AND M3)( MOV R3H,%M1 ADD R3H,%M2 MOV %M2,R3H MOV R3H,%M1 ADD R3H,%M3 MOV %M3,R3H )
The following call (there is no blank after TO and AND):
%ADD ATOM TOBILL ANDLIST
returns the following code after expansion:
MOV R3H,ATOM ADD R3H,BILL MOV BILL,R3H MOV R3H,ATOM ADD R3H,LIST MOV LIST,R3H
The delimiters we used with the user-defined macros (parentheses and commas) were literal delimiters. A literal delimiter can be any character except the metacharacter.
When you define a macro using a literal delimiter, you must use exactly that delimiter when you call the macro.
When defining a macro, you must literalize the delimiter string, if the delimiter you wish to use meets any of the following conditions:
You can use the escape function (%n) or the bracket function (%()) to literalize the delimiter string.
Before Macro Expansion After Macro Expansion %*DEFINE(MAC(A,B))(%A %B) -> null string %MAC(2,3) -> 2 3
In the following example brackets are used instead of parentheses. The commercial at symbol separates the parameters:
%*DEFINE(OR[A%(@)B])(OR %A,%B) -> null string %OR[A1@A2] -> OR A1,A2
In the next example, delimiters that could be identifier delimiters have been defined as litteral delimiters:
%*DEFINE(ADD(A%(AND)B))(AND %A,%B) -> null string %ADD (R3H AND #34H) -> AND R3H , #27H
The spaces around AND are considered as part of the argument string.
Next folllows an example to demonstrate the difference between identifier delimiters and literal delimiters.
%*DEFINE(ADD M1%(TO)M2%(AND)M3)( MOV R3H,%M1 ADD R3H,%M2 MOV %M2,R3H MOV R3H,%M1 ADD R3H,%M3 MOV %M3,R3H )
The following call:
%ADD ATOM TOBILL ANDLIST
returns the following code after expansion (the TO in ATOM is recognized as the delimiter):
MOV R3H,R3H ADD R3H,M TOBILL MOV M TOBILL,R3H MOV R3H,R3H ADD R3H,LIST MOV LIST,R3H
In normal mode, the macro preprocessor scans text looking for the metacharacter. When it finds one, it begins expanding the macro call. Parameters and macro calls are expanded. This is the usual operation of the macro preprocessor, but sometimes it is necessary to modify this mode of operation. The most common use of the literal mode is to prevent macro expansion. The literal character in DEFINE prevents the expansion of macros in the macro-body until you call the macro.
When you place the literal character in a DEFINE call, the macro preprocessor shifts to literal mode while expanding the call. The effect is similar to surrounding the entire call with the bracket function. Parameters to the literalized call are expanded, the escape, comment, and bracket functions are also expanded, but no further processing is performed. If there are any calls to other, they are not expanded.
If there are no parameters in the macro being defined, the DEFINE built-in function can be called without the literal character. If the macro uses parameters, the macro will attempt to evaluate the formal parameters in the macro-body as parameterless macro calls.
The following example illustrates the difference between defining a macro in literal mode and normal mode:
%SET(TOM,1) %*DEFINE (M1)( %EVAL(%TOM) ) %DEFINE (M2)( %EVAL(%TOM) )
When M1 and M2 are defined, TOM is equal to 1. The macro-body of M1 has not been evaluated due to the literal character, but the macro-body of M2 has been completely evaluated, since the literal character is not used in the definition. Changing the value of TOM has no affect on M2, it changes the return value of M1 as illustrated below:
Before Macro Expansion After Macro Expansion %SET(TOM,2) %M1 -> 02H %M2 -> 01H
The macros themselvescan be called with the literal character. The return value then is the unexpanded body:
%*M2 -> 01H %*M1 -> %EVAL(%TOM)
Sometimes it is necessary to obtain access to parameters by several macro levels. The literal mode is also used for this purpose. The following example assumes that the macro M1 called in the macro-body is predefined.
@*DEFINE (M2(P1))( MOV R3H,%P1 %M1(%P1) )
In the above example, the formal parameter %P1 is used once as a simple place holder and once as an actual parameter for the macro M1.
Actual parameters in the contents must not be known in literal mode, since they are not expanded. If the definition of M2, however, occurred in normal mode, the macro preprocessor would try to expand the call from M1 and, therefore, the formal parameter %P1 (used as an actual parameter). However, this first receives its value when called from M2. If its contents happen to be undefined, an error message is issued.
Another application possibility for the literal mode exists for macro calls that are used as actual parameters (macro-strings, macro-variables, macro-calls).
%M1(%*M2)
The formal parameter of M1 was assigned the call from M2 ('%M2') by its expansion. M2 is expanded from M1 when the formal parameters are processed.
In normal mode, M2 is expanded in its actual parameter list immediately when called from M1. The formal parameters of M1 in its body are replaced by the prior expanded macro-body from M2.
The following example shows the different use of macros as actual parameters in the literal and normal mode.
%SET(M2,1) %*DEFINE (M1(P1))( %SET(M2,%M2 + 1) %M2, %P1 ) %M1(%*M2) -> 02H, 02H %M1(%M2) -> 03H, 02H %M1(%*M2) -> 04H, 04H
The algorithm of the macro preprocessor used for evaluating the source file can be broken down into 6 steps:
1) Scan the input stream until the metacharacter is found.
2) Isolate the macro-name.
3) If macro has parameters, expand each parameter from left to right (initiate step one on actual parameter), before expanding the next parameter.
4) Substitute actual parameters for formal parameters in macro-body.
5) If the literal character is not used, initiate step one on macro-body.
6) Insert the result into output stream.
The terms 'input stream' and 'output stream' are used because the return value of one macro may be a parameter to another. On the first iteration, the input stream is the source line. On the final iteration, the output stream is passed to the assembler.
The examples below illustrate the macro preprocessor's evaluation algorithm:
%SET(TOM,3) %*DEFINE (STEVE)(%SET(TOM,%TOM - 1) %TOM) %DEFINE (ADAM(A,B))( DB %A, %B, %A, %B, %A, %B )
The call ADAM is presented here in the normal mode with TOM as the first actual parameter and STEVE as the second actual parameter. The first parameter is completely expanded before the second parameter is expanded. After the call to ADAM has been completely expanded, TOM will have the value 02H.
Before Macro Expansion After Macro Expansion %ADAM(%TOM,%STEVE) -> DB 03H, 02H, 03H, 02H, 03H, 02H
Now reverse the order of the two actual parameters. In this call to ADAM, STEVE is expanded first (and TOM is decremented) before the second parameter is evaluated. Both parameters have the same value.
%SET(TOM,3) %ADAM(%STEVE,%TOM) -> DB 02H, 02H, 02H, 02H, 02H, 02H
Now we will literalize the call to STEVE when it appears as the first actual parameter. This prevents STEVE from being expanded until it is inserted in the macro-body, then it is expanded for each replacement of the formal parameters. TOM is evaluated before the substitution in the macro-body.
%SET(TOM,3) %ADAM(%*STEVE,%TOM) -> DB 02H, 03H, 01H, 03H, 00H, 03H
prxa IEEE object reader
Displays the contents of a relocatable object file or an absolute file
prxa [option]... file
prxa -V
prxa -? ( UNIX C-shell: "
-?" or -\? )
prxa gives you a high level view of an object file which has been created by a tool from the TASKING XA tool chain. Note that prxa can be used as a disassembler with the -il4 option.
Options start with a '-' sign and can be combined after a single '-'. There are options to print a specific part of an object file. For example, with option -h you can display the header part, the environment part and the AD/extension part as a whole. These parts are small, and you cannot display these parts separately. If you do not specify a part, the default is -hscegd0i0 (all parts, the debug part and the image part displayed as a table of contents).
Furthermore, there are some additional options by which you can control the output.
-ffile Read command line information from file. If file is a '-', the information is read from standard input.
1. It is possible to have multiple arguments on the same line in the command file.
2. To include whitespace in the argument, surround the argument with either single or double quotes.
3. If single or double quotes are to be used inside a quoted argument, we have to go by the following rules:
a. If the embedded quotes are only single or double quotes, use the opposite quote around the argument. Thus, if a argument should contain a double quote, surround the argument with single quotes.
b. If both types of quotes are used, we have to split the argument in such a way that each embedded quote is surrounded by the opposite type of quote.
Example:
"This has a single quote ' embedded"
or
'This has a double quote " embedded'
or
'This has a double quote " and \ a single quote '"' embedded"
4. Some operating systems impose limits on the length of lines within a text file. To circumvent this limitation it is possible to use continuation lines. These lines end with a backslash and newline. In a quoted argument, continuation lines will be appended without stripping any whitespace on the next line. For non-quoted arguments, all whitespace on the next line will be stripped.
Example:
"This is a continuation \ line" -> "This is a continuation line" control(file1(mode,type),\ file2(type)) -> control(file1(mode,type),file2(type))
5. It is possible to nest command line files up to 25 levels.
-H or -? Display an explanation of options at stdout.
-V Display version information at stderr.
-Wn Set output width to n columns. Default 128, minimum 78.
-ln Level control, see paragraph 11.6.3.
-ofile Name of the output file, default stdout.
-v Print the selected parts in a verbose form.
-vn Print level n verbose, see paragraph 11.6.3.
-wn Suppress messages above warning level n.
-c Print call graphs.
-d Print all debug info except for the global types.
-d0 Print table of contents for the debug part.
-dn Print debug info from file number n.
-e Print variables with external scope.
-e1 Print variables with external scope and precede symbol name with name of the object file.
-g Print global types.
-h Print general file info.
-i Print all section images.
-i0 Print table of contents for the image part.
-in Print image of section n.
-s Print section info.
There are three files which are used in this chapter to show how you can use prxa. These files are:
If you want to try the examples yourself, prepare these files by copying the calc example files to a working directory. Be sure that the XA tools can be found via a search path. Make the files with the following command:
ccxa -M -Wa -gs -tiof -nolib calc.asm startup.asm initseg.asm -o calc.abs -tmp
The -h option gives you general information of the file. The invocation:
prxa -h calc.out
Gives the following information:
File name = calc.out: Format = Relocatable Produced by = XA object linker Date = dec 9, 1996 11:14:55h
This output speaks for itself. You may combine the -h switch with the verbose option:
prxa -hv calc.out
The output is extended with more general information of less importance:
File name = calc.out: Format = Relocatable Produced by = XA object linker Date = dec 9, 1996 11:14:55h Obj version = 1.1 Processor = XA Address size = 24 bits Byte order = Least significant byte at lowest address Host = Sun
Part File offset Length -------------------------------------------------- Header part 0x00000000 0x00000051 AD Extension part 0x00000051 0x00000033 Environment part 0x00000084 0x00000029 Section part 0x000000ad 0x00000089 External part 0x00000136 0x0000008c Debug/type part 0x000001c2 0x000074ce Data part 0x00007690 0x000003db Module end 0x00007a6b
The table gives you the file offsets and the length of the main object parts.
With the -s option, you can obtain the section information from an object module. The section contents can be obtained with the -i option, see 11.6.2.7.
prxa -s calc.out
Section Size -------------------------- CALC_PR 0x00003e CALC_INI_NE 0x000001 CALC_CLR_NE 0x000002 START_PR 0x000020 RESET_VECTOR 0x000004 INIT_PR 0x0000c4
Note that the section information is not available any more in a located file. Once located, the separate sections are combined to new clusters. For an absolute file 'prxa -s' will give the cluster information:
prxa -s calc.abs
Section Size ------------------------ data_clstr 0x010000 code_clstr 0x010000
The locate map shows you which section is located in which cluster. Of course, you can also use the verbose option to see all section information available:
prxa -sv calc.out
Section Size Address Algn PageSize Mau Attributes
-----------------------------------------------------------------------------
CALC_PR 0x00003e - 0x002 - - Execute Space 10 Cumulate
CALC_INI_NE 0x000001 - 0x001 - - Write Space 8 Initialized
Cumulate
CALC_CLR_NE 0x000002 - 0x002 - - Write Space 8 Cleared Cumulate
START_PR 0x000020 - 0x002 - - Execute Space 10 Cumulate
RESET_VECTOR 0x000004 - 0x001 - - Execute Space 10 Cumulate
INIT_PR 0x0000c4 - 0x002 - - Execute Space 10 Cumulate
The first two columns give you the section name and the section size. The column 'Address' gives you the section address, or a '-' if the section is still relocatable. The section alignment is 1 (byte) or 2 (word) for the XA. The page size is valid only for the short sections. Mau is the minimum addressable unit of an address space (in bits). There are two main groups of section attributes, the allocation attributes, used by the locator and the overlap attributes, used by the linker:
Allocation attributes | |||||||||
Write | Must be located in ram | ||||||||
ReadOnly | May be located in rom | ||||||||
Execute | May be located in rom | ||||||||
Space num |
Must be located in addressing mode num
Abs |
Already located by the assembler |
Cleared |
Section must be initialized to '0' |
Initialized |
Section must be copied from ram to rom |
Scratch |
Section is not filled or cleared | |
Table 11-2: Allocation attributes
Overlap attributes | |
MaxSize | Use largest length encountered |
Unique | Only one section with this name allowed |
Cumulate | Concatenate sections with the same name to one bigger section |
Overlay | Sections with the name name@func must be combined to one section name, according to the rules for func obtained from the call graph. |
Separate | Sections are not linked. |
Table 11-3: Overlap attributes
The call graph is used by the linker overlaying algorithm. Once a file is linked and overlaying is done, the call graph information is removed from the object file. If you try to see the call graph in calc.out you will get the message 'No call graph found'.
The file calc.obj is not yet linked. You can use this file to see what a call graph looks like:
prxa -c calc.obj
Call graph(s) ============= Call graph 0: factorial ->See call graph 0 Call graph(s) ============= Call graph 1: entry ->See call graph 0
Each call graph consists of a function (factorial in graph 0), followed by a list of functions and/or other graphs, which are called by the first function. The functions and call graphs called by this function are indented by two spaces. If a function calls other functions, those functions are listed again with another indentation of two spaces.
As you can see, there are references from one call graph to another. Call graph 0 even calls itself!! This means that function factorial() is a recursive function.
If a function is a static function the source name is added to the function name to avoid name conflicts.
If you want a call graph with resolved call graph references, you can use the linker to generate one:
lkxa -o call.out -Mcr calc.obj
Option -M tells the linker to generate a .lnl file. This file contains the call graph in the verbose layout. Option -c causes the linker to generate a .cal file. This file contains also the (same) call graph, but in the compact (non verbose) layout. Option -r tells the linker that this is an incremental link.
In the external part of an object file, you can find all symbols used at link time. These symbols have an external scope. With the -e option (or -e0) prxa displays the external symbols:
prxa -e calc.out
Variable S Address/Size ------------------------- entry I CALC_PR + 0x00 num I CALC_INI_NE + 0x00 result I CALC_CLR_NE + 0x00 __START I START_PR + 0x00 initseg I INIT_PR + 0x00 __lc_es X - __lc_cp X -
With option -e1 also the name of the output object file is displayed.
prxa -e1 calc.out
Variable S Address/Size ---------------------------------- calc.out:entry I CALC_PR + 0x00 calc.out:num I CALC_INI_NE + 0x00 calc.out:result I CALC_CLR_NE + 0x00 calc.out:__START I START_PR + 0x00 calc.out:initseg I INIT_PR + 0x00 calc.out:__lc_es X - calc.out:__lc_cp X -
The first column contains the name of the symbol. In general, this symbol is a high level symbol with an underscore added at the front. The next column gives you the symbol status. This can be I for a defined symbol, and X for a symbol which is referred to, but which is not yet defined. In the last column you can find the symbols address. If this address is still relocatable, the section offsets are printed in the form 'section + offset'. If a symbol has already received an absolute address, this address is printed. Symbols that are not yet defined (marked with a X) have a dash printed as address, indicating unknown.
You can add the verbose option as usual. With verbose on more information is printed:
prxa -ev calc.out
Variable S Type Attrib MAU Amod Address/Size -------------------------------------------------------------- entry I - - 8 10 CALC_PR + 0x00 num I - - 8 8 CALC_INI_NE + 0x00 result I - - 8 8 CALC_CLR_NE + 0x00 __START I - - 8 10 START_PR + 0x00 initseg I - - 8 10 INIT_PR + 0x00 __lc_es X - - 8 7 - __lc_cp X - - 8 10 -
Four additional columns appear. The Type column gives you the symbol type, if available. You can find the meaning of the types in the global type part, section 11.6.2.5. The global types are used to type check the symbols during linking. The Attribute column specifies the attribute of the symbol, if available. For example, the attribute value 0x0020 indicates that the symbol is generated by the assembler. The MAU colomn indicates the minimum addressable unit in bits. So, MAU 8 means the symbol is 8-bit addressable. The Amod column lists the addressing mode of the symbol.
The linker uses the global type information to check on type mismatches of the symbols in the external part. This information is always available, unless you explicitly suppress the generation of these types with option -gn at compile time. Of course, type checking can only be done if the types are available. The global types in calc.out:
prxa -g calc.out
In this example you will get the message 'No global types available'. The following is just an example of what the global type information could look like:
Tp# Mnem Name Entry --------------------------- 101 X - 0, T10, 0, 0 102 X - 0, T1, 0, 0 103 X - 0, T1, 0, 1, T104 104 P - T105 105 n - T2, 1 106 X - 0, T1, 0, 1, T10 107 X - 0, T10, 0, 1, T10 108 X - 0, T1, 0, 2, T109, T109 109 T Byte T3 10a X - 0, T1, 0, 1, T109 ... 10f X - 0, T1, 0, 3, T12, T110, T12 110 O - T111 111 n - T2, 0 112 Z - T2, 13 113 Z - T2, 7
In the first column you find the type index. This is the number by which the type is referred to. This number is always a hexadecimal number. Numbering starts at 0x101, because the indices less than 0x100 are reserved for, so-called, 'basic types'. The second column contains the type mnemonic. This mnemonic defines the new 'high level' type. In the Name column you will find the name for the type, if any.
The last column contains type parameters. They tell you which (basic) types a high level type is based on and give other parameters such as modes and sizes. Types are preceded by a T. So, in the example above, type 105 is based upon type 2 (T2 in the parameter list) and type 103 is based upon type 1 and type 104.
In the next table you can find an overview of the basic types:
Type index | Type | Meaning |
1 | void | - |
2 | char | 8 bits signed |
3 | unsigned char | 8 bits unsigned |
4 | short | 16 bits signed |
5 | unsigned short | 16 bits unsigned |
6 | long | 32 bits signed |
7 | unsigned long | 32 bits unsigned |
10 | float | 32 bit floating point |
11 | double | 64 bit floating point |
16 | int | 16 bits signed |
17 | unsigned int | 16 bits unsigned |
Table 11-4: Basic types
The type mnemonics define the class of the newly created type. The next table shows the type mnemonics with a short description:
Mnemonic | Description | Parameters |
G | generalized structure | size, [member, Tindex, offset, size ]... |
N | enumerated type | [name, value ]... |
n | pointer qualifier | Tindex, memspace |
O | small pointer | Tindex |
P | large pointer | Tindex |
Q | type qualifier | q-bits, Tindex |
S | structure | size, [member, Tindex, offset ]... |
T | typedef | Tindex |
t | compiler generated type | Tindex |
U | union | size, [member, Tindex, offset ]... |
X | function | x-bits, Tindex, 0, nbr-arg, [ Tindex ]... |
Z | array | Tindex, upper-bound |
g | bit type | sign, nbr-of-bits |
Table 11-5: Type mnemonics
The Tindex for mnemonic n, O, P, Q, T, t and Z are the types upon which the new type is built. The Tindex for the union and the structures are the type indices for the members. For the function type, the first Tindex is the return type of the function. The second Tindex is repeated for each parameter, and gives the type of each parameter. The value -1 (0xffffffff) always means 'unknown'. This can occur with a function type if the number of parameters is unknown, or with an array if the upper bound in unknown. The sizes and offset for the generalized structure are in bits. The first size is the size of the structure, the second size is the size for the member.
The type information obtained with the -g switch has no verbose equivalent.
The -d switch has two variants. With -d0 you get a table of contents:
prxa -d0 calc.out
Choose option -d with the number of the file: 1 - calc.obj 2 - startup.obj 3 - initseg.obj
Now, you can use -dn to examine a single (linked) file. For instance, -d1 shows you only the debug info of calc.obj. It is also possible to see all debug info, by using option -d without a value.
The -d switch without the verbose option -v shows you only local variables and procedure information. If you combine the -d switch with the verbose switch -v, also local type info, line numbers, stack update information and more procedure information is displayed.
In the example you are using the verbose switch. Where required, the remark 'Only with verbose on' will be given.
prxa -d1v calc.out
The object reader starts with a header, followed by the local type information:
************************************* * O b j e c t c a l c . o b j * ************************************* M o d u l e i n f o =====================
Type info calc.obj: =================== No local types available
This type info is only printed if you use the verbose option -v. The information found in this table is exactly the same as the information explained for the global type information, see 11.6.2.5.
After the local types, you will find the local symbols.
Symbols calc.obj: ================= Variable S Type Attrib MAU Amod Address/Size -------------------------------------------- bcr N - 0x0010 8 8 - BCR N - 0x0010 8 8 - btrh N - 0x0010 8 8 - BTRH N - 0x0010 8 8 - btrl N - 0x0010 8 8 - BTRL N - 0x0010 8 8 - ....
The value for the symbol status in the external part was an I or an X. Here, you can see a new letter. The N stands for a local symbol. Other possible entires can have the letter G or S. They are no symbols, but procedures. These procedures are printed at this place in order to define their relative position. The actual procedure information is given in the next block of information. Here you can find the additional procedure information. The procedure block is printed only if you use the verbose switch:
Procedures calc.obj: ==================== No procedures
The following is an example of some procedures:
Name S Additional information ----------------------------------------- main G 0x00, 0x00, T101, QUEENS_PR + 0x00, ( QUEENS_PR + 0x49 ) - 0x01 find_legal_row S 0x00, 0x00, T120, QUEENS_PR + 0x49, ( QUEENS_PR + 0x156 ) - 0x01 display_board S 0x00, 0x00, T10a, QUEENS_PR + 0x156, ( QUEENS_PR + 0x2a4 ) - 0x01 display_field S 0x00, 0x00, T121, QUEENS_PR + 0x2a4, ( QUEENS_PR + 0x302 ) - 0x01 display_status S 0x00, 0x00, T103, QUEENS_PR + 0x302, ( QUEENS_PR + 0x31d ) - 0x01
The first two columns are the same as those in the local variable table. The G stands for an external (global) function, the S for a static (local) function.
Each function has 5 parameters with the following meaning:
param #1 Frame type, not used
param #2 Frame size, the distance from the stack pointer before the function call to the stack position just after the local variables.
param #3 The type of the function
param #4 The start address of the function. In a relocatable object the syntax 'section + offset' is used.
param #5 The last function address. See also param #4.
Next in the debug info is the line number information and the stack information. Both items are only printed if you had turned the verbose switch on:
Lines include/stdarg.h:
=======================
No line info available
Lines include/stdio.h:
======================
No line info available
Lines queens.c:
===============
Address | Line Address | Line Address
...
--------------------------- --------------------------- ---------------
QUEENS_PR + 0x000000 | 52 QUEENS_PR + 0x0000c2 | 90 QUEENS_PR
+ ...
QUEENS_PR + 0x000000 | 53 QUEENS_PR + 0x0000d9 | 101 QUEENS_PR
+ ...
QUEENS_PR + 0x000006 | 55 QUEENS_PR + 0x0000d9 | 103 QUEENS_PR
+ ...
. . .
. . .
. . .
QUEENS_PR + 0x0000bd | 98 QUEENS_PR + 0x00018e | 133 QUEENS_PR
+ ...
QUEENS_PR + 0x0000c0 | 99 QUEENS_PR + 0x000190 | 136 QUEENS_PR
+ ...
QUEENS_PR + 0x0000c2 | 100 QUEENS_PR + 0x00019f | 137
Stack info include/stdarg.h:
============================
No stack info available
Stack info include/stdio.h:
===========================
No stack info available
Stack info queens.c:
====================
No stack info available
The stack info gives the actual stack position for each executable address. This value is measured from the start position, just after the functions local variables to the actual stack position. If you push one byte on stack, the delta will be increased by one.
The debug info per module ends with a block for each function. Within this block the local variables per function are displayed:
P r o c e d u r e i n f o ===========================
Procedure find_legal_row: ========================= Symbols find_legal_row: ======================= Variable S Type Attrib Mau Amod Address/Size ----------------------------------------------------- accepted N 0x0109 0x0004 0 0 QUEENS_DA + 0x09 row N 0x0109 0x0805 0 0 0x02 col N 0x0109 0x0805 0 0 0x03 chk_row N 0x0109 0x0005 0 0 0x01 chk_col N 0x0109 0x0005 0 0 0x00
E n d o f p r o c e d u r e i n f o =========================================
As with the -d option, you can ask a table with available section images by specifying option -i0:
prxa -i0 calc.out
Choose option -i with the number of the section: 1 - CALC_PR 2 - CALC_INI_NE 3 - CALC_CLR_NE 4 - START_PR 5 - RESET_VECTOR 6 - INIT_PR
You can select the image to display by specifying the image number:
prxa -i1 calc.out
Section CALC_PR: ================ 86 rr rr c5 03 00 8e rr rr 80 d6 00 72 99 04 00 84 02 0f 74 94 02 02 04 f0 08 99 01 00 0d fe 00 84 02 07 20 81 30 b1 84 02 07 91 01 02 1f 8a c5 ed ff 27 8a 20 e4 02 89 70 99 04 00 80 d6
It is also possible to get the section offsets or absolute addresses by specifying the verbose flag:
prxa -i1v calc.out
Section CALC_PR:
================
000000 86 rr rr c5 03 00 8e rr rr 80 d6 00 72 99 04 00 ............r...
000010 84 02 0f 74 94 02 02 04 f0 08 99 01 00 0d fe 00 ...t............
000020 84 02 07 20 81 30 b1 84 02 07 91 01 02 1f 8a c5 ... .0..........
000030 ed ff 27 8a 20 e4 02 89 70 99 04 00 80 d6 ..'.
...p.....
The dump always shows the hexadecimal byte value per address. Sometimes however, this is not possible. First of all, it is possible that a certain byte cannot be determined because it is not yet relocated. In this case the byte is represented as rr.
Secondly, it is possible that there is no section image allowed. This is for instance the case for sections that are cleared during startup. After the invocation (verbose on) the reader prints:
prxa -i3v calc.out
Section CALC_CLR_NE: ==================== No image allowed, cleared during startup
It is possible that you read an absolute file. In the absolute file it is possible to combine different sections to new clusters. These clusters do not have the same attributes as the sections and the reader does no longer know where the overlay area is positioned:
prxa -v -i2 calc.abs
Section code_clstr:
===================
000000 8f 00 ff 04 ss ss ss ss ss ss ss ss ss ss ss ss ................
000010 ss ss ss ss ss ss ss ss ss ss ss ss ss ss ss ss ................
000020 ss ss ss ss ss ss ss ss ss ss ss ss ss ss ss ss ................
000030 ss ss ss ss ss ss ss ss ss ss ss ss ss ss ss ss ................
....
As you see, the reader only prints bytes that it actually can read from the object file. The ss in the dump means scratch memory. It may or may not be initialized by the start-up code. This information is not available anymore to the reader. The start-up code can use a locator generated table to get the information. See the Locator chapter.
With the option combination -il4, prxa can produce disassembly output. It disassembles all code image parts which are executable.
prxa -i1l4 calc.out
Section CALC_PR: ================ 0000 86 rr rr mov.b R0L,0x000 0003 c5 00 03 call 0x0000c 0006 8e rr rr mov.w R0,0x000 0009 d6 80 ret 000b 00 nop
prxa -il4 calc.abs
Section data_clstr: =================== 0000 until ffff scratch memory Section code_clstr: =================== 0000 00 nop 0001 8f 04 ff popu.w 0x4ff 0004 ss Unknown opcode 0005 ss Unknown opcode ... fec6 86 00 02 mov.b R0L,0x002 fec9 c5 00 03 call 0x0fed2 fecc 8e 08 00 mov.w 0x000,R0 fecf d6 80 ret fed1 00 nop ...
As with the well known OSI layer model for communication, you can also distinguish layers in an object file. The object file is a medium for the compiler which lets the compiler communicate with the debugger or the target board. The lowest level can be classified as mass storage, mostly the disc. The lowest viewable level for the readers concern are the raw bytes.
prxa knows this layer as level 0.
Of course, the bytes in level 0 have a meaning. Because the object format is an format according to IEEE 695, the object file is a collection of MUFOM commands. The general idea is, that an object producing tool sends commands to a object consuming tool. These commands are described in detail by the official IEEE standard (IEEE Trial Use Standard for Microprocessor Universal Format for Object Modules (IEEE std. 695), IEEE Technical Committee on Microcomputers and Microprocessors of the IEEE Computer Society, 1990) . The raw bytes from level 0 appear to be encoded MUFOM commands. The MUFOM commands are interpreted in a layer just above the raw bytes layer.
prxa knows this layer as level 1.
The next layer is the MUFOM environment, the type and section tables are built, values are assigned, attributes are set just by performing the MUFOM commands. The IEEE document describes also some predefined meanings about scope, section attributes naming conventions for MUFOM variables. This knowledge is available in the highest MUFOM layer.
prxa knows this layer as level 2.
With these first layers, the compiler and debugger/target board have a perfect communication channel. The next layers (not supported by the reader at this moment) define a protocol between compiler and debugger about target and language specific information.
In the next sections you can find some examples about the use of the reader at lower levels. Until now, you used the default level of the reader, level 2.
Switching to another level is simple. You can use the -l option with the level you want to see. As an example, the section part of calc.out at level 1:
prxa -l1 -s calc.out
ST: 1, XY10C, CALC_PR SA: 1, 2 AS: S1, 0x3e ST: 2, WIY8C, CALC_INI_NE AS: S2, 0x1 ST: 3, WBY8C, CALC_CLR_NE SA: 3, 2 AS: S3, 0x2 ST: 4, XY10C, START_PR SA: 4, 2 AS: S4, 0x20 ST: 5, XY10C, RESET_VECTOR AS: S5, 0x4 ST: 6, XY10C, INIT_PR SA: 6, 2 AS: S6, 0xc4
If you are not familiar with the MUFOM commands, you can use the verbose switch. The abbreviated commands such as AS, SA or ST are expanded to Assignment, Section alignment and Section type:
prxa -v -l1 -s calc.out
ST: Section type: Nbr = 1, type = XY10C, name = CALC_PR SA: Section align: Nbr = 1, align = 2 AS: Assignment: Variable = S1, expression = 0x3e . . ST: Section type: Nbr = 6, type = XY10C, name = INIT_PR SA: Section align: Nbr = 6, align = 2 AS: Assignment: Variable = S6, expression = 0xc4
The Ln and Sn MUFOM variables are defined as the address and the size of section n. At level 2 you saw (refer to section 11.6.2.2) that the level 2 view did not mention the L and S variables, because at level 2 the meaning of the L and S variables are known!
Switching to level 0 is accomplished by using -l0 (as you expected):
prxa -l0s calc.out
e6 01 d8 d9 0a c3 07 43 41 4c 43 5f 50 52 e7 01 02 e2 d3 01 3e ... e6 06 d8 d9 0a c3 07 49 4e 49 54 5f 50 52 e7 06 02 e2 d3 06 81 c4
The bytes are printed in the MUFOM command structure. It should be easy to find the encoding for the used MUFOM commands. You can use the verbose switch if you want to see file offsets:
prxa -l0vs calc.out
0000ad e6 01 d8 d9 0a c3 07 43 41 4c 43 5f 50 52 .......CALC_PR 0000bb e7 01 02 ... 0000be e2 d3 01 3e ...> ... 000120 e6 06 d8 d9 0a c3 07 49 4e 49 54 5f 50 52 .......INIT_PR 00012e e7 06 02 ... 000131 e2 d3 06 81 c4 .....
You can also mix the levels. It is for instance possible to see level 0 and 1 together by specifying option -l01 (equivalent to -l10 or -l0 -l1):
prxa -sl01 calc.out
ST: 1, XY10C, CALC_PR e6 01 d8 d9 0a c3 07 43 41 4c 43 5f 50 52 SA: 1, 2 e7 01 02 AS: S1, 0x3e e2 d3 01 3e . . . ST: 6, XY10C, INIT_PR e6 06 d8 d9 0a c3 07 49 4e 49 54 5f 50 52 SA: 6, 2 e7 06 02 AS: S6, 0xc4 e2 d3 06 81 c4
And of course, you can turn on the verbose switch. The switch between level 0 and level 1 is done per MUFOM command. This is because a MUFOM command is the smallest unit at level 1.
If you should display level 1 and 2, the switch is made per object part, because the object parts are the smallest units at level 2. It is not possible to show the results of all section related commands before all these commands are executed:
prxa -s -l1 -l2 calc.out
ST: 1, XY10C, CALC_PR e6 01 d8 d9 0a c3 07 43 41 4c 43 5f 50 52 SA: 1, 2 e7 01 02 AS: S1, 0x3e e2 d3 01 3e . . . ST: 6, XY10C, INIT_PR SA: 6, 2 AS: S6, 0xc4
Section Size -------------------------- CALC_PR 0x00003e CALC_INI_NE 0x000001 CALC_CLR_NE 0x000002 START_PR 0x000020 RESET_VECTOR 0x000004 INIT_PR 0x0000c4
As you have read in section 11.6.3.2, you can switch to a lower level with the level switch -ln. If you want a verbose printout, you can use the -v option.
It is also possible to specify -v0 to see a verbose output of level 0, option -vn is a shorthand for options -v -ln (or -vln). The new notation has the advantage that if you want a mixed level output, you are able to choose the verbose option per level. You may specify -l0 -v1, and you get a non verbose level 0 and a verbose level 1:
prxa -sl0v1 calc.out
ST: Section type: Nbr = 1, type = XY10C, name = CALC_PR e6 01 d8 d9 0a c3 07 43 41 4c 43 5f 50 52 SA: Section align: Nbr = 1, align = 2 e7 01 02 AS: Assignment: Variable = S1, expression = 0x3e e2 d3 01 3e . . . ST: Section type: Nbr = 6, type = XY10C, name = INIT_PR e6 06 d8 d9 0a c3 07 49 4e 49 54 5f 50 52 SA: Section align: Nbr = 6, align = 2 e7 06 02 AS: Assignment: Variable = S6, expression = 0xc4 e2 d3 06 81 c4
The general verbose switch -v (without a number) makes all selected levels verbose. The verbose switch -vn selects level n and makes only level n verbose.