I want to divide a 16bit number by two. My solution to the problem was as below
lda $17 ;set high byte
ldx $32 ;set low byte
divide:
PHA ;push A to stack
TXA ;X > A
LSR ;divide low byte by 2
TAX ;A > X
PLA ;pull A from stack
LSR ;divide high byte by 2
BCC + ;C=0, skip
PHA ;while C=1
TXA ;add $80 to the lsb
ADC #$80
TAX
PLA
+
+printDecimal $0400+120
All PHA/PLA
trickery is because my printDecimal
macro reads MSB from A and LSB from X.
When I check alternatives online, I found 4 instruction alternative to my humble division routine. But I didn't understand.
div2:
LDA counter_hi ;Load the MSB
ASL ;Copy the sign bit into C
ROR counter_hi ;And back into the MSB
ROR counter_lo ;Rotate the LSB as normal
LDA counter_hi
LDX counter_lo
+printDecimal $0400+40
How this works?
Division by 2 (of an unsigned number) is the same as shifting all bits one position to the right. For example, the number 100 is represented in binary by:
Moving all positions one to the right yields
which is the binary representation of 50.
The ROR command moves all positions to the right. The new MSB of the byte will be equal to the old value of the carry flag, while the new value of the carry flag will be equal to the old LSB of the byte.
If the the 16-bit number is unsigned, it is sufficient to shift the high and the low byte of the number to the right:
LSR and ROR both shift their argument to the right, but LSR makes the MSB of counter_hi 0 and shifts the LSB of counter_hi into the carry flag, while ROR makes the MSB of counter_lo equal to the (old) LSB of counter_hi.
If the number is signed, you need to store the sign bit and make sure that the sign bit of the new number is the same. That is what the first two commands of the code you quoted do. Note that this works because the number is stored in two's complement.