DirectivesBy directive we understand those commands placed in assembly code that are targeted to the Assembler, as opposite to instructions which are targeted to the computer running the resulting binary code.
Directives start with the sharp character (#) followed by the directive's name, then the argument. These three parts are separated from each other by the mean of spaces or tabs.
The following directives are currently available.
Include
Syntax:
#include FILE_NAME
This directive causes the given file (FILE_NAME) to be opened and processed immediately as if it were part of the current file. This action is recursive so further #include directives found in included file will be processed in the encountered order.
The #include's argument (FILE_NAME) is the name of a source file expected to be in the "include directory"; the later was passed explicitly in the command line (second argument) when the assembler was launched, or was automatically extracted otherwise from the source-file path (first argument) at that time.
You can also specify a full path in the #include directive. That may be the case of being using reusable code from files placed in separate directories for better organization. The assembler will realize whether the #include argument is a filename or a full path and it will act accordingly. Either case, if the file does not exist, an error will be reported.
A given file can be #included more than once. This might be used to compensate for the lack of Macros, as in the following example:
; Using reusable code for sorting a list in memory.
; The included code accepts arguments in registers d, c.
mvi d, BUFF ; List in memory to be sort out
ld c, BUFF_SIZE ; Certain var in memory holding the buffer's size
; The included code does the job...
#include /home/armando/src/lib/quick_sort.asm
Org
Syntax:
#org ADDRESS
Sets the origin address, effective since the first instruction following the directive's line. ADDRESS can be either a symbol or a numerical expression.
The following statements are valid:
START equ 0x400
#org START
#org 0x400
The following will result in error: "Illegal use of string":
#org $START
Data
Syntax:
#data EXPRESSION
This directive is useful for filling areas of memory with fixed data such as lookup tables and string messages, as illustrated below.
#define MSG_TABLE = 0x800
#org MSG_TABLE
#data $File not found
#data $Stack overflow
Starting at address 0x800 will be the (null-terminated) string "File not found" followed by the string "Stack overflow" (30 words total).
Define
Syntax:
#define SYMBOL = VALUE
This directive defines a symbol by indicating the expression (VALUE) it represents. The same can also be done with the equ construct for numeric expressions as illustrated in previous examples.
Actually, support for equ was introduced in H1ASM for compatibility with such "traditional" construct. However, the #define directive is conceptually more robust and more powerful in practice since it allows for symbolic strings too.
The previous example could also be written this way:
#define MSG_TABLE = 0x800
#define ERR_MSG_F_NOFOUND = $File not found
#define ERR_MSG_S_OV = $Stack overflow
:MSG_TABLE
#data ERR_MSG_F_NOFOUND
#data ERR_MSG_S_OV
Set
Syntax:
#set VAR = VALUE
The set directive is used to assign a value to a variable. If the variable didn't exist, it is created at that time. VALUE can be either a symbol, an expression, another variable or even the same variable (which doesn't sound too much useful but it is legal anyways).
Once a variable is created, it can be used in instructions in place of the operand, as illustrated in the following example.
#define BUFF_TAPE_1 = 0x4000
#define BUFF_TAPE_2 = 0x4100
; Call subroutine passing argument in variable:
#set @_buff = BUFF_TAPE_1
call READ_TAPE
; Call subroutine again passing a different argument in the same variable:
#set @_buf = BUFF_TAPE_2
call READ_TAPE
;
; -- SUBROUTINE --
;
:READ_TAPE
; Variable used as operand:
ld e, @_buff
Symbols and variables can not share names; failure to observe this will result in errors reported by the assembler. To overcome this limitation, naming conventions must be employed. We suggest to write symbols with uppercases and variables, written with lowercases, to start with the '@' character as illustrated in the previous example.
The need for variables comes from the lack of macros in H1ASM. In fact, you can "encapsulate" reusable generic code into separate source files, then #include it in your "client code" passing arguments through variables. Here is an example:
#set @_quick_sort_buff = BUFF_ADDR
#set @_quick_sort_buff_size = BUFF_SIZE_VAR
; The included code does the job. It uses the above variables:
#include /home/armando/src/h1_lib/quick_sort.asm
Format
Syntax:
#format FORMAT
Specifies the output format as explained in section Assembler Output.
|