OzanGazi
Joined: 03 Mar 2008 Posts: 6
|
Integer Fast Math Library Using 8x8 Hardware Multiplier |
Posted: Fri Jan 02, 2009 6:37 am |
|
|
Hi all!!
in the past i was composed a fast math library for realtime RMS measurement. Now i recomposed the Library for CCS forum users.
These are functions and calculation times on 40Mhz clock...
res16=fast_SquareRoot(val32); calculation time ~105uS
res32=fast_Square(val16); calculation time ~6 uS
res32=fast_Divide32by16(val32,val16); calculation time ~60uS
res32=fast_Multiply16by16(val16,val16); calculation time ~6 uS
Code edited.. on Fri Jan 02, 2009 7:00 am
Code: |
///////////////////////////////////////////////////////////////////////
// //
// fastmath.c //
// //
// //
// Integer Fast Operations Library Using 8x8 Hardware Multiplier //
// //
// This Code composed by OzaNGazi //
// //
// 0x010-0x01B RAM area is allocated for using asm functions //
// //
// !! Hardware Mutliplier Registers must be defined !! //
// //
// (e.g. pic18f452) //
// #byte PRODL=0xFF3 //
// #byte PRODH=0xFF4 //
// //
// //
// Functions //
// //
// res16=fast_SquareRoot(val32); //calculation time ~105 uS //
// res32=fast_Square(val16); //calculation time ~6 uS //
// res32=fast_Divide32by16(val32); //calculation time ~60uS //
// res32=fast_Multiply16by16(val16); //calculation time ~6 uS //
// //
// //
///////////////////////////////////////////////////////////////////////
unsigned long fast_SquareRoot(unsigned long long kok_girdi_);
unsigned long long fast_Square(unsigned long kare_girdi_);
unsigned long long int fast_Divide32by16(unsigned long long int Dividend_ , unsigned long int Divisor_ );
Unsigned Long long int fast_Multiply16by16(unsigned long int mul1 , unsigned long int mul2) ;
unsigned long long fast_Square(unsigned long kare_girdi_)
{
unsigned long long Kare_Sonuc;
#locate Kare_Sonuc = 0x010
#Byte SQRES0 = 0x010
#Byte SQRES1 = 0x011
#Byte SQRES2 = 0x012
#Byte SQRES3 = 0x013
unsigned long Kare_Girdi;
#locate Kare_Girdi = 0x014
#Byte ARG1L = 0x014
#Byte ARG1H = 0x015
kare_girdi=kare_girdi_;
#asm
; *******************************************************************
; *********** 16 X 16 Unsigned Square *****************************
; SQRES3:SQRES0 = ARG1H:ARG1L ^2
Sq16:
movf ARG1L, W
mulwf ARG1L ; ARG1L * ARG2L ->
; PRODH:PRODL
movff PRODH, SQRES1 ;
movff PRODL, SQRES0 ;
movf ARG1H, W
mulwf ARG1H ; ARG1H * ARG2H ->
; PRODH:PRODL
movff PRODH, SQRES3 ;
movff PRODL, SQRES2 ;
movf ARG1L, W
mulwf ARG1H ; ARG1L * ARG2H ->
; PRODH:PRODL
movf PRODL, W ;
addwf SQRES1, F ; Add cross
movf PRODH, W ; products
addwfc SQRES2, F ;
clrf WREG ;
addwfc SQRES3, F ;
movf ARG1H, W ;
mulwf ARG1L ; ARG1H * ARG2L ->
; PRODH:PRODL
movf PRODL, W ;
addwf SQRES1, F ; Add cross
movf PRODH, W ; products
addwfc SQRES2, F ;
clrf WREG ;
addwfc SQRES3, F ;
#endasm
return(Kare_Sonuc);
}
unsigned long fast_SquareRoot(unsigned long long kok_girdi_)
{
unsigned long long Kare_Sonuc;
unsigned long Kare_Girdi;
unsigned long long Kok_Girdi;
unsigned long Kok_Sonuc;
#locate Kare_Sonuc = 0x010
#Byte SQRES0 = 0x010
#Byte SQRES1 = 0x011
#Byte SQRES2 = 0x012
#Byte SQRES3 = 0x013
#locate Kare_Girdi = 0x014
#Byte ARG1L = 0x014
#Byte ARG1H = 0x015
#locate Kok_Girdi = 0x016
#Byte ARGA0 = 0x016
#Byte ARGA1 = 0x017
#Byte ARGA2 = 0x018
#Byte ARGA3 = 0x019
#locate Kok_Sonuc = 0x01A
#Byte RES0 = 0x01A
#Byte RES1 = 0x01B
unsigned int temp0,temp1,bitloc0,bitloc1;
kok_girdi=kok_girdi_;
#asm
square:
; *******************************************************************
; ******************** Square Root **********************************
; Sqrt32(ARGA3:ARGA2:ARGA1:ARGA0) = RES1:RES0
Sqrt32:
clrf TEMP0 ; clear the temp solution
clrf TEMP1
clrf BITLOC0 ; setup the first bit
clrf RES0
movlw 0x80
movwf BITLOC1 ; BitLoc = 0x8000
movwf RES1 ; RES = 0x8000
Squar16:
movff RES0, ARG1L ; square the guess
movff RES1, ARG1H
call Sq16
movf SQRES0, W ; ARGA - PROD test
subwf ARGA0, W
movf SQRES1, W
subwfb ARGA1, W
movf SQRES2, W
subwfb ARGA2, W
movf SQRES3, W
subwfb ARGA3, W
btfsc STATUS,0
bra NxtBt16 ; if positive then next bit
; if negative then rotate right
addlw 0x00 ; clear carry
movff TEMP0, RES0 ; move last good value back into RES0
movff TEMP1, RES1
rrcf BITLOC1, F ; then rotote the bit and put it
rrcf BITLOC0, F
movf BITLOC1, W ; back into RES1:RES0
iorwf RES1, F
movf BITLOC0, W
iorwf RES0, F
btfsc STATUS, 0 ; if last value was tested then get
bra Done32 ; out
bra Squar16 ; elso go back for another test
NxtBt16:
addlw 0x00 ; clear carry
movff RES0, TEMP0 ; copy the last good approximation
movff RES1, TEMP1
rrcf BITLOC1, F ; rotate the bit location register
rrcf BITLOC0, F
movf BITLOC1, W ; and put back into RES1:RES0
iorwf RES1, F
movf BITLOC0, W
iorwf RES0, F
btfsc STATUS, 0 ; if last value was tested then get
bra Done32 ; out
bra Squar16
Done32:
movff TEMP0,RES0 ; put the final result in RES1:RES0
movff TEMP1,RES1
bra over
; *******************************************************************
; *********** 16 X 16 Unsigned Square *****************************
; SQRES3:SQRES0 = ARG1H:ARG1L ^2
Sq16:
movf ARG1L, W
mulwf ARG1L ; ARG1L * ARG2L ->
; PRODH:PRODL
movff PRODH, SQRES1 ;
movff PRODL, SQRES0 ;
movf ARG1H, W
mulwf ARG1H ; ARG1H * ARG2H ->
; PRODH:PRODL
movff PRODH, SQRES3 ;
movff PRODL, SQRES2 ;
movf ARG1L, W
mulwf ARG1H ; ARG1L * ARG2H ->
; PRODH:PRODL
movf PRODL, W ;
addwf SQRES1, F ; Add cross
movf PRODH, W ; products
addwfc SQRES2, F ;
clrf WREG ;
addwfc SQRES3, F ;
movf ARG1H, W ;
mulwf ARG1L ; ARG1H * ARG2L ->
; PRODH:PRODL
movf PRODL, W ;
addwf SQRES1, F ; Add cross
movf PRODH, W ; products
addwfc SQRES2, F ;
clrf WREG ;
addwfc SQRES3, F ;
return
over:
#endasm
return(kok_sonuc);
}
Unsigned Long long int Fast_Divide32by16(unsigned long long int Dividend_ , unsigned long int Divisor_ )
{
unsigned int bitcnt;
unsigned Long long int Dividend;
#locate dividend =0x010
#byte divid0 =0x010
#byte divid1 =0x011
#byte divid2 =0x012
#byte divid3 =0x013
unsigned long int Divisor;
#locate Divisor =0x014
#byte DivisL =0x014
#byte DivisH =0x015
unsigned long int Remdr;
#locate Remdr =0x016
#byte RemdrL =0x016
#byte RemdrH =0x017
Dividend=Dividend_;
Divisor=Divisor_;
#asm
divide:
movlw 0x20 ; 32-bit divide by 16-bit
movwf bitcnt
clrf remdrH ; Clear remainder
clrf remdrL
dvloop:
bcf STATUS,0 ; Set quotient bit to 0
; Shift left dividend and quotient
rlcf divid0,f ; lsb
rlcf divid1,f
rlcf divid2,f
rlcf divid3,f ; lsb into carry
rlcf remdrL,f ; and then into partial remainder
rlcf remdrH,f
btfsc STATUS,0 ; Check for overflow
goto subd
movf divisH,W ; Compare partial remainder and divisor
subwf remdrH,w
btfss STATUS,2
goto testgt ; Not equal so test if remdrH is greater
movf divisL,W ; High bytes are equal, compare low bytes
subwf remdrL,w
testgt:
btfss STATUS,0 ; Carry set if remdr >= divis
goto remrlt
subd:
movf divisL,W ; Subtract divisor from partial remainder
subwf remdrL
btfss STATUS,0 ; Test for borrow
decf remdrH ; Subtract borrow
movf divisH,w
subwf remdrH
bsf divid0,0 ; Set quotient bit to 1
; Quotient replaces dividend which is lost
remrlt:
decfsz bitcnt
goto dvloop
#endasm
return(dividend);
}
Unsigned Long long int Fast_Multiply16by16(unsigned long int mul1_ , unsigned long int mul2_)
{
unsigned long int wrd;
unsigned long int luk;
unsigned long long int res;
unsigned int C3;
#locate res = 0x010
#locate wrd = 0x010
#Byte wrd_L = 0x010
#Byte wrd_H = 0x011
#locate ext = 0x012
#Byte ext_L = 0x012
#Byte ext_H = 0x013
#locate luk = 0x014
#Byte luk_L = 0x014
#Byte luk_H = 0x015
wrd=mul1_;
luk=mul2_;
#asm
;Multiplication 16bit * 16bit -> 32bit
;WRD * LUK -> EXTWRD
;detailed: WRD_H:WRD_L * LUK_H:LUK_L -> EXT_H:EXT_L:WRD_H:WRD_L
;LUK value remains. Affected registers: temp reg C3
MULW: movf WRD_H,w
mulwf LUK_H ; LUK_H * WRD_H
movff PRODH,EXT_H
movff PRODL,EXT_L
movf WRD_L,w
mulwf LUK_L ; LUK_L * WRD_L
movff PRODH,C3
movff PRODL,WRD_L
mulwf LUK_H ; LUK_H * WRD_L
movf PRODL,w
addwf C3,f ; Add cross
movf PRODH,w ; products
addwfc EXT_L,f
clrf WREG
addwfc EXT_H,f
movf WRD_H,w
mulwf LUK_L ; LUK_L * WRD_H
movf PRODL,w ;
addwf C3,w ; Add cross
movwf WRD_H
movf PRODH,w ; products
addwfc EXT_L,f
clrf WREG
addwfc EXT_H,f
#endasm
return(res);
}
|
|
|