Last time, we saw how to use assembly to perform arithmetic calculations. We saw the following instructions:

`mov``add``sub``mul``and``orr``eor`

We saw the following shifts which can be applied to the last operand:

`lsl``lsr``asr``ror`

And we saw how immediate values can be placed into instructions. Next we will look at how to control execution flow.

Assembly languages do not have control structures like if and else blocks,
for loops or while loops. Instead, these can be built using *branch*
instructions which are like `goto` statements that jump to a particular
point in the program.

The simplest branch is done with the `b` instruction which always
branches to its destination. The destinations are specified with *labels*
which are just symbolic names inserted into the code followed by a colon.

For instance, the following function just loops forever:

```
.global forever
forever:
.top: @ a label for the top of the function
b .top @ branch to the top label
```

By convention, labels used for branches (as opposed to functions) begin with a '.' symbol.

In addition to making unconditional branches like this, we can make the
branches depend on some condition. This is done with the `cmp`
instruction which takes two arguments and compares them. It sets a "status
register" in the processor which can be checked by a branch instruction.
The following branches check the status register:

`beq`- Branch when equal.`bne`- Branch when not equal.`blt`- Branch when less than.`ble`- Branch when less than or equal.`bgt`- Branch when greater than.`bge`- Branch when greater than or equal.

For instance, the following function returns the absolute value of its argument:

```
@ abs.s
/* function to find the absolute value of a number */
.global abs
abs:
cmp r0, #0
bge .end
mvn r1, r0
add r0, r1, #1
.end:
mov pc, lr
```

This program uses `cmp` to compare `r0` to 0. It then uses
`bge` to branch to the `.end` label when the number is 0 or greater.
Otherwise, the branch has no effect, so the program just moves to the next two
lines which serve to negate the number. The `mvn` instruction moves and
does a bitwise inversion into `r1`. We then add 1 to the value. Together
they do the "invert and add one" necessary to negate a two's complement number.

We could have multiplied by -1 instead, but this is faster.

We can use these compare and branch instructions to write loops in assembly programs. For example, we can calculate the factorial of a number in assembly with the following function:

```
@ fact.s
/* function to calculate the factorial of a number */
.global fact
fact:
sub r1, r0, #1
.top:
cmp r1, #0
beq .done
mul r0, r1, r0
sub r1, r1, #1
b .top
.done:
mov pc, lr
```

This program uses `r0` to store the factorial as its being calculated,
starting with the number passed in. It uses `r1` to store the next value
to be multiplied in. The initial `sub` instruction starts `r1`
at one less than the number passed in.

Inside the loop, we compare `r1` with 0. When they are equal, the
function jumps to the end of the function and returns. Otherwise, it multiplies
`r0` by `r1`, storing the result back into `r0`, then subtracts
1 from `r1` and jumps back to the top of the loop.

Copyright © 2024 Ian Finlayson | Licensed under a Creative Commons BY-NC-SA 4.0 License.