Search code examples
assemblyavratmega16

How does division by constant work in avr-gcc?


In avr assembly, I wanted to divide a number by a constant. I checked how to see how avr-gcc does it. So in a c file I have :

#include <stdint.h>

uint8_t divide_by_6(uint8_t x) {
    return x / 6;
}

and when I run avr-gcc -O3 -mmcu=atmega16 -D__AVR_ATmega16__ -S main.c it gives me:

divide_by_6:
    ldi r25,lo8(-85)
    mul r24,r25
    mov r24,r1
    clr r1
    lsr r24
    lsr r24
    ret

But I do not understand what this assembly is doing. How does this assembly code perform division?


Solution

  • -85 is 0xFFFFFFFFFFFFFFAB, so lo8(-85) is 0xAB, which is 171.

    The code is multiplying the argument by 171, and then returning the most significant byte of the product, shifted right by 2 (i.e. divided by 4).

    So it's effectively returning x * 171 / (256 * 4) == x * 171 / 1024, which is approximately == x * 1 / 6 == x / 6.