7
\$\begingroup\$

What's the fastest way to toggle a bit1 in MPASM for the 14-bit enhanced instruction set? (I'm working with a PIC16F1829)

The code has to be standalone - I mean that it can be called on any moment, without knowing the value of the bit on that moment.

Key criteria is speed here: a program with fewer instruction cycles is better. The number of instructions cycles is calculated as the number when the bit is 0 + the number when the bit is 1, divided by 2.

1: with toggle I mean that the code has to be similar to pin=!pin in C

\$\endgroup\$
  • \$\begingroup\$ What is a PIC16 device? Better call it by the core, I guess you mean the 14-bit (non-enhanced) core? \$\endgroup\$ – Wouter van Ooijen May 27 '13 at 12:51
  • \$\begingroup\$ @WoutervanOoijen thanks, good idea - it's the enhanced core for this chip by the way, but you couldn't know that of course. \$\endgroup\$ – user17592 May 27 '13 at 12:52
  • \$\begingroup\$ Interestingly enough, 'pin = !pin' in C can blow up badly. XC16 for PIC24 turns this into 11-12 assembly instructions as it's oblivious to the BTG instruction. (GCC compilers target portability over optimization, hence the need for things like __builtin_btg) \$\endgroup\$ – Adam Lawrence May 27 '13 at 13:00
  • 1
    \$\begingroup\$ @Madmanguruman I mean it has to do the same, not that it has to be as fast as that :) \$\endgroup\$ – user17592 May 27 '13 at 13:01
  • \$\begingroup\$ @CamilStaps wouldn't it be better to preclude my answer by invalidating it (retrospectively) with some edited words in the question. As the question stands, my answer is the fastest way to achieve your goal and someone coming to this question late may wonder why you have not accepted my answer. I'm quite happy to delete my answer if you can preclude it some way. \$\endgroup\$ – Andy aka May 27 '13 at 21:45
14
\$\begingroup\$

You could try the following using an XOR:

movlw 0x01 ; move 0x01 to W register
xorwf lat, F ; XOR W with port & store result in port latch

An exclusive OR operation will preserve the values in bits where the bits in the working register are set to zero and invert the values where it is set. So you could also use the same technique to toggle multiple bits.

| improve this answer | |
\$\endgroup\$
  • 2
    \$\begingroup\$ PeterJ, are you aware of the Read-Modify_write problem? - update: Camil clarified the rules: 14-bit enhanced core ==> use the LAT register instead of the PORT!!! \$\endgroup\$ – Wouter van Ooijen May 27 '13 at 12:51
  • \$\begingroup\$ I think this is the shortest you'll get on devices that don't support a BTG instruction (PIC18, PIC24, etc.) \$\endgroup\$ – Adam Lawrence May 27 '13 at 12:57
  • \$\begingroup\$ @WoutervanOoijen, yes good point I'll update the answer \$\endgroup\$ – PeterJ May 27 '13 at 13:01
1
\$\begingroup\$

I came up with this:

;                                                           Cycles if 1 | Cycles if 0
btfss    port, pin  ; skip next instruction if 1            1           | 1
goto     $+3        ; pin=0, goto PC+3                      1           | 2
bcf      port, pin  ; pin=1, clear pin and...               1           | 
goto     $+2        ;   ...proceed program                  2           |
bsf      port, pin  ; pin=0, set pin and proceed program                | 1           +
; ...                                                       ---------------------------
;                                                           5             4

This takes 4 or 5 instructions cycles. Is something faster possible?

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I think PeterJ's XOR is the fatest. But sticking to your style: try to skip the pin-setting instruction instead of jumping around it. pin-setting won't chnange the flags, so you can skip both the then and the else clause this way. \$\endgroup\$ – Wouter van Ooijen May 27 '13 at 12:59
  • \$\begingroup\$ @WoutervanOoijen you mean btfss; bsf; bcf? Then the bit would get cleared regardless of the state. What do you mean? :) \$\endgroup\$ – user17592 May 27 '13 at 13:03
  • \$\begingroup\$ If not set then do_set then do_clear else do_clear. This works for me too. \$\endgroup\$ – Andy aka May 27 '13 at 13:17
  • \$\begingroup\$ @Andyaka this is a if not_set then do_clear else do_set \$\endgroup\$ – user17592 May 27 '13 at 13:18
  • \$\begingroup\$ @CamilStaps I was commenting on your interpretation of Wouter's comment - I was being a little playful because I don't think you have nailed the question - I believe you want the "code" to invert a bit then exit OR invert the bit, then invert again then exit. \$\endgroup\$ – Andy aka May 27 '13 at 13:38
1
\$\begingroup\$

What's the fastest way to toggle a bit1 in MPASM for the 14-bit enhanced instruction set? (I'm working with a PIC16F1829)

The code has to be standalone - I mean that it can be called on any moment, without knowing the value of the bit on that moment.

Key criteria is speed here: a program with fewer instruction cycles is better. The number of instructions cycles is calculated as the number when the bit is 0 + the number when the bit is 1, divided by 2.

1: with toggle I mean that the code has to be similar to pin=!pin in C

I have assumed that the bit you want toggle is part of a register that has "don't cares" in the other bits and therefore swap nibbles would work. You never said it couldn't work like this and if you are so short of registers that you need the other bits then a code rewrite or MCU upgrade is recommended.

You'd need to setup 11110000 (any pattern would do providing bn does not equal bn+4) initially but after that every time you want to invert one of the bits you use: -

swapf f,d

It's a one cycle operation and doesn't need 1 in the w register setting up.

Of course, in the rest of the programme you'd have to adhere to this method of changing the bit BUT again, you haven't said that you can't - in other words BCF or BSF instructions are outlawed.

I thought about rotates but they rotate thru carry and this would probably corrupt stuff - I haven't written PIC code in over 20 years so forgiveness ought to be at the forefront of your mind when down-voting!!!

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

If you want to invert a PIN, you have to load the state of the pin, so you will have to select the bank for PORTA first. So here's the code in C:

// PORTAbits.RA5=~PORTAbits.RA5;
PORTA=PORTA ^ 0b00100000;

with the result in ASM :

 MOVLB 0x0
 MOVF PORTA, W
 XORLW 0x20
 MOVWF PORTA
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Looks like the accepted answer is faster by one cycle, even if the bank switch is incorporated (which is not always needed if you keep track of in which bank you are). Of course, the C compiler doesn't always give the fastest compiled code - especially Microchip's free compilers generate very unoptimised code. \$\endgroup\$ – user17592 Aug 30 '17 at 14:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy