In the code below, the person points a register at an address, I get that. Why is it that later on he didn't just load R3 into R1, why did it have to be offset by 0x14?
How did R1 move in a few lines of code and what made it do it? It's really confusing me and hours of searching has shown no clear answer.
The code is stolen from here.
http://mbed.org/forum/mbed/topic/3205/
my_asm
; setup a pointer to the base address of port 1
LDR R1,=0x2009c020 ; pointer to base of port1
LDR R3,=0x00040000 ; set LED 1 port pin to output
STR R3,[R1,#0x00] ; set direction bits (base+0x00)
loop
LDR R3,=0x00000000 ; set LED 1 off (all bits 'zero')
STR R3,[R1,#0x14] ; set outputs directly (base+0x14)
LDR R3,=0x00040000 ; set LED 1 on (bit 18 aka P1.18 is 'one')
STR R3,[R1,#0x14] ; set outputs directly (base+0x14)
B loop ; branch to loop (endless loop!)
ALIGN
END
Offsets are used in assembler to access data structures.
In the code you are using, you can see the base address being loaded. This is the starting address of a data structure.
The data structure will be defined some place, but not in the code. The definition is often as a table, showing, for example
Modern processors use memory maps like this for input and output. Each device is "mapped" to a particular address. That's the base address in your code.
Without knowing what hardware is attached to your processor, we can't tell you what the data structure has in it.
The reason is that it's the shortest (fewest instructions) way to accomplish the desired effect. Two things are being done: (1) configuring the port for output, and (2) toggling an output. Since the memory locations that need to be written to in order to perform these operations are nearby, it makes to use the processor's base/offset facilities to address both.
The same effect could be achieved with the following code, but for no benefit. It's larger (less likely to fit in fixed storage) and the loop is no faster (the processor still has to add zero to the new value in R1 when executing the STR instructions).
my_asm
; setup a pointer to the base address of port 1
LDR R1,=0x2009c020 ; pointer to base of port1
LDR R3,=0x00040000 ; set LED 1 port pin to output
STR R3,[R1,#0x00] ; set direction bits (base+0x00)
LDR R1,=0x2009c034 ; pointer to port1 outputs <-- change R1
loop
LDR R3,=0x00000000 ; set LED 1 off (all bits 'zero')
STR R3,[R1,#0x00] ; set outputs <-- no more offset
LDR R3,=0x00040000 ; set LED 1 on (bit 18 aka P1.18 is 'one')
STR R3,[R1,#0x00] ; set outputs <-- no more offset
B loop ; branch to loop (endless loop!)
ALIGN
END
Register 1 is being loaded with the base address for Port 1 and the third instruction...
STR R3, [R1, #0x00] ; set direction bits (base + 0x00)
...suggests that the second byte of the data addressed by the contents of R1 are the direction bits for the LED on port 1.
You probably could, theoretically, load R1 to address the data at offset 0x014 after this instruction has completed but this would mean you include an extra - and unnecessary - instruction. Typically, if you're writing something in Assembly, you're trying to do it as efficiently as possible.
STR R3, [R1, #0x14] ; set outputs directly (base + 0x14)
What you can learn from the code above is the direction indicators are at offset 1 and the outputs are at byte 15 (I think) in the data relating to Port 1. Other than that, we don't have any information.
However, if you needed to access any of the other data relating to Port 1 later in the process, and had updated the base register to point at offset 0x14 past the start of the record for port 1, you'd have to load the address for that, or reload the base and get the offset particularly if it was somewhere between the base of the data for port 1 and offset 14.
It's more efficient, if you're doing with a specific record/piece of data, to use a base register and offset it rather than loading a register with the direct address in storage that you wish to update every time you need to do so.
User contributions licensed under CC BY-SA 3.0