Pseudo
|
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<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 ALIGNIndeed, 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<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
ALIGNThe 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 <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 <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.
=
' as a short-hand version of EQUB.
NOPAs 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 <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.