Category:ARM Assembly: Difference between revisions

Content added Content deleted
m (→‎Setting Flags: clarification)
m (added more info on registers)
Line 1: Line 1:
{{stub}}{{language}}{{assembler language}}
{{stub}}{{language}}{{assembler language}}
The ARM architecture is widely used on mobile phones and tablets. It falls under the category of RISC (Reduced Instruction Set Computer) processors, which means it has fewer opcodes than a CPU such as those in the x86 family. However, it makes up for this with its speed. The ARM and its variants are used in many well-known systems such as the Raspberry Pi, Nintendo DS, iPad, and more.
The ARM architecture is widely used on mobile phones and tablets. It falls under the category of RISC (Reduced Instruction Set Computer) processors, which means it has fewer opcodes than a CPU such as those in the x86 family. However, it makes up for this with its speed. The ARM and its variants are used in many well-known systems such as the Raspberry Pi, Nintendo DS, iPad, and more.

===Instruction Size===
Every instruction that the ARM can execute is 32 bits. While other processors can have variable length instructions, the ARM does not. This means that the ARM doesn't need to parse where an instruction begins and ends, which makes it run very fast. What you might not expect is that this 32-bit instruction size includes both the actual instruction and the operands! Let's take a look at a [[Z80 Assembly]] instruction and compare it to an ARM instruction.

<lang z80>LD HL,&8040 ;bytecode is 0x21 0x40 0x80</lang>

<lang ARM Assembly>mov r4,#0x04000000 ;bytecode is 0xE3A04301</lang>

So where did the <code>0x04000000</code> go? It's actually been compressed and fit within those 4 bytes you saw earlier. The ARM is very good at decompressing it, since it's been shrunk to an 8-bit number that can be rotated by an even number of bits. Unfortunately, this compression method is a double-edged sword - some 32-bit numbers can't be compressed this way, and thus many instructions can't work with them!

===Registers===
===Registers===
The ARM has 15 main registers the programmer can use, numbered <code>R0</code> through <code>R15</code>. The higher-numbered ones have special purposes, but <code>R0</code> through <code>R10</code> can be used for anything. In other words, there are no commands that only work with <code>R0</code> (system calls notwithstanding). Registers with a specific purpose have alternate abbreviations that your assembler allows you to use for clarity.
The ARM has 15 main registers the programmer can use, numbered <code>R0</code> through <code>R15</code>. The higher-numbered ones have special purposes, but <code>R0</code> through <code>R10</code> can be used for anything. In other words, there are no commands that only work with <code>R0</code> (system calls notwithstanding). Registers with a specific purpose have alternate abbreviations that your assembler allows you to use for clarity.

Registers are much more flexible than immediate operands. Unlike immediate operands, which must be 8-bit rotateable, the ARM can simply reference a register operand by its register number. This means that any value in a register is fair game. Certain instructions such as <code>MUL</code> cannot use immediate operands at all, so loading the values you want to multiply into registers will be necessary.

In addition, registers are the only way the ARM can interact with memory. Using the <code>LDR</code> and <code>STR</code> commands, a register enclosed in square brackets becomes a pointer to the memory location of equal value. For example, if <code>R1 = 0x02000000</code>, then the command <code>LDR R0,[R1]</code> will load <code>R0</code> with the four bytes stored in memory location <code>0x02000000</code>. Many other CPUs can load directly from constant memory addresses - the ARM cannot.

Getting an address in a register can be achieved with the <code>MOV</code> command, but there are limitations to that which will be explained in detail later. It's more reliable to use <code>ADR</code> which loads a nearby address into a register. This address has to be within a certain distance from the current program counter or it can't be loaded, so it's not a reliable way to load from the heap on many machines. It's mostly intended for loading from nearby read-only data, such as text strings or stored immediates (more on that later).
===Barrel Shifter===
===Barrel Shifter===