Branching in Assembly Code
Branches
In high-level programming languages, we usually don't have to think
about how our code branches -- it is implicit in the control structures
and the curly braces. For example, we know implicitly that if an
if condition is false our program will branch to the else clause,
and that at the closing brace of a loop body our program will branch
back up to the loop condition at the top.
In assembly language, however, these branches are not implicit, but instead they are very explicit -- you have to pick them and place them in the right spots.
Branches encode the relation operators
In high-level languages, we use relational operators in our conditional expressions, and it would be natural to think that these operators have some synonymous assembly language instruction that implements it, but this is not exactly true!
Rather, in assembly code it is the conditional branch instructions that encode the relational operator. There is only one kind of instruction that compares values -- but there are many different branch instructions that encode the relational operator -- such as BRGE for "branch if greater than or equal" and BRNE for "branch if not equal to", and more.
So for relational operators, in assembly language you need to do a two step process: compare and branch. The comparison instruction never changes (except the form in terms of what operands it uses), but the branch instruction changes based on what relational condition you are checking.
Signed versus unsigned branches
As we learned earlier, with two's complement (2C) representation for signed values, the arithmetic operations don't change -- they just work properly! But the place in your program where it DOES matter if your program is using signed or unsigned data is in choosing the branch instructions.
The four relational operators (greater-than, less-than, greater-than-or-equal, and less-than-or-equal) need eight different instructions, one each for unsigned and signed data. The AVR CPU actually only implements four of these: it does not implement "greater than" and "less than or equal" since you can always just flip your operands around and change them into "less than" and "greater than or equal". The AVR conditional branches for these are:
Operator Unsigned Signed Greater than or equal BRHS BRGE Less than BRLO BRLT
The two equality checks (equal to and not equal to) are the same for signed and unsigned: BREQ and BRNE. But for the others, it is very important for you to pick the right branch depending on your data. The wrong branch simply will not work!
Branch addressing
Branch instructions need to store their destination as an operand -- the place they will branch to if the condition is true. they do not store this as an absolute address (e.g., like extended addressing does), but rather they use a relative addressing mode.
Specifically, the AVR branch instruction uses a 7-bit two's complement (i.e., signed) offset relative to the address of the branch opcode, plus
- Put another way, the target address for the branch is the branch opcode address plus 1 plus the relative offset:
Target-address = Branch-opcode-address + 1 + Offset
Remember that AVR program memory is word-addressed, so a 7-bit 2C offset allows branches to branch backwards or forwards approximately 64 instructions, though a few instructions take 2 words to store and so could affect this rough estimate.
There is also a "relative jump" instruction, RJMP, which has a 12-bit offset and uses the same formula as the branch instructions. This can branch backwards or forwards approximately 2048 addresses.
How branch instructions interact with compare instructions
There's no hidden magic in computers, especially at the assembly language level. So how does the branch instruction know the result of the comparision instruction?
The answer is in the Status Register (SREG).
On another note page, we explained the SREG in detail. The lower five bits of the SREG (the C, V, Z, N, and S bits) are indicators of arithmetic overflow and condition flags. The thing to remember is that "a comparison is a subtraction". That is, the compare instruction subtracts one operand from the other, and in the process it sets the codes in the SREG. Even though it throws the value result of the subtraction away, the SREG values will tell the next branch instruction whether to branch or not.
In the instruction table, each branch instruction has in its description a mathematical boolean formula that looks at the SREG codes and determines whether to branch or not.