# ARMv4T Assembly Pseudo-Instructions **Shortened and programmer-friendly instructions translated into real instructions for the processer by the assembler.** *Pseudo-instructions* streamlines the programming process around the limitations imposed by the hardware. ## No operation ```armasm NOP{cond} ``` - `cond` - [[ARMv4T Assembly#Conditional execution|condition]] for execution. The `NOP` or *no operation* instruction causes the processor to *do nothing*. It is typically used for timing purposes or forced memory alignment. The assembler translates it into: ```armasm MOV{cond} r0, r0 ``` ## Loading constants ```armasm LDR{cond} <Rd> =<constant> ``` - `cond` - [[ARMv4T Assembly#Conditional execution|condition]] for execution. - `Rd` - the *destination* register. - `constant` - a *32-bit* number. 32-bit constants can be loaded into registers with the inclusion of `=` along with an `LDR` instruction. As data processing instructions can only take immediate operands of a [[ARM Instruction Encoding#Immediate|subset of 32-bit numbers]], this pseudo-instruction allows *all* 32-bit numbers to be *easily available* as valid operands by placing them in available registers. The assembler handles this pseudo-instruction in two ways. ### MOV/MVN and rotation If the requested constant is representable by an *8-bit number* and an *even number of [[Bit Shift#Rotate|rotations]]* between 0 and 30, such as valid [[ARM Instruction Encoding#Immediate|data processing immediate operands]], then the assembler will use the `MOV` instruction with an optional rotation. If the requested constant is representable by the *complement* of the above *rotation method*, then the assembler will use the `MVN` instruction. >[!8-bit representable number and an even number of rotations]- > The number $4080_{10}$ is equal to $1111\;1111\;0000_{2}$. > > It can be represented by $1111\;1111_{2}=\text{FF}_{16}$ *rotated left* by 4 bits. A left rotation by $n$ bits is equivalent to a right rotation by $32-n$ bits. > > The result will be a 32-bit number with *8 leading zeros*, followed by $1111\;1111\;0000$. > > Thus, `LDR r0, =4080` is replaced by `MOV r0, #0xFF, ROR 28`. >[!Number representable as the complement of a rotated 8-bit number]- > The number $16777215_{10}$ is equal to $1111\;1111\;1111\;1111\;1111\;1111_{2}$. > > It can be represented by $1111\;1111_{2}=\text{FF}_{16}$ *rotated right* by 8 bits and then complemented. > > The right rotation will create a 32-bit number with $1111\;1111$ as its leading bits followed by *24 trailing zeros*. The complement of this will be the number required. > > Thus, `LDR r0, =16777215` is replaced by `MVN r0, #0xFF, ROR 8`. ### Literal pool If the requested constant is *not a valid operand* for the `MOV` and `MVN` instructions, then the constant must be stored in a space in the program *after the code* known as a *literal pool*. The assembly translates the pseudo-instruction to load the constant from memory through *PC-offset addressing*. >[!Number stored in literal pool]- >```armasm >func LDR r1, =0x55555555 > LDR r2, =0xFFFFFFFF > MOV PC, lr > > END >``` >The above code block is translated to the one below. Note that creation of the literal pool through the use of the [[ARMv4T Assembly#DCD|DCD]] directive and the translation of the lines `LDR r1, =0x55555555` and `LDR r2, =0xFFFFFFFF`. > >```armasm >func LDR r1, [PC, #8] > MVN r2, #0 > MOV PC, lr > > END > > literalPool DCD 0x55555555 >``` #### LTORG Literal pools are accessed by [[ARM Instruction Encoding#Pre-indexed addressing|pre-indexed addressing]] which is limited by an [[ARM Instruction Encoding#Immediate offset|offset]] that is *12-bits* long. In long programs the *default* literal pool may be unreachable. The `LTORG` directive can be used to build the current literal pool *immediately* at the location of the directive. The assembler replaces the `LTORG` line with the correct `DCD` block. >[!Untranslated and translated example]- > ```armasm > func LDR r1, =0x55555555 > LDR r2, =0xFFFFFFFF > ADD r0, r0, r2 > MOV PC, lr > LTORG > ``` > > ```armasm > func LDR r1, =0x55555555 > LDR r2, =0xFFFFFFFF > ADD r0, r0, r2 > MOV PC, lr > literalPool DCD 0x55555555 > ``` `LTORG` must be placed where the program will not *automatically enter* by PC stepping. To ensure this `LTORG` directives must be placed either: - At the end of a *subroutine*; i.e. preceded by `MOV PC lr`. - After *unconditional branch* instructions. ## Loading addresses The addresses of labels can be loaded into registers using two methods, depending on the location of the label. These pseudo-instructions removes the requirement of manually tracking label addresses. ### ADR If the label is *within* the *current section* of code and within *255 words* from the PC, then the address of the label can be loaded with: ```armasm ADR{cond} <Rd> <label> ``` The assembler automatically calculates the *number of bytes offset* between the label and the PC and translates the instruction into: ```armasm ADD <Rd>, PC, #<offset> SUB <Rd>, PC, #<offset> ``` The limitation of range is caused by the 8-bit [[ARM Instruction Encoding#Immediate|immediate operand size]]. >[!Untranslated and translated example]- > In the following code the two `ADR` lines are translated. >```armasm > start BL func > stop B stop > > func ADR r0, start > ADR r1, data > ADD r2, r2, r3 > MOV PC, lr > data SPACE 8000 > END >``` > >```armasm > start BL func > stop B stop > > func SUB r0, PC, #16 > ADD r1, PC, #4 > ADD r2, r2, r3 > MOV PC, lr > data SPACE 8000 > END >``` ### ADRL If the label is *within* the *current section* of code but not within *255 words* from the PC, then the address of the label can be loaded with: ```armasm ADR{cond}L <Rd> <label> ``` `ADRL` behaves like `ADR` except it is translated into *two* `ADD` or `SUB` instructions. ### LDR If the label is *outside* the *current section* of the code or further than 255 words from the PC, then the address of the label can be loaded with: ```armasm LDR{cond} <Rd>, =<label> ```