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