Extending Xassembler with directives
published: 4 April 2021 / updated 8 April 2021
Assembly directives
Let's go back to the assembly code PLUS.ASM:
.include "m328pdef.inc" .include "macros.inc" .cseg .org 0x00 PLUS: ld t0, Y+ ld t1, Y+ add tosl, t0 adc tosh, t1 ret
If we take the line of code ld t0, Y+
, we see the operand t0
which is not defined in Xassembler. Ditto for t1
t0 and t1 are defined in assembler in the macros.inc file. Extract:
.def t0 = r16 .def t1 = r17
For our first meta-assembly test, we defined t0 and t1
with constant
as follows in FORTH language:
r16 constant t0 r17 constant t1 r24 constant tosl r25 constant tosh : plus [ t0 Y+ ld, ] [ t1 Y+ ld, ] [ tosl t0 add, ] [ tosh t1 adc, ] [ ret, ] ;
Defining t0 t1 as constants is acceptable for a small example, but not valid for a large program.
Under gForth, if we define the same constant more than once, we will end up with uncontrollable values in the code to be meta-assembled.
The most elegant idea would be to create words .def .equ .set
, having the
same properties as their assembler equivalent, although the syntax is a little different. Example:
.def t0 = r16
becomes in FORTH:
r16 .def t0
The .def directive
The .def
directive defines a synonym for a registry. Here is
how is defined .def
in Xassembler.txt:
\ Defines a synonym for a register, syntax: \ R16 .def MyReg : .def ( comp: n --| exec: -- n) value ;
Example of source code in assembler:
; Register definitions .def upl = r2 ; not in interrupt .def uph = r3 ; not in interrupt .def r_zero = r5 ; read only zero .def r_one = r6 ; read only one .def r_two = r7 ; read only two .def t8 = r8 ; Not in interrupt .def wflags = r9 ; not in interrupt
rewritten in FORTH:
\ Register definitions r2 .def upl \ not in interrupt r3 .def uph \ not in interrupt r5 .def r_zero \ read only zero r6 .def r_one \ read only one r7 .def r_two \ read only two r8 .def t8 \ Not in interrupt r9 .def wflags \ not in interrupt
The .equ directive
The .equ
directive defines a symbol by assigning a value to it.
The value can be changed later. Here is
how is defined .equ
in Xassembler.txt:
\ Defines a symbol and sets its value \ later changes of this value remain possible, syntax: \ 1234 .equ test : .equ ( comp: n --| exec: -- n) >in @ >r bl word count 2dup find-name \ leave nfa or 0 ?dup if \ word defined r> drop name>int \ nfa > cfa 16 + >r \ cfa > pfa 2drop r> ! \ store value else \ word undefined drop r> >in ! drop value then ;
Example of source code in assembler:
; ***** DATA MEMORY DECLARATIONS ***************************************** .equ FLASHEND = 0x3fff ; Note: Word address .equ IOEND = 0x00ff .equ SRAM_START = 0x0100 .equ SRAM_SIZE = 2048 .equ RAMEND = 0x08ff .equ XRAMEND = 0x0000 .equ E2END = 0x03ff .equ EEPROMEND = 0x03ff .equ EEADRBITS = 10
rewritten in FORTH:
\ ***** DATA MEMORY DECLARATIONS ***************************************** $3fff .equ FLASHEND \ Note: Word address $00ff .equ IOEND $0100 .equ SRAM_START 2048 .equ SRAM_SIZE $08ff .equ RAMEND $0000 .equ XRAMEND $03ff .equ E2END $03ff .equ EEPROMEND 10 .equ EEADRBITS
Our word .equ
tests whether the symbol already exists. If the symbol does not exist
pas, it creates this symbol by assigning it the desired value. If the symbol already has
been defined, it simply modifies its value.
The .set directive
This .set
directive sets the value of a symbol. This value cannot
not be changed. No example.