Category:ARM Assembly: Difference between revisions
Content added Content deleted
Puppydrum64 (talk | contribs) No edit summary |
Puppydrum64 (talk | contribs) (Added better examples.) |
||
Line 15: | Line 15: | ||
Checking for condition codes isn't just limited to branching on the ARM. Almost every instruction can be made conditional. If the condition is not met, the opcode will have no effect. This saves a lot of cycles that would be spent branching just to execute a single instruction. |
Checking for condition codes isn't just limited to branching on the ARM. Almost every instruction can be made conditional. If the condition is not met, the opcode will have no effect. This saves a lot of cycles that would be spent branching just to execute a single instruction. |
||
Compare the following snippets of code. The first is written in 8086 Assembly, the second in ARM. Both do the same thing, but ARM can do it without branching. |
|||
⚫ | |||
⚫ | |||
<lang asm>mov ax, word ptr [ds:TestData] ;dereference the pointer to TestData and store the value contained within that address into ax |
|||
add ax,1 ;add 1 to ax |
|||
jo OverflowSet ;the addition caused an overflow, jump to this label. |
|||
ret ;return from subroutine |
|||
OverflowSet: |
|||
sub ax,1 ;rollback the previous addition. |
|||
ret ;return from subroutine.</lang> |
|||
The same code translated to ARM doesn't need to branch: |
|||
<lang ARM Assembly>mov r1,#TestData ;get the address of TestData |
|||
ldr r0,[r1] ;load the 32-bit value stored at TestData into r0 |
|||
adds r0,r0,#1 ;add 1 to r0 and store the result in r0, updating the flags accordingly. |
|||
subvs r0,r0,#1 ;subtract 1 from r0 and store the result in r0, <i>only if the overflow flag was set.</i></lang> |
|||
If your code does one thing when a flag is set and another when that same flag is clear, the ARM can do both without having to branch at all. |
|||
<lang ARM Assembly>;ARM ASSEMBLY |
|||
mov r1,#TestData ;get the address of TestData |
|||
ldrs r0,[r1] ;load the 32-bit value stored at TestData into r0, updating the flags accordingly. |
|||
⚫ | |||
subne r0,r0,r2 ;if r0 doesn't equal zero, subtract r2 from r0 and store the result in r0.</lang> |
|||
The equivalent in x86 would take at least one branch, maybe 2 depending on the outcome: |
|||
<lang asm>;x86 ASSEMBLY |
|||
mov ax, word ptr [ds:TestData] |
|||
cmp ax,0 |
|||
bne subtract_bx |
|||
add ax,bx |
|||
jmp done |
|||
subtract_bx: |
|||
sub ax,bx |
|||
done:</lang> |
|||
===Setting Flags=== |
===Setting Flags=== |
||
The flags, or condition codes, are only set by instructions that end in an "s". This lets you "preserve" the processor's state after an important calculation, but do some other things before execution branches depending on the result of that calculation. On any other processor, the calculation that determines whether a branch occurs MUST happen JUST before that branch statement or the branch will be taken based on the wrong data. |
The flags, or condition codes, are only set by instructions that end in an "s," or by compare commands such as <code>CMP</code>. This lets you "preserve" the processor's state after an important calculation, but do some other things before execution branches depending on the result of that calculation. On any other processor, the calculation that determines whether a branch occurs MUST happen JUST before that branch statement or the branch will be taken based on the wrong data. |
||
<lang ARM Assembly>cmp r0,r1 ;compare r0 to r1 |
|||
ldr r2,[r3] ;load r2 from the address stored in r3 |
|||
ldr r3,[r4] ;load r3 from the address stored in r4 |
|||
bne myLabel ;branch to myLabel if the result of "cmp r0,r1" was not equal to zero.</lang> |
|||
Most processors would have to push and pop the condition code register between the compare and the branch. Otherwise, the act of loading <code>r2</code> and <code>r3</code> would affect the outcome of the branch. Not so on the ARM! |
|||
⚫ |