# Bit selection / control

Status
Not open for further replies.

#### SPDCHK

##### Member
I'm not even sure how to phrase the heading but here goes.

I would like to write shorter and more efficient assembler code (MPLAB PIC Microchip) to do the following...

My variable is called RxNode, and it will contain a number (decimal) from 0 to 7. (It will never fall outside of these values). Now, I want to bit switch another variable (NodeData) with the respective node address, i.e. if RxNode = 5, I want to be able to BSF of BCF NodeData,5 without affecting the rest of the Bits in NodeData

Code:
NodeData         7 6 5 4 3 2 1 0
| | | | | | | |
RxNode (=7) -----+ | | | | | | |
RxNode (=6) -------+ | | | | | |
RxNode (=5) ---------+ | | | | |
RxNode (=4) -----------+ | | | |
RxNode (=3) -------------+ | | |
RxNode (=2) ---------------+ | |
RxNode (=1) -----------------+ |
RxNode (=0) -------------------+

BTW, this is not homework. I would just like a method shorter than the one I’m currently using.

Code:
...

Node_:		movf		RxNode,w	; Decode receiving node data
andlw		0x07		;
goto		Node00		; If RxNode = 0
goto		Node01		; If RxNode = 1
goto		Node02		; If RxNode = 2
goto		Node03		; If RxNode = 3
goto		Node04		; If RxNode = 4
goto		Node05		; If RxNode = 5
goto		Node06		; If RxNode = 6
goto		Node07		; If RxNode = 7

Node00:		btfss		GenPurp,3	; Test if Node is ON
bcf		NodeData,0	;
btfsc		GenPurp,3	;
bsf		NodeData,0	;
return				;

Node01:		btfss		GenPurp,3	; Test if Node is ON
bcf		NodeData,1	;
btfsc		GenPurp,3	;
bsf		NodeData,1	;
return				;
etc...

Thanks

#### Nigel Goodwin

##### Super Moderator
To be honest that looks short and fast, a jump table is a very efficient technique - why do you have a problem with it?.

#### SPDCHK

##### Member
I just thought there might be a better/faster method that I don’t know about. I had a look at Mike’s code (Pommie) and he pulled some fancy trick setting TRIS on GPIO, and that made me think maybe there’s better ways of programming?
Code:
movlw	b'11111111'-(1<<GPIO5)-(1<<RS232)

I know that what he's done here only applies to, before being compiled/linked, but I was looking for something where variable data can be passed around inside an actual running application.

#### Diver300

##### Well-Known Member
Code:
Node_:
incf	RxNode, f
clrf	temp1
bsf		SR, C			;set the carry bit
node_loop
rlf		temp, f
decfsz	RxNode, f
goto	node_loop

;now just one bit of temp is set, and that bit is
;the one numbered what was RxNode

comf	temp, w
andwf	NodeData	;This clears the target bit
movf	temp, w
btfsc	GenPurp,3
iorwf	NodeData           ;and this sets the target bit if required
return

That will be slower but is more compact. It will zero RxNode but you can use a copy for the loop counter if you want.

BTW, in your code you don't need to use the
Code:
btfss		GenPurp,3
line, because the lines just after will selectively set the bit or not.

You could write:-

Code:
Node_:		rlf		RxNode,f	; Decode receiving node data
rlf		RxNode,w
andlw		0x01c		;

bcf		NodeData,0	;
btfsc		GenPurp,3	;
bsf		NodeData,0	;
return				;

bcf		NodeData,1	;
btfsc		GenPurp,3	;
bsf		NodeData,1	;
return				;
etc...

That will jump 4 places forward for each value of RxNode, and without the unnecessary btfss line, each node code is 4 lines long, so there is no need for the goto lookup table. The code is within the lookup table instead.

#### SPDCHK

##### Member
Thank you

Thanks Diver300. I will implement and test.

##### Banned
Are you worried about running out of code space? If not don't bother, there is almost always a direct correlation between the size of ASM code and it's speed, being longer code is faster, short code is slower. Atmel has an appnote for software multiplication/division that has two version of each math routine, speed optimized and code optimized.

#### Mike - K8LH

##### Well-Known Member
If all you're doing is toggling a bit, you might do it like this?

Code:
        movf    RxNode,W        ;
andlw   7               ; index 0..7
xorwf   NodeData,F      ; toggle bit
........

addwf   PCL,F           ; W = index, 0..7
retlw   b'00000001'     ; index 0
retlw   b'00000010'     ; index 1
retlw   b'00000100'     ; index 2
retlw   b'00001000'     ; index 3
retlw   b'00010000'     ; index 4
retlw   b'00100000'     ; index 5
retlw   b'01000000'     ; index 6
retlw   b'10000000'     ; index 7
You could also use an "in-line" table. It saves one stack level but uses more instruction cycles for the lower index values. The first value in each "in-line table" operand is the return value, the second value cancels out WREG, and the third value (in parenthesis) cancels out the following line.

Code:
        movf    RxNode,W               ;
andlw   7                      ; W = index, 0..7
xorlw   0x01^0x00^(0x02^0x01)  ; index 0 returns b'00000001'
xorlw   0x02^0x01^(0x04^0x02)  ; index 1 returns b'00000010'
xorlw   0x04^0x02^(0x08^0x03)  ; index 2 returns b'00000100'
xorlw   0x08^0x03^(0x10^0x04)  ; index 3 returns b'00001000'
xorlw   0x10^0x04^(0x20^0x05)  ; index 4 returns b'00010000'
xorlw   0x20^0x05^(0x40^0x06)  ; index 5 returns b'00100000'
xorlw   0x40^0x06^(0x80^0x07)  ; index 6 returns b'01000000'
xorlw   0x80^0x07              ; index 7 returns b'10000000'
xorwf   NodeData,F             ; toggle NodeData bit

Last edited:

#### blueroomelectronics

##### Well-Known Member
Are you using a 12,14 or 16bit core PIC?

#### SPDCHK

##### Member
Are you using a 12,14 or 16bit core PIC?

Hi Bill,

I'm using 12F675 PICs as the remote receiver end and 16F628A as the Master controller.

#### SPDCHK

##### Member
If all you're doing is toggling a bit, you might do it like this?

Code:
        movf    RxNode,W        ;
andlw   7               ; index 0..7
xorwf   NodeData,F      ; toggle bit
........

addwf   PCL,F           ; W = index, 0..7
retlw   b'00000001'     ; index 0
retlw   b'00000010'     ; index 1
retlw   b'00000100'     ; index 2
retlw   b'00001000'     ; index 3
retlw   b'00010000'     ; index 4
retlw   b'00100000'     ; index 5
retlw   b'01000000'     ; index 6
retlw   b'10000000'     ; index 7
You could also use an "in-line" table. It saves one stack level but uses more instruction cycles for the lower index values. The first value in each "in-line table" operand is the return value, the second value cancels out WREG, and the third value (in parenthesis) cancels out the following line.

Code:
[COLOR="Red"]        movf    RxNode,W               ;
andlw   7                      ; W = index, 0..7
xorlw   0x01^0x00^(0x02^0x01)  ; index 0 returns b'00000001'
xorlw   0x02^0x01^(0x04^0x02)  ; index 1 returns b'00000010'
xorlw   0x04^0x02^(0x08^0x03)  ; index 2 returns b'00000100'
xorlw   0x08^0x03^(0x10^0x04)  ; index 3 returns b'00001000'
xorlw   0x10^0x04^(0x20^0x05)  ; index 4 returns b'00010000'
xorlw   0x20^0x05^(0x40^0x06)  ; index 5 returns b'00100000'
xorlw   0x40^0x06^(0x80^0x07)  ; index 6 returns b'01000000'
xorlw   0x80^0x07              ; index 7 returns b'10000000'
xorwf   NodeData,F             ; toggle NodeData bit[/COLOR]

Hi Mike,

I like this second part. It even toggles the bit and that ‘s exactly what I was going to try and code today. You saved me that little headache. Thanks.

Thanks to you and all who replied.

Last edited:

#### Mike - K8LH

##### Well-Known Member
SPDCHK,

Happy to help.

Just be careful where you place those "table" type routines in program memory so the table doesn't straddle a 256 byte boundary. Or, make the routines "boundary tolerant". I can give you examples if you like.

Diver300's "loop" type routine wouldn't suffer from the same problem but I would modify it to use one less variable and to prevent destroying the RxNode index variable.

Code:
;
;  set or clear NodeData,RxNode bit (determined by
;  the GenPurp,3 flag)
;
;  12 words, 1 RAM variable, doesn't destroy RxNode
;  15-50 cycles including call and return
;
Node_ver1
comf    RxNode,W        ; index, 0..7, inverted
setc                    ;
bnc     mlp             ;
iorwf   NodeData,F      ; set bit unconditionally
btfss   GenPurp,3       ; set? yes, skip, else
xorwf   NodeData,F      ; clr bit
return                  ;
;
The "table" routines are fast but if you have to make them "boundary tolerant" they're quite a bit longer then the "loop" routines. The "loop" routines are much smaller but can use a lot more cycles.

Here's another routine I developed which is fast like the "table" method, without having to worry about 256 byte boundaries, and reasonably small like the "loop" method. The second listing is how you might adapt the routine for use as your Node subroutine;

Code:
;
;  11 words, 14 cycles (isochronous), 2 vars (subroutine)
;
movwf   index           ; save index (0..7)               |B0
movlw   b'00000100'     ; ndx 2                           |B0
btfss   index,1         ; bit 1 set? no, skip, else       |B0
movlw   b'00000001'     ; ndx 0                           |B0
btfsc   index,0         ; bit 0 set? no, skip, else       |B0
btfsc   index,2         ; bit 2 set? no, skip, else       |B0
return                  ;                                 |B0
;
Code:
;
;  13 words, 16 cycles (isochronous) including call and return
;
Node_ver3
movlw   b'00000100'     ; ndx 2                           |B0
btfss   RxNode,1        ; bit 1 set? no, skip, else       |B0
movlw   b'00000001'     ; ndx 0                           |B0
btfsc   RxNode,0        ; bit 0 set? no, skip, else       |B0
btfsc   RxNode,2        ; bit 2 set? no, skip, else       |B0
iorwf   NodeData,F      ; set bit unconditionally         |B0
btfss   GenPurp,3       ; set? yes, skip, else            |B0
xorwf   NodeData,F      ; clr bit                         |B0
return                  ;                                 |B0
;
You might also consider using a few simple macros along with that ndx2mask subroutine from above which would allow you to use instructions like these in your code;

Code:
;
;  example macro usage
;
setbit  NodeData,RxNode ;                                 |B0
clrbit  NodeData,RxNode ;                                 |B0
tglbit  NodeData,RxNode ;                                 |B0
Code:
setbit  macro   file,ndxvar     ; 16 cycles
movf    ndxvar,W        ; W = index 0..7                  |B0
iorwf   file,F          ; set bit                         |B0
endm

clrbit  macro   file,ndxvar     ; 17 cycles
movf    ndxvar,W        ; W = index 0..7                  |B0
xorlw   0xFF            ; invert mask                     |B0
andwf   file,F          ; clr bit                         |B0
endm

tglbit  macro   file,ndxvar     ; 16 cycles
movf    ndxvar,W        ; W = index 0..7                  |B0
xorwf   file,F          ; toggle bit                      |B0
endm
Food for thought. Have fun. Regards, Mike, K8LH

Status
Not open for further replies.

Replies
8
Views
2K
Replies
11
Views
2K
Replies
5
Views
2K
Replies
21
Views
2K
Replies
8
Views
1K