;*** ; двухбайтное сравнение ldi r16,low(777) cpi zh,high(777) cpc zl,r16 ========== .def dataL = r4 ; multiplicand low byte .def dataH = r5 ; multiplicand high byte .def KoeffL = r2 ; multiplier low byte .def koeffH = r3 ; multiplier high byte .def temp = r16 ; result byte 0 (LSD) .def temp1 = r17 ; result byte 1 .def temp2 = r18 ; result byte 2 (MSD) ;************************************************************************** ; умножение двух 16-разрядных величин, только для Mega ; исходные величины dataH-dataL и KoeffH-KoeffL ; результат 3 байта temp2:temp1:temp Mul16: clr temp2 ; очистить старший mul dataL,KoeffL ; умножаем младшие mov temp,r0 ; в R0 младший результата операции mul mov temp1,r1 ; в R1 старший результата операции mul mul dataH,KoeffL ; умножаем старший на младший add temp1,r0 ; в R0 младший результата операции mul adc temp2,r1 ; в R1 старший результата операции mul mul dataL,KoeffH ; умножаем младший на старший add temp1,r0 ; в R0 младший результата операции mul adc temp2,r1 ; в R1 старший результата операции mul mul dataH,KoeffH ; умножаем старший на старший add temp2,r0 ; 4-й разряд нам тут не требуется, но он - в R1 ret ;************************************************************************** ================================== ;*************************************************************************** ; перемножение двух 16-разрядных величин, ; результат 3 байта mpy16u: clr tmp2 ldi count,16 ;init loop counter m16u_1: lsr KoeffH ror KoeffL brcc noad8 ;if bit 0 of multiplier set add tmpm,IzmL ;add multiplicand Low to byte 2 of res adc tmp2,IzmH ;add multiplicand high to byte 3 of res noad8: ror tmp2 ;rotate right result byte 2 ror tmpm ;rotate result byte 1 and multiplier High ror temp ;rotate result byte 0 and multiplier Low dec count ;decrement loop counter brne m16u_1 ;if not done, loop more ret ;*************************************************************************** ; перемножение двух 16-разрядных величин, результат 4 байта, рабочая ; множимое KoeffH:KoeffL, множитель IzmH:IzmL, результат tmp3:tmp2:tmpm:temp ; использует count ; слов: 14 + return. циклов: 153 + return + rcall mpy16u: clr tmp3 ;clear 2 highest bytes of result clr tmp2 ldi count,16 ;init loop counter m16u_1: lsr KoeffH ror KoeffL brcc noad8 ;if bit 0 of multiplier set add tmp2,IzmL ;add multiplicand Low to byte 2 of res adc tmp3,IzmH ;add multiplicand high to byte 3 of res noad8: ror tmp3 ;shift right result byte 3 ror tmp2 ;rotate right result byte 2 ror tmpm ;rotate result byte 1 and multiplier High ror temp ;rotate result byte 0 and multiplier Low dec count ;decrement loop counter brne m16u_1 ;if not done, loop more ret ================================== ;*************************************************** ;* Mutiply 32x32 -> 64 bit ;* A B C ;* R24:R21 x R5:R2 -> R15:R8 ;* ;* 88 cycles + 4 (RET) = 92 Cycles ;* mult32: clr R16 mul R21,R2 ; умножили A1 на Б1 movw R8,R0 ; рез положили в Ц1-2 clr R10 clr R11 clr R12 clr R13 clr R14 clr R15 mul R22,R2 ; умн А2 на Б1 add R9,R0 ; рез1 доб к Ц2 adc R10,R1 ; рез2 доб к Ц3 mul R23,R2 ; умн А3 на Б1 add R10,R0 ; рез1 доб к Ц3 adc R11,R1 ; рез2 доб к Ц4 mul R24,R2 ; А4 умн на Б1 add R11,R0 ; рез1 доб к Ц4 adc R12,R1 ; рез2 доб к Ц5 mul R21,R3 add R9,R0 adc R10,R1 adc R11,R16 adc R12,R16 adc R13,R16 mul R22,R3 add R10,R0 adc R11,R1 adc R12,R16 adc R13,R16 mul R23,R3 add R11,R0 adc R12,R1 adc R13,R16 mul R24,R3 add R12,R0 adc R13,R1 mul R21,R4 add R10,R0 adc R11,R1 adc R12,R16 adc R13,R16 adc R14,R16 mul R22,R4 add R11,R0 adc R12,R1 adc R13,R16 adc R14,R16 mul R23,R4 add R12,R0 adc R13,R1 adc R14,R16 mul R24,R4 add R13,R0 adc R14,R1 mul R21,R5 add R11,R0 adc R12,R1 adc R13,R16 adc R14,R16 adc R15,R16 mul R22,R5 add R12,R0 adc R13,R1 adc R14,R16 adc R15,R16 mul R23,R5 add R13,R0 adc R14,R1 adc R15,R16 mul R24,R5 add R14,R0 adc R15,R1 ret ================================== ;*************************************************** ;* Mutiply 24x16 -> 40 bit (3*2=5 Bytes) ;* A B C ;* R23:R21 x R3:R2 -> R12:R8 ;* ;* 30 cycles + 4 (RET) = 34 Cycles ;* mul24x16: clr R16 mul R21,R2 ; A1*B1 movw R8,R0 ; Rez->C1C2 clr R10 clr R11 clr R12 mul R22,R2 ; A2*B1 add R9,R0 ; C2+=Rez1 adc R10,R1 ; C3+=Rez2 mul R23,R2 ; A3*B1 add R10,R0 ; C3+=Rez1 adc R11,R1 ; C4+=Rez2 mul R21,R3 ; A1*B2 add R9,R0 ; C2+=Rez1 adc R10,R1 ; C3+=Rez2 adc R11,R16 ; C4+=C flag adc R12,R16 ; C5+=C flag mul R22,R3 ; A2*B2 add R10,R0 ; C3+=Rez1 adc R11,R1 ; C4+=Rez2 adc R12,R16 ; C5+=C flag mul R23,R3 ; A3*B2 add R11,R0 ; C4+=Rez1 adc R12,R1 ; C5+=Rez2 ret ;*************************************************************************** ;* ;* "mpy16u8" - 16x8 Bit Unsigned Multiplication ;* ;* This subroutine multiplies 16-bit and 8-bit register variables ;* mp16uH:mp16uL and mc16uL ;* The result is placed in m16u2:m16u1:m16u0. ;* ;* Number of words :13 + return ;* Number of cycles :137? + return ;* Low registers used :1 (R0) ;* High registers used :5 (mc16uL,mp16uL/m16u0,mp16uH/m16u1,m16u2,mcnt16u) ;* ;*************************************************************************** ;***** Subroutine Register Variables .def mc16uL =r16 ;multiplicand low 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 mcnt16u =r22 ;loop counter ;***** Code mpy16u8:clr R0 clr m16u2 ;clear high byte of result ldi mcnt16u,16 ;init loop counter m16u_1: lsr mp16uH ror mp16uL brcc noad8 ;if bit 0 of multiplier set add m16u1,mc16uL ;add multiplicand Low to byte 1 of res adc m16u2,R0 ;add multiplicand high to byte 2 of res noad8: 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 ================================== ;************************************************************************* ; div32x8 - 32/8 деление беззнаковых чисел ; Делимое и результат в countHH (старший), countTH, ; countTM, countTL (младший) ; делитель в cikle ; требуется четыре рабочих регистра dremL — dremHH ; из диапазона R16-R31 для хранения остатка div32x8: clr temp ; "ZERO" clr dremL ;clear remainder Low byte clr dremM ;clear remainder clr dremH ;clear remainder sub dremHH,dremHH ;clear remainder High byte and carry ldi cnt,33 ;init loop counter d_1: rol countTL ;shift left dividend rol countTM rol countTH rol countHH dec cnt ;decrement counter brne d_2 ;if done ret ;return d_2: rol dremL ;shift dividend into remainder rol dremM rol dremH rol dremHH sub dremL,cikle ;remainder = remainder — divisor sbc dremM,temp sbc dremH,temp sbc dremHH,temp brcc d_3 ;if result negative add dremL,cikle ;restore remainder adc dremM,temp adc dremH,temp adc dremHH,temp clc ;clear carry to be shifted into result rjmp d_1 ;else d_3: sec ; set carry to be shifted into result rjmp d_1 ; ************************************************************** конец 32/8 ==================================== ;*************************************************************************** ;* ;* "div24u16" - 24/16 Bit Unsigned Division ;* (по сути это 24/24) ;* Эта процедура делит 3-х байтное число на 2-х байтное ;* "dd16uH:dd16uM:dd16uL" (dividend) and "dv16uH:dv16uL" (divisor). ;* The result is placed in "dres16uH:dres16uM:dres16uL" and the remainder in ;* "drem16uH:drem16uM:drem16uL". ;* ;* Number of words :25 (50 bytes) ;* Number of cycles :?/? (Min/Max) ;* Low registers used :7 (drem16uL,drem16uM,drem16uH,dres16uL/dd16uL,dres16uM/dd16uM,dres16uH/dd16uH,ZERO) ;* High registers used :3 (dv16uL,dv16uH,dcnt16u) ;* ;*************************************************************************** ;***** Subroutine Register Variables .def ZERO =R12 .def drem16uL=r13 .def drem16uM=r14 .def drem16uH=r15 .def dres16uL=r16 .def dres16uM=r17 .def dres16uH=r18 .def dd16uL =r16 .def dd16uM =r17 .def dd16uH =r18 .def dv16uL =r19 .def dv16uH =r20 .def dcnt16u =r21 ;***** Code div24u: clr ZERO clr drem16uL ;clear remainder Low byte clr drem16uM ;clear remainder Middle byte sub drem16uH,drem16uH;clear remainder High byte and carry ldi dcnt16u,25 ;init loop counter d24u_1: rol dd16uL ;shift left dividend rol dd16uM rol dd16uH dec dcnt16u ;decrement counter brne d24u_2 ;if done ret ; return d24u_2: rol drem16uL ;shift dividend into remainder rol drem16uM rol drem16uH sub drem16uL,dv16uL ;remainder = remainder - divisor sbc drem16uM,dv16uH sbc drem16uH,ZERO brcc d24u_3 ;if result negative add drem16uL,dv16uL ; restore remainder adc drem16uM,dv16uH adc drem16uH,ZERO clc ; clear carry to be shifted into result rjmp d24u_1 ;else d24u_3: sec ; set carry to be shifted into result rjmp d24u_1 ; ************************************************************************* ; процедура деления 24/8 отличается от 24/16 только тем, ; что старший байт делителя всегда равен 0 ; ************************************************************************* ; div24u8 - 24/8 деление беззнаковых чисел ; Делимое и результат в countH (старший), countTM, countTL (младший) ; делитель в divisor, использует R0, cnt ; требуется три рабочих регистра dremL — dremH для хранения остатка ; 25 слов, 5+24*(17-19)+5+4=(408-456)+14=422--470 тактов ; + 3 такта на rcall :-) div24u8:clr R0 clr dremL ;clear remainder Low byte clr dremM ;clear remainder Midle byte sub dremH,dremH ;clear remainder High byte and carry ldi cnt,25 ;init loop counter d_1: rol countTL ;shift left dividend rol countTM rol countTH dec cnt ;decrement counter brne d_2 ;if done ret ;return d_2: rol dremL ;shift dividend into remainder rol dremM rol dremH sub dremL,divisor ;remainder = remainder — divisor sbc dremM,R0 sbc dremH,R0 brcc d_3 ;if result negative add dremL,divisor ;restore remainder adc dremM,R0 adc dremH,R0 clc ;clear carry to be shifted into result rjmp d_1 ;else d_3: sec ; set carry to be shifted into result rjmp d_1 ; ************************************************************** конец 24/8 ;*************************************************************************** ;* ;* "div16u8" - 16/8 Bit Unsigned Division ;* ;* This subroutine divides the 16-bit / 8-bit numbers ;* "dd16uH:dd16uL" (dividend) and "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 :4 (dres16uL/dd16uL,dres16uH/dd16uH,dv16uL,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 dcnt16u =r19 ;***** Code div16u: clr R0 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,R0 ; brcc d16u_3 ;if result negative add drem16uL,dv16uL ; restore remainder adc drem16uH,R0 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 ==================================== ;****************************** ; делим двубайтное число на 10 ; вход: JobH:JobL ; выход: XH:XL, остаток может быть в JobL ; использует: DIV16_10: clr XL ; инициируем счётчик десятков clr XH sbiw X,1 DIV16_10_l1: adiw X,1 ; увеличили счётчик sbiw JobL,10 ; уменьшили исходное число brsh DIV16_10_l1 ; если остаток > 0 -- ещё на круг ; inc JobL ; если нужен остаток ret