News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Small issue with ~ (invert)

Started by Frizie, May 31, 2022, 12:14 PM

Previous topic - Next topic

Frizie

I noticed that an output pulses very briefly when using the invert (~).
Without invert no pulse on the output.

SYMBOL TestBitOut = PORTC.1
DIM    TestBit  AS BIT

TestBit    = FALSE
TestBitOut = ~TestBit


The assembler routine explains why:

F1_000383 equ $ ; in [TEST.BAS] TestBit = FALSE
    bcf _B__VR1,4,0
F1_000384 equ $ ; in [TEST.BAS] TestBitOut = ~TestBit
    btfsc _B__VR1,4,0
    bsf PORTC,1,0     <<<<<<<<< This shouldn't be here
    btfss _B__VR1,4,0
    bcf PORTC,1,0
    btg LATC,1,0

Regards,
Frizie.
Ohm sweet Ohm | www.picbasic.nl

tumbleweed

There's a little more to it than that.

The expression 'TestBitOut = ~TestBit' is done in two stages. It's the equivalent of:
TestBitOut = TestBit
TestBitOut = ~TestBitOut

You can see this from the disassembly, which pretty much matches yours:
F1_000009 equ $ ; in [TEST.BAS] TestBitOut = TestBit
    btfsc _B__VR1,0,0
    bsf PORTC,1,0
    btfss _B__VR1,0,0
    bcf PORTC,1,0
F1_000010 equ $ ; in [TEST.BAS] TestBitOut = ~TestBitOut
    btg LATC,1,0

If you want to avoid any intermediate values then do it the "long way":
If testBit = 0 Then
    TestBitOut = 1   
Else
    TestBitOut = 0
EndIf


RGV250

Hi,
I am not sure why you have the 2 different bits TesBit & TestBitOut but if you do

TestBitOut = False
TestBitOut = ~TestBitOut
or
TestBitOut = True
TestBitOut = ~TestBitOut
It seems to be what you want.

Bob

Frizie

I know how to prevent that pulse, that's not the problem  ;)

My point here is that I just pass on that the inverted bitvalue applied to an output port produces a short pulse.

The actual program is not like the example given.
I've just stripped out all the unnecessary and left only what's needed to show what's happening in the assembler listing.

When you invert just a bit variable to another bit variable, there is no problem.
But if that bit variable is an outputpin, than you get that short pulse.
Not a big deal, but I'll pass it on here anyway, because it caught my eye  :o
Ohm sweet Ohm | www.picbasic.nl

tumbleweed

Quote from: Frizie on May 31, 2022, 03:51 PMWhen you invert just a bit variable to another bit variable, there is no problem.

It does the same thing when you have two bit variables, it's just that you don't care so much when the result is just a variable and not a port pin.
Dim TestBit  As Bit
Dim TestBit2 As Bit

TestBit2 = TestBit
TestBit2 = ~TestBit

produces
F1_000007 equ $ ; in [TEST.BAS] TestBit2 = TestBit
    bsf _B__VR1,1,0
    btfss _B__VR1,0,0
    bcf _B__VR1,1,0
F1_000008 equ $ ; in [TEST.BAS] TestBit2 = ~TestBit
    bsf _B__VR1,1,0
    btfss _B__VR1,0,0
    bcf _B__VR1,1,0
    btg _B__VR1,1,0

This also might matter if the result was a register bit since it would set/clear the bit before toggling it.


Yasin

Using "TOGGLE" for bit inversion is the right choice. It should be more accurate to use "~" to invert the bits in the variable. So "Complement ~" should be used for byte, word (ect), type variables.

Best regards.

top204

When an SFR is the assignment, the assembler code is longer because it does not change a bit within it while testing it.

I'll take a look in the source codes, and see if I can make it more robust with complements when using SFRs as well.

top204

Thanks to your vigilance Frizie, I have now altered the compiler's code generator so that if an SFR (Special Function Register) is the assignment to a bit complement, it will produce different assembler code, so that the SFR is not effected before the bit complement takes place. i.e. the original Btg on an 18F device.

For example, the code:
    Device = 18F25K20
    Declare Xtal = 16

    Dim tBitIn As Bit = 1
    Dim tAliasOut As PORTB.3
   
    tAliasOut = ~tBitIn

Will now produce the assembler code:
    movlw 0
    btfss _B__VR1,0,0
    movlw 1
    btfsc STATUS,2,0
    bcf LATB,3,0
    btfss STATUS,2,0
    bsf LATB,3,0

Where "_B__VR1,0" is the RAM byte used for the tBitIn variable.

The assembler code is a bit longer, but that is the price to pay for fully working code sometimes. Notice that the tAliasOut variable is PORTB, but the assembler code automatically sets the bits of LATB for it, so that the Read-Modify-Write anomaly does not occur with the microcontroller. The compiler does this as much as it can within the assembler code it produces for 18F devices. When the assignment is not an SFR, the compiler produces smaller assembler code.

Also, now that the newer enhanced 14-bit core devices have moved the PORT, TRIS and LAT SFRs into the same RAM bank, as it should have always been, I will be modifying the compiler to also do the same with them with PORT and LAT. I did not with the early enhanced 14-bit core devices because they are all in different RAM banks and the bank switching mnemonics required made the code too bloated for automatic operations.

A free anomaly correcting update will be uploaded and posted on the forum ASAP.

tumbleweed

Quote from: top204 on Jun 01, 2022, 12:40 PM... Will now produce the assembler code:
    movlw 0
    btfss _B__VR1,0,0
    movlw 1
    btfsc STATUS,2,0
    bcf LATB,3,0
    btfss STATUS,2,0
    bsf LATB,3,0

Les - maybe I missed it, but where in that sequence is the STATUS Z flag being modified so it can be tested?

Frizie

Thank you very much Les! ;D

As said, for me it's not a big deal, and keeps no hurry.
For me personally it only needs to be adjusted in a next update. :)
Ohm sweet Ohm | www.picbasic.nl

top204

#10
Well spotted tumbleweed. I also noticed that with the code this morning after posting it, and have changed it. However, the Isis simulator I have, altered the Z flag of the STATUS register with the Movlw mnemonic and it slipped my mind that it should not effect any STATUS flag.

So the movlw 0 mnemonic has been changed to clrf WREG and the movlw 1 has been changed to addlw 1