Procedura mnożenia dwóch 32-bitowych liczb bez znaku w asemblerze dla AVR
Mnożenie 32x32-bit
From: <a___a_at_nospam_wp.pl>
Subject: Mnożenie 32x32-bit
Date: 19 Mar 2002 08:19:10 +0100
Witam
Czy ktoś z grupowiczów posiada procedurę w asemblerze na AVRy,
mnożenia dwóch liczb 32-bitowych bez znaku?
Pozdrawiam
aa
--
Wysłano z serwisu OnetNiusy: http://niusy.onet.pl
From: "ErrOR" <error_at_nospam_2com.pl>
Subject: Re: Mnożenie 32x32-bit
Date: Tue, 19 Mar 2002 13:37:23 +0100
Czy ktoś z grupowiczów posiada procedurę w asemblerze na AVRy,
mnożenia dwóch liczb 32-bitowych bez znaku?
Oto kod operacji 32 bitowych dla up atmel'51
(dodawanie,odejmowanie,mnozenie,dzielenie). moze cos ci sie przyda :
NAME Math_32_Module
;
PUBLIC Load_16, ?Load_16?byte
PUBLIC Load_32, ?Load_32?byte
PUBLIC Mul_16, ?Mul_16?byte
PUBLIC Div_16, ?Div_16?byte
PUBLIC Add_16, ?Add_16?byte
PUBLIC Sub_16, ?Sub_16?byte
PUBLIC Add_32, ?Add_32?byte
PUBLIC Sub_32, ?Sub_32?byte
PUBLIC Low_16, Mid_16, High_16
;
Math_32_Data SEGMENT DATA
Math_32_Code SEGMENT CODE
;
RSEG Math_32_Data
?Load_16?byte: DS 2
?Load_32?byte: DS 4
?Mul_16?byte: DS 2
?Div_16?byte: DS 2
?Add_16?byte: DS 2
?Sub_16?byte: DS 2
?Add_32?byte: DS 4
?Sub_32?byte: DS 4
OP_0: DS 1
OP_1: DS 1
OP_2: DS 1
OP_3: DS 1
TMP_0: DS 1
TMP_1: DS 1
TMP_2: DS 1
TMP_3: DS 1
;
$eject
RSEG Math_32_Code
;
Load_16:
;Load the lower 16 bits of the OP registers with the value supplied
MOV OP_3,#0
MOV OP_2,#0
MOV OP_1,?Load_16?byte
MOV OP_0,?Load_16?byte + 1
RET
Load_32:
;Load all the OP registers with the value supplied
MOV OP_3,?Load_32?byte
MOV OP_2,?Load_32?byte + 1
MOV OP_1,?Load_32?byte + 2
MOV OP_0,?Load_32?byte + 3
RET
Low_16:
;Return the lower 16 bits of the OP registers
MOV R6,OP_1
MOV R7,OP_0
RET
Mid_16:
;Return the middle 16 bits of the OP registers
MOV R6,OP_2
MOV R7,OP_1
RET
High_16:
;Return the high 16 bits of the OP registers
MOV R6,OP_3
MOV R7,OP_2
RET
$eject
Add_16:
;Add the 16 bits supplied by the caller to the OP registers
CLR C
MOV A,OP_0
ADDC A,?Add_16?byte + 1 ;low byte first
MOV OP_0,A
MOV A,OP_1
ADDC A,?Add_16?byte ;high byte + carry
MOV OP_1,A
MOV A,OP_2
ADDC A,#0 ;propagate carry only
MOV OP_2,A
MOV A,OP_3
ADDC A,#0 ;propagate carry only
MOV OP_3,A
RET
Add_32:
;Add the 32 bits supplied by the caller to the OP registers
CLR C
MOV A,OP_0
ADDC A,?Add_32?byte + 3 ;lowest byte first
MOV OP_0,A
MOV A,OP_1
ADDC A,?Add_32?byte + 2 ;mid-lowest byte + carry
MOV OP_1,A
MOV A,OP_2
ADDC A,?Add_32?byte + 1 ;mid-highest byte + carry
MOV OP_2,A
MOV A,OP_3
ADDC A,?Add_32?byte ;highest byte + carry
MOV OP_3,A
RET
$eject
Sub_16:
;Subtract the 16 bits supplied by the caller from the OP registers
CLR C
MOV A,OP_0
SUBB A,?Sub_16?byte + 1 ;low byte first
MOV OP_0,A
MOV A,OP_1
SUBB A,?Sub_16?byte ;high byte + carry
MOV OP_1,A
MOV A,OP_2
SUBB A,#0 ;propagate carry only
MOV OP_2,A
MOV A,OP_3
SUBB A,#0 ;propagate carry only
MOV OP_3,A
RET
Sub_32:
;Subtract the 32 bits supplied by the caller from the OP registers
CLR C
MOV A,OP_0
SUBB A,?Sub_32?byte + 3 ;lowest byte first
MOV OP_0,A
MOV A,OP_1
SUBB A,?Sub_32?byte + 2 ;mid-lowest byte + carry
MOV OP_1,A
MOV A,OP_2
SUBB A,?Sub_32?byte + 1 ;mid-highest byte + carry
MOV OP_2,A
MOV A,OP_3
SUBB A,?Sub_32?byte ;highest byte + carry
MOV OP_3,A
RET
$eject
Mul_16:
;Multiply the 32 bit OP with the 16 value supplied
MOV TMP_3,#0 ;clear out upper 16 bits
MOV TMP_2,#0
;Generate the lowest byte of the result
MOV B,OP_0
MOV A,?Mul_16?byte+1
MUL AB
MOV TMP_0,A ;low-order result
MOV TMP_1,B ;high_order result
;Now generate the next higher order byte
MOV B,OP_1
MOV A,?Mul_16?byte+1
MUL AB
ADD A,TMP_1 ;low-order result
MOV TMP_1,A ; save
MOV A,B ; get high-order result
ADDC A,TMP_2 ; include carry from previous operation
MOV TMP_2,A ; save
JNC Mul_loop1
INC TMP_3 ; propagate carry into TMP_3
Mul_loop1:
MOV B,OP_0
MOV A,?Mul_16?byte
MUL AB
ADD A,TMP_1 ;low-order result
MOV TMP_1,A ; save
MOV A,B ; get high-order result
ADDC A,TMP_2 ; include carry from previous operation
MOV TMP_2,A ; save
JNC Mul_loop2
INC TMP_3 ; propagate carry into TMP_3
Mul_loop2:
; Now start working on the 3rd byte
MOV B,OP_2
MOV A,?Mul_16?byte+1
MUL AB
ADD A,TMP_2 ;low-order result
MOV TMP_2,A ; save
MOV A,B ; get high-order result
ADDC A,TMP_3 ; include carry from previous operation
MOV TMP_3,A ; save
; Now the other half
MOV B,OP_1
MOV A,?Mul_16?byte
MUL AB
ADD A,TMP_2 ;low-order result
MOV TMP_2,A ; save
MOV A,B ; get high-order result
ADDC A,TMP_3 ; include carry from previous operation
MOV TMP_3,A ; save
; Now finish off the highest order byte
MOV B,OP_3
MOV A,?Mul_16?byte+1
MUL AB
ADD A,TMP_3 ;low-order result
MOV TMP_3,A ; save
; Forget about the high-order result, this is only 32 bit math!
MOV B,OP_2
MOV A,?Mul_16?byte
MUL AB
ADD A,TMP_3 ;low-order result
MOV TMP_3,A ; save
; Now we are all done, move the TMP values back into OP
MOV OP_0,TMP_0
MOV OP_1,TMP_1
MOV OP_2,TMP_2
MOV OP_3,TMP_3
RET
$eject
Div_16:
;This divides the 32 bit OP register by the value supplied
MOV R7,#0
MOV R6,#0 ;zero out partial remainder
MOV TMP_0,#0
MOV TMP_1,#0
MOV TMP_2,#0
MOV TMP_3,#0
MOV R1,?Div_16?byte ;load divisor
MOV R0,?Div_16?byte+1
MOV R5,#32 ;loop count
;This begins the loop
Div_loop:
CALL Shift_D ;shift the dividend and return MSB in C
MOV A,R6 ;shift carry into LSB of partial remainder
RLC A
MOV R6,A
MOV A,R7
RLC A
MOV R7,A
;now test to see if R7:R6 >= R1:R0
CLR C
MOV A,R7 ;subtract R1 from R7 to see if R1 < R7
SUBB A,R1 ; A = R7 - R1, carry set if R7 < R1
JC Cant_sub
;at this point R7>R1 or R7=R1
JNZ Can_sub ;jump if R7>R1
;if R7 = R1, test for R6>=R0
CLR C
MOV A,R6
SUBB A,R0 ; A = R6 - R0, carry set if R6 < R0
JC Cant_sub
Can_sub:
;subtract the divisor from the partial remainder
CLR C
MOV A,R6
SUBB A,R0 ; A = R6 - R0
MOV R6,A
MOV A,R7
SUBB A,R1 ; A = R7 - R1 - Borrow
MOV R7,A
SETB C ; shift a 1 into the quotient
JMP Quot
Cant_sub:
;shift a 0 into the quotient
CLR C
Quot:
;shift the carry bit into the quotient
CALL Shift_Q
; Test for competion
DJNZ R5,Div_loop
; Now we are all done, move the TMP values back into OP
MOV OP_0,TMP_0
MOV OP_1,TMP_1
MOV OP_2,TMP_2
MOV OP_3,TMP_3
RET
$eject
Shift_D:
;shift the dividend one bit to the left and return the MSB in C
CLR C
MOV A,OP_0
RLC A
MOV OP_0,A
MOV A,OP_1
RLC A
MOV OP_1,A
MOV A,OP_2
RLC A
MOV OP_2,A
MOV A,OP_3
RLC A
MOV OP_3,A
RET
Shift_Q:
;shift the quotent one bit to the left and shift the C into LSB
MOV A,TMP_0
RLC A
MOV TMP_0,A
MOV A,TMP_1
RLC A
MOV TMP_1,A
MOV A,TMP_2
RLC A
MOV TMP_2,A
MOV A,TMP_3
RLC A
MOV TMP_3,A
RET
END