Menu

Your thoughts please - bitwise shift operation

Anobium
2025-01-08
2025-01-10
  • Anobium

    Anobium - 2025-01-08

    Help and comments please.

    I need help to get this right. The change to the compiler is actually very small. But, getting the syntax right is very critical.

    The other day I was contact regarding porting LATA ^=(1 << 6); to GCBASIC. This is a question I have seen many times.

    This operation equates to LATA = LATA XOR 64 but we have lots of options in GCBASIC ( and, I am sure there are more ways to do this) but none are an like for like implementation.

    All of the following work - the first two are optimised but all but the last option change the context of the shift operation.

    Instruction ASM Size Comment
    PORTA = PORTA xor 64 2 The user have to calculate the bit value ( 64 )
    PORTA = PORTA XOR 0b01000000 2 The user have to calculate the bit value ( 64 )
    PORTA.6 = NOT PORTA.6 6 Logically correct and easy to use
    PORTA.6 = PORTA.6 XOR 1 8 This option is useful but code is large.
    SetWith( PORTA.6, !PORTA.6 ) 9 The oldest GCBASI C way!!!
    PORTA = PORTA XOR FnLSR ( 1, 6 ) 19 A true maths conversion... the slowest to execute.

    The GCBASIC compiler really should convert (1 << 6) as follows

    #chip 16F877a
    #option Explicit
    
    #DEFINE myShift 4  // could be any value constant/register mask. I am using the constant value of 4
    
    Do
        porta = porta XOR ( 1 << myShift )
        wait 100 ms
    Loop
    

    Explanation:

    porta is typically a register that controls the state of the pins on port A of the microcontroller.

    XOR (exclusive OR) is a bitwise operation that toggles specific bits.

    1 << myShift: This is a bitwise left shift operation. It shifts the bit 1 to the left by myShift positions. So 1 << 4 equals 16 in decimal, or 0b10000 in binary.

    The XOR operation will toggle the bit at position 4 of register.

    ASM

    The ASM generated follows. It is optimised and is easy to understand.

    Instruction ASM Size Comment
    porta = porta XOR ( 1 << myShift ) 2 Simple and fast.

    This is generated by my prototype implementation.

       ;porta = porta XOR ( 1 << myShift )
        movlw   16
        banksel PORTA
        xorwf   PORTA,F
    

    Syntax and Error Handling

    result_register = ( VALUE_CONSTANT [<< | >> ] NUM_OF_POSITIONS_CONSTANT )

    [EDITED] The shift operations would have to support constants only. There is huge difference between using constants to variables. Constants can be calculated during compilation. Variables are a run time coding and is not scope for this potential piece of work.

    See next post regarding variables as parameters

    This seems to be so easy but this where I need your thoughts to get the syntax right.

    How to handle errors? what are errors? etc.
    Is this valid syntax ? porta = porta XOR 1 << myShiftNo parentheses
    How handle ? porta = porta XOR 1 << Where there is no shift parameter
    How handle ? porta = porta XOR 1 << undefined_consant Where there is no shift parameter as the constant does not exist.
    How to handle ? Using a variable as a shift parameter? Just throw a compilation error.
    Other things that need to be handled ?


    Evan

     

    Last edit: Anobium 2025-01-08
  • Anobium

    Anobium - 2025-01-08

    Change of plan ... as I posted a private message to Chris Roper ( he wrote many of the Bitwise operations many years ago... I had a flash of inspiration.

    Support of variables as the parameters is easily do able. If either of the parameters are not constants then call then transform the instruction ( in the compier) to call methods FnLSL() or FnLSR() within the compiled ASM - the user source remains the same!

    **Prototype Compiler Implementation **

    Dim myShiftVar as Byte
    myShiftVar = 4
    
    Do
        porta = porta XOR ( 1 << myShiftVar )
        wait 100 ms
    Loop
    

    Generated ASM!

    ;porta = porta XOR ( 1 << myShiftVar )
        movlw   1
        movwf   SYSBYTETEMPB
        movlw   4
        banksel NUMBITS
        movwf   NUMBITS
        call    FN_FNLSL91
        movf    PORTA,W
        xorwf   SYSFNLSLBYTE,W
        movwf   PORTA
    
    ...
    ...
    
    ;Overloaded signature: BYTE:BYTE:, Source: stdbasic.h (427)
    FN_FNLSL91
    ;Repeat NumBits
        movf    NUMBITS,W
        movwf   SysRepeatTemp1
        btfsc   STATUS,Z
        goto    SysRepeatLoopEnd1
    SysRepeatLoop1
    ;Set C Off
        bcf STATUS,C
    ;Rotate SysByteTempB Left
        rlf SYSBYTETEMPB,F
    ;End Repeat
        decfsz  SysRepeatTemp1,F
        goto    SysRepeatLoop1
    SysRepeatLoopEnd1
    ;FnLSL = SysByteTempB
        movf    SYSBYTETEMPB,W
        movwf   FNLSL
        return
    

    Crikey - this works!!

     
  • Anobium

    Anobium - 2025-01-10

    I have completed an implementation.

    Handles use of constants or variables.

    porta =  porta XOR 1 << 6
    
    Gens
    
    ;porta =  porta XOR ( 1<<6 )
        movlw   64
        banksel PORTA
        xorwf   PORTA,F
    

    or

    Dim Numbits as Byte
    Numbits = 6
    porta =  porta XOR 1 << Numbits
    
    Gens
    
    ;Dim Numbits as Byte
    ;Numbits = 6
        movlw   6
        banksel NUMBITS
        movwf   NUMBITS
    ;porta =  porta XOR 1 << Numbits
        movlw   1
        movwf   SYSBYTETEMPB
        call    FN_FNLSL91       // Call to FNLSL or FNLSR as appropriate
        movf    PORTA,W
        xorwf   SYSFNLSLBYTE,W
        movwf   PORTA
    

    There is lots of syntax checking but it may not cover all cases.

    Anyone interested in testing?

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.