Rotate a byte a variable number of positions
by Isaac Marino Bavaresco
I was needing a (very) efficient way to rotate a byte a variable number
of positions when the following popped on my mind(code in PIC18 assembly, see more code lower in the page):
btfsc TABLAT, 2, ACCESS
swapf PRODL, F, ACCESS
btfsc TABLAT, 1, ACCESS
rrncf PRODL, F, ACCESS
btfsc TABLAT, 1, ACCESS
rrncf PRODL, F, ACCESS
btfsc TABLAT, 0, ACCESS
rrncf PRODL, F, ACCESS
The number of positions to rotate is in TABLAT and the value to be
rotated is in PRODL.
The routine can rotate from zero to 7 positions, takes only 8
instructions and as a bonus it is isochronous.
Any other registers can be used. If banked registers are used then the bank selection must be cared of properly.
Macros for the PIC18 architecture:
;===============================================================================
; Macro to rotate a register a variable number of positions to the right.
; The number of positions to rotate must be in another register.
;
; Input:
; value: Register with the value to be rotated.
; vacc: Access method (ACCESS or BANKED) for the value.
; positions: Register with the number of positions to rotate.
; pacc: Access method (ACCESS or BANKED) for the positions.
;
; Output:
; "value" register with the result.
;
; Changes:
; "value" register.
;
; Side effects:
; Flags Z and N may be affected.
;
; Notes:
; - If both registers use access method BANKED, both must reside in the
; same bank.
; - The code is isochronous (runs always in the same number of cycles).
rrvar macro value,vacc,positions,pacc
btfsc positions, 2, pacc
swapf value, F, vacc
btfsc positions, 1, pacc
rrncf value, F, vacc
btfsc positions, 1, pacc
rrncf value, F, vacc
btfsc positions, 0, pacc
rrncf value, F, vacc
endm
;===============================================================================
; Macro to rotate a register a variable number of positions to the left.
; The number of positions to rotate must be in another register.
;
; Input:
; value: Register with the value to be rotated.
; vacc: Access method (ACCESS or BANKED) for the value.
; positions: Register with the number of positions to rotate.
; pacc: Access method (ACCESS or BANKED) for the positions.
;
; Output:
; "value" register with the result.
;
; Changes:
; "value" register.
;
; Side effects:
; Flags Z and N may be affected.
;
; Notes:
; - If both registers use access method BANKED, both must reside in the
; same bank.
; - The code is isochronous (runs always in the same number of cycles).
rlvar macro value,vacc,positions,pacc
btfsc positions, 2, pacc
swapf value, F, vacc
btfsc positions, 1, pacc
rlncf value, F, vacc
btfsc positions, 1, pacc
rlncf value, F, vacc
btfsc positions, 0, pacc
rlncf value, F, vacc
endm
;===============================================================================
; Macro to rotate a register a fixed number of positions to the right.
; The number of positions to rotate must be a numeric constant.
;
; Input:
; value: Register with the value to be rotated.
; vacc: Access method (ACCESS or BANKED) for the value.
; positions: Constant with the number of positions to rotate.
;
; Output:
; "value" register with the result.
;
; Changes:
; "value" register.
;
; Side effects:
; Flags Z and N may be affected.
;
; Notes:
; - The code generated may range from one to four instructions.
rrcon macro value,vacc,positions
if positions & b'00000100'
swapf value, F, vacc
endif
if positions & b'00000010'
rrncf value, F, vacc
rrncf value, F, vacc
endif
if positions & b'00000001'
rrncf value, F, vacc
endif
endm
;===============================================================================
; Macro to rotate a register a fixed number of positions to the left.
; The number of positions to rotate must be a numeric constant.
;
; Input:
; value: Register with the value to be rotated.
; vacc: Access method (ACCESS or BANKED) for the value.
; positions: Constant with the number of positions to rotate.
;
; Output:
; "value" register with the result.
;
; Changes:
; "value" register.
;
; Side effects:
; Flags Z and N may be affected.
;
; Notes:
; - The code generated may range from one to four instructions.
rlcon macro value,vacc,positions
if positions & b'00000100'
swapf value, F, vacc
endif
if positions & b'00000010'
rlncf value, F, vacc
rlncf value, F, vacc
endif
if positions & b'00000001'
rlncf value, F, vacc
endif
endm
;===============================================================================
Macros for the baseline/midrange architecture:
;===============================================================================
; Macro to rotate a register a variable number of positions to the right.
; The number of positions to rotate must be in another register.
;
; Input:
; value: Register with the value to be rotated.
; positions: Register with the number of positions to rotate.
;
; Output:
; "value" register with the result.
;
; Changes:
; "value" register, WREG.
;
; Side effects:
; Flag C is affected.
;
; Notes:
; - Both registers must reside in the same bank.
; - The code is isochronous (runs always in the same number of cycles).
rrvar macro value,positions
btfsc positions, 2
swapf value, F
rrf value, W
btfsc positions, 1
rrf value, F
btfsc positions, 1
rrf value, F
btfsc positions, 0
rrf value, F
endm
;===============================================================================
; Macro to rotate a register a variable number of positions to the left.
; The number of positions to rotate must be in another register.
;
; Input:
; value: Register with the value to be rotated.
; positions: Register with the number of positions to rotate.
;
; Output:
; "value" register with the result.
;
; Changes:
; "value" register, WREG.
;
; Side effects:
; Flag C is affected.
;
; Notes:
; - Both registers must reside in the same bank.
; - The code is isochronous (runs always in the same number of cycles).
rlvar macro value,positions
btfsc positions, 2
swapf value, F
rlf value, W
btfsc positions, 1
rlf value, F
btfsc positions, 1
rlf value, F
btfsc positions, 0
rlf value, F
endm
;===============================================================================
; Macro to rotate a register a fixed number of positions to the right.
; The number of positions to rotate must be a numeric constant.
;
; Input:
; value: Register with the value to be rotated.
; positions: Constant with the number of positions to rotate.
;
; Output:
; "value" register with the result.
;
; Changes:
; "value" register, "WREG".
;
; Side effects:
; Flag C is affected.
;
; Notes:
; - The code generated may range from one to five instructions.
rrcon macro value,positions
if positions & b'00000100'
swapf value, F
endif
if positions & b'00000011' != 0
rrf value, W
endif
if positions & b'00000010'
rrf value, F
rrf value, F
endif
if positions & b'00000001'
rrf value, F
endif
endm
;===============================================================================
; Macro to rotate a register a fixed number of positions to the left.
; The number of positions to rotate must be a numeric constant.
;
; Input:
; value: Register with the value to be rotated.
; positions: Constant with the number of positions to rotate.
;
; Output:
; "value" register with the result.
;
; Changes:
; "value" register, WREG.
;
; Side effects:
; Flag C is affected.
;
; Notes:
; - The code generated may range from one to five instructions.
rlcon macro value,positions
if positions & b'00000100'
swapf value, F
endif
if positions & b'00000011' != 0
rlf value, W
endif
if positions & b'00000010'
rlf value, F
rlf value, F
endif
if positions & b'00000001'
rlf value, F
endif
endm
;===============================================================================