====== PIC18: branch instructions ======
{{:pic18_branch:tux-ascii.png |}}Skimming through the PIC 18F4550 istruction set we can see, among others, a bunch of //branch// instructions.
What are they for and what's their relationship with the STATUS register? Let's see them in practice using some assembly code examples. This will also be a nice occasion to do a bit of simple HEX math.
===== Branch instructions =====
**BC** - Branch if Carry
**BN** - Branch if Negative
**BNC** - Branch if Not Carry
**BNN** - Branch if Not Negative
**BNOV** - Branch if Not Overflow
**BNZ** - Branch if Not Zero
**BOV** - Branch if Overflow
**BRA** - Branch Unconditionally
**BZ** - Branch if Zero
Those instructions make the program counter (PC) jump to another part in the program code **on the evaluation of the STATUS register** (that's not true for the //BRA// instruction which branches //unconditionally//).
So it's important to understand the various flags of this register and how they are affected by the execution of other instructions; for this purpose we are going to use a great piece of Windows software named //PIC18 Simulator IDE//, which runs fine under Linux thanks to Wine.
===== The STATUS register =====
{{:pic18_branch:pic18-status-register.png|}}
Every flag in the STATUS register can be intercepted by the correspondent branch instruction; let's see this in practice.
This is the first code we are going to assemble and load onto PIC18 Sim:
processor 18F4550
INCLUDE
testreg equ 0x00
org 0x00
goto Start
org 0x08
nop
org 0x18
nop
Start
movlw .1
movwf testreg
; Main loop
Main
movlw .4
addwf testreg
bra Main
END
//testreg// is defined as a file register located at 0x00 and loaded with .1
Then what the Main loop does is adding the value .4 to it over and over again to see how that's reflected on the STATUS register.
==== Digit carry bit ====
The values that //testreg// goes through are: 1h, 5h, 9h, Dh. Let's stop here and do the next operations by ourselves.
0Dh +
04h =
___
11h
There is a //carry// for the lower //nibble//, which is added to the higher nibble; it is called a **digit carry** and that situation is reflected on **bit 1** of the STATUS register:
{{:pic18_branch:pic18-sim01.png|}}
==== Overflow and negative bits ====
Let's go on and keep adding .4 to //testreg// until we come to the value 7Dh and do the math:
7Dh +
04h =
___
81h
Like before we have a //digit carry// (a carry resulting from the addition of the lower nibbles) ; as for the higher nibble, its most significant bit is on and that corresponds, in 2's complement notation, to a **negative number**: that turns on **bit 4** of the STATUS reg.
> That alone doesn't make the number //negative//; it all //depends on the instruction// that uses the operand (the register) to //interpret it as a signed number or a positive one//.
There is also an **overflow**, a condition which is met when there is a //change in the sign//, from positive to negative as in this case: **bit 3** is therefore also on.
{{:pic18_branch:pic18-sim02.png|}}
==== Carry bit ====
In the next situation testreg is now FDh:
FDh +
04h =
____
101h
The result i 101h, but since testreg, as all GPRs, is an 8 bit register the leading '1' is truncated and 01h is instead saved; both the higher and lower nibble had a carry, so **bit 0** (**carry**) is also on:
{{:pic18_branch:pic18-sim03.png|}}>
The Carry bit (but //not// the Digit Carry) is also affected by //register rotate instructions// like //RLCF (Rotate Left f through Carry)// and //RRCF (Rotate Right f through Carry)//:
{{:pic18_branch:pic18-rlcf.png|}}
Start
movlw .1
movwf testreg
; Main loop
Main
rrcf testreg,F
bra Main
{{:pic18_branch:pic18-sim05.png|}}
==== Zero bit ====
This should be simple; for example:
Start
movlw .255
movwf testreg
; Main loop
Main
incf testreg,F
bra Main
{{:pic18_branch:pic18-sim04.png|}}
We can see that **bit 2**, the STATUS bit that intercepts operations which lead to a result equal to Zero, is turned on, but also bit 0 (Carry) and bit 1 (Digit Carry). Let's try to explain that:
FFh +
01h =
____
100h
When we sum the lower nibbles (Fh + 1h) we have a carry, so Digit Carry bit is on; the carry is then added to the higher nibbles (1h + Fh + 0), which makes the Carry bit on.
==== Borrow and Digit borrow bits ====
Carry and Digit Carry bits are affected by additions; but **when numbers are subtracted they become Borrow and Digit Borrow bits, which are //active low//**; this means that **when there is a borrow the bits are //off//**.
Start
movlw .1
movwf testreg
; Main loop
Main
decf testreg,F
bra Main
In the above example the subtraction is:
01h -
01h =
___
00h
First the lower nibbles are subtracted (1h - 1h); there's no borrow so Digit Borrow bit (**bit 1**) is //on//; then the higher nibbles are subtracted (0 - 0): no borrow so Borrow bit (**bit 0**) is //on//:
{{:pic18_branch:pic18-borrow.png|}}
(Zero bit - bit 2 - is also on)
If we go further with the next subtraction:
00h -
01h =
___
FFh
The lower nibbles are subtracted: there's a need for borrow (Digit Borrow bit //off//), which is also needed in turn by the higher nibbles (Borrow bit //off//):
{{:pic18_branch:pic18-borrow02.png|}}
(Negative bit - bit 4 - is also on)
With the following subtraction only the Digit Borrow bit is affected and so it is turned //off//:
F0h -
01h =
___
EFh
{{:pic18_branch:pic18-borrow03.png|}}