All our examples thus far have used only registers, not RAM. In the next program, Prg3.s, we'll work with values stored in memory, using two new instructions: ldr ("load register") to copy values from memory into a register and str ("store register"), to copy values from a register into memory.
But before we look at Prg3.s, let's talk a bit about ldr and str. At a glance, you might expect an instruction that loads a value from memory into a register to look like this:
ldr r1, <memory address>
This would mean "load the four bytes at the specified address into r1".
But, that's not the way ldr and str work. Neither of them include a memory address as part of the instruction. And there's a good reason for this.
See if you can come up with a reason why ldr and str can't include a memory address in the instruction. Consider both the number of bits in a memory address, and the number of bits in an ARM machine language instruction.
Answer 1
The solution is to hold the memory address in another register, called the address register, and specify the address register as well as the target register. So, a real ldr instruction looks like this:
ldr r1, [r4]
R1 is the target register, and r4 is the address register. So this instruction uses r4's content as a memory address, and copies the RAM at that address into r1. For it to work, we'd expect a memory address in R4, perhaps address 10004, for instance. This would indicate that the ldr should load from that address in memory.
The idea that r4 contains the address of the data, not the data itself, is critical. This ldr instruction does not copy the content of r4 into r1. We already have a perfectly good mov instruction that can do that. R4 does not contain the data itself. It tells where the data is in memory.
If you are familiar with the idea of a pointer or reference from higher level languages, then you can think of r4 as a pointer or reference. The assembly term for the same idea is an indirect address.
And, to be complete, str works the same way. We might write:
str r1, [r6]
And if r6 contained the address 10008, this would copy from r1 to location 10008 in RAM.
And, to be clear, ldr and str each copy 4 bytes, or 32 bits, so in the examples we just did, the ldr would copy bytes 10004-10007 and the str would write to bytes 10008-10011.
And there's more to the story. A 32-bit instruction can specify an opcode and two registers, with bits left over for other purposes, so the ldr and str instructions have bits left over. They use some of those remaining bits for an address offset -- a constant value that gets added to the address register. So, for instance:
ldr r1, [r4, #8]
says to load ldr instruction
The address offset values are limited by the number of bits in the instruction that are devoted to the offset. The values can range from
For instance, an address offset is often used with the PC as the address register:
ldr r1, [pc, #32] @ or ldr r1 [r15, #32]
If an assembly program is set up so that memory contains some data near the machine language code, then the right offset relative to the PC will load that data. This is PC-relative addressing, and we'll see this used in Prg3.s.
If the program is at a certain machine instruction, and we want to use PC-relative addressing to load data from memory, how many machine instructions may be in memory between our location and the desired data, before the data would be out of range of PC-relative addressing?
Answer 2
In summary:
ldr and str transfer data to/from registers and memory.There are several other variations in the ldr and str instructions that appear in Prg3.s. We'll cover these as they arise in the next segments.