optimizing bit test instructions

Coding and general discussion relating to the compiler

Moderators: David Barker, Jerry Messina

Post Reply
Jerry Messina
Swordfish Developer
Posts: 1469
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

optimizing bit test instructions

Post by Jerry Messina » Sat Jul 02, 2016 12:41 pm

Normally, SF does an excellent job of translating single bit tests into pretty optimal code. Statements like this:

Code: Select all

while (SSPSTAT.bits(0) = 0)
end while
produce a bit test and loop. Hard to get much better than that!

Code: Select all

WHILE_2
    BTFSS SSPSTAT,0,0
    BRA WHILE_2
However, if the SFR isn't located in the special access bank of the PIC18 then things can get a little worse.
This is due to the fact that it now has to use bank instructions to get to the register, and the code
generator does some extra stuff so that it always produces the correct code when you have complex 'IF-THEN'
expressions.

For example, on the J94 SSP2STAT is located in bank 15 outside the access RAM, so that while loop above might end up like:

Code: Select all

?I000001_F000_000041_M000000 ; L#MK WHILE (SSP2STAT.BITS(0) = 0)
WHILE_5
    BCF STATUS,3,0
    MOVLB 15
    BTFSC SSP2STAT,0
    BSF STATUS,3,0
    MOVLB 0
    BTFSS STATUS,3,0
    BRA WHILE_5
Usually the extra few instructions don't really matter in the grand scheme of things, but they can
if you're trying to squeak out every last bit of performance (pun intended).

If you find yourself in that situation, here are some macros you can use to reduce the overhead.

Code: Select all

// optimized bit test/wait macros
// usage:
//   reg = SFR register name
//   bitno = 0 to 7
//   state = desired bit state...0 or 1
//
// wait until reg.bitno = state
public macro wait_for_bit(reg, bitno, state)
  if (state = 0) then
    asm
        banksel reg
        btfsc reg, bitno, 1     ; use BSR
        bra $-2
    end asm
  else
    asm
        banksel reg
        btfss reg, bitno, 1     ; use BSR
        bra $-2
    end asm
  endif
end macro

// wait while reg.bitno = state
public macro while_bit(reg, bitno, state)
  if (state = 0) then
    asm
        banksel reg
        btfss reg, bitno, 1     ; use BSR
        bra $-2
    end asm
  else
    asm
        banksel reg
        btfsc reg, bitno, 1     ; use BSR
        bra $-2
    end asm
  endif
end macro

// examples:
//   wait_for_bit(SSP2STAT, 0, 1)      ' waits until SSP2STAT.0 is high
//   while_bit(SSP2STAT, 0, 0)         ' waits while SSP2STAT.0 is low (same as above)
//
// asm results:
//    BANKSEL SSP2STAT
//    BTFSS SSP2STAT, 0, 1     ; USE BSR
//    BRA $-2
The two macros produce identical code... it's just a difference in how you want to express what you're doing.

If you define const names for the individual bits then you can use the bit names too...

Code: Select all

// SSPxSTAT register bits
public const
    BF = 0,
    UA = 1,
    R_W = 2,
    S = 3,
    P = 4,
    D_A = 5,
    CKE = 6,
    SMP = 7
    
while_bit(SSP2STAT, BF, 0)
This usually only comes into play on the bigger devices that have lots of SFR registers, so check the datasheet for the pic you're using to see where the registers are located.
Most of them have a 'Register File Summary' in the 'Data Memory Organization' section, and a note in the Data Memory Map showing where the access bank is.

bitfogav
Registered User
Registered User
Posts: 169
Joined: Sat Oct 09, 2010 1:39 pm
Location: United Kingdom

Re: optimizing bit test instructions

Post by bitfogav » Sun Jul 03, 2016 5:01 pm

That's great info, thanks Jerry.

Post Reply