Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

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		;
		addwf		PCL,f		;
		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
 
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.
 
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		;

		addwf		PCL,f		;
        	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.
 
Thank you

Thanks Diver300. I will implement and test.
 
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.
 
If all you're doing is toggling a bit, you might do it like this?

Code:
        movf    RxNode,W        ;
        andlw   7               ; index 0..7
        call    Ndx2Mask        ; returns mask 10000000..00000001
        xorwf   NodeData,F      ; toggle bit
........

Ndx2Mask
        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
        addwf   PCL,F                  ; 
        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:
If all you're doing is toggling a bit, you might do it like this?

Code:
        movf    RxNode,W        ;
        andlw   7               ; index 0..7
        call    Ndx2Mask        ; returns mask 10000000..00000001
        xorwf   NodeData,F      ; toggle bit
........

Ndx2Mask
        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
        addwf   PCL,F                  ; 
        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:
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
        clrf    mask            ;
        setc                    ;
mlp     rlf     mask,F          ; build 'mask'
        addlw   1               ;
        bnc     mlp             ;
        movf    mask,W          ;
        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)
;
ndx2mask
        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
        movwf   mask            ;                                 |B0
        btfsc   index,0         ; bit 0 set? no, skip, else       |B0
        addwf   mask,F          ; ndx 3 or ndx 1                  |B0
        btfsc   index,2         ; bit 2 set? no, skip, else       |B0
        swapf   mask,F          ;                                 |B0
        movf    mask,W          ;                                 |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
        movwf   mask            ;                                 |B0
        btfsc   RxNode,0        ; bit 0 set? no, skip, else       |B0
        addwf   mask,F          ; ndx 3 or ndx 1                  |B0
        btfsc   RxNode,2        ; bit 2 set? no, skip, else       |B0
        swapf   mask,F          ;                                 |B0
        movf    mask,W          ;                                 |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
        call    ndx2mask        ; convert to bitmask              |B0
        iorwf   file,F          ; set bit                         |B0
        endm

clrbit  macro   file,ndxvar     ; 17 cycles
        movf    ndxvar,W        ; W = index 0..7                  |B0
        call    ndx2mask        ;                                 |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
        call    ndx2mask        ; convert to bitmask              |B0
        xorwf   file,F          ; toggle bit                      |B0
        endm
Food for thought. Have fun. Regards, Mike, K8LH
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top