Hobby Cross Assembler v0.201


Copyright (C) 2004-2013 by Anton Treuenfels


License and Terms

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

Page Top


Introduction to HXA

HXA is a macro cross assembler created simply for fun as a hobby project (hence the name). HXA reflects many of my own ideas about what is and is not important in assembler design.

Perhaps the most central idea from a programmer's viewpoint is that HXA requires almost every programmer intention to be made explicit in assembly source code. I've had the experience of trying to read source code in unfamiliar languages for assemblers whose manuals I did not have. That's not so easy, so HXA tries to make sure both writer and reader have no doubt about what is supposed to happen.

An area of ongoing concern is error detection and reporting. HXA has been designed from the start to detect many possible source code errors. If found, errors are reported in a consistent manner that attempts to make clear what, why and where something went wrong. The aim is to give a progammer trying to fix an error a "fighting chance".

HXA makes an effort to accomodate programmers used to the conventions of other assemblers. It is fairly agnostic with regard to how numeric literals are specified and what the exact names of pseudo ops are.

A couple of things I don't worry much about are size and speed. Current machines are very fast and have very large memories, so concerns of this nature in an assembler aren't too pressing. While trying to never needlessly inflate HXA, when push comes to shove I permit it to get larger and slower. That said, the MS-DOS version of HXA typically assembles source code at 400-500 lines per second on an old Pentium 166.

I hope you find using HXA to be both productive and enjoyable. If you have any questions or comments, please let me know. There are many excellent ideas still unstolen, and these will help decide which ones are plundered next :)

- Anton Treuenfels

Page Top


Contact Information

Snail-mail:

E-mail:

Page Top


Scope of This Document

HXA is designed to be fairly portable between various processors. This document describes only those portions of HXA which are processor-independent.

As assemblers in general are largely concerned with textual manipulation of assembly source code, this is actually most of HXA.

In the present version of HXA the only portions which "understand" the processor instruction opcodes of any particular assembly language are isolated in a single one of its own source files. Replacement of this file is one method of producing variants of HXA capable of handling different assembly languages. Each existing such variant is discussed in a separate document.

Page Top


Related Resources

HXA

HXA Variants

Page Top


HXA Features

Labels

Expressions

Pseudo Opcodes

File Output

Page Top


New in v0.201

All Versions

Extended

A complete list of all changes in v0.201 can be found in the implementation documentation.

Page Top


"Hello, World!"

The short "Hello, World!" program is the first example on the first page of "The C Programming Language" by Kernighan and Ritchie. First published in 1978, it has since become a very popular example for introducing almost any programming language.

While HXA is not a programming language per se , the assembly languages it supports are. The "Hello, World!" Demos provide short examples of how HXA may be used to create real programs for real computers.

Page Top


Executing HXA

All variants of HXA accept a single filename as a command-line argument:

HXAxx filename

HXAxx is the specific variant of HXA invoked, where " xx " is replaced by a variant identifier.

Filename is assumed to be a text file containing assembly language source code.

If multiple source files are to be assembled together, they must be specified within the root filename by using the "INCLUDE" pseudo opcode.

Filename may contain device and/or directory specifiers (ie., a path ). If filename contains a path, HXA automatically prefixes every other input and output file named within filename with that same path. The only exception is if a named file has its own path containing a device identifier or starts from the root directory, in which case HXA uses that path instead.

The effect is that files named within filename can normally be specified by their location relative to it, but if desired an absolute location can be specified instead.

There are no command-line options or flags. Changes to HXA's default behavior are made explicit by pseudo opcodes used within the source file(s).

By default HXA produces no output other than status and error messages. These are sent to stdout , which is normally the screen (console). If no screen output is desired, stdout may be re-directed on the command line to a file (to capture all such output) or the null (NUL) device (to ignore all such output).

Several "--FILE" pseudo ops can direct HXA to produce error, raw binary, Intel hex, Motorola hex and/or listing files as desired.

At exit HXA returns a value of zero if no warnings or errors were encountered during assembly. An exit value of one to seven is bit-mapped to report the type of problem(s) encountered:

Bit Value Detected
$01 Warning(s)
$02 Error(s)
$04 Fatal Error

A value of two or higher implies HXA halted assembly and produced only an error file (if one was specified).

Page Top


Source Code Format

HXA accepts standard ASCII text files as source code. Each line of a text file is treated as a separate source code line.

A source code line may consist of up to four logical fields:

LABEL OPCODE EXPRESSION COMMENT

These fields are separated from each other by one or more whitespace characters. Each field is optional, but if present must appear in the order shown. The only restriction is that expressions must follow an opcode; they cannot appear alone or directly following a label.

Malformed source lines are an error.

Note that the actual column position of any field within a source code line is not important to HXA. What a field represents is more important than where it is.

Examples

Page Top


Label and Opcode Fields

HXA is case-insensitive with respect to labels and opcodes:

All The Same To HXA
User Label Pseudo Opcode
MYLABEL BYTE
mylabel byte
MyLabel Byte

Note that the opcode field may contain processor instruction opcodes, assembler pseudo opcodes or macro names . As used here, opcode refers to all these types.

Page Top


Expression Field

The expression field is separated from its preceeding opcode by whitespace, and continues until the end of the source line or the start of the comment field, whichever comes first. Whitespace may be used in the expression field as desired.

HXA normally divides the expression field into sub-fields before further processing. Each comma (',') in the expression field marks the start of a separate argument to the opcode it follows. Leading and trailing whitespace is discarded from each sub-field. Blank or empty sub-fields are not allowed.

There are exceptions where a comma does not divide:

The escape mechanism is the most general method of preventing the expression field from being divided. Commas in literal values and those separating function arguments can also be escaped, if desired (although there is no practical advantage in doing so).

Page Top


Comment Field

Source lines which have an asterisk ('*') in the first column, or whose first non-whitespace character is a semi-colon (';'), are considered comment lines, and are ignored.

A comment following a label, opcode or expression is indicated by a semi-colon immediately preceeded by at least one whitespace character. Note that if this sequence appears in a string or regular expression literal, the semi-colon must be escaped in order to be handled properly.

Examples

Page Top


Labels

In assembly languages labels are symbolic names used to represent values. The symbolic names can then be used in expressions in place of those values.

Using symbolic names for values has at least three great advantages over using the values directly. First, a well-chosen name is much easier to remember than an obscure value. Second, the same value may mean different things in different contexts, and giving the same value a different name for each different context helps keep each use of it clear. Third, if the value associated with a name is ever changed it is guaranteed that every use of that name is "automatically" updated, but avoids changing the use of any other name that happens to have the same value.

Page Top


Names

The basic form of named HXA labels starts with an alphabetic or underscore character ('A-Z' or '_') followed by zero or more alphanumeric or underscore characters ('A-Z0-9' or '_').

Period ('.') characters may also be used in a named label, but only between two non-period characters. Periods cannot be the first or last character of a named label, nor can there be two consecutive period characters.

A final colon (':') suffix is optional for label names. This is generally ignored by HXA, so ' MyLabel: ' and ' MyLabel ' can be used interchangeably to represent the same value in both label and expression fields.

Note however a colon suffix on the first field of a source code line forces HXA to recognize the field as a label. This can be used to distinguish a new label name from an existing macro name.

Colons on label names can also help distinguish them from other sorts of character groupings in search and replace operations while editing source code.

Valid Label Names
myLabel _mylabel my.label mylabel:
wname __XName__ y.n.a.m.e Z_Name:
target1 target_2 t.123 trgt.3:

Page Top


Types

HXA allows labels to represent numeric and string values. The type of a label is made manifest by the presence or absence of a dollar sign suffix ('$'): a label without this suffix represents a numeric value, a label with it a string. If a string label also has a colon suffix, the dollar sign preceeds the colon (ie., any colon is always the last character of any named label).

Label Types
Numeric String
myNumLabel myStrLabel$
temp1 t2$
colonNum: colonStr$:

HXA extends its manifest typing system to distinguish several sub-types of numeric and string labels. The sub-type of a label is distinguished by the first character of its name.

HXA Label Sub-Types
Sub-Type Indicator Initial Character Ex: Numeric Ex: String
Global Alphabetic or underscore '_A-Z' myGlobal aGlobal$
Local "At" sign '@' @myLocal @aLocal$
Variable Right bracket ']' ]myVar ]aVar$
Branch Target Plus | Minus | Colon '[+-:]' + n/a

Notes:

Page Top


Values

Labels appearing in the label field of a source code line are assigned values. Most often the value is the current value of the program counter. HXA makes this assignment automatically; in most cases a programmer doesn't know (or need to know) what the actual value of such a label is.

For numeric labels this value is an integer which can be used directly as a memory address. For string labels this value takes the form of a decimal string representation of the same memory address.

Both types of labels can also be assigned explicit values with the "EQU" pseudo opcode. For string labels this is the most common method.

Examples

Page Top


Global

Global labels, as their name implies, have global scope. The value represented by a global label can be accessed from anywhere in the source code file(s).

Global labels are fixed. Once assigned a value, that value cannot be changed. However the same value may be assigned to the same global label any number of times.

Global label names must be unique. No two global labels can have the same name.

A global label in the label field of a source code line causes the current local scope to terminate. All current local label names and values are forgotten, and a new local scope begins.

In general global label names which match processor instruction opcodes, assembler pseudo opcodes , or previously defined macro names should be avoided. Global labels in the first field of source code line which match any of these will not be recognized correctly (however a global name with a colon suffix will not match any existing name except another global name).

Examples

Page Top


Local

Local labels, as their name implies, have local scope. The value represented by a particular local label cannot be accessed outside the scope it is created in. Expressions within one local scope cannot successfully "reach out" of it to use the value of a local label in another scope.

Local labels are fixed. Once assigned a value, that value cannot be changed. However the same value may be assigned to the same local label in the same local scope any number of times.

Local label names within the same local scope must be unique. Local labels in different local scopes may have the same name.

In HXA local scoping is for the most part managed automatically based on block concepts: entering a block creates a new local scope and exiting a block ends it. Since blocks can be nested, so can local scopes.

A file is a block, thus the first local scope is the same as the first source file. File inclusion causes HXA to automatically create a nested local scope for each file included.

Any given level of nested scope is further subdivided by global labels. Used in the label field, a global label ends the current local scope and opens a new one at the same level.

If there is only one block in a source file, then the value of any particular local label can be accessed only between the two global labels it is surrounded by (or, at the extremes, between a global label and the start or end of the file). If such a source file had no global labels, any local label in it would have to be unique.

Nested local scopes are also created by the expansion of macro , repeat and while blocks.

In segmented source files, each use of a segment fragment creates a nested local scope while that fragment is active.

All these scopes follow the same rules as the original file-level local scope. That is, they can be subdivided by global labels and any local labels in a subdivision must be unique.

Examples

Page Top


Variable

Variable labels have global scope. The current value represented by one of these labels can be accessed from anywhere in the source code file(s).

Variable labels, as their name implies, are not fixed. The value represented by one of these labels can be changed at any time by using it in the label field of any source code line which allows labels.

Variable label names are by default unique. Any use of a particular variable label name is considered to refer to the same variable label.

References to variable labels normally represent the value they were most recently assigned. Thus variable labels in expression should usually be used only for backward references. That is, they should appear in a label field before they are used in an expression field, so that they have a known value.

HXA does permit forward reference to variable labels, but this useage is obscure and difficult to use successfully.

Examples

Page Top


Branch Target

Branch target labels (also called anonymous or unnamed labels) have global scope. The value represented by one of these labels can be accessed from anywhere in the source code file(s).

Branch target labels are fixed. Once assigned, their values cannot be changed.

Branch target label names are not unique. There are only three names: plus sign ('+'), minus sign ('-') and colon (':').

A plus sign marks its location as a forward target, a minus sign as a backward target, and a colon as both a forward and backward target. The plus and minus signs may also be used together ('+-' or '-+') to mark a location as both a forward and backward target.

To mark a source code line as a branch target, use a branch target name in the label field. There are no restrictions on how often any of the three names may be used. Each time a branch target label is found in the label field, HXA associates it with a unique internal name.

The terms forward and backward in this context mean where in the source code these names appear in relation to references to them in the expression fields of other source code lines. If a name appears in a label field before a reference to it in an expression field, the reference is backward and the name must be either minus sign or colon. If a name appears in a label field after a reference to it in an expression field, the reference is forward and the name must be either plus sign or colon.

As there name implies, branch target labels are meant to serve as the destination points of program control branches. Branch target labels relieve the programmer of the burden of creating a unique label name for what is frequently a one-time-only use.

Branch target labels most often appear on a source code line either by themselves or together with a processor instruction mnemonic. Thus the value of the name is usually the current value of the program counter.

HXA actually permits branch target labels to be used with any pseudo opcodes which accept labels, but this useage is unusual and generates a warning. If a branch target label really is meant to refer to the location of a pseudo opcode, the warning can be avoided by placing the label on a line by itself and the pseudo opcode on the next following line.

Note that colons (or plus-minus pairs) can be used for all branch target labels if desired. There is no penalty for not using a forward/backward target label in both directions. More generally, there is no penalty for not using any named or unnamed label in any expression at all.

In the expression field references to branch targets are considered references to numeric labels .

Examples

Page Top


Predefined

All versions of HXA define at least one label:

Name Value
__HXA__ TRUE

This label is intended mainly for use in "IFDEF" conditional blocks, but may be used in any legal context.

Processor-specific versions of HXA may also define additional predefined labels. These can be used for identifying the supported processor or processor family or to prevent register names from being used as labels.

All predefined labels have a value of TRUE and are available for use as soon as HXA begins reading source code.

Page Top


Expressions

HXA supports both numeric and string expressions. Legal expressions consist of at least one operand and zero or more operators . Operands and operators may be separated by spaces for clarity.

Page Top


Numeric Expressions

HXA performs numeric expression evaluation with a final result in the range of a 32-bit integer, signed or unsigned.

Numeric Range
- Binary Decimal Hexadecimal
Signed Minimum %100000000000000000000000000000000 -2147483648 $80000000
Unsigned Minimum %000000000000000000000000000000000 0 $00000000
Signed Maximum %011111111111111111111111111111111 2147483647 $7FFFFFFF
Unsigned Maximum %111111111111111111111111111111111 4294967295 $FFFFFFFF

It may be observed that the normal count of values that can be represented by 32 bits is 2^32, and that the range from signed minimum to unsigned maximum is half again as large. It is the underlying run-time package used by HXA which permits this. Values outside the range of a signed integer are maintained as signed double precision floating point. When necessary HXA renders these in the bit patterns appropriate for 32-bit unsigned integers.

Note that use of double precision floats means intermediate overflow of 32 bits in calculations does not result in "wrapping" of values from positive to negative or vice-versa. That is, arithmetic is not modular. This facility should be used carefully or not at all.

Page Top


Octet Extraction Order

During file output HXA extracts all or part of 32-bit numeric values based on the -BIT-- pseudo ops associated with them.

If the four 8-bit octets of a 32-bit value are labeled "3-2-1-0" from most to least significant, then the default extraction sequences are:

Octets Appear in Output in the Order
- LSB Processor MSB Processor
-BIT08-- 0 0
-BIT16-- 0-1 1-0
-BIT24-- 0-1-2 2-1-0
-BIT32-- 0-1-2-3 3-2-1-0

Custom extraction orders can be specified using the "ASSUME" psedo op. Specify the base -BIT-- or -BIT--R family name and the desired order:

Examples

Notes

Page Top


String Expressions

String expressions yield string results (note that many operators on string operands have numeric results). The only string operation is concatenation , which joins two strings together to form a longer one. HXA has no explicit concatenation operator; concatenation is implied by placing two string operands adjacent to each other.

The results of string expressions may be up to at least 8000 characters in length. The underlying run-time package used by HXA may permit longer strings, but this is not guaranteed in all versions of HXA.

Page Top


Operands

There are three basic kinds of operands: literals, symbols and functions . Each operand kind comes in two or more types.

Page Top


Literals


Numbers

HXA recognizes binary, decimal and hexadecimal numeric literals in Motorola, Intel and C/C++ formats. For hexadecimals, the numbers 10 to 15 are represented by the characters 'A-F' or 'a-f' (case doesn't matter).

In general, the base chosen to express a numeric literal should make its intended use as clear as possible. Leading zeros are always ignored, so they may be used freely to help clarify the use intended.

Numeric literals are always interpreted as unsigned integers. Negative values are obtained by applying the unary negate operator ('-').

Integer numeric literals may be used wherever a numeric value is expected.

Example: The Number One Hundred Ninety-two
- Binary Decimal Hexadecimal
Motorola %11000000 192 $C0
Intel 11000000B 192D 0C0H
C/C++ 0b11000000 192 0xC0

Intel-format number notes:

C/C++ format number notes:

Examples

Page Top


Characters

A character literal is a single character code delimited by single quote marks ("'"). A single quote mark may itself be included in a character literal by escaping it.

A character code may be specified by either its printable ASCII representation or an escape sequence . The numeric value of a printable character is normally its position in the ASCII collating sequence. If the value of a character code according to the current character set translation is desired instead, it can be obtained using the XLATE() function.

Character literals may be used wherever a numeric value is expected.

Examples

Page Top


Strings

A string literal is a sequence of zero or more character codes delimited by double quote marks ('"'). A double quote mark may itself be included in a literal string by escaping it.

Each character code may be specified by either its printable ASCII representation or an escape sequence . The numeric value of each printable character is normally its position in the ASCII collating sequence.

String literals may be used wherever a string value is expected. Note that when used with string comparison and pattern matching operators, string literals are not affected by the current character set translation .

String literals may also be used in some circumstances where a numeric value is expected. In such cases a string is converted to a numeric value by an implied comparison against the null string before any numeric operator is applied.

Examples

Page Top


Regular Expressions

A regular expression pattern literal is a sequence of one or more character codes delimited by forward slash ('/') characters. A forward slash may itself be included in a regular expression by escaping it.

Only pattern match operators apply to regular expressions. Any escape sequences in a regular expression are evaluated before a pattern match is attempted.

Regular expression patterns provide a compact and flexible way to specify multiple partial or exact matches to a string. They are provided by HXA mainly as an aid to macro creation.

A full tutorial in the use of regular expression patterns is beyond the scope of this document. Briefly, a regular expression pattern consists of normal characters, which match those characters, and meta-characters , which match character types, groups or positions. Most of the power of regular expressions is provided by meta-characters singly or in combination with others.

For a fuller explanation, consult any AWK/GAWK/NAWK reference.

Partial List of Recognized Meta-Characters
To match Notation "abc" Matches "abc" does NOT Match
Any single character '.' /a.c/ /xy./
Any character in a set [(set)] /[cde]/ /[xyz]/
Any character not in a set [^(set)] /[^ghe]/ /[^abc]/
Zero or more occurances of regular expression '*' /ax*/ /axy*/
One or more occurances of regular expression '+' /ab+/ /ax+/
Zero or one occurance of regular expression '?' /abcd?/ /abcd?e/
At start of string '^' /^abc/ /^abcd/
At end of string '$' /abc$/ /ebc$/
Either of two regular expressions '|' /abc|def/ /def|wxyz/

Notes

Regular expression literals may be used wherever a regular expression is expected.

Examples

Page Top


Escape Sequences

Escape sequences can be used in character constants, string literals and regular expression patterns to represent character codes that are difficult to specify otherwise (eg., control codes). There are two types of escape sequences, mnemonic and hexadecimal .

Mnemonic Escape Sequences

Mnemonic escapes take the form of a backslash ('\') followed by a printable character.

Mnemonic Escape Sequences
Character Name Sequence
0 null \0
BS backspace \b
FF formfeed \f
NL newline \n
CR carriage return \r
space space \s
HT tab \t
VT vertical tab \v

Any other characters following a backslash simply become themselves. This can be used to "turn off" the normal interpretation of certain characters.

Example Escaped Interpretations
Sequence Indicates Commonly Used
\, a comma in the expression field
\" a double quote mark within literal strings
\\ a single backslash within literal strings

Hexadecimal Escape Sequences

Hexadecimal escapes take the form of a backslash ('\') followed by a hexadecimal number in Motorola, Intel or C formats. When a hexadecimal escape is recognized the longest possible sequence of successive legal hexadecimal digits will be accepted, but at most only the final two will determine the value of the sequence. That is, the hexadecimal value can be considered as being bit-wise ANDed with the hexadecimal value $FF, producing a value in the range $00-FF.

Example Hexadecimal Escape Sequences
Decimal Motorola Escape Intel Escape C Escape
12 \$00C \0CH \0x0C
128 \$80 \0080H \0x80
254 \$FE \0FEH \0x12345FE

Examples

Page Top


Symbols


Numeric Labels

Global , local and variable numeric labels may be used wherever a numeric value is expected. When referenced, the value of the label is used during evaluation.

References to branch target labels in an expression consist of a colon (':') character immediately followed by one or more plus ('+') or minus ('-') signs. Sequences of plus signs designate forward references, while sequences of minus signs designate backward references.

For example, in an expression ' :+ ' refers to the next forward branch target label from the current position, ' :++ ' to the second, ' :+++ ' to the third, and so on. The expression ' :- ' refers to the most recent preceeding backward branch target label, ' :-- ' to the one before that, and so on.

HXA is not confused by branch target references of any length or distance, but programmers may find that beyond the nearest three or so in either direction they become difficult to follow in source code.

With the colon prefix, branch target references can be used in any numeric expression (although they may need to separated from an immediately following plus or minus sign by a space). If a branch target reference is the only term in an expression (ie., it appears alone without any other operators or operands), then the colon prefix is optional and may be omitted.

Examples

Page Top


String Labels

Global , local and variable string labels may be used wherever a string value is expected. When referenced, the value of the label is used during evaluation.

String labels may also be used in some circumstances where a numeric value is expected. In these cases a string value is subject to an implied comparison against the null string before any numeric operator is applied.

Examples

Page Top


Program Counter

The current value of the program counter is represented in expressions by either an asterisk ('*') or a dollar sign ('$').

The minimum program counter value is zero. The maximum is between 2^8-1 and 2^32-1, depending on the processor in use.

The program counter value may be used wherever a numeric value is expected.

Examples

Page Top


Forward Reference

A symbol is forward referenced when it is used as an operand in an expression but its actual value is not known at that time.

In a monolithic program only labels have this property. It is assumed that sooner or later the label will appear in the label field and thereby acquire a known value.

In a segmented program, every segment that is not absolute origin has only unknown values for both its labels and its program counter until after the first pass is complete. It is assumed that at that time their values will become fixed.

HXA allows forward reference in any construct which ultimately generates code or data of a known size, such as instruction opcodes or "BIT--" pseudo ops. HXA saves any partially evaluated expression and completes evaluation during the second pass. At this point all program counters have been made absolute and the value of all labels is known.

HXA forbids forward reference whenever the value of an expression must be known during the first pass. These situations include conditional pseudo ops, because HXA must make a decision when the expression is first encountered. Other pseudo ops such as "STRING--" and "HEX" advance the program counter by an amount that must be known during the first pass, so they too do not allow forward reference.

Page Top


Functions

Conventions

Argument Types

Page Top


CHR$()

Useage: CHR$( num_expr )

CHR$() returns a string of length one whose single character has the value num_expr & $FF . The bitwise-AND ensures that the value will fit in a single 8-bit character.

CHR$() is not affected by character set translation .

CHR$() is the inverse of ORD() .

Examples

Page Top


CPU$()

Useage CPU$()

CPU$() returns the name of the current processor as an uppercase string. If a processor has not yet been specified (by using the CPU pseudo opcode), CPU$() returns the null string.

Examples

Page Top


DEFINED()

Useage: DEFINED( name$ )

DEFINED() returns logical TRUE if its argument is a currently defined macro , otherwise logical FALSE.

A non-fatal error occurs if name$ is a string expression which does not evaluate to the form of a global name. The expression containing DEFINED() is treated as incompletely evaluated.

Examples

Page Top


EMPTY()

Useage: EMPTY()

EMPTY() returns logical TRUE if the user string stack is empty, otherwise logical FALSE.

Examples

Page Top


FILE$()

Useage: FILE$()

FILE$() returns the base name of the current source file, either root or include, as an uppercase string. No path or directory information is included.

Examples

Page Top


FORWARD()

Useage: FORWARD( str_expr$ )

FORWARD() returns logical TRUE if str_expr$ , converted to a numeric expression, contains one or more forward references , otherwise logical FALSE.

A non-fatal error occurs if str_expr$ cannot be converted to a legal numeric expression. The expression containing FORWARD() is treated as incompletely evaluated.

Because a label by itself is a legal expression, FORWARD() can be used to determine if a numeric label is in the symbol table. FORWARD() returns FALSE if it is, TRUE if it is not.

Used in the manner, FORWARD() is similar to LABEL() , but returns the opposite sense. Unlike LABEL() , FORWARD() works for any numeric label type, not just globals.

Examples

Page Top


INDEX()

Useage: INDEX( str_expr1$, str_expr2$ [, num_expr] )

INDEX() returns the leftmost starting index of str_expr2$ in str_expr1$ .

If str_expr2$ does not occur in str_expr1$ , the result is zero.

If either string argument is the null string, the result is zero.

If num_expr is not present, the search begins at index one (the first, or leftmost, character of str_expr1$ ).

If the absolute value of num_expr is between one and LEN( str_expr1$ ) inclusive, the search begins using that value as the starting index. If num_expr is positive the index is counted from the start of the string toward its end. If num_expr is negative the index is counted from the end of the string toward its start.

For any other value of num_expr the result is zero.

Examples

Page Top


INDEXR()

Useage: INDEXR( str_expr1$, str_expr2$ [, num_expr] )

INDEXR() function returns the rightmost starting index of str_expr2$ in str_expr1$ .

If str_expr2$ does not occur in str_expr1$ , the result is zero.

If either string argument is the null string, the result is zero.

If num_expr is not present, the search begins at index LEN( str_expr1$ ) (the last, or rightmost, character of str_expr1$ ).

If the absolute value of num_expr is between one and LEN( str_expr1$ ) inclusive, the search begins using that value as the starting index. If num_expr is positive the index is counted from the start of the string toward its end. If num_expr is negative the index is counted from the end of the string toward its start.

For any other value of num_expr the result is zero.

Examples

Page Top


LABEL()

Useage: LABEL( name$ )

LABEL() returns logical TRUE if its argument is a global numeric name currently present in the symbol table, otherwise logical FALSE.

A non-fatal error occurs if name$ is a string expression which does not evaluate to the form of a global name. The expression containing LABEL() is treated as incompletely evaluated.

LABEL() interrogates the symbol table directly, but only works for global numeric labels. Because a label by itself is a legal expression, FORWARD() can be used to indirectly determine the existence of any numeric label tpe.

Examples

Page Top


LEN()

Useage: LEN( str_expr$ )

LEN() returns the number of 8-bit character codes in str_expr$ .

Examples

Page Top


MATCH$()

Useage: MATCH$( str_expr$, regex [, num_expr] )

MATCH$() returns the leftmost substring of str_expr$ that matches the regular expression pattern regex . If regex does not match str_exrpr , the result is the null string.

If num_expr is not present, the search begins at index one (the first, or leftmost, character of str_expr$ ).

If the absolute value of num_expr is between one and LEN( str_expr1$ ) inclusive, the search begins using that value as the starting index. If num_expr is positive the index is counted from the start of the string toward its end. If num_expr is negative the index is counted from the end of the string toward its start.

For any other value of num_expr the result is the null string.

Examples

Page Top


MESG$()

Useage: MESG$( str_expr$ )

MESG$() returns the full text of any message HXA can display.

Str_expr$ is an index into the table of messages . If str_expr$ is not found, the "BadMsg" index message is returned with str_expr$ flagged as part of the text.

Examples

Page Top


MID$()

Useage: MID$( str_expr$, num_expr1 [, num_expr2] )

MID$() returns a substring of str_expr$ .

If str_expr$ is the null string, the result is the null string.

If the absolute value of num_expr1 is between one and LEN( str_expr$ ) inclusive, the substring begins using that position as the starting index. If num_expr1 is positive the index is counted from the start of the string toward its end. If num_expr1 is negative the index is counted from the end of the string toward its start.

For any other value of num_expr1 the result is the null string.

If num_expr2 is not present or has a value greater than the number of characters in str_expr$ from the start position to its end, the returned substring consists of all characters of str_expr$ from the start position onwards.

If num_expr2 is present and has a value between one and the number of characters in str_expr$ from the start position to the end inclusive, the returned substring consists of num_expr2 characters of str_expr$ beginning at the start position.

If num_expr2 is less than one the result is the null string.

Examples

Page Top


ORD()

Useage: ORD( str_expr$ [, num_expr] )

ORD() returns the 8-bit numeric value of a character in str_expr$ .

If str_expr$ is the null string, ORD() returns zero.

If num_expr is not present, the first character of str_expr$ is used.

If the absolute value of num_expr is between one and LEN( str_expr1$ ) inclusive, the character at that index is used. If num_expr is positive the index is counted from the start of the string toward its end. If num_expr is negative the index is counted from the end of the string toward its start.

For any other value of num_expr the result is zero.

ORD() is not affected by character set translation .

ORD() is the inverse of CHR$() .

Examples

Page Top


PEEK$()

Useage: PEEK$( [num_expr] )

PEEK$() returns an entry from the user string stack without removing it from the stack.

If the optional num_expr argument is not present, PEEK$() returns the topmost entry on the stack (ie., the string most recently placed on the stack).

If num_expr is present and has a value between one and the number of stack entries inclusive, the entry at that index is returned. The topmost entry has an index of one, the entry "under" the topmost has an index of two, and so on. The bottom entry (ie., the first one placed on the stack) has an index equal to the total number of entries currently on the stack.

A non-fatal error occurs if num_expr does not correspond to a stack entry (eg., is negative or greater than the current number of entries). The expression containing PEEK$() is treated as incompletely evaluated.

Examples

Page Top


POP$()

Useage: POP$()

POP$() returns the topmost entry on the user string stack and removes it from the stack.

POP$() is the complement of the PUSHS pseudo op, which places strings on the user stack. For every use of POP$(), there must be an earlier one of PUSHS. The numbers must balance by the end of the first pass.

It is an error to use POP$() on an empty stack.

Examples

Page Top


SEG--()

Useage: SEG--( name$ )

Variants

SEGBEG() returns the absolute start address of segment name$ . That is, the address that contains the first byte used by name$ .

SEGEND() returns the absolute end address plus one of segment name$ . That is, the address following the last byte used by name$ . Note that SEGEND() equals SEGBEG() if nothing has ever caused the segment program counter to increment.

SEGLEN() returns the length of segment name$ . That is, the value of SEGEND() - SEGBEG().

SEGOFF() returns the byte offset of segment name$ from the first segment. That is, the sum of the lengths of all data-containing segments before segment name$ in the output sequence. It is the same as the zero-based byte offset of segment name$ from the start of a raw binary output file.

It is an error to use SEGOFF() on uninitialized segments. They do not appear in output files and thus have no meaningful offset value.

name$ may be a forward reference to a segment which has not yet been encountered.

A non-fatal error occurs if name$ is a string expression which does not evaluate to the form of a global name. The expression containing SEG--() is treated as incompletely evaluated.

Examples

Page Top


STR$()

Useage: STR$( num_expr )

STR$() converts num_expr to a string consisting of its decimal representation.

A non-fatal error occurs if num_expr is not in the range of a signed or unsigned 32-bit integer. The expression containing STR$() is treated as incompletely evaluated.

Examples

Page Top


TIME$()

Useage: TIME$()

TIME$() returns the current time as a string in the form:

"Sat May 28 17:49:30 2011"

Examples

Page Top


TOLOWER$() and TOUPPER$()

Useage: TOLOWER$( str_expr$ ) Useage: UPPER$( str_expr$ )

TOLOWER$() returns a string the same as str_expr$ , except that any upper case alphabetic characters have been converted to lower case.

TOUPPER$() returns a string the same as str_expr$ , except that any lower case alphabetic characters have been converted to upper case.

Examples

Page Top


VAL()

Useage: VAL( str_expr$ )

VAL() converts str_expr$ to a numeric expression and evaluates it. The converted expression may use forward reference in any context it is normally allowed.

A non-fatal error occurs if str_expr$ cannot be converted to a legal numeric expression. The expression containing VAL() is treated as incompletely evaluated.

Examples

Page Top


VER() and VER$()

Useage: VER()

Useage: VER$()

VER() has no arguments and returns the HXA version number.

This value is decimal coded by nybbles (4-bits), or BCD encoding.

Bit Interpretation

Examples:

It is unlikely that 99,999 major versions will ever be released.

VER$() has no arguments and returns the HXA version name in the form:

"HXA v0.200"

Examples

Page Top


XLATE()

Useage: XLATE( num_expr )

XLATE() returns the numeric value at index num_expr & $FF in the current character set translation table. The bitwise-AND ensures the index is always within the range zero to 255, the size of the translation table.

Examples

Page Top


Operators

HXA provides operators which work with numeric, string and regular expression operands. Results can be numeric or string (logical operator results are either zero (FALSE) or one (TRUE)).

Each operator has an associated precedence which determines the order in which operators are applied to operands. In the standard algebraic manner, groups of operands and operators inside pairs of parentheses will be evaluated before those outside, and sets of parentheses nest.

Although some assembly languages use pairs of parentheses to indicate address indirection, this usually does not cause HXA any difficulty. When used as address indirection indicators, parentheses normally surround the entire expression of interest. The value of an entire expression surrounded by parentheses is no different than the value of the same expression not surrounded by parentheses, so no special treatment is required by HXA.

Page Top


Operator Precedence

Operators are arranged in order of precedence, from highest to lowest. Those of higher precedence are evaluated before those of lower precedence.

Operators grouped together have equal precedence.

Expression Operators
Operator Notation Result Type
--- --- ---
Built-in Functions F() Any
--- --- ---
String Concatenation S1 S2 String
--- --- ---
String Equal S1 == S2 Logical
String NOT Equal S1 != S2
String Less Than S1 < S2
String Greater Than S1 > S2
String Less Than or Equal S1 <= S2
String Greater Than or Equal S1 >= S2
--- --- ---
String Matches Regular Expression S ~ RE Logical
String NOT Match Regular Expression S !~ RE
--- --- ---
Unary Plus +N Numeric
Unary Minus -N
Logical NOT !N Logical
Bitwise NOT ~N Numeric
Extract Bits 0..7 <N
Extract Bits 8..15 >N
Extract Bits 16..31 ^N
--- --- ---
Multiply N1 * N2 Numeric
Divide N1 / N2
Remainder (aka Modulus) N1 % N2
--- --- ---
Add N1 + N2 Numeric
Subtract N1 - N2
--- --- ---
Left Shift N1 << N2 Numeric
Right Shift N1 >> N2
--- --- ---
Less Than N1 < N2 Logical
Greater Than N1 > N2
Less Than or Equal N1 <= N2
Greater Than or Equal N1 >= N2
--- --- ---
Equal N1 == N2 Logical
NOT Equal N1 != N2
--- --- ---
Bitwise AND N1 & N2 Numeric
--- --- ---
Bitwise Exclusive OR N1 ^ N2 Numeric
--- --- ---
Bitwise Inclusive OR N1 | N2 Numeric
--- --- ---
Logical AND N1 && N2 Logical
--- --- ---
Logical OR N1 || N2 Logical
--- --- ---
Conditional cond_expr ? true_expr : false_expr Any

Notes:

Examples

Page Top


Unary Operators

Consecutive unary operators of equal precedence are evaluated right-to-left, rather than left-to-right.

The unary plus operator yields the absolute value of its operand.

The "bit extract" operators ('<', '>' and '^') are essentially shorthand for a right shift (to move the bits of interest to the least significant bit positions) followed by a bitwise AND (to set the bits not of interest to zero). The resultant value is a full 32 bits long (and usually a positive integer).

The "bit extract" operators are affected by non-standard byte sizes . In general, '<' always refers to the least significant byte, '>' to the next significant byte, and '^' to the most significant word. These concepts change when the size of a "byte" changes.

If unary operators are applied to string operands, the strings are implicitly compared to the null string before the operator is applied. The final result is numeric.

Page Top


Logical Short Circuit

The logical operators AND (&&) and OR (||) generally have the form cond_expr1 op cond_expr2 . If the result of op can be determined by evaluating just cond_expr1 , these operators short circuit , skipping over cond_expr2 without evaluating it.

For example, if cond_expr1 has a value of zero, the result of logical AND must be zero whatever the value of cond_expr2 is. Thus there is no need to evaluate it.

The types of cond_expr1 and cond_expr2 must match, both being either numeric (TRUE if non-zero) or string (TRUE if non-null).

Page Top


Ternary Conditional

The ternay conditional cond_expr ? true_expr : false_expr accepts multiple expression types in all branches.

Cond_expr may be either numeric (TRUE if non-zero) or string (TRUE if non-null).

True_expr and false_expr must both have the same type. They can be numeric, strings, global names or regular expressions, as long as their type is correct in context.

In some cases a true_expr or false_expr or both may be coerced to the expected type. For example, numbers to strings or strings to global names.

Page Top


Undetected Errors

In some cases an expression may contain an error which might not be detected by HXA. Undetected errors may be of two general kinds, parse and unevaluable .

A parse error occurs when an expression is malformed. In some cases HXA may not detect this because no parse is attempted. For example, in false "IF" conditional branchs HXA does not attempt to parse any expression following a nested "IF" or "ELSEIF" pseudo opcode because no result of any subsequent evaluation can change a false branch to true.

An unevaluable error occurs when an expression parses properly but can never be fully evaluated (eg., it contains an unresolvable forward reference or a division by zero). In some cases HXA may not detect this because evaluation is never attempted. The logical operators "&&" and "||" and the ternary operator "?:" can cause part of the expression they appear in to be skipped over during evaluation. HXA does not determine whether or not skipped-over parts can be evaluated.

Page Top


Caching

HXA handles expressions in two phases. Each expression is first converted to an internal form. If that succeeds without error, the internal form is then evaluated.

Conversion to internal form can take a significant amount of time. If any single expression is heavily used, it usually pays to convert it once and then cache the internal form. Evaluation then happens on the quickly-fetched cached internal form.

HXA automatically caches expressions which meet two conditions. First, to increase the chance any particular expression is heavily used, it must occur inside a macro expansion. Second, to increase the chance conversion is actually time-consuming, it must have at least one operator (ie., expressions consisting of a lone operand are not cached).

HXA periodically purges its expression cache every time it reaches a certain size, in part to eliminate infrequently used cached expressions.

Programmers may take advantage of this caching strategy when designing macros. The basic idea is to minimize the number of variant expressions encountered. One way to accomplish this is to place the results of argument evaluations into variable labels, then using the variable labels within expressions in the remainder of the macro body. Since their parsing then does not change when the macro arguments change, their cached values can be used repeatedly.

Even better results can be had if the same expressions using the same variable labels can be used in multiple macros. This can frequently be easily be arranged, for example if the macros are being used to simulate a processor instruction set.

Page Top


Pseudo Opcodes

Pseudo opcodes (or pseudo ops ) appear in the opcode field of a source code line but are not processor instruction opcodes. Instead they control the assembler itself (and so are sometimes also called assembler directives ). They provide facilities such as data storage, conditional assembly, macro assembly and file inclusion.

HXA's pseudo ops may be optionally prefixed with a period ('.') or sharp ('#') character. These are allowed merely for visual distinctiveness, however. HXA disregards these prefix characters when identifying a pseudo op, so conflicts with user names should be avoided.

There are built-in aliases for many HXA pseudo ops. Programmers may use either the base form or the alias with identical results. The "PSALIAS" pseudo op allows further aliasing if desired.

Page Top


Alphabetic Ordering

Pseudo Opcodes
ABSEND ASSERT ASSUME
BIT08 BIT16 BIT16R BIT24 BIT24R BIT32 BIT32R
BYTE
COMMON CPU
DS
ECHO ELSE ELSEIF
END
ENDIF ENDMACRO ENDREPEAT ENDSEGMENT ENDWHILE
ERRFILE ERROR
EQU
EXIT EXITIF
FATAL
FILL
HEX
HEXFILE HEXBYBLOCK HEXBYSEG
IF
IFDEF IFNDEF
INCBIN INCLUDE
LINESPACE
LISTFILE LISTOFF LISTON
LONG
MACRO
MARGINS
MAXDEPTH MAXERR MAXPUTBACK MAXSTACK MAXWARN
MESGTEXT
OBJBYBLOCK OBJBYSEG OBJFILE
ORG
PAGE PAGESIZE
PADTO
PSALIAS PSNULL
PUSHS
PUTBACK PUTBACKS
RBIT08 RBIT16 RBIT16R RBIT24 RBIT24R RBIT32 RBIT32R
READONCE
RELEND RELORG
REPEAT
SHOWTIMER
SRECBYBLOCK SRECBYSEG SRECFILE
STARTTIMER STOPTIMER
SBIT08 SBIT16 SBIT16R SBIT24 SBIT24R SBIT32 SBIT32R
SEGMENT
STRING STRINGR
TITLE
UBIT08 UBIT16 UBIT16R UBIT24 UBIT24R UBIT32 UBIT32R
UNDEF UNINITIALIZED USESEGMENTS
WARN
WHILE
WORD
XLATE

Page Top


Functional Ordering

Set CPU

Set Program Counter

Assign Label Value

Data Storage

Pass Termination

Output Files

Macros and Repeat Blocks

Conditional Assembly Blocks

File Inclusion

Segments

User Messages

Limits

Program Listing

Assembler Customization

User Stack

Miscellaneous

Page Top


Reference

Conventions

Argument Types

Page Top


The Equality Idiom

Several HXA pseudo ops accept or require equality (or assignment ) arguments. The general form of these arguments are opt_strs containing a single un-escaped equals sign ('='):

The meaning is that whatever appears on the right side is assigned to whatever appears on the left side. This is similar the normal right-to-left assignment of most high-level languages.

The argument may or may not be a string expression. If it begins with a string literal, label or function it is treated as a const_expr$ . Note the argument is twice subjected to escape processing , once when it is first evaluated and once again when it is split at the equals sign.

If the argument is not a string expression it is accepted "as-is", and is not subject to escape processing.

Equality arguments are similar in many ways to sub-fields of the expression field , except that the separator character is an equals sign instead of a comma. In particular:

A difference:

Page Top


ASSERT

ASSERT conditional_expr

"ASSERT" evaluates conditional_expr and issues an error message if the result is FALSE, otherwise it is silent.

A failed assertion is reported as soon as it is known. If conditional_expr cannot be resolved and checked during the first pass, it will be during the second.

Examples

Page Top


ASSUME

ASSUME opt_str [[, opt_str]..]

"ASSUME" primarily provides a method to control several optional HXA settings. In effect this mainly substitutes a proliferation of "ASSUME" control strings for a proliferation of pseudo ops.

"ASSUME" controls some processor-independent HXA options:

If "ASSUME" does not recognize an opt_str as one of these, it is passed to the processor-specific portion of the HXA variant in use. What effect, if any, a control string has is completely arbitrary. There is no requirement that any string do anything, or that unrecognized strings trigger an error.

The documention of each HXA variant lists recognized strings and what they do.

Examples

Page Top


BIT--

[label] BIT-- num_expr [[, num_expr]..]

Variants

The "BIT--" pseudo ops store part or all of num_expr into the object code.

Num_expr is a signed or unsigned 32-bit integer value.

"BIT08" stores the least significant 8 bits, "BIT16-" the least significant 16 bits, "BIT24-" the least significant 24 bits, and "BIT32-" the entire 32 bits.

Bits not stored are ignored, so num_expr can have a value larger than the storage space alloted will hold.

By default storage of multi-byte values is in native CPU order, either least significant byte (LSB) first or most significant byte (MSB) first. The "R" suffix reverses the native order of stored bytes, so "BIT32R" used on an LSB first CPU will store the MSB first in the object code.

The "BIT--" pseudo ops require at least one numeric expression argument. Each separate expression is treated a separate 32-bit value to be stored according to the specific "BIT--" rules.

Note that some assemblers allow mixed string and numeric expressions to follow "BYTE" (or equivalent) pseudo ops. HXA does not permit this for "BIT--", but does for "STRING" .

The available "BIT--" pseudo ops are affected by non-standard byte sizes .

Examples

Page Top


BIT-- Aliases

Variants

There are built-in aliases for "-BIT--" pseudo ops.

The "-REV-" aliases reverse the native order of stored bytes.

The available "-BIT--" aliases are affected by non-standard byte sizes .

Page Top


--BYBLOCK

--BYBLOCK [filename]

Variants

The "--BYBLOCK" pseudo ops cause HXA to produce a separate output file for each contiguous group of data-containing segments of a segmented program. They have no effect in monolithic programs.

Two data-containing segments are considered contiguous if they are consecutively numbered and the ending address of the lesser is equal to the starting address of the greater. HXA continues outputting segments to the same file as long as each successive segment is contiguous with its predecessor. A non-contiguous successor causes HXA to close the current output file and open a new one.

"HEXBYBLOCK" creates text files containing object code translations of the source in Intel Hexadecimal Object File format. The start address record (if any) is written in the last file output.

"OBJBYBLOCK" produces binary files containing object code translations of the source in raw format (no additions or subtractions).

"SRECBYBLOCK" creates text files containing object code translations of the source in Motorola Hexadecimal Object File format. Every file has the required start address record, but only the last file output can have a non-zero value (if any).

If no filename is provided, the "--BYBLOCK" pseudo ops create default names based on the names of the first segment in each contiguous group (which must respect operating system conventions). They replace the filename extension (if any) with new extensions.

Replacement Filename Extensions
Pseudo Op Replacement
HEXBYBLOCK HEX
OBJBYBLOCK OBJ
SRECBYBLOCK S19|S28|S37

If a filename is provided, it is interpreted as a filename template . The template is used to differentiate each output file by tagging it with the number of its first segment.

The template must contain within it exactly one instance of a format specification. The format is a subset of the C/C++ language "printf()" format specification.

The basic specification must be one of '%0d', '%0x' or '%0X', allowing zero-filled decimal or hexadecimal numbering. A single digit character from '1' to '9' is allowed immediately after '%0' to specify a minimum field width. The template cannot lead the name but can be the extension.

Examples of legal filename templates:

An illegal filename template:

Segments are numbered according to the order in which they are first encountered in the source code. Segments numbers are reported in the segment map portion of a list file.

By default the "--BYBLOCK" pseudo ops place their output in the same directory the first source file resides in. By providing these pseudo ops with a path and filename, output files can be placed in any directory with any name.

"--BYBLOCK" pseudo ops may appear any number of times in the source code. However if any subsequent use specifies a different filename than the first use, HXA issues a warning message and ignores the new filename.

Examples

Page Top


--BYSEG

--BYSEG [filename]

Variants

The "--BYSEG" pseudo ops cause HXA to produce a separate output file for each data-containing segment of a segmented program. They have no effect in monolithic programs.

"HEXBYSEG" creates text files containing the object code translations of the source in Intel Hexadecimal Object File format. The start address record (if any) is written in the last file output.

"OBJBYSEG" produces binary files containing object code translations of the source in raw format (no additions or subtractions).

"SRECBYSEG" creates text files containing object code translations of the source in Motorola Hexadecimal Object File format. Every file has the required start address record, but only the last file output can have a non-zero value (if any).

If no filename is provided, the "--BYSEG" pseudo ops create default names based on the names of each segment (which must respect operating system conventions). They replace the filename extension (if any) with new extensions.

Replacement Filename Extensions
Pseudo Op Replacement
HEXBYSEG HEX
OBJBYSEG OBJ
SRECBYSEG S19|S28|S37

If a filename is provided, it is interpreted as a filename template . The template is used to differentiate each output file by tagging it with its segment number.

The template must contain within it exactly one instance of a format specification. The format is a subset of the C/C++ language "printf()" format specification.

The basic specification must be one of '%0d', '%0x' or '%0X', allowing zero-filled decimal or hexadecimal numbering. A single digit character from '1' to '9' is allowed immediately after '%0' to specify a minimum field width. The template cannot lead the name but can be the extension.

Examples of legal filename templates:

An illegal filename template:

Segments are numbered according to the order in which they are first encountered in the source code. Segments numbers are reported in the segment map portion of a list file.

By default the "--BYSEG" pseudo ops place their output in the same directory the first source file resides in. By providing these pseudo ops with a path and filename, output files can be placed in any directory with any name.

"--BYSEG" pseudo ops may appear any number of times in the source code. However if any subsequent use specifies a different filename than the first use, HXA issues a warning message and ignores the new filename.

Examples

Page Top


COMMON

COMMON

The "COMMON" pseudo op can be used in segmented programs to cause every fragment of a particular segment to start (or end) at the same memory address. That is, all the fragments of a common segment overlay each other. The size of a common segment is the size of its largest fragment.

"COMMON" cannot be used in segments which contain data. Use of "COMMON" implicitly flags a segment as "UNINITIALIZED" . If "COMMON" can be used in a segment it can be used any number of times.

The "COMMON" pseudo op is designed to simplify management of "scratch" memory in segmented source code. A single memory block may be re-divided by the "DS" pseudo op as convenient. That is, multiple temporary variables with names convenient for whatever routine is using them can occupy the same space (though of course not at the same time).

Common segments do not occupy any space in any output file. While they have absolute start and end addresses and lengths, they do not have any offset value.

Examples

Page Top


CPU

CPU opt_str

By default HXA does not recognize any particular microprocessor instruction set. "CPU" enables HXA to recognize the instruction set of a specific microprocessor.

A CPU can specified at any point before the first time the program counter is altered by the source code. In particular, a CPU must be specified before the first "ORG" pseudo op is encountered.

The "CPU" pseudo op can be used any number of times. If any use after the first specifies a different CPU than the first, HXA will issue a warning message and ignore it.

As currently implemented one or more CPU instruction sets are hard-coded into different versions of HXA. The specific name of an HXA executable indicates which CPU or related CPUs it is meant for. For example, HXA_T is meant for the imaginary "T_XX" processors used to test all processor-independent portions of HXA.

Examples

Page Top


DS

[label] DS const_expr

The "DS" pseudo op adds const_expr to the program counter. No object code is generated for any skipped address.

If the value of const_expr forces the program counter outside its valid range a fatal error occurs.

In monolithic programs negative values of const_expr are allowed and have the effect of decrementing the program counter, but a warning is issued.

Although "DS" itself does not store data, its use can cause data to be stored at non-consecutive addresses. There is an overall limit of 1023 on the number of times such "address jumps" are allowed in monolithic programs.

In segmented programs negative values of const_expr are a fatal error.

"DS" cannot be used in segments which contain data. If a segment is not already flagged as <UNINITIALIZED|"UNINITIALIZED">, use of "DS" implicitly does so.

"DS" is especially convenient for allocating consecutive variables which are left uninitialized at assembly time.

Examples

Page Top


ECHO

ECHO [opt_str]

If opt_str is present, the "ECHO" pseudo op copies it to stdout , the standard output file. If opt_str is not present, a blank line is output to stdout .

If an error file has been specified, the output of "ECHO" is sent there as well.

Examples

Page Top


END

Monolithic Source

[label] END [num_expr ]

Segmented Source

END [num_expr]

During its first pass HXA normally processes source code lines up through the last line of the first file it encounters (ie., the root source file named when HXA is invoked). If there are no errors, HXA then begins subsequent processing.

The "END" pseudo op can be used to immediately terminate the processing of any source file. Every following line in that file is ignored.

A label may be used in the default monolithic source organization and is assigned the current value of the program counter. In segmented source organization the program counter is invalid outside any segment, hence no label may be used.

If num_expr follows an "END" in the root file, it is assumed to represent a start address to be included in a hexadecimal output file. Whether or not any such file has actually been specified, num_expr is always evaluated and range-checked.

"END" issues warnings if:

Examples

Page Top


--END

Variants

The "--END" pseudo ops cause HXA to make segments absolute based on their ending rather than starting addresses.

"ABSEND" makes a segment absolute end , forcing it to end at const_expr . Note the last actual byte of the segment will be placed at const_expr - 1 . That is, one byte before the address represented by const_expr . If label is present it is assigned the value of const_expr . The segment program counter is not changed.

"RELEND" makes a segment relative end , forcing it to end at the absolute start address of the following segment. Note the last actual byte of the segment will have an address one byte before the start address of that successor segment.

Any segment may be absolute end, but a relative end segment cannot be the last segment nor may it immediately preceed a relative origin segment.

"ABSEND" and "RELEND" may only be used within a segment fragment. They must be used before the segment program counter has changed, but can be used any number of times after that. The const_expr of "ABSEND" must have the same value each time.

Neither "ABSEND" nor "RELEND" can be used in any segment which already has another type. They cannot be padded .

Addresses in "ABSEND" and "RELEND" segments are always relative during the first pass. The absolute addresses of the data they contain cannot be determined until their final sizes are known. Thus references to locations and labels within them are always forward references .

Examples

Page Top


ERROR

ERROR [opt_str]

The "ERROR" pseudo op enables programmer-triggered error messages.

These messages are the same in every respect as their internally triggered equivalents. They are sent to stdout and also to to the error file if one has been specified. The "ERROR" pseudo op also contributes to the running total of such messages necessary to halt assembly altogether.

The optional opt_str argument can be used to provide a more detailed description of what triggered the message. In particular, a string expression may be used to display the value(s) of one or more labels at the point of the error.

Page Top


Error Message Guidelines

While there are no hard and fast rules as to which message type is appropriate when, HXA itself generally uses these:

Examples

Page Top


EQU

Numeric Label

label EQU const_expr

String Label

label$ EQU const_expr$

Variants

The "EQU" pseudo op examines the type of the label and evaluates an expression matching that type. The result is assigned to the label.

Global and local labels can be assigned the same value any number of times. Assignment of a different value to an existing label is not allowed unless the label is variable .

Examples

Page Top


EXIT--

EXIT

EXITIF conditional_expr

The "EXIT" pseudo op unconditionally stops HXA from processing the remainder of the closest enclosing macro , repeat , or while block expansion.

The "EXITIF" pseudo op is a conditional version of "EXIT". It behaves as "EXIT" if conditional_expr is TRUE, otherwise it is ignored and processing of the current block expansion continues.

"EXIT" can also be made conditional by using it within a conditional assembly block which is itself within the body of the currently expanded block.

Both "EXIT" and "EXITIF" are legal only within block expansions.

HXA always recognizes any label attached to the pseudo op marking the end of the block whether or not processing of the block is stopped early.

Examples

Page Top


FATAL

FATAL [opt_str]

The "FATAL" pseudo op enables programmer-triggered fatal error messages. Assembly halts immediately.

These messages are the same in every respect as their internally triggered equivalents. They are sent to stdout and also to to the error file if one has been specified.

The optional opt_str argument can be used to provide a more detailed description of what triggered the message. In particular, a string expression may be used to display the value(s) of one or more labels at the point of the error.

While there are no hard and fast rules as to which message type is appropriate when, HXA itself generally uses these guidelines .

Examples

Page Top


--FILE

--FILE [filename]

Variants

By default HXA produces no output other than status and error messages, which are sent only to stdout . The "--FILE" pseudo opcodes direct HXA to produce several kinds of output files.

"ERRFILE" writes error messages to a text file in addition to stdout . This is particularly useful if there are so many error messages they cause the screen to scroll.

"HEXFILE" creates a text file containing the complete object code translation of the source in Intel Hexadecimal Object File format. The file must be further processed by a loader program before it can be executed.

"HEXFILE" is affected by non-standard byte sizes .

"LISTFILE" creates a text file containing both source code and a text representation of the object code produced. This pseudo op is useful for experimentation as well as documentation purposes.

"OBJFILE" produces a binary file containing the complete object code translation of the source in raw format (no additions or subtractions). If the source code represents an executable image, the file will also be executable.

"SRECFILE" creates a text file containing the complete object code translation of the source in Motorola Hexadecimal Object File format. The file must be further processed by a loader program before it can be executed.

"SRECFILE" is affected by non-standard byte sizes .

If no filename is provided, the "--FILE" pseudo ops create a default name based on the name of the first source file encountered. They replace the filename extension (if any) with new extensions.

Replacement Filename Extensions
Pseudo Op Replacement
ERRFILE ERR
HEXFILE HEX
LISTFILE LST
OBJFILE OBJ
SRECFILE S19|S28|S37

By default the "--FILE" pseudo ops place their output in the same directory the first source file resides in. By providing these pseudo ops with a path and filename, output files can be placed in any directory with any name.

"--FILE" pseudo ops may appear any number of times in the source code. However if any subsequent use specifies a different filename than the first use, HXA issues a warning message and ignores the new filename.

Examples

Page Top


FILL

[label] FILL const_expr [, hex_str ]

The "FILL" pseudo op inserts const_expr bytes into the object code.

Const_expr must have a value in the range one to the maximum value of the program counter plus one. Otherwise "FILL" is always ignored, and an error occurs if const_expr is not zero.

By default "FILL" inserts zero bytes ($00) into the object code. If the optional hex_str is supplied, its values are used instead. Bytes are taken from hex_str in the same left-to-right order they appear, regardless of CPU byte orientation.

"FILL" uses only as many bytes of hex_str as needed. If more are needed than hex_str supplies, it is duplicated as often as required.

"FILL" may be used in monolithic or segmented source whenever the program counter is valid. Filling appears in the object code starting at the current value of the program counter.

Segments cannot be both filled and uninitialized . A fill which causes a segment program counter to exceed its range is an error.

"FILL" is affected by non-standard byte sizes .

Examples

Page Top


HEX

[label] HEX hex_str [[, hex_str]..]>

The "HEX" pseudo op stores byte values specified by hex_str into the object code. Each hex_str must contain a even number of Ascii hexadecimal characters (0-9A-Fa-f). Each pair of characters is interpreted as one byte value to be stored.

Typically each hex_str is an "as-is" value, that is, no delimiters or other string expression markers are used that force expression evaluation. Thus the values to be stored can be determined by inspection. However any string expression may be used, as long as the result contains an even number of Ascii hexadecimal characters.

Although a hex_str may any length, using commas to separate multiple hex_strs can make inspection easier.

"HEX" processes each hex_str from left-to-right, so byte values are stored into the object code in the same order they appear in each successive hex_str .

Any hex_str may optionally contain a radix indicator, which are the only non-hexdecimal characters allowed, However "HEX" is intended mainly as a convenience for entering binary data by eliminating that requirement.

"HEX" is affected by non-standard byte sizes .

Examples

Page Top


IF..ELSEIF..ELSE..ENDIF

IF conditional_expr

[[source code]..]

[ ELSEIF conditional_expr ]

[[source code]..]

[ ELSE ]

[[source code]..]

ENDIF

A conditional assembly block consists of an unnamed group of zero or more source code lines delimited by a matched pair of "IF".."ENDIF" pseudo ops. The grouped source lines are called the body of the conditional assembly block.

Evaluation of the conditional_expr following the "IF" pseudo op controls whether or not HXA processes the body of the conditional assembly block. If it is TRUE, the body is processed. If it is FALSE, the body is skipped.

The body of a conditional assembly block may be subdivided into branches by using the optional "ELSEIF" and "ELSE" pseudo ops. At most only one branch of a conditional assembly block is ever processed.

Any number of "ELSEIF" pseudo ops may be used in a conditional assembly block to evaluate alternate conditions. The conditional_expr following "ELSEIF" is evaluated only if no previous branch has been processed, otherwise it and the entire branch are skipped. If conditional_expr evaluates as true, the branch is processed and any following branches are skipped.

The first "ELSE" pseudo op encountered allows processing of its branch only if no previous branch has been processed. After the first "ELSE" at least one branch has always been processed, so any following branches are always skipped Thus there is usually at most one "ELSE" controlling only the last branch of a conditional block.

Conditional assembly blocks may be nested to any depth by directly nesting "IF".."ENDIF" pairs.

Examples

Page Top


INCBIN

INCBIN filename_str [[,const_expr1] , const_expr2]

The "INCBIN" pseudo op causes HXA to begin reading raw data from filename_str , which is assumed to contain arbitrary binary data to be stored directly into the object code without any processing.

By default HXA reads all of filename_str into the object code. If const_expr1 is specified and is a positive integer, it represents the maximum number of bytes to read. Reading stops when const_expr1 bytes have been read or the end of file is reached, whichever occurs first. If const_expr1 is less than one, the entire file is read.

By default HXA begins reading at the start of filename_str , which is at byte offset zero. If const_expr2 is specified and is a positive integer, reading begins at byte offset const_expr2 , which is byte const_expr2 + 1 of the file. Reading continues until const_expr1 bytes have been read or the end of the file is reached, whichever occurs first. If startpos is less than one reading begins at the start of filename_str .

Note that const_expr2 cannot be specified unless const_expr1 has been also. However const_expr1 can be a negative value, which effectively forces the entire remainder of the file to be read.

Examples

Page Top


IF--DEF

IF--DEF name$

Variants

"IFDEF" and "IFNDEF" may be used instead of an IF pseudo opcode to begin any conditional assembly block . They test whether or not the global numeric label name$ is present in the symbol table. "IFDEF" is TRUE only if name$ is present. "IFNDEF" is TRUE only if name$ is not present.

Note that only the existence of name$ , not its value, is important in this context.

All variants of HXA support one or more predefined labels which can be used with these pseudo ops.

Examples

Page Top


INCLUDE

INCLUDE filename_str

The "INCLUDE" pseudo op causes HXA to begin reading source code lines from filename_str , which is assumed to be a text file containing assembly language source code. When all lines of filename_str have been read, HXA resumes reading input lines from the file that contained the "INCLUDE".

"INCLUDE" may not be used within a macro, repeat or while expansion.

An included file has its own local scope. Local labels in an include file will not conflict with labels of the same name in other source files.

File inclusion may be nested to any depth by using the "INCLUDE" pseudo op within an included file.

Because HXA accepts only one filename on its command line, multiple source files can be assembled together only by using this pseudo op within that file.

Examples

Page Top


LINESPACE

LINESPACE const_expr

The "LINESPACE" pseudo op sets the number of page lines each printed line in a listfile uses. For each line listed on a page, "LINESPACE" minus one blank lines are also printed.

The default and minimum "LINESPACE" value is one. There are no blank lines between listing lines.

The maximum allowed value is the maximum page length minus one. This is not the same as the actual page length. In particular, "LINESPACE" may have a value greater than the actual page length. This results in only one line printed on each listfile page.

"LINESPACE" may be used as many times as desired, but must have the same value each time. Use of an illegal value causes an error and line spacing retains its current value.

Examples

Page Top


LIST--

LIST-- [flagname] [[,flagname]..]

Variants

The "LIST--" pseudo ops enable or disable various listing options used by HXA to create a listfile . They also influence which source lines HXA saves during the first pass, which is done in order to create a listfile without re-reading and re-processing the entire source.

"LIST--" pseudo ops can appear any number of times in the source code file(s). Note that when a listing begins, the listing flags are in the state set by their last use in the source code.

A listing file has up to five major sections: object , labels , cross-refernce , segments and statistics .

Object Section

The object section lists all or part of the source code together with a text representation of the object code produced. The OBJECT flag controls both whether or not there is an object section at all and, if there is, whether or not particular portions of the source are listed.

The default state of the OBJECT flag is ON. In this state there is an object section, and every source and expansion line which results in object code is listed regardless of the state of any lower-priority object listing flag.

If the OBJECT flag is turned OFF at any point in the source code, there will be no object listing from that point until it is turned ON again.

If the OBJECT flag is OFF at the end of assembly there will be no object section listing at all.

Object Listing Control Flags (In order of priority)
Flag Name Lists Default State
OBJECT Source lines which produce object code ON
SOURCE Source lines which do not produce object code ON
INCLUDES Contents of "INCLUDE" files ON
MACROS Macro expansions OFF
UNTAKEN Untaken conditional branches OFF
ALLEQU Non-global EQU values OFF

Notes

Source code lines are tagged with a prefix character indicating where they came from:

Origin of Source Code Line
Prefix From
' ' root source file
'+' included source file
'^' macro expansion in root file
'>' macro expansion in included file

Many pseudo ops are displayed with associated addresses and values:

Addresses and Values
Pseudo Op Address Value
ABSEND Always Zero End Address
ASSERT Always Zero Always One
-BIT-- Program Counter 1 to 4 bytes
DS Program Counter Length
END Program Counter 1 zero byte (monolithic w/o start)
END Program Counter Start Address (monolithic w/ start)
END Always Zero Start Address (segmented w/ start)
EQU Always Zero 4 bytes (numeric)
EQU Always Zero 1 to 4 bytes (string)
ORG Org Address Org Address
ORG Always Zero Org Address (segmented second+ use)

Notes

Labels Section

The labels section lists some or all of the symbols defined during assembly. The state of the LABELS flag controls whether or not a labels section is produced. If the LABELS flag is OFF when assembly ends, then no labels section is produced.

If the LABELS flag is ON when assembly ends (the default), then four groups of names are listed in the following order:

Symbol Names Ordering
Numeric Global and Variable Alphabetic
Numeric Global and Auto Numeric
String Global, Variable and Auto Alphabetic
Macro Alphabetic

All names are listed together with a count of how often they were referred to and their final value (if applicable).

"Auto" labels appear only if the AUTOS flag is ON.

Label Listing Control Flags
Flag Name Lists Default State
LABELS Global and variable labels and macro names ON
AUTOS Internal form of local and branch target labels OFF

Cross-Reference Section

The cross-reference section lists events, line numbers and source files related to global labels and macro names.

The XREF flag controls whether or not a cross-reference section is produced. If it is OFF (the default), no cross-reference section will appear. The XREF flag may be turned ON and OFF as often as desired. Whenever it is ON, data is collected that is used to create this section.

Each global numeric label, global string label and macro name referenced while the XREF flag is ON has its own sub-section in the cross-reference section.

The first line of a sub-section lists the name and the number of times it was referenced. This is followed by detail lines for each of those references showing:

Notes

Segments Section

The segments section can appear only if a segmented source program is used. It lists the named segments in the order they appear in the object code, together with their type, start and end addresses, sizes and padding (if any).

The state of the SEGMENTS flag controls whether or not a segment map is produced for a segmented program. If it is ON (the default) the map is produced.

Statistics Section

The statistics section lists miscellaneous data concerning the current assembly. The state of the STATS flag controls whether or not a statistics section is produced. If the STATS flag is OFF when assembly ends (the default), then no statistics section is produced.

If the STATS flag is ON when assembly ends, HXA currently reports:

Global Flags

Global flags affect all other flags and/or sections.

The ALL flag sets every other flag to ON or OFF, depending on which pseudo op it follows.

The LINEWRAP flag is ON by default. Text which exceeds the allowed line width is "wrapped" to successive lines as often as needed until completely printed. If this flag is OFF at the end of assembly, text which exceeds one line is truncated at the end of the first line.

The LINENUMS flag is OFF by default. If it is ON at the end of assembly, every line of any listing is consecutively numbered at its start.

Global Flags
Flag Name Affects Default State
ALL every other flag N/A
LINEWRAP line wrapping ON
LINENUMS line numbers OFF

Alphabetical Ordering of Listing Control Flags

Name Section Type Default State
ALL N/A Global N/A
AUTOS Labels Secondary OFF
INCLUDES Object Secondary ON
LABELS Labels Master ON
LINENUMS All Global OFF
LINEWRAP All Global ON
MACROS Object Secondary OFF
OBJECT Object Master ON
SOURCE Object Secondary ON
STATS Statistics Master OFF
UNTAKEN Object Secondary OFF
XREF Cross-Reference Master OFF

Examples

Page Top


MACRO..ENDMACRO

Preferred Useage

MACRO name$ [[, ?arg[=default]]..]

[[source code]..]

[label] ENDMACRO [name$]

Alternate Useage

name MACRO [?arg[=default] [[, ?arg[=default]]..]]

[[source code]..]

[label] ENDMACRO

Variants

A macro consists of a named group of zero or more source code lines delimited by a matched pair of "MACRO".."ENDMACRO" pseudo ops. The grouped source lines are called the body of the macro.

A "MACRO".."ENDMACRO" pair is used to define a macro. Once a macro has been defined, use of its name in the opcode field of a source code line causes macro expansion . This has the effect of inserting the body of the macro into the source code at that point.

The preferred form of macro definition permits string expressions to denote name$ , but the alternate form requires a literal name . Macro names must be unique. No two macros can have the same name at the same time, nor can a macro have the same name as an existing label or opcode.

Note that if "ENDMACRO" is labeled, the label is considered to be within the body of the macro. It is duplicated each time the macro is expanded, hence global labels are discouraged here.

If "ENDMACRO" is followed by a name$ , it must match the name$ of the "MACRO" it is paired with.

Macros are an advanced assembler function. They are not necessary, but whenever a programmer uses similar sequences of source code in different places, macros can help make that code clear, correct and compact.

Macro Arguments

Macros can optionally be (and usually are) defined to accept arguments . Arguments "customize" a macro by allowing its body to be altered each time it is expanded.

There are two kinds of arguments, formal and actual . Both kinds appear in the expression field following a macro name. If a macro has more than one argument, they are separated by commas.

Formal arguments are used during macro definition. Formal text arguments names have the same form as global labels , except their type is indicated by an initial question mark ('?') character. Within the body of the macro, formal arguments may be freely used in the expression field of any source line. To use formal arguments in the label or opcode fields, the "PUTBACK" pseudo op must be employed.

Actual arguments are used during macro expansion. The first actual argument text will replace the first formal argument name wherever it appears in the macro body ( including within quoted string literals), the second actual will replace the second formal, and so on.

Replacement is performed as a straight text substitution. There is no other interpretation or understanding of the arguments. In particular, escape sequences in actual arguments are not processed until the expanded line is assembled.

The number of actual arguments provided to a macro expansion must always match the number of formal arguments declared during macro definition.

Default Actual Arguments

A default actual argument is declared during macro definition using the equality idiom (except only literal values, not string expressions, are recognized here):

During macro expansions default actual arguments will be substituted for any formal arguments which have them and for which no other actual argument has been provided.

Note that because blank sub-fields are not allowed in the expression field it is not possible to skip over default actual arguments. Thus,

Variable and Local Label Formal Arguments

In addition to text formal arguments, variable and local labels may be used as formal arguments in macro definitions. Like text formal arguments, variable and local label formal arguments may have default actual arguments.

At the start of each macro expansion the actual argument of each variable or local formal argument is treated as an expression. It is evaluated and the result assigned to the corresponding variable or local formal argument.

This is equivalent in every way to an "EQU" pseudo opcode within the body of a macro using a variable or local label on the left-hand side and a formal text argument on the right. It is essentially a short-hand method of accomplishing the same task.

At expansion time variable and local labels used as formal arguments are assigned actual argument evaluation results in the same left-to-right order they appear in the macro definition.

Thus this form of definition:

MACRO mymacro, ?myarg1, ?myarg2, ?myarg3 ]myvar1 EQU ?myarg1 @myvar2 EQU ?myarg2 ]myvar3$ EQU ?myarg3

ENDMACRO

and this form:

MACRO mymacro, ]myvar1, @myvar2, ]myvar3$

ENDMACRO

are completely equivalent.

If the listing flag ALLEQU is ON, expansions of macros with one or more formal arguments which are local and variable labels will show the results of assignments to them in the listing.

Macros and Local Scopes

Every macro expansion causes a nested local scope to be created without ending the existing one. Local labels with the same name as others outside the new local scope do not conflict with those names. Local scopes can be nested to any depth by nesting macro expansions. As each expansion ends, so does the nested local scope it created.

Macro Nesting

Macro definitions can be nested in two different ways. First, "MACRO".."ENDMACRO" pairs may be directly nested during definition. Second, a macro body may contain the name of another macro to be expanded.

Note that these two forms have slightly different expansion behavior. When expanding an outer definition of the first form, the delimiters of any inner definition are simply ignored (note this same principle prevents a macro definition from being recognized within repeat and while blocks). Because only one macro definition is expanded, only one new local scope is created.

Expanding the second form causes a new local scope to be created for each macro expansion invoked.

Examples

Page Top


MARGINS

MARGINS const_expr1, const_expr2 [, const_expr3, const_expr4]

The "MARGINS" pseudo op sets the top, right, bottom and left margins (in that order) of each page in a listfile .

Margins are the number of lines (top and bottom) or character positions (left and right) that are skipped at each page edge without being printed to. The default value of each margin is zero, meaning that lines and characters are printed flush with each page edge. This is suitable for "printing" to files meant to be loaded into a text editor, but may not be in other circumstances.

The pair const_expr1, const_expr2 sets the top and left margins, respectively. The optional pair const_expr3, const_expr4 sets the bottom and right margins, respectively.

The top and bottom margins combined must be less than the page length. The left and right margins combined must be less than the page width minus the minimum allowed width. It may be helpful to use the "PAGESIZE" pseudo op before "MARGINS".

"MARGINS" may be used as many times as desired, but must have the same values each time. Use of an illegal value causes an error and the affected parameter retains its current value.

Examples

Page Top


MAX--

MAX-- const_expr

Variants

The "MAX--" pseudo ops set limiting values on various internal counters. If a limit is exceeded assembly halts.

Const_expr can be any value, although negative values generate a warning and will cause assembly to stop the first time the limit is tested.

Limit Controls
Name Limits Default Maximum
MAXDEPTH Local Scope Nesting Depth 128
MAXERR Error Messages Reported 25
MAXPUTBACK Consecutive "PUTBACK" Lines 128
MAXSTACK User stack depth 128
MAXWARN Warning Messages Reported 50

HXA automatically opens a new nested local label scope in many circumstances, such as block expansion or file inclusion. "MAXDEPTH" controls the maximum number of nested scopes that may be open at one time.

"MAXERROR" and "MAXWARN" respectively set the maximum number of error and warning messages HXA will report before halting assembly altogether.

The "PUTBACKS" pseudo op is capable of inserting a copy of itself and its arguments into the input stream, leading to an infinite loop. "MAXPUTBACK" guards against this possibility while allowing the limit to be changed if it proves an obstacle.

"MAXSTACK" controls the number of items that may be pushed onto the user stack at any one time.

Examples

Page Top


MESGTEXT

MESGTEXT ndx=mesg [[, ndx=mesg]..]

All HXA-originated messages displayed to the user are created based on an index into a table of assembler message texts .

The "MESGTEXT" pseudo op assigns arbitrary text to an index using the equality idiom . HXA's default messages can thus be replaced by user-chosen messages.

Ndx must match an internal HXA message index exactly (ie., the match is case-sensitive).

All characters in mesg outside the range $20-$7E are converted to a printable hexadecimal representation before assignment to ndx .

Examples

Page Top


ORG

[label] ORG const_expr

Variants

The "ORG" pseudo op evaluates const_expr and assigns the result to the program counter and, if present, to label .

Depending on how and where it is used "ORG" also helps determine whether a source program is organized as monolithic or segmented .

HXA uses the program counter to determine address information for assembled code and data. Every source code line that generates code or data automatically updates the value of the program counter by the size of that code or data.

The program counter has no default value. It must be explicitly set by using an "ORG" pseudo op anywhere before the first code- or data-generating source line is encountered.

Every time the value of the program counter changes, it is checked against the legal range of values it may assume for the current CPU . Any attempt to generate code or data outside the legal range causes an error. There is no "wrapping" of program counter values from highest to lowest addresses or vice versa.

Note that because "ORG" itself changes the value of the program counter, the current CPU must be specified before "ORG" can be used.

Source Code Organization

If "ORG" appears before any "SEGMENT" or "USESEGMENTS" pseudo op, the source code is considered monolithic ("one block"). If a "SEGMENT" or "USESEGMENTS" pseudo op appears before any "ORG", the source code is considered segmented.

In monolithic source code "ORG" can be used at any time. The program counter may assume the same value more than once. All code and data is output as a single block in the same order it is defined.

There is a limit of 1023 on the number of times two consecutive object bytes can have non-consective addresses as determined by the program counter. That is, there can be no more than 1023 "address jumps" in a monolithic program.

In segmented source code "ORG" can only be used within segment fragments. In any particular segment "ORG" may be used any number of times in any number of its fragments. However every use in the same segment must have the same value each time, and only the first use actually sets the program counter. After that the program counter can only increase in value, and never repeats.

"ORG" flags the whole segment a fragment belongs to as absolute origin . Absolute origin segments are the only segment type in which backward references are possible during the first pass. Constant expressions may refer to locations and labels which are already known at the time the expression is evaluated.

"ORG" cannot be used in any segment which already has another type.

Examples

Page Top


PADTO

PADTO const_expr [, hex_str ]

The "PADTO" pseudo op inserts bytes into the object code until the program counter is a multiple of const_expr . That is, if the remainder of dividing the current value of the program counter by const_expr is non-zero, pad bytes are inserted until it is.

For example:

PADTO 2

inserts a zero byte into the output if the value of the program counter is odd, otherwise it does nothing.

Const_expr must have a value in the range one to the maximum value of the program counter plus one. Otherwise "PADTO" is always ignored, and an error occurs if const_expr is not zero.

Note that if const_expr is larger than the value of the program counter at the time padding starts, it essentially represents an absolute address to pad to, since that is where the first zero remainder will occur.

By default "PADTO" inserts zero bytes ($00) into the object code. If the optional hex_str is supplied, its values are used instead. Bytes are taken from hex_str in the same left-to-right order they appear, regardless of CPU byte orientation.

"PADTO" uses only as many bytes of hex_str as needed. If more are needed than hex_str supplies, it is duplicated as often as required.

"PADTO" may be used in monolithic or segmented source whenever the program counter is valid.

In monolithic source "PADTO" may be used any number of times with any argument values. Each time it is executed immediately. Any padding appears in the object code starting at the current value of the program counter.

In segmented source "PADTO" can be used only within fragments of absolute origin and relative origin segments. Any particular segment may use it any number of times, but it must have the same value(s) each time. Different segments may use different values for "PADTO". Padding is delayed until address resolution occurs. Any padding appears at the end of each padded segment in the object code.

Segments cannot be both padded and uninitialized .

"PADTO" is affected by non-standard byte sizes .

Examples

Page Top


PAGE

PAGE

The "PAGE" pseudo op unconditionally prints enough blank lines to fill the remainder of the current page in a listing file. The next printed line will appear at the top of the next page.

"PAGE" has no effect during assembly, in unpaginated listing files or in unlisted portions of the source code.

Examples

Page Top


PAGESIZE

PAGESIZE const_expr1 [, const_expr2]

The "PAGESIZE" pseudo op sets the width and length of a page in a listfile . Both the width and length can be set to any value from zero to 255 inclusive.

Const_expr1 controls the page width, the total number of characters that can fit across a page (including margins). The default value is 75. A page width of zero is interpreted as meaning infinite width, so that every output line is printed in its entirety without wrapping or truncation.

The page width can be altered independently of the page length.

The optional const_expr2 controls the page length, the total number of lines that can fit on a page (including margins). The default value is zero, which is interpreted as meaning all output is on one page of infinite length.

The default values are suitable for "printing" to files meant to be loaded into a text editor, but may not be in other circumstances.

"PAGESIZE" may be used as many times as desired, but must have the same value(s) each time. Use of an illegal value causes an error and the affected parameter retains its current value (although because of the error no listing will occur).

Examples

Page Top


PSALIAS

PSALIAS psop=alias [[, psop=alias]..]

The "PSALIAS" pseudo op assigns user-chosen names to existing pseudo op names using the equality idiom . A user-chosen name can then be used in place of the original pseudo op whereever it is legal to do so.

Alias names have the same form as global labels . Aliases must be unique. No two aliases can have the same name, nor can an alias have the same name as an existing label or opcode.

Examples

Page Top


PSNULL

[label] PSNULL [text [,text1]..]

The "PSNULL" pseudo op simply ignores each and every label and expression field value it may be associated with.

"PSNULL" is meant to ease porting source code to HXA. Such code may contain one or more pseudo ops for which HXA has no built-in equivalent. If any can be safely ignored, they may be aliased to "PSNULL", which will allow HXA to effectively skip them whenever encountered.

Examples

Page Top


PUSHS

PUSHS const_expr$|const_expr [[,const_expr$|const_expr]..]

The "PUSHS" pseudo op pushes its argument(s) onto the user string stack as a single entry.

"PUSHS" treats its arguments as constant expressions to be evaluated. Expressions may be either string or numeric. Numeric expressions are coerced to one-character strings by the equivalent of CHR$(const_expr & $FF) .

All arguments are concatenated together before being pushed onto the user stack. Null strings are legal.

"PUSHS" is the complement of the POP$() function, which removes strings from the user stack. For every use of "PUSHS", there must be a later one of POP$(). The numbers must balance by the end of the first pass.

Examples

Page Top


PUTBACK--

PUTBACK [text [[,text]..]]

PUTBACKS const_expr$|const_expr [[,const_expr$|const_expr]..]

Variants

The "PUTBACK--" pseudo ops "push back" their argument(s) onto the input stream, which then become the next input line.

"PUTBACK" and "PUTBACKS" can only be used within macro , repeat and while blocks. Outside of these they cause an error.

HXA normally performs a minimal amount of processing on every source code line in order to verify required syntax. The "PUTBACK--" pseudo ops satisfy this check during block definition. Processing of the remainder of these "protected" source code lines is delayed until expansion occurs.

PUTBACK

During block expansion, "PUTBACK" does nothing to its arguments except remove any whitespace between comma-separated arguments. The net effect is that the next input line read is the same as the current line except that the leading "PUTBACK" has been removed.

This allows the use of formal macro arguments in the label and opcode fields of a source line. It can also be used to permit forward reference to a macro which is not yet defined (including recursive macro definitions).

If "PUTBACK" has no argument or the argument has the form of a line HXA normally ignores (eg., a comment), it does nothing.

PUTBACKS

During block expansion, "PUTBACKS" evaluates its arguments as constant string or numeric expressions. Numeric expressions are coerced to one-character strings by the equivalent of CHR$(const_expr & $FF) . All evaluated arguments are concatenated together before being "pushed back" onto the input.

"PUTBACKS" can be used to dynamically create input lines during assembly.

"PUTBACKS" requires at least one argument. If the argument(s) evaluate to the null string, "PUTBACKS" issues a warning. If to a line HXA normally ignores (eg., a comment), it does nothing.

Examples

Page Top


READONCE

READONCE

The "READONCE" pseudo op causes any file it is used in to be silently ignored by any future "INCLUDE" pseudo op. It is meant to ensure that a particular file is included only once in an assembly no matter how many times that file appears as the operand of an "INCLUDE".

"READONCE" can be used anywhere in a file. A warning is issued if HXA detects that the file has used "INCLUDE" (or "INCBIN") before "READONCE" because of the possibility of circular file references.

"READONCE" prevents future inclusion based on the full name (including any path) of the file currently being read. It cannot prevent at least one extra inclusion for each different path to the same file supplied to "INCLUDE". Because of that possibility a warning can be issued if the base filename (the part following any path information) matches the base filename of any previously included file.

Examples

Page Top


RBIT--

[label] RBIT-- num_expr [[,num_expr]..]

Variants

The "RBIT--" pseudo ops store part or all of a signed offset_value relative to the program_counter into the object code.

The offset value is calculated as:

offset_value = num_expr - ( program_counter + data_size )

Num_expr is a 32-bit signed integer value. Program_counter is the value of the program counter at the first byte of the stored data. Data_size is the number of bytes of data stored (the same as the number of bits divided by eight).

In other words, the value of the program counter at the location immediately following the stored data is subtracted from num_expr to create the actual value stored.

"RBIT08" stores the least significant 8 bits, "RBIT16-" the least significant 16 bits, "RBIT24-" the least significant 24 bits, and "RBIT32-" the entire 32 bits.

The "RBIT--" pseudo ops perform two range checks before storing any values.

First, num_expr must be within the program counter range. That is, it must be greater than or equal to zero and less than 2^(pc_bits). For example, with a 16-bit program counter the maximum value of num_expr must be less than 2^16 (= 65536, or $10000).

Second, offset_value must fit into the storage space allowed. That is, bits not stored must be zero. Note offset_value is positive if num_expr is greater than program_counter + data_size , otherwise it is negative.

RBIT-- Ranges
Pseudo Op Min Dec Max Dec Min Hex Max Hex
RBIT08- -128 127 $00000080 $0000007F
RBIT16- -32768 32767 $00008000 $00007FFF
RBIT24- -8388608 8388607 $00800000 $007FFFFF
RBIT32- -2147483648 2147483647 $80000000 $7FFFFFFF

By default storage of multi-byte values is in native CPU order, either least significant byte (LSB) first or most significant byte (MSB) first. The "R" suffix reverses the native order of stored bytes, so "RBIT24R" used on an LSB first CPU will store the MSB first in the object code.

The "RBIT--" pseudo ops require at least one numeric expression argument. Each separate expression is treated a separate value to be stored according to the specific "RBIT--" rules.

The available "RBIT--" pseudo ops are affected by non-standard byte sizes .

Examples

Page Top


RELORG

RELORG

The "RELORG" pseudo op makes a segment relative origin . When it is made absolute it will start at the ending address of the preceeding segment. That is, one past the last address actually used by that segment.

Use of "RELORG" is optional because it is the default segment type. If a segment program counter changes before any type is explicitly declared, that segment automatically becomes relative origin. However "RELORG" can make the intention explicit, and may also help prevent accidentally setting another type later.

A relative origin segment cannot be the first segment, nor may it immediately follow a relative end segment.

"RELORG" may only be used within a segment fragment. It is the only type that does not have to be used before the segment program counter changes. It may be used any number of times in the same segment.

"RELORG" cannot be used in any segment which already has another type.

Examples

Page Top


REPEAT..ENDREPEAT

[label] REPEAT const_expr

[[source code]..]

[label] ENDREPEAT

Variants

A repeat block consists of an unnamed group of zero or more source code lines delimited by a matched pair of "REPEAT".."ENDREPEAT" pseudo ops. The grouped source lines are called the body of the repeat block.

A "REPEAT".."ENDREPEAT" pair is used to define a repeat block. Because they are unnamed (and thus cannot be referred to later), repeat blocks are expanded as soon as their definition is complete. The expansion has the effect of duplicating the body of the repeat block const_expr number of times into the source code at that point. If const_expr is less than one, the body is skipped and there is no effect.

Repeat blocks are an advanced assembler function. They are not necessary, but are particularly helpful for building tables of data.

Repeat Blocks and Local Scopes

Repeat blocks may be nested to any depth by directly nesting "REPEAT".."ENDREPEAT" pairs.

Every individual repeat expansion block causes a nested local scope to be created without ending the existing one. Each repeat expansion block creates only one local scope no matter how many times the repeat body is duplicated. As each expansion ends, so does the nested local scope it created.

Note that the const_expr controlling any repeat block is not evaluated until that block is expanded. This allows the control expression of a nested repeat block to depend on values which are set only during the expansion of a nesting block.

Repeat blocks are similar to while blocks , except with a fixed rather than conditional control expression.

Examples

Page Top


SBIT--

[label] SBIT-- num_expr [[,num_expr]..]

Variants

The "SBIT--" pseudo ops store all or part of num_expr into the object code.

Num_expr is a signed 32-bit integer value.

"SBIT08" stores the least significant 8 bits, "SBIT16-" the least significant 16 bits, "SBIT24-" the least significant 24 bits, and "SBIT32-" the entire 32 bits.

The "SBIT--" pseudo ops generate an error if num_expr will not fit into the storage space allowed. That is, bits not stored must be zero.

SBIT-- Ranges
Pseudo Op Min Dec Max Dec Min Hex Max Hex
SBIT08- -128 127 $00000080 $0000007F
SBIT16- -32768 32767 $00008000 $00007FFF
SBIT24- -8388608 8388607 $00800000 $007FFFFF
SBIT32- -2147483648 2147483647 $80000000 $7FFFFFFF

By default storage of multi-byte values is in native CPU order, either least significant byte (LSB) first or most significant byte (MSB) first. The "R" suffix reverses the native order of stored bytes, so "SBIT24R" used on an LSB first CPU will store the MSB first in the object code.

The "SBIT--" pseudo ops require at least one numeric expression argument. Each separate expression is treated a separate signed value to be stored according to the specific "SBIT--" rules.

The available "SBIT--" pseudo ops are affected by non-standard byte sizes .

Examples

Page Top


SEGMENT..ENDSEGMENT

SEGMENT name$

[[source code]..]

ENDSEGMENT [name$]

Variants

By default HXA assumes source code is organzied in a monolithic ("one block") manner. This means that it is in the same order as the physical object code to be produced.

Segments are an optional method of organizing source code in a manner convenient to the programmer while still providing complete control over the object code order.

A segment fragment consists of a named group of zero or more source code lines delimited by a matched pair of "SEGMENT..ENDSEGMENT" pseudo ops. The grouped source lines are called the body of the segment fragment.

A "SEGMENT..ENDSEGMENT" pair identifies a segment fragment as belonging to a particular named segment . All segment fragments with the same name belong to the same segment, regardless of where in the source code they appear.

A segment fragment does not necessarily have to contain code or data. If no fragment of a segment contains code or data (eg., it is used only to specify where in memory certain variables are to be placed), then that segment will not appear in the object file.

If an object file is created, all segments which have at least one fragment containing code or data will be output in the same order those segments were first encountered in the source code.

One way to control the order of all segments is to create a "segment map" near the start of the source code that simply creates one fragment for every segment to be used. The fragments can be typed here, but do not have to contain any code or data. This organization allows convenient changes to the "map" whenever necessary.

For each segment output, all the non-empty fragments of that segment will be output in the same order they were first encountered in the source code. All the non-empty fragments of the same segment thus appear as a single block in the object file. This is how the physical order of the object code may be different from the physical order of the source code which created that object.

Source Code Organization

Although in principle there is nothing to stop an assembly language program from freely mixing together executable code, constant data and variable locations in the object code, in practice these are usually separated into separate memory blocks for both safety and consistency. To accomplish this with monolithic source code often means placing constant data and variable locations far away from the executable code that will use them.

Segments offer the advantage that in the source executable code can be placed near the constant data and variable locations it will use, and in the object code these will all be cleanly separated from each other. The main disadvantage is that segments require explicit management.

Selecting Monolithic or Segmented Source Code

The decision to use a monolithic or segmented source code organization is an all-or-nothing choice. HXA does not permit the two approaches to be mixed. Programmers should choose whichever form makes their task easiest.

The default monolithic organization is chosen if the "ORG" pseudo op is used before and outside of any segment fragment. That is, if HXA encounters "ORG" before "SEGMENT" (or "USESEGMENTS" ), the organization is monolithic and no segments will be allowed.

The optional segmented organization is chosen if "ORG" is first used inside a segment fragment. That is, if HXA encounters "SEGMENT" (or "USESEGMENTS") before the first "ORG", the organization is segmented. The program counter is then invalid outside of any segment fragment, and every "ORG" used must appear within a segment fragment.

Segment Types

HXA recognizes four types of segments: absolute origin , relative origin , absolute end and relative end . Any of these types may also be flagged as common segments, which do not hold any data and are used only for variable storage.

Every segment has its own program counter, each the same size as the "CPU" program counter. Unlike a monolithic program counter, segment program counters can only increase in value. They can never be reset to go down in value or repeat themselves.

The default segment type is relative origin. All other types must be explicitly declared. It is usually convenient that a declaration appears in the first fragment of any particular segment, but not necessary. A declaration may actually appear in any fragment as long as the segment program counter has not yet changed. That is, before any code or data has been stored or the "DS" pseudo op has been used.

There must be at least one absolute segment , which can be either absolute origin or absolute end. If there is only one, it can be preceeded only by relative end segments, and can be followed only by relative origin segments.

Segments and Forward Reference

If a segment is not absolute origin, the only labels within it which have a value known during the first pass are those defined by "EQU" . The values of all other labels in such segments depend directly or indirectly on the segment program counter, which during the first pass represents an offset rather than an absolute address. Hence in expressions all use of these labels, or the segment program counter itself, are forward references .

In general this does not cause any difficulty, as HXA resolves (or forbids) these references as it does all forward references. However because all references to labels defined in non-absolute origin segments are forward, some expressions which work perfectly well in monolithic programs will fail in segmented programs.

For example, in a monolithic program the value of any label which has appeared in the label column of a source line is available for use in any expression context. But in non-absolute segments, similar labels can be used in constant expressions only if they were part of an "EQU" assignment.

Segments and Local Scopes

Segment fragments may be nested to any depth by directly nesting "SEGMENT".."ENDSEGMENT" pairs. It is legal for a fragment to nest inside another fragment of the same segment.

Every segment fragment causes a nested local scope to be created without ending the existing one. As each fragment ends, so does the nested local scope it created.

Monolithic vs. Segmented Source Code

Significant Differences
- Monolithic Segmented
Max# Segments 1023* 1023
Max# Segment Fragments n/a unlimited
Listing File no segment map default segment map
"DS" psop value can be negative value cannot be negative
"END" psop can be labelled cannot be labelled
"ORG" psop any value any time one value per absolute segment
"PADTO" psop any value any time; immediate execution; pads from current pc value one value per segment; delayed execution; pads at end of segment

Notes:

Examples

Page Top


STRING--

[label] STRING-- const_expr$|const_expr [[,const_expr$|const_expr]..]

Variants

The "STRING--" pseudo ops store characters into the object code. Each character is mapped through the current character set translation before being stored.

At least one argument is required. It must be a constant expression, but can be either string or numeric. Numeric arguments are coerced to one-character strings by the equivalent of CHR$(const_expr & $FF) .

If more than one argument is provided, all are concatenated together as one string before storage.

Object bytes are stored consecutively starting at the current program counter location. "STRING" proceeds from left to right through its (concatenated) argument(s). That is, in the order they appear as arguments. "STRINGR" processes its (concatenated) argument(s) from right to left. That is, in reverse order.

If the result of concatenation is null HXA issues a warning and no object code is created.

Note that some assemblers allow mixed string and numeric expressions to follow "BYTE" (or equivalent) pseudo ops. HXA does not permit this for "BIT--" , but does for "STRING".

Character values in strings are affected by non-standard byte sizes .

Examples

Page Top


--TIMER

--TIMER name$

Variants

The "--TIMER" pseudo ops provide programmer access to the same start, stop and elapsed time functions HXA uses to measure its own pass times. User-named timers allow comparisons of the assembly times of alternative program constructs to be made.

Names must be unique within all timers. No two timers can have the same name.

Timers are accurate only to the nearest second.

"STARTTIMER" creates a new timer and records the current time. This pseudo op may be used only once for any given timer.

"STOPTIMER" stops the named timer and records the current time. This pseudo op may be used only once for any given timer.

"SHOWTIMER" echoes the value of the named timer in "HH:MM:SS" format. If the timer is stopped, the value is the difference between its start and stop times. If the timer is not stopped, the value is the difference between its start time and the current time. This pseudo op may be used any number of times with any given timer.

Examples

Page Top


TITLE

TITLE [opt_str]

The "TITLE" pseudo op replaces the default document title of an HXA list file with opt_str .

The title appears once starting at the first printable line of the first page of a listing.

If opt_str is not provided or is the null string, the listing file will have no title but the first line will be blank.

Examples

Page Top


UBIT--

[label] UBIT-- num_expr [[,num_expr]..]

Variants

The "UBIT--" pseudo ops store all or part of num_expr into the object code.

Num_expr is an unsigned 32-bit integer value.

"UBIT08" stores the least significant 8 bits, "UBIT16-" the least significant 16 bits, "UBIT24-" the least significant 24 bits, and "UBIT32 the entire 32 bits.

The "UBIT--" pseudo ops generate an error if num_expr will not fit into the storage space allowed. That is, bits not stored must be zero.

The available "UBIT--" pseudo ops are affected by non-standard byte sizes .

UBIT-- Ranges
Pseudo Op Min Dec Max Dec Min Hex Max Hex
UBIT08- 0 255 $00000000 $000000FF
UBIT16- 0 65535 $00000000 $0000FFFF
UBIT24- 0 16777215 $00000000 $00FFFFFF
UBIT32- 0 4294967295 $00000000 $FFFFFFFF

By default storage of multi-byte values is in native CPU order, either least significant byte (LSB) first or most significant byte (MSB) first. The "R" suffix reverses the native order of stored bytes, so "UBIT24R" used on an LSB first CPU will store the MSB first in the object code.

The "UBIT--" pseudo ops require at least one numeric expression argument. Each separate expression is treated a separate unsigned value to be stored according to the specific "UBIT--" rules.

Examples

Page Top


UNDEF

UNDEF name$ [[, name$]..]

The "UNDEF" pseudo op deletes each name$ from the current set of macro definitions known to HXA.

It is not an error to delete a macro which is not currently defined.

Examples

Page Top


UNINITIALIZED

UNINITIALIZED

Variants

UNINITIALIZED alias NODATA

"UNINITIALZED" explicitly flags a segment as containing no code or data.

This pseudo op can be used any number of times within any fragment of a segment. However the first use must occur before any data is stored in any fragment of that segment or each one causes an error.

Once a segment has been flagged as uninitialized any attempt to store data in that segment is an error.

Every uninitialized segment has a starting and ending address and a length, but has no offset value in the output file because it will not be output.

The "COMMON" and "DS" pseudo ops can be used in uninitialized segments. They also implicitly flag a segment as uninitialized if they are legally used in a segment which has not already been explicitly declared to be.

Page Top


USESEGMENTS

USESEGMENTS

The "USESEGMENTS" pseudo op explicitly instructs HXA to treat the source program as segmented rather than monolithic.

"USESEGMENTS" can be used as often as desired both within and outside segments, but only the first use actually does anything. The main restriction is that "USESEGMENTS" must be used before the first "ORG" pseudo op, otherwise the source program is treated as monolithic and "USESEGMENTS" is not allowed.

Use of this pseudo op is optional because the "SEGMENTS" pseudo op implicitly performs the same task as "USESEGMENTS". However, it can help make programmer intent clearer.

Examples

Page Top


WARN

WARN [opt_str]

The "WARN" pseudo op enables programmer-triggered warning messages.

These messages are the same in every respect as their internally triggered equivalents. They are sent to stdout and also to to the error file if one has been specified. The "WARN" pseudo op also contributes to the running total of such messages necessary to halt assembly altogether.

The optional opt_str argument can be used to provide a more detailed description of what triggered the message. In particular, a string expression may be used to display the value(s) of one or more labels at the point of the warning.

While there are no hard and fast rules as to which message type is appropriate when, HXA itself generally uses these guidelines .

Examples

Page Top


WHILE..ENDWHILE

[label] WHILE conditional_expr

[[source code]..]

[label] ENDWHILE

Variants

A while block consists of an unnamed group of zero or more source code lines delimited by a matched pair of "WHILE".."ENDWHILE" pseudo ops. The grouped source lines are called the body of the while block.

A "WHILE".."ENDWHILE" pair is used to define a while block. Because they are unnamed (and thus cannot be referred to later), while blocks are expanded as soon as their definition is complete. Conditional_expr is evaluated, and if it is TRUE the body of the while block is duplicated into the source code at that point. If FALSE, the body is skipped and there is no effect.

Conditional_expr is re-evaluated each time the body has been completely processed by the assembler. As long as the result is TRUE the body is duplicated once more.

While blocks are an advanced assembler function. They are not necessary, but are particularly helpful for building tables of data.

While Blocks and Local Scopes

While blocks may be nested to any depth by directly nesting "WHILE".."ENDWHILE" pairs.

Every individual while expansion block causes a nested local scope to be created without ending the existing one. Each while expansion block creates only one local scope no matter how many times the while body is duplicated. As each expansion ends, so does the nested local scope it created.

Note that the conditional_expr controlling any while block is not evaluated for the first time until that block is expanded. This allows the control expression of a nested while block to depend on values which are set only during the expansion of a nesting block.

While blocks are similar to repeat blocks , except with a conditional rather than fixed control expression.

Examples

Page Top


XLATE

XLATE code=value [[, code=value]..]

All character codes that appear as arguments of a STRING-- pseudo op or XLATE() function are subject to translation . Character code values in the range zero to 255 are re-mapped to arbitrary values in the range zero to 255 by means of a translation table . Translation permits use of the ASCII character set in a program destined for a non-ASCII environment.

The default translation table simply maps each code value to itself. The "XLATE" pseudo op alters the translation table.

"XLATE" uses the equality idiom to specify how character codes are to be re-mapped. There are several different forms of "XLATE" arguments depending on how many character codes are to be re-mapped at one time.

Map One New Value onto One Character Code

Both code and value are either single printable characters or escape sequences . If expressed as a printable character, the ASCII value of the character is used.

Map One New Value onto a Range of Character Codes

A range is expressed as a character code, followed by a dash ('-'), followed by a character code.

HXA will issue a warning if the end of any range is less than its start, and nothing will happen.

Map a Range of New Values onto a Range of Character Codes

HXA does not complain if the two ranges are not equal in extent. If the code range is smaller, re-mapping stops when the end of the code range is reached. If the value range is smaller, its last value is repeated until the code range is complete.

Map A Range of New Values onto One Character Code

This form is legal but merely maps begvalue onto code and stops. It is equivalent to the first form listed.

Examples

Page Top


Non-Standard BYTE Sizes

The most common contemporary size of a processor's smallest addressable unit is eight bits, also commonly known as a "byte". However this is not the only possible size, and historically many processors have used other minimum addressable unit sizes.

For convenience we'll continue to call the minimum addressable unit of any processor a "byte". If we want to particularly distinguish an 8-bit byte we will refer to an "octet".

HXA can handle processor "byte" sizes of 8-, 16- and 32-bits. Which size to use is specified by the CPU descriptor during initialization.

The main documentation generally assumes a "byte" is equivalent to an "octet". This document outlines what changes when they are not the same.

Page Top


BIT-- Pseudo Ops

Base description (BIT-- form; RBIT--, SBIT-- and UBIT-- also)

The "bytes" of the base description refer to octet values.

The pseudo opcodes "-BYTE-", "-WORD-" and "-LONG-" are actually aliases for various "-BIT--" pseudo opcodes. Which "-BIT--" pseudo opcodes they alias changes depending on the byte size. Not all aliases are available in every byte size.

Alias Assignments

Byte Size vs. -BIT-- Availability
- 8 Bits Alias 16 Bits Alias 32 Bits Alias
-BIT08- Yes BYTE n/a n/a n/a n/a
-BIT16- Yes WORD Yes BYTE n/a n/a
-BIT24- Yes n/a n/a n/a n/a n/a
-BIT32- Yes LONG Yes WORD Yes BYTE

Notes

Page Top


FILL Pseudo Op

Base description

The number of bytes to fill automatically takes into account the byte size, so the description remains valid.

If the optional fill value is supplied and number of octets it contains is not an integer multiple of the byte size, the last byte will be silently padded with trailing nulls ($00) to reach it.

Page Top


HEX Pseudo Op

Base description

The "bytes" in the base description refer to octet values.

If the number of octets supplied is not an integer multiple of the byte size, the last byte will be silently padded with trailing nulls ($00) to reach it.

Page Top


INCBIN Pseudo Op

Base description

The optional numeric expressions representing how much to read and the starting file offset represent octet values, ie., "standard bytes".

If the number of octets read is not an integer multiple of the byte size, the last byte will be silently padded with trailing nulls ($00) to reach it.

Page Top


PADTO Pseudo Op

Base description

The value to pad to automatically takes into account the byte size, so the description remains valid.

If the optional pad value is supplied and number of octets it contains is not an integer multiple of the byte size, the last byte will be silently padded with trailing nulls ($00) to reach it.

Page Top


STRING-- Pseudo Ops

Base description

Characters are always octet values in the range $00-FF.

If a byte is larger than an octect, string characters will be padded with nulls ($00) to reach the byte size. The nulls will appear on the "left" or "right" of the character octet depending on whether the processor is Most Significant Byte First or Least Significant Byte First. The character octet itself will appear in the least significant position.

Page Top


Bit Extraction Operators

The "extract" operators ("<", ">" and "^") are essentially shorthand for a right shift (to move the bits of interest to the least significant bit positions) followed by a bitwise AND (to set the bits not of interest to zero). The resultant value is a full 32 bits long (and usually a positive integer).

Since HXA only supports 32-bit values, any attempt to extract bits from positions greater than 32 always yields a value of zero.

Operators

Bits Extracted for Byte Size
- 8 Bits 16 Bits 32 Bits
< 7..0 15..0 31..0
> 15..8 31..16 yields zero
^ 31..16 yields zero yields zero

Page Top


Hexadecimal Output Files

Intel Hexadecimal Object File Format Base Description

Motorola Hexadecimal Object File Format Base Description

Hexadecimal output files are modified in a non-standard way for 16- and 32-bit byte sizes. Generally, the record mark character is changed to indicate a non-standard byte size. Whatever the byte size, all addresses contained in records are correct for that size.

Page Top


Last revised: Tue Sep 17 11:22:41 2013