;*************************************************************************** ;* ;* "div16u" - 16/16 Bit Unsigned Division ;* ;* This subroutine divides the two 16-bit numbers ;* "dd8uH:dd8uL" (dividend) and "dv16uH:dv16uL" (divisor). ;* The result is placed in "dres16uH:dres16uL" and the remainder in ;* "drem16uH:drem16uL". ;* ;* Number of words :19 ;* Number of cycles :235/251 (Min/Max) ;* Low registers used :2 (drem16uL,drem16uH) ;* High registers used :5 (dres16uL/dd16uL,dres16uH/dd16uH,dv16uL,dv16uH, ;* dcnt16u) ;* ;*************************************************************************** ;***** Subroutine Register Variables .def drem16uL=r14 .def drem16uH=r15 .def dres16uL=r16 .def dres16uH=r17 .def dd16uL =r16 .def dd16uH =r17 .def dv16uL =r18 .def dv16uH =r19 .def dcnt16u =r20 ;***** Code div16u: clr drem16uL ;clear remainder Low byte sub drem16uH,drem16uH;clear remainder High byte and carry ldi dcnt16u,17 ;init loop counter d16u_1: rol dd16uL ;shift left dividend rol dd16uH dec dcnt16u ;decrement counter brne d16u_2 ;if done ret ; return d16u_2: rol drem16uL ;shift dividend into remainder rol drem16uH sub drem16uL,dv16uL ;remainder = remainder - divisor sbc drem16uH,dv16uH ; brcc d16u_3 ;if result negative add drem16uL,dv16uL ; restore remainder adc drem16uH,dv16uH clc ; clear carry to be shifted into result rjmp d16u_1 ;else d16u_3: sec ; set carry to be shifted into result rjmp d16u_1 ;*************************************************************************** ;* ;* "mpy8u" - 8x8 Bit Unsigned Multiplication ;*************************************************************************** ;***** Subroutine Register Variables .def mc8u =r16 ;multiplicand .def mp8u =r17 ;multiplier .def m8uL =r17 ;result Low byte .def m8uH =r18 ;result High byte .def mcnt8u =r19 ;loop counter ;***** Code mpy8u: clr m8uH ;clear result High byte ldi mcnt8u,8 ;init loop counter lsr mp8u ;rotate multiplier m8u_1: brcc m8u_2 ;carry set add m8uH,mc8u ; add multiplicand to result High byte m8u_2: ror m8uH ;rotate right result High byte ror m8uL ;rotate right result L byte and multiplier dec mcnt8u ;decrement loop counter brne m8u_1 ;if not done, loop more ret ;*************************************************************************** ;* ;* "mpy16u" - 16x16 Bit Unsigned Multiplication ;***** Subroutine Register Variables .def mc16uL =r16 ;multiplicand low byte .def mc16uH =r17 ;multiplicand high byte .def mp16uL =r18 ;multiplier low byte .def mp16uH =r19 ;multiplier high byte .def m16u0 =r18 ;result byte 0 (LSB) .def m16u1 =r19 ;result byte 1 .def m16u2 =r20 ;result byte 2 .def m16u3 =r21 ;result byte 3 (MSB) .def mcnt16u =r22 ;loop counter ;***** Code mpy16u: clr m16u3 ;clear 2 highest bytes of result clr m16u2 ldi mcnt16u,16 ;init loop counter lsr mp16uH ror mp16uL m16u_1: brcc noad8 ;if bit 0 of multiplier set add m16u2,mc16uL ;add multiplicand Low to byte 2 of res adc m16u3,mc16uH ;add multiplicand high to byte 3 of res noad8: ror m16u3 ;shift right result byte 3 ror m16u2 ;rotate right result byte 2 ror m16u1 ;rotate result byte 1 and multiplier High ror m16u0 ;rotate result byte 0 and multiplier Low dec mcnt16u ;decrement loop counter brne m16u_1 ;if not done, loop more ret ;********************************************* ;NewDiv.asm --> div16s -> based on a 24-bit by 16 divide scheme from Atmel's 16x16 divide ;Notes: ;highly specialized for point.asm ;remainder does not contain correct value ;does not check for divide by 0 ;does not check for over/underflow ;only checks the dividend for negative sign, does not check divisor ;48 words, 405 cycles, 101.25us @ 4MHz ;uses 17 high registers, 3 low registers ;written by Michael Katz 1/9/00 ;********************************************* ;***** Subroutine Register Variables .def d16s =r30 ;sign register .def drem16sL=r9 ;remainder low byte .def drem16sH=r11 ;remainder high byte .def drem16s3=r10 .def dres16s2=r16 ;result middle byte .def dres16s1=r18 ;result highest byte .def dres16s3=r17 ;result lowest byte .def dd16s2 =r16 ;dividend low byte .def dd16s1 =r18 ;dividend high byte .def dd16s3 =r17 ;dividend zero byte .def dv16sL =r19 ;divisor low byte .def dv16sH =r20 ;divisor high byte .def dcnt16s =r31 ;loop counter ;***** Code div16s: clr d16s ;clear sign register tst dd16s1 ;if dividend negative, set sign register brge div_0 ser d16s com dd16s1 ; change sign of dividend com dd16s2 subi dd16s2,low(-1) sbci dd16s2,high(-1) div_0: clr dd16s3 ;make 24-bit # clr drem16sL ;sets remainder to 0 clr drem16sH ldi dcnt16s, 0x18 ;sets counter at 24 div_1: clc rol dres16s3 ;shift dividend left rol dres16s2 rol dres16s1 rol drem16sL ;shift remainder left + carry in from dividend rol drem16sH sub drem16sL, dv16sL ;remainder = remainder - divisor sbc drem16sH, dv16sH brcc div_2 ;negative? add drem16sL, dv16sL ; restore remaidner adc drem16sH, dv16sH rjmp div_3 div_2: ori dres16s3, 0x01 ;positive --> Q0 = 1 div_3: dec dcnt16s ;count-- brne div_1 tst d16s brge div_end com dres16s2 ; change sign of result com dres16s3 subi dres16s3,low(-1) sbci dres16s2,high(-1) div_end: ret ;*************************************************************************** ;* ;* "div8u" - 8/8 Bit Unsigned Division ;* ;* This subroutine divides the two register variables "dd8u" (dividend) and ;* "dv8u" (divisor). The result is placed in "dres8u" and the remainder in ;* "drem8u". ;* ;* Number of words :14 ;* Number of cycles :97 ;* Low registers used :1 (drem8u) ;* High registers used :3 (dres8u/dd8u,dv8u,dcnt8u) ;* ;*************************************************************************** ;***** Subroutine Register Variables .def drem8u =r15 ;remainder .def dres8u =r16 ;result .def dd8u =r16 ;dividend .def dv8u =r17 ;divisor .def dcnt8u =r18 ;loop counter ;***** Code div8u: sub drem8u,drem8u ;clear remainder and carry ldi dcnt8u,9 ;init loop counter d8u_1: rol dd8u ;shift left dividend dec dcnt8u ;decrement counter brne d8u_2 ;if done ret ; return d8u_2: rol drem8u ;shift dividend into remainder sub drem8u,dv8u ;remainder = remainder - divisor brcc d8u_3 ;if result negative add drem8u,dv8u ; restore remainder clc ; clear carry to be shifted into result rjmp d8u_1 ;else d8u_3: sec ; set carry to be shifted into result rjmp d8u_1