Connect with us

AVR-ASM Set/Clear Bit Routines

Discussion in 'Microcontrollers, Programming and IoT' started by Fish4Fun, Nov 26, 2018.

  1. Fish4Fun

    Fish4Fun So long, and Thanks for all the Fish!

    431
    98
    Aug 27, 2013
    Toggling bits is pretty straight forward with an 8-bit AVR with a priori knowledge of the the particular bit to be toggled, especially if the bit to be toggled is in the address range of $20 to $3F (Registers $00 to $1F) ...

    Code:
         sbi   PORTA, 0     ; 1 Set PORTA.0
         cbi   PORTA, 1     ; 1 Clear PORTA.1
    ;------------------------------------------
    ;    1 Clock Each
    
    Still assuming a priori knowledge of the particular bit, but extending the scope to some random data space byte one might do the following:

    Code:
    ;Assumes Y Points to Data Space Byte where bit.0 needs to be cleared .... 
    ;Temp = r16
    ;All Registers Preserved
    DS_ClearBit_0:          ; 5 clks for call
         push  Temp         ; 2     
         ld    Temp, Y      ; 2
         andi  Temp, $FE    ; 1
         st    Y, Temp      ; 2
         pop   Temp         ; 2
         ret                ; 5 clks for return
    ;------------------------------
    ;                        19 including Call & Return
    DS_SetBit_0:          ; 5 clks for call
         push  Temp         ; 2     
         ld    Temp, Y      ; 2
         ori   Temp, 1      ; 1
         st    Y, Temp      ; 2
         pop   Temp         ; 2
         ret                ; 5 clks for return
    ;------------------------------
    ;                        19 including Call & Return
    
    With out a priori knowledge about the particular bit, there would need to be separate routines for bits 0-7 for both the set-bit and clear-bit functions ... one approach might be to create a jump table based on the bit provided ,,, following is the expansion of the ClearBit routines

    Code:
    ;Assumes Bit to be cleared is in Temp = r16
    ;Assumes Y points to Dataspace byte
    ;Preserves Z
    ;Temp is Trashed
    ;66 Instructions
    DS_ClearBit_X:                            ; 5 for Call
         push  ZH                             ; 2
         push  ZL                             ; 2
         andi  Temp, 7                        ; 1 limit bits to 0-7
         lsl   Temp                           ; 1 Multiply Temp by 2
         ldi   ZH, High(2*DS_ClearBit_X_JT)   ; 1
         ldi   ZL, Low(2*DS_ClearBit_X_JT)    ; 1
         add   ZL, Temp                       ; 1
         clr   Temp                           ; 1
         adc   ZH, Temp                       ; 1
         ijmp                                 ; 2
    ;-----------------------------------------------
    ;                                          16
      DS_ClearBit_X_JT:
         jmp   DS_ClearBit_0                  ; 3 + 16
         jmp   DS_ClearBit_1                  ; 3 + 16
         jmp   DS_ClearBit_2                  ; 3 + 16
         jmp   DS_ClearBit_3                  ; 3 + 16
         jmp   DS_ClearBit_4                  ; 3 + 16
         jmp   DS_ClearBit_5                  ; 3 + 16
         jmp   DS_ClearBit_6                  ; 3 + 16
         jmp   DS_ClearBit_7                  ; 3 + 16
         
    DS_ClearBit_0:          ;19 to Here
         ld    Temp, Y      ; 2
         andi  Temp, $FE    ; 1
         st    Y, Temp      ; 2
         pop   ZL           ; 2
         pop   ZH           ;
         ret                ; 5 clks for return
    ;------------------------------
    ;                        31 including Call & Return
    DS_ClearBit_1:          ;19 to Here
         ld    Temp, Y      ; 2
         andi  Temp, $FD    ; 1
         st    Y, Temp      ; 2
         pop   ZL           ; 2
         pop   ZH           ;
         ret                ; 5 clks for return
    ;------------------------------
    ;                        31 including Call & Return
    DS_ClearBit_2:          ;19 to Here
         ld    Temp, Y      ; 2
         andi  Temp, $FB    ; 1
         st    Y, Temp      ; 2
         pop   ZL           ; 2
         pop   ZH           ;
         ret                ; 5 clks for return
    ;------------------------------
    ;                        31 including Call & Return
    DS_ClearBit_3:          ;19 to Here
         ld    Temp, Y      ; 2
         andi  Temp, $F7    ; 1
         st    Y, Temp      ; 2
         pop   ZL           ; 2
         pop   ZH           ;
         ret                ; 5 clks for return
    ;------------------------------
    ;                        31 including Call & Return
    DS_ClearBit_4:          ;19 to Here
         ld    Temp, Y      ; 2
         andi  Temp, $EF    ; 1
         st    Y, Temp      ; 2
         pop   ZL           ; 2
         pop   ZH           ;
         ret                ; 5 clks for return
    ;------------------------------
    ;                        31 including Call & Return
    DS_ClearBit_5:          ;19 to Here
         ld    Temp, Y      ; 2
         andi  Temp, $DF    ; 1
         st    Y, Temp      ; 2
         pop   ZL           ; 2
         pop   ZH           ;
         ret                ; 5 clks for return
    ;------------------------------
    ;                        31 including Call & Return
    DS_ClearBit_6:          ;19 to Here
         ld    Temp, Y      ; 2
         andi  Temp, $BF    ; 1
         st    Y, Temp      ; 2
         pop   ZL           ; 2
         pop   ZH           ;
         ret                ; 5 clks for return
    ;------------------------------
    ;                        31 including Call & Return
    DS_ClearBit_7:          ;19 to Here
         ld    Temp, Y      ; 2
         andi  Temp, $7F    ; 1
         st    Y, Temp      ; 2
         pop   ZL           ; 2
         pop   ZH           ;
         ret                ; 5 clks for return
    ;------------------------------
    ;                        31 including Call & Return
    
    
    A more compact approach replaces the separate routines and jump table with a data table, and trashes Z to reduce the clock count to 23:

    Code:
        ; Zero = r15 Initialized to 0
        ; Temp = r16
        ; Temp = Bit Number 0-7
        ; Y Address Points to DataSpace Byte to Set Bit **Left Unchanged**
        ; Z Trashed
        ; Temp Trashed
        ;Instruction Count = 10 
        ; 8 Data Table Bytes
    DS_ClearBit_X:                                  ; 5 for Call
              andi     Temp, 7                      ; 1 Temp = XXXX XXXX ==> 0000 0XXX
              ldi      ZH, High(2 * InsD9_DT)       ; 1 Get Data Table Address high byte
              ldi      ZL,  Low(2 * InsD9_DT)       ; 1 Get Data Table Address Low byte
              add      ZL, Temp                     ; 1
              adc      ZH, Zero                     ; 1
              lpm      Temp, Z                      ; 3
              ld       ZL, Y                        ; 2 Get Value @ Address
              and      ZL, Temp                     ; 1
              st       Y, ZL                        ; 2
              ret                                   ; 5
    ;***********************************************************************************
              ;                                       23 Including Call and Return
              ;
    InsD9_DT:
    .db $FE, $FD, $FB, $F7, $EF, $DF, $BF, $7F
    
    
    Allowing Z to be trashed in the routine saves a tremendous amount of overhead in cases where numerous bits need to be set/cleared within a single routine .... the calling routine could preserve Z once and then make numerous bit manipulations before restoring Z.

    Obviously the DS_SetBit_X routine is virtually identical replacing |AND| with |OR| and using a different data table....

    If anyone has a more compact // lower clock count routine for general 8-Bit AVR Data Space bit manipulation please share!

    Thanks in Advance!

    Fish
     
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.