Menu

SHIFT Command. New command.

Anobium
4 days ago
2 days ago
  • Anobium

    Anobium - 4 days ago

    Syntax

    Shift Variable, Direction
    

    Description

    Shift moves all bits in a byte, word or long variable one position to the left or right.

    • A 0 is always shifted into the vacated bit.
    • The bit shifted out is discarded (not placed in the carry flag).
    • Multi‑byte types (Word, Long) shift correctly across all bytes using the carry flag internally.

    For rotation with carry‑feedback, use Rotate instead.


    Parameters

    • Variable — Any integer type: Byte, Word, or Long. Modified in place.
    • Direction
    • LEFT (or L) — shift toward the MSB (equivalent to multiplying by 2).
    • RIGHT (or R) — shift toward the LSB (equivalent to unsigned divide by 2).

    Notes

    • The variable is updated directly.
    • The shifted‑out bit is lost.
    • LEFT shift inserts 0 into bit 0.
    • RIGHT shift inserts 0 into the MSB.
    • Parentheses are allowed:
      Shift (Variable) Direction
    • Comma is optional:
      Shift Variable, Direction

    Example

    Dim TestByte As Byte
    Dim TestWord As Word
    
    ' Byte shift left (multiply by 2)
    TestByte = 1          ' 00000001
    Shift TestByte, LEFT  ' 00000010  result = 2
    
    ' Byte shift right (divide by 2)
    TestByte = 128        ' 10000000
    Shift TestByte, RIGHT ' 01000000  result = 64
    
    ' Word shift left across both bytes
    TestWord = 0x0080     ' 0000 0000 1000 0000
    Shift TestWord, LEFT  ' 0000 0001 0000 0000  result = 256
    
    ' Word shift right across both bytes
    TestWord = 0x0100     ' 0000 0001 0000 0000
    Shift TestWord, RIGHT ' 0000 0000 1000 0000  result = 128
    
    ' Alternative syntax forms
    Shift TestByte LEFT
    Shift TestByte, LEFT
    Shift ( TestByte ) LEFT
    Shift ( TestByte, LEFT )
    

    See Also

    • Rotate

    PIC AVR
    Byte Pre-clear carry (bcf STATUS,C) then rlf/rrf on the single byte lsl/lsr on the single byte — carry cleared implicitly
    Word (2 bytes) Pre-clear carry (bcf STATUS,C) then rlf/rrf byte 0, rlf/rrf byte 1 lsl/lsr byte 0, then rol/ror byte 1
    Long (4 bytes) Pre-clear carry (bcf STATUS,C) then rlf/rrf byte 0, 1, 2, 3 in order lsl/lsr byte 0, then rol/ror bytes 1, 2, 3 in order
    Direction LEFT rlf — rotate left through carry, byte 0 first to byte N lsl byte 0, rol bytes 1..N — lowest byte first
    Direction RIGHT rrf — rotate right through carry, byte N first to byte 0 lsr byte N, ror bytes N-1..0 — highest byte first
    Carry into first byte Always 0 — forced by bcf STATUS,C before the loop Always 0 — lsl/lsr shifts a 0 into the vacated bit
    Carry chaining Carry out of each byte feeds naturally into next rlf/rrf Carry out of lsl/lsr feeds into next byte via rol/ror
    Bit shifted off the end Discarded — carry after last byte is not fed back Discarded — carry after last byte is not fed back
    Memory operands (AVR) N/A — PIC rlf/rrf operates on file registers directly lds SysValueCopy / operate / sts back to memory
    Register operands (AVR) N/A Operate directly on the hardware register

    Impact Statement

    gcbasic.bas — Preprocessor

    One new ElseIf block added to the existing preprocessor tokenisation loop. The ROTATE block is completely unchanged.

    Change Detail
    New block ElseIf Left(CurrLine->Value, 6) = "SHIFT " added after the existing ROTATE block
    Responsibility Strips parentheses, removes commas, collapses whitespace, converts RIGHTR and LEFTL
    Risk to existing code None — the block is isolated, ROTATE is untouched, no shared state
    Lines affected ~15 new lines inserted at one location

    gcbasic.bas — Compiler

    One new sub CompileShift added. CompileROTATE is completely unchanged.

    Change Detail
    New sub Sub CompileShift added alongside existing Sub CompileROTATE
    Responsibility Parses the normalised SHIFT VarName R/L token, emits correct AVR (lsl/lsr/rol/ror) or PIC (bcf/rlf/rrf) instructions for Byte, Word and Long variables
    Call site One new call to CompileShift added in the same location that CompileROTATE is called from
    Risk to existing code None — new sub, no modification to any existing sub
    Lines affected ~100 new lines for the sub, 1 new line at the call site

    Summary

    File Existing code touched New code added
    gcbasic.bas preprocessor 0 lines changed ~15 lines
    gcbasic.bas compiler 1 line (call site) ~100 lines
     

    Last edit: Anobium 4 days ago
  • Anobium

    Anobium - 4 days ago

    Test program and results.

    ' Test routine for SHIFT command
    ' Tests Byte, Word and Long for both LEFT and RIGHT shifts
    ' Results are printed via serial so connect a terminal at 9600 baud
    '
    ' Expected results are shown in comments for each test
    
    #chip mega328p, 16
    #option explicit
    
    ' Serial for output
    #define USART_BAUD_RATE 9600
    #define USART_TX_BLOCKING
    #define USART_DELAY OFF
    
    ' Variables
    Dim TestByte As Byte
    Dim TestWord As Word
    Dim TestLong As Long
    Dim PassCount As Byte
    Dim FailCount As Byte
    
    PassCount = 0
    FailCount = 0
    
    
    wait 3 s
    
    HSerPrintCRLF
    HSerPrint "SHIFT Command Test Suite"
    HSerPrintCRLF
    HSerPrint "========================"
    HSerPrintCRLF
    
    ' -------------------------------------------------------
    ' BYTE TESTS
    ' -------------------------------------------------------
    HSerPrint "--- Byte Tests ---"
    HSerPrintCRLF
    
    ' Byte LEFT: 1 -> 2
    TestByte = 1
    Shift TestByte, LEFT
    If TestByte = 2 Then
        HSerPrint "PASS: Byte LEFT  1->2 got "
        HSerPrint TestByte
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Byte LEFT  1->2 got "
        HSerPrint TestByte
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Byte LEFT: 64 -> 128
    TestByte = 64
    Shift TestByte, LEFT
    If TestByte = 128 Then
        HSerPrint "PASS: Byte LEFT  64->128 got "
        HSerPrint TestByte
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Byte LEFT  64->128 got "
        HSerPrint TestByte
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Byte LEFT: 128 -> 0 (bit falls off the end, no carry back)
    TestByte = 128
    Shift TestByte, LEFT
    If TestByte = 0 Then
        HSerPrint "PASS: Byte LEFT  128->0 got "
        HSerPrint TestByte
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Byte LEFT  128->0 got "
        HSerPrint TestByte
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Byte RIGHT: 128 -> 64
    TestByte = 128
    Shift TestByte, RIGHT
    If TestByte = 64 Then
        HSerPrint "PASS: Byte RIGHT 128->64 got "
        HSerPrint TestByte
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Byte RIGHT 128->64 got "
        HSerPrint TestByte
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Byte RIGHT: 2 -> 1
    TestByte = 2
    Shift TestByte, RIGHT
    If TestByte = 1 Then
        HSerPrint "PASS: Byte RIGHT 2->1 got "
        HSerPrint TestByte
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Byte RIGHT 2->1 got "
        HSerPrint TestByte
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Byte RIGHT: 1 -> 0 (bit falls off the end, no carry back)
    TestByte = 1
    Shift TestByte, RIGHT
    If TestByte = 0 Then
        HSerPrint "PASS: Byte RIGHT 1->0 got "
        HSerPrint TestByte
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Byte RIGHT 1->0 got "
        HSerPrint TestByte
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' -------------------------------------------------------
    ' WORD TESTS
    ' -------------------------------------------------------
    HSerPrint "--- Word Tests ---"
    HSerPrintCRLF
    
    ' Word LEFT: 1 -> 2
    TestWord = 1
    Shift TestWord, LEFT
    If TestWord = 2 Then
        HSerPrint "PASS: Word LEFT  1->2 got "
        HSerPrint TestWord
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Word LEFT  1->2 got "
        HSerPrint TestWord
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Word LEFT: 128 -> 256 (carry from byte 0 into byte 1)
    TestWord = 128
    Shift TestWord, LEFT
    If TestWord = 256 Then
        HSerPrint "PASS: Word LEFT  128->256 got "
        HSerPrint TestWord
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Word LEFT  128->256 got "
        HSerPrint TestWord
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Word LEFT: 32768 -> 0 (MSB falls off, no carry back)
    TestWord = 32768
    Shift TestWord, LEFT
    If TestWord = 0 Then
        HSerPrint "PASS: Word LEFT  32768->0 got "
        HSerPrint TestWord
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Word LEFT  32768->0 got "
        HSerPrint TestWord
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Word RIGHT: 256 -> 128 (carry from byte 1 into byte 0)
    TestWord = 256
    Shift TestWord, RIGHT
    If TestWord = 128 Then
        HSerPrint "PASS: Word RIGHT 256->128 got "
        HSerPrint TestWord
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Word RIGHT 256->128 got "
        HSerPrint TestWord
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Word RIGHT: 32768 -> 16384
    TestWord = 32768
    Shift TestWord, RIGHT
    If TestWord = 16384 Then
        HSerPrint "PASS: Word RIGHT 32768->16384 got "
        HSerPrint TestWord
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Word RIGHT 32768->16384 got "
        HSerPrint TestWord
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Word RIGHT: 1 -> 0 (LSB falls off, no carry back)
    TestWord = 1
    Shift TestWord, RIGHT
    If TestWord = 0 Then
        HSerPrint "PASS: Word RIGHT 1->0 got "
        HSerPrint TestWord
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Word RIGHT 1->0 got "
        HSerPrint TestWord
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' -------------------------------------------------------
    ' LONG TESTS
    ' -------------------------------------------------------
    HSerPrint "--- Long Tests ---"
    HSerPrintCRLF
    
    ' Long LEFT: 1 -> 2
    TestLong = 1
    Shift TestLong, LEFT
    If TestLong = 2 Then
        HSerPrint "PASS: Long LEFT  1->2 got "
        HSerPrint TestLong
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Long LEFT  1->2 got "
        HSerPrint TestLong
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Long LEFT: 128 -> 256 (carry from byte 0 into byte 1)
    TestLong = 128
    Shift TestLong, LEFT
    If TestLong = 256 Then
        HSerPrint "PASS: Long LEFT  128->256 got "
        HSerPrint TestLong
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Long LEFT  128->256 got "
        HSerPrint TestLong
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Long LEFT: 32768 -> 65536 (carry from byte 1 into byte 2)
    TestLong = 32768
    Shift TestLong, LEFT
    If TestLong = 65536 Then
        HSerPrint "PASS: Long LEFT  32768->65536 got "
        HSerPrint TestLong
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Long LEFT  32768->65536 got "
        HSerPrint TestLong
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Long LEFT: 8388608 -> 16777216 (carry from byte 2 into byte 3)
    TestLong = 8388608
    Shift TestLong, LEFT
    If TestLong = 16777216 Then
        HSerPrint "PASS: Long LEFT  8388608->16777216 got "
        HSerPrint TestLong
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Long LEFT  8388608->16777216 got "
        HSerPrint TestLong
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Long RIGHT: 256 -> 128 (carry from byte 1 into byte 0)
    TestLong = 256
    Shift TestLong, RIGHT
    If TestLong = 128 Then
        HSerPrint "PASS: Long RIGHT 256->128 got "
        HSerPrint TestLong
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Long RIGHT 256->128 got "
        HSerPrint TestLong
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Long RIGHT: 65536 -> 32768 (carry from byte 2 into byte 1)
    TestLong = 65536
    Shift TestLong, RIGHT
    If TestLong = 32768 Then
        HSerPrint "PASS: Long RIGHT 65536->32768 got "
        HSerPrint TestLong
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Long RIGHT 65536->32768 got "
        HSerPrint TestLong
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' Long RIGHT: 16777216 -> 8388608 (carry from byte 3 into byte 2)
    TestLong = 16777216
    Shift TestLong, RIGHT
    If TestLong = 8388608 Then
        HSerPrint "PASS: Long RIGHT 16777216->8388608 got "
        HSerPrint TestLong
        HSerPrintCRLF
        PassCount = PassCount + 1
    Else
        HSerPrint "FAIL: Long RIGHT 16777216->8388608 got "
        HSerPrint TestLong
        HSerPrintCRLF
        FailCount = FailCount + 1
    End If
    
    ' -------------------------------------------------------
    ' SUMMARY
    ' -------------------------------------------------------
    HSerPrintCRLF
    HSerPrint "========================"
    HSerPrintCRLF
    HSerPrint "PASS: "
    HSerPrint PassCount
    HSerPrintCRLF
    HSerPrint "FAIL: "
    HSerPrint FailCount
    HSerPrintCRLF
    
    Do
    Loop
    

    Test results on real UNO.

    SHIFT Command Test Suite
    ========================
    --- Byte Tests ---
    PASS: Byte LEFT  1->2 got 2
    PASS: Byte LEFT  64->128 got 128
    PASS: Byte LEFT  128->0 got 0
    PASS: Byte RIGHT 128->64 got 64
    PASS: Byte RIGHT 2->1 got 1
    PASS: Byte RIGHT 1->0 got 0
    --- Word Tests ---
    PASS: Word LEFT  1->2 got 2
    PASS: Word LEFT  128->256 got 256
    PASS: Word LEFT  32768->0 got 0
    PASS: Word RIGHT 256->128 got 128
    PASS: Word RIGHT 32768->16384 got 16384
    PASS: Word RIGHT 1->0 got 0
    --- Long Tests ---
    PASS: Long LEFT  1->2 got 2
    PASS: Long LEFT  128->256 got 256
    PASS: Long LEFT  32768->65536 got 65536
    PASS: Long LEFT  8388608->16777216 got 16777216
    PASS: Long RIGHT 256->128 got 128
    PASS: Long RIGHT 65536->32768 got 32768
    PASS: Long RIGHT 16777216->8388608 got 8388608
    
    ========================
    PASS: 19
    FAIL: 0
    
     
  • miniTesla

    miniTesla - 4 days ago

    Wonderful! Can't wait to test it on some of my applications. I use SHIFT often in my coding.

     
  • Anobium

    Anobium - 4 days ago

    I can drop this into a ZIP. Would that work for you? Onedrive download again?

    Changes will get longer and longer to implement... on vacation soon

     
    • miniTesla

      miniTesla - 4 days ago

      Yes, zip file on Onedrive works for me.

       
  • Roger Jönsson

    Roger Jönsson - 4 days ago

    On a PIC this is exactly the same as Clear C+rotate?
    Still, very nice not having to keep nulling status C!

     
  • Anobium

    Anobium - 4 days ago

    Yep. That is it.

     
    👍
    1
  • miniTesla

    miniTesla - 4 days ago

    You can now consider changing the dozens, if not hundreds, of instances of "SET C OFF : ROTATE" to "SHIFT" in all the .h and library files. Casually browsing through some of them I saw many. This will improve the emitted assembler code for microcontrollers that have a native shift instruction. At least on AVRs this will make a noticeable difference.

    Shifting is used in many places. Think about all the serial communication where bytes have to be shifted out and in. Think about all the multiplications and divisions by powers-of-2 that the shift will speed up.

     
    • Anobium

      Anobium - 4 days ago

      That would be a 'no'. We would have to test on real silicon across 1000's of programs.

      Shift is a single command for clear and shift.

       
      👍
      1
  • mmotte

    mmotte - 2 days ago

    Some sensors require shifting of the raw data.

    ie. adc_T = adc_T/16 ' shift to the right 4 places

    the code would be :
    shift adc_T, right
    shift adc_T, right
    shift adc_T, right
    shift adc_T, right

    Looks like you need a number in your command?

    Sorry, Greetings Anobium!

     
    • Anobium

      Anobium - 2 days ago

      :-)

      Not able to do changes for a while.

      Have a look at the change in gcbasic.bas and preprocessor. I committed. Have a go at extending.

      The syntax would need to default to 1, then you need to make the decision what is fastest? or is it hybrid? Is multiple instructions faster then a repeat N - end repeat cycles? You would to analyse. One shift v two shifts v repeat n: one shift: end repeat.

       
  • mmotte

    mmotte - 2 days ago

    In some other language:
    int left = x << 2; // Shift left by 2 -> 00000100 (Decimal 20)
    int right = x >> 1; // Shift right by 1 -> 00000010 (Decimal 2)

    I am only giving suggestions. Not asking for change.
    BW
    M

     

    Last edit: mmotte 2 days ago
    • Anobium

      Anobium - 2 days ago

      You do that in GCBASIC. All the does is call fnLsL or fnLrL and this is where this started as that is not optimised code is all case ( constants are OK).

      ;Dim varstart = 4
      ldi SysValueCopy,4
      sts VARSTART,SysValueCopy

      ;Dim varright = varstart >> 1; // Shift right by 1 -> 00000010 (Decimal 2)
      lds SYSBYTETEMPB,VARSTART
      ldi SysValueCopy,1
      sts NUMBITS,SysValueCopy
      rcall FN_FNLSR88
      lds SysValueCopy,SYSFNLSRBYTE
      sts VARRIGHT,SysValueCopy
      ;
      Dim varright = 4 >> 1
      ldi SysValueCopy,2
      sts VARRIGHT,SysValueCopy

      ;varright = varstart
      lds SysValueCopy,VARSTART
      sts VARRIGHT,SysValueCopy
      ;shift varright, right
      lsr SysValueCopy
      sts VARRIGHT,SysValueCopy

      So, it depends what is needed.

       

Log in to post a comment.

MongoDB Logo MongoDB