Pseudo
instructions

 

The BASIC assembler and many DDE assemblers provide you with a selection of pseudo-instructions. These are instructions which are not actually understood by the processor, but are converted into something that may be understood, or otherwise used to make the code 'correct'. They exist to make your programming simpler.

 

ADR : load ADRess

   ADR<suffix> <register>, <label>
This loads the address referred into the given register:
   00008FE4                    OPT     l%
   00008FE4 E28F0004           ADR     R0, text
   00008FE8 EF000002           SWI     "OS_Write0"
   00008FEC E1A0F00E           MOV     PC, R14
   00008FF0                    .text
   00008FF0                    EQUS    "Hello!" + CHR$13 + CHR$10 + CHR$0
   00008FFC                    ALIGN

The following code has the exact same effect:

   00008FE4                    OPT     l%
   00008FE4 E28F0004           ADD     R0, R15, #4
   00008FE8 EF000002           SWI     "OS_Write0"
   00008FEC E1A0F00E           MOV     PC, R14
   00008FF0                    .text
   00008FF0                    EQUS    "Hello!" + CHR$13 + CHR$10 + CHR$0
   00008FFC                    ALIGN
Indeed, a disassembly of either of the above would show:
   *MemoryI 8FE4 +18
   00008FE4 :  E28F0004 : .. : ADR     R0,&00008FF0
   00008FE8 :  EF000002 : ... : SWI     "OS_Write0"
   00008FEC :  E1A0F00E : . : MOV     PC,R14
   00008FF0 :  6C6C6548 : Hell : STCVSTL CP5,C6,[R12],#-&120 ; =288
   00008FF4 :  0A0D216F : o!.. : BEQ     &003515B8
   00008FF8 :  00000000 : .... : DCD     &00000000

 

ADR is a useful instruction, though, as you do not need to worry about R15's offset (ie, why do we only add four?) nor do you need to calculate the offset over a block of code. Simply use ADR Rx, label and the assembler will sort it out for you using ADD, SUB, MOV or MVN as is best appropriate.
The limiting factor, however, is you can only reference within a 4096 byte range (not strictly true, it typically uses ADD or SUB with eight bits rotated by a multiple of two, but for argument's sake we'll assume the range is 4K).

Therefore...

 

 

ADRL : load ADRess Long

   ADRL<suffix> <register>, <label>
This is not supported by BASIC's assembler, though some extensions add it.

The ADRL instruction uses a combination of ADR and ADD, or ADR and SUB, to generate a wider range of addresses which may be reached. However this always uses two instructions, so a more workable arrangement may be to try to restructure your code so that a normal ADR will work.

There is also, in some assemblers, an ADRX which uses three instructions to address even more locations.

Here is a macro for ADRL that you may use to address within a 64K range:

   DEFFNadrl(register%, location%, pass%)
   REM Uses two instructions to load an address within a 64K range
   LOCAL progcnt%
   progcnt% = P%
   IF (location% > progcnt%) THEN
     [ OPT     pass% ; positive offset
       ADR     register%, (location% - ((location% - progcnt%) AND &FFFFFF00))
       ADD     register%, register%, #((location% - progcnt%) AND &FFFFFF00)
     ]
   ELSE
     [ OPT     pass%
       ADR     register%, (location% + ((progcnt% - location%) AND &FFFFFF00))
       SUB     register%, register%, #((progcnt% - location%) AND &FFFFFF00)
     ]
   ENDIF
   = 0

 

 

ALIGN : ALIGN pointers

   ALIGN
The ALIGN instruction sets P% (and, if required, O%) to be aligned on a word boundary. This is usually required following a string or one or more bytes of data, and should be used before further code is assembled.

The BASIC assembler is quite smart, and experience shows that it will deal with alignment issues for you, if you neglect to do it...

   00008FF4                    OPT     l%
   00008FF4 E28F0004           ADR     R0, text
   00008FF8 EF000002           SWI     "OS_Write0"
   00008FFC EA000004           B       carryon
   00009000                    .text
   00009000                    EQUS    "unaligned text!!!" + CHR$0
   00009012                    .carryon
   00009014 E1A0F00E           MOV     PC, R14

 

 

DCx : initialise data storage

   DCx <value>
There is no DCx instruction; the small 'x' denotes a range of possibilities. These are:
   DCB    Reserve a byte (8 bit value)
   DCW    Reserve a half-word (16 bit value)
   DCD    Reserve a word (32 bit value)
   DCS    Reserve up to 255 bytes as required by given string

   DCF    Reserve space for a floating point value (not in 'normal' BASIC assembler).
For example:
   .start_counter
     DCB     1

   .pointer
     DCD     0

   .error_block
     DCD     17
     DCS     "Uh-oh! It all went wrong!" + CHR$0
     ALIGN

 

 

EQUx : initialise data storage

   EQUx <value>
objasm does not provide the EQUx versions, but you can add them as macros if you do not like DCx.

There is no EQUx instruction; the small 'x' denotes a range of possibilities. These are:

   EQUB   Reserve a byte (8 bit value)
   EQUW   Reserve a half-word (16 bit value)
   EQUD   Reserve a word (32 bit value)
   EQUS   Reserve up to 255 bytes as required by given string

   DCF    Reserve space for a floating point value (not in 'normal' BASIC assembler).
This is exactly the same as DCx (above), simply understood by a different name.
You can use '=' as a short-hand version of EQUB.

 

 

NOP : No OPeration

   NOP
As you'll see, sometimes it is necessary to do nothing for a cycle after a mode change or the like. This is where NOP comes in, so there is a use for an instruction that does nothing!

Actually, this instruction is translated to MOV R0, R0 which does something, but it is pretty pointless and has no side effects; thus it is an admirable NOP.

Please note that some (dated) sources may suggest you use an instruction with an NV condition code, like MOVNV R0, R0. Not only is this pointless (why bother not executing it if executing it doesn't have any side effects?), but also the 'NV' condition code was been withdrawn... well, for at least a decade. With all the Thumb extensions, I would not be surprised if the bit pattern used by 'NV' meant something entirely different on newer ARM processors.

 

OPT : set assembler OPTions

   OPT <value>
This sets various assembler options; produce listing? offset assembly? ignore errors? and the like. You will find more detail in the document devoted to OPT.

Not discussed here, but OPT also has meanings to objasm. Refer to your assembler programming user guide (probably on the C/C++ DDE CD-ROM as a PDF file) for further details.

 


Return to assembler index
Copyright © 2004 Richard Murray