Category:ARM Assembly: Difference between revisions

 
(2 intermediate revisions by the same user not shown)
Line 46:
MyCode:
adr R2,RAM_Address ;get the address of a nearby place to store values.
MOV R0,#0x12345678 ;the value to store.
STR R0,[R2] ;store 0x12345678 into the first 32-bit slot.</lang>
 
Line 162:
===Limitations of the ARM===
While the ARM has a rich amount of features that other processors only dream of having, there are a few limitations.
The biggest one (which was more of an issue on earlier versions such as the ARM7TDMI CPU in the Game Boy Advance) is the limitation of the <code>MOV</code> command. Arguably the most important command any processor has (apart from <code>JMP</code>), the <code>MOV</code> command on the ARM is often limited in what can be loaded into a register in a single command. Depending on the pattern of bits, some immediate values cannot be loaded into a register directly. The key features of the ARM instructions (barrel shifter, conditional commands, etc) all take up bytes in each command, whether they are used in a given instance of a command or not. So in order to store 32 bit numbers in a <code>MOV</code> command, the value has to be "8-bit rotatable," meaning that it can be expressed as an 8 bit number if you shift it enough times. Basically if there are too many 1s in the binary equivalent of the number you're trying to load, it can't be done in one go.
 
Looking at the following in C and its ARM assembly equivalent (I've cut the stack twiddling and the return statement for clarity) we can see just what exactly happens:
Most of the time, this isn't a huge deal, as the easiest way around this is to define a data block nearby containing the value you wish to load. Since each command on the ARM takes 4 bytes of storage, this is guaranteed to take equal or fewer bytes than loading the number into a register piece-by-piece.
 
<lang ARM AssemblyC>movint r0,#0x04000000main(){
return 0xFFFF;
add r0,r0,#0x130
}</lang>
 
<lang ARM Assembly>mov r0, #255 ;MOV R0,#0xFF
orr r0, r0, #65280 ;ORR R0,#0xFF00 (0xFF00|0x00FF = 0xFFFF)</lang>
 
 
It's very common to store "complicated" numbers into a nearby data block and just load from that data block with PC-relative addressing. These data blocks are usually placed after the nearest return statement so that they don't get executed as instructions.
<lang ARM Assembly>ldr r0,testData ;load 0xABCD1234 into R0
bx lr ;return
testData:
.long 0xABCD1234</lang>
 
;compare to:
TestDataAddr: .word 0x04000130
ldr r0,TestDataAddr</lang>
 
Thankfully, there's an even easier solution than this. The GNU Assembler saves the day with the following special notation.
1,489

edits