Search code examples
assembly6502c64

How to divide 16bit number by 2 in 6502 asm?


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?


Solution

  • 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:

    01100100
    

    Moving all positions one to the right yields

    00110010
    

    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 counter_hi
    ROR counter_lo
    

    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.