Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

AVR Code for Dividing 16 Bits by 8-Bit Constant

Status
Not open for further replies.

Kerim

Member
Hello,

Here is a common AVR assembly code for dividing 16-bit register by any 8-bit constant divisor [2 to 255] with rounding.
By the way, about a year ago, I also shared it at “AVRfreaks forum” in case there are members here who used visiting it (unfortunately, I can’t join it lately, due to world’s regulations).

The speed of this versatile code is not bad [37/33 cycles, max/min; excluding RET and RCALL].
It uses 32 words.
To use this code (posted below), only the constant divisor ‘reg_N’ needs to be changed,

The next thread will be about how this code could be updated to divide 16-Bit register by an 8-Bit register (if its value is not zero).

Kerim

Code:
;==============================================================
; *** Division of 16-bit register {A} by 8-bit constant {N} ***
;==============================================================

; {R}={A}/{N} = r17:r16 / {N} = r17:r16 * {Kd} /256 /256 then rounding

; {A} dividend in r17:r16 [0 to 65535]
; {N} constant divisor [N=2 to 255]
; {R} result in r21:r20 , {A}/{N} rounded
; {Kd} = round(256*256/{N},0), the division constant
; {Kr} = INT[ (1-{N})/2 ]    , the rounding constant
; used registers: r19,r18,r14,r13,r1,r0
; 32 words , excluding RET and RCALL
; 40, 43, or 44 cycles = 33c|36c|37 code + 4c RET + 3c RCALL

.set reg_N = 113                  ; {N}
.set reg_Kd=(2*256*256/reg_N+1)/2 ; {Kd}
.set reg_Kr=(1-reg_N)/2           ; {Kr}

D16_nnn:
    LDI   r18,  low(reg_Kd)     ;1abc
    MOV   r13, r18              ;1abc
    LDI   r18, high(reg_Kd)     ;1abc
    MOV   r14, r18              ;1abc, 4abc
; r14:r13 = reg_Kd

; multiplicand in r17:r16 = {A}
; multiplier   in r14:r13 = {Kd}
; mul. result  in r21:r20:r19:r18
; valid result in r21:r20
    MUL   r17, r14              ;2abc
    MOVW  r21:r20, r1:r0        ;1abc
    MUL   r16, r13              ;2abc
    MOVW  r19:r18, r1:r0        ;1abc
    MUL   r17, r13              ;2abc
    CLR   r13                   ;1abc
    ADD   r19, r0               ;1abc
    ADC   r20, r1               ;1abc
    ADC   r21, r13              ;1abc
    MUL   r14, r16              ;2abc
    ADD   r19, r0               ;1abc
    ADC   r20, r1               ;1abc
    ADC   r21, r13              ;1abc +17abc= 21abc
; {B} = r21:r20 = r17:r16 * r14:r13 /256/256 = {A}*{Kd}/256/256
; {R} = {B} or {B}+1

; for rounding
    LDI   r18, reg_N            ;1abc
    MOV   r13, r18              ;1abc
; r13 = {N}

    MUL   r20, r13              ;2abc
    MOVW  r19:r18, r1:r0        ;1abc
    MUL   r21, r13              ;2abc
    ADD   r19, r0               ;1abc, +8abc= 29abc
; {C} = r19:r18 = {B}*{N} = r21:r20 * r13

; the following conditions were deduced empirically
; if( Carry_1=0, {R}={B}, if({D2}>0, {R}={B}, {R}={B}+1 ) )

    SUB   r18, r16              ;1abc
    SBC   r19, r17              ;1abc
; {D1} = r19:r18 = {C} - {A} = r19:r18 - r17:r16

    BRCC  DIV_ret               ;2a|1bc +4a=[33a]
; if Carry_1=0, {R}={B}

    SUBI  r18,  low(reg_Kr)     ;1bc
    SBCI  r19, high(reg_Kr)     ;1bc
; {D2} = r19:r18 = {D1} - {Kr} = r19:r18 - {Kr}

    BRPL  DIV_ret               ;2b|1c, +7b=[36b]
; if {D2} positive, {R}={B}

    SUBI  r20,  low(-1)         ;1c
    SBCI  r21, high(-1)         ;1c, +8c=[37c]
; {R}={B}+1

DIV_ret:
    RET                         ;4
; {R} = r21:r20 = {B} or {B}+1 [ {A}/{N} rounded ]
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top