Branch

jumps to a routine based on the value in the w register.

Branch is the PBASIC equivalent of the ON x GOTO statement of older BASICs, and the CASE statement of newer ones. The advantages are similar to those of CASE statements over multiple IF/THENs: The code is more compact, more understandable, and executes more quickly. It also forces the programmer to consider every possible combination of inputs and explicitly program the responses. With comparisons, it's easy to disregard "impossible" cases and let them slip through the cracks.

In assembly, the Branch instruction is coded as a jump table. You put the number of the routine to call into w, then execute a jmp pc+w instruction. This is followed by a series of normal jmps to the desired destinations, starting with the one that should execute if w = 0.

There are a couple of restrictions on using this technique. First, the jump table must be located in the first 256 words of a 512-word program-memory page because of the way the PIC's computed-jump mechanism works. Second, the program must ensure that the number in w never exceeds the number of the highest entry in the table. For example, say a jump table has 6 entries. Jumping into the table with a 0 in w would invoke the first jump, 1 the second...and so on, up to 5. If w contained 6, jmp pc+w would jump completely over the table!

One powerful use for the jump-table technique is handling a series of compound logic statements of the form IF A AND (B OR C) BUT NOT D, THEN ACTION... Take each of the elements, A through D in this case, and assign it a bit flag in the lower bits of a variable. For example, for a variable called flags, the program would include equate directives of the form A = flags.0, B = flags.1, and so on.

Next, translate your logic statements into a series of true/false (1/0) entries for each of the elements. The example above works out to 0111, 0101 and 0011, where A is the least-significant bit.

Finally, set up a jump table with entries to accommodate every combination of A, B, C, and D, represented by the numbers 0000 through 1111 binary. If you later have to modify the logic of the program, it's a simple matter of moving the jump-table entries around. To use the jump table, move flags into w and go to the instruction jmp pc+w. The program executes the routine corresponding to the number in w.

Demonstrating Branch.

To see Branch in operation, either run the program with the PSIM simulator, or connect the circuit below to an erasable PIC or PIC emulator, such as the Parallax downloader. Assemble and run BRANCH.SRC. When you press switches corresponding to one of the patterns that causes Branch to jump to the routine Action (0111, 0101 or 0011), the LED will blink. Any other pattern of switch closures will be ignored.


;
; ***************************************************************************
; ***  Bubble Software Parallax to PIC Source Converter. Copyright 1999.  ***
; ***  http://www.bubblesoftonline.com                 email: sales@picnpoke.com  ***
; ***************************************************************************
;
; BRANCH offset (in w), jump table
; Jumps to the routine corresponding to offset in the jump	table.
; Makes evaluating compound logic expressions easy.
; Since this example uses data straight from port RA, it could move RA
; into w, then go to the jump table. However, we're using a separate variable
; to demonstrate the technique.	

; Device data and reset vector
	P = pic16c55
	#include <16c55.inc>   ; processor assembler definitions
	_CONFIG _xt_osc & _wdt_off & _protect_off
 reset start

 org 8
	flags	Res d'1'	; Variable to hold bits.
	temp	Res d'1'	; Variables for delay
	temp2	Res d'1'	; in Action.

 org 0

start        MOVLW d'255'               ; All inputs for switches.
             TRIS 5h
             MOVLW d'0'                 ; All outputs for LEDs
             TRIS 6h
             CLRF 6h                    ; Ensure that LEDs are off.
             CLRF flags                 ; Initialize flags.

; For the sake of the example, we'll move each bit into place separately.
; However, always look for opportunities to move several bits at a time.
; For example, the four movb operations below could be replaced with
; mov flags,ra. Make sure that you strip off any extraneous bits if you use

; a port that is wider than the desired number of bits.

Get_bits
	BTFSS flag.0	; Move bits of ra into flags.
	BCF ra.0 
	BTFSC flag.0 
	BSF ra.0

	BTFSS flag.1
	BCF ra.1 
	BTFSC flag.1 
	BSF ra.1

	BTFSS flag.2
	BCF ra.2
	BTFSC flag.2
	BSF ra.2

	BTFSS flag.3
	BCF ra.3
	BTFSC flag.3
	BSF ra.3

; We want to jump to Action IF A AND (B OR C) BUT NOT D.
; That corresponds to the bit patterns 0111, 0101 and 0011,
; (see diagram below) table entries 7, 5 and 3.

;	Bits:	|	D	|	C_	|	B	|	A	|
;	Flags:	| flags.3 | flags.2 | flags.1 | flags.0 |


; BRANCH (cont)

Branch       MOVF flags,w               ; Move flags into w.
             ADDWF pcl                  ; Table of 16 possible actions.
             GOTO Get_bits              ; DCBA=0000: try again.
             GOTO Get_bits              ; DCBA=0001: try again.
             GOTO Get_bits              ; DCBA=0010: try again.
             GOTO Action                ; DCBA=0011: Action!
             GOTO Get_bits              ; DCBA=0100: try again.
             GOTO Action                ; DCBA=0101: Action!
             GOTO Get_bits              ; DCBA=0110: try again.
             GOTO Action                ; DCBA=0111: Action!
             GOTO Get_bits              ; DCBA=1000: try again.
             GOTO Get_bits              ; DCBA=1001: try again.
             GOTO Get_bits              ; DCBA=1010: try again.
             GOTO Get_bits              ; DCBA=1011: try again.
             GOTO Get_bits              ; DCBA=1100: try again.
             GOTO Get_bits              ; DCBA=1101: try again.
             GOTO Get_bits              ; DCBA=1110: try again.
             GOTO Get_bits              ; DCBA=1111: try again.

; When the switches on port RA are in the correct combination,
; the LEDs on port RB blink.
Action       MOVLW d'255'               ; Toggle LEDs.
             XORWF 6h
Action_loop  DECFSZ temp                ; Short delay.
             GOTO Action_loop
             DECFSZ temp2               
             GOTO Action_loop
             GOTO Get_bits              ; Resume checking RA.
             
             
             end



; BRANCH offset (in w), jump table
; Jumps to the routine corresponding to offset in the jump	table.
; Makes evaluating compound logic expressions easy.
; Since this example uses data straight from port RA, it could move RA
; into w, then go to the jump table. However, we're using a separate variable
; to demonstrate the technique.	

	org	8
flags	ds	1	; Variable to hold bits.
temp	ds	1	; Variables for delay
temp2	ds	1		; in Action.
A	=	flags.0		; The elements of our
B	=	flags.1		; compound logic expression.
C_	=	flags.2		; "C" is carry bit
D	=	flags.3

; Device data and reset vector
	device	pic16c55,xt_osc,wdt_off,protect_off
	reset	start
	org	0

start	mov	!ra, #255	; All inputs for switches.
	mov	!rb, #0		; All outputs for LEDs
	clr	rb		; Ensure that LEDs are off.
	clr	flags		; Initialize flags.

; For the sake of the example, we'll move each bit into place separately.
; However, always look for opportunities to move several bits at a time.
; For example, the four movb operations below could be replaced with
; mov flags,ra. Make sure that you strip off any extraneous bits if you use

; a port that is wider than the desired number of bits.

Get_bits
	movb	A,ra.0		; Move bits of ra into flags.
	movb	B,ra.1
	movb	C_,ra.2
	movb	D,ra.3

; We want to jump to Action IF A AND (B OR C) BUT NOT D.
; That corresponds to the bit patterns 0111, 0101 and 0011,
; (see diagram below) table entries 7, 5 and 3.

;	Bits:	|	D	|	C_	|	B	|	A	|
;	Flags:	| flags.3 | flags.2 | flags.1 | flags.0 |


; BRANCH (cont)

Branch	mov	w,flags		; Move flags into w.
	jmp	pc+w		; Table of 16 possible actions.
	jmp	Get_bits	; DCBA=0000: try again.
	jmp	Get_bits	; DCBA=0001: try again.
	jmp	Get_bits	; DCBA=0010: try again.
	jmp	Action		; DCBA=0011: Action!
	jmp	Get_bits	; DCBA=0100: try again.
	jmp	Action		; DCBA=0101: Action!
	jmp	Get_bits	; DCBA=0110: try again.
	jmp	Action		; DCBA=0111: Action!
	jmp	Get_bits	; DCBA=1000: try again.
	jmp	Get_bits	; DCBA=1001: try again.
	jmp	Get_bits	; DCBA=1010: try again.
	jmp	Get_bits	; DCBA=1011: try again.
	jmp	Get_bits	; DCBA=1100: try again.
	jmp	Get_bits	; DCBA=1101: try again.
	jmp	Get_bits	; DCBA=1110: try again.
	jmp	Get_bits	; DCBA=1111: try again.

; When the switches on port RA are in the correct combination,
; the LEDs on port RB blink.
Action	XOR	rb,#255		; Toggle LEDs.
:loop	djnz	temp,:loop	; Short delay.
	djnz	temp2,:loop
	jmp	Get_bits	; Resume checking RA.


See also: