Fish4Fun
So long, and Thanks for all the Fish!
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) ...
Still assuming a priori knowledge of the particular bit, but extending the scope to some random data space byte one might do the following:
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
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:
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
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