ARM assembler in Raspberry Pi – Chapter 7
ARM architecture has been for long targeted at embedded systems. Embedded systems usually end being used in massively manufactured products (dishwashers, mobile phones, TV sets, etc). In this context margins are very tight so a designer will always try to spare as much components as possible (a cent saved in hundreds of thousands or even millions of appliances may pay off). One relatively expensive component is memory although every day memory is less and less expensive. Anyway, in constrained memory environments being able to save memory is good and ARM instruction set was designed with this goal in mind. It will take us several chapters to learn all of these techniques, today we will start with one feature usually named shifted operand.
We have seen that, except for load (
ldr), store (
str) and branches (
bXX), ARM instructions take as operands either registers or immediate values. We have also seen that the first operand is usually the destination register (being
str a notable exception as there it plays the role of source because the destination is now the memory). Instruction
mov has another operand, a register or an immediate value. Arithmetic instructions like
and (and many others) have two more source registers, the first of which is always a register and the second can be a register or an immediate value.
These sets of allowed operands in instructions are collectively called indexing modes. Today this concept will look a bit off since we will not index anything. The name indexing makes sense in memory operands but ARM instructions, except load and store, do not have memory operands. This is the nomenclature you will find in ARM documentation so it seems sensible to use theirs.
We can summarize the syntax of most of the ARM instructions in the following pattern
There are some exceptions, mainly move (
mov), branches, load and stores. In fact move is not so different actually.
Rsource1 must be registers. In the next section we will talk about
We will discuss the indexing modes of load and store instructions in a future chapter. Branches, on the other hand, are surprisingly simple and their single operand is just a label of our program, so there is little to discuss on indexing modes for branches.
What is this mysterious
source2 in the instruction patterns above? If you recall the previous chapters we have used registers or immediate values. So at least that
source2 is this: register or immediate value. You can use an immediate or a register where a
source2 is expected. Some examples follow, but we have already used them in the examples of previous chapters.
source2 can be much more than just a simple register or an immediate. In fact, when it is a register we can combine it with a shift operation. We already saw one of these shift operations in chapter 6. Not it is time to unveil all of them.
LSL #nLogical Shift Left. Shifts bits
ntimes left. The
nleftmost bits are lost and the
nrightmost are set to zero.
LSL Rsource3Like the previous one but instead of an immediate the lower byte of a register specifies the amount of shifting.
LSR #nLogical Shift Right. Shifts bits
ntimes right. The
nrightmost bits are lost and the
nleftmost bits are set to zero,
LSR Rsource3Like the previous one but instead of an immediate the lower byte of a register specifies the amount of shifting.
ASR #nArithmetic Shift Right. Like LSR but the leftmost bit before shifting is used instead of zero in the
ASR Rsource3Like the previous one but using a the lower byte of a register instead of an immediate.
ROR #nRotate Right. Like LSR but the
nrightmost bits are not lost but pushed onto the
ROR Rsource3Like the previous one but using a the lower byte of a register instead of an immediate.
In the listing above,
n is an immediate from 1 to 31. These extra operations may be applied to the value in the second source register (to the value, not to the register itself) so we can perform some more operations in a single instruction. For instance, ARM does not have any shift right or left instruction. You just use the
You may be wondering why one would want to shift left or right the value of a register. If you recall chapter 6 we saw that shifting left (
LSL) a value gives a value that the same as multiplying it by 2. Conversely, shifting it right (
ASR if we use two's complement,
LSR otherwise) is the same as dividing by 2. Since a shift of
n is the same as doing
n shifts of 1, shifts actually multiply or divide a value by 2n.
We can combine it with
add to get some useful cases.
You can do something similar with
ARM comes with a handy
rsb (Reverse Substract) instruction which computes
Rdest ← source2 - Rsource1 (compare it to
sub which computes
Rdest ← Rsource1 - source2).
Another example, a bit more contrived.
You are probably wondering why would we want to use shifts to perform multiplications. Well, the generic multiplication instruction always work but it is usually much harder to compute by our ARM processor so it may take more time. There are times where there is no other option but for many small constant values a single instruction may be more efficient.
Rotations are less useful than shifts in everyday use. They are usually used in cryptography, to reorder bits and "scramble" them. ARM does not provide a way to rotate left but we can do a
n rotate left doing a
32-n rotate right.
That's all for today.