24 Bit Floating Point Square Root
;**********************************************************************
;By Nikolai Golovchenko
;24 BIT FLOATING POINT SQARE ROOT
;Input:
;AARGB0 - high byte with sign bit
;AARGB1 - low byte
;AEXP - exponent 2^(AEXP - 127)
;FPFLAGS, RND - rounding/truncating (not used)
;Result:
;AARGB0-1, AEXP - 24 bit floating point
;Used:
;BARGB0-1, BEXP - temporary for result
;TEMPB0-1
;LOOPCOUNT - counter
;Memory used
;91 instructions
;9 RAM bytes
;Timing (includes call and return)
;6 cycles best case
;5+21+8*25-1+4+8*26-1+12= 445 cycles worst case
;**********************************************************************
;NOTES: 1)Square root is taken on absolute value of the number
; (sign bit is ignored)
; 2)Rounding not implemented yet
;**********************************************************************
FPSQRT24
;Normalize input
;1)Check for zero input - if zero then exit
;2)Change sign to 1 and use sign bit as explicit MSB
;3)BEXP = AEXP - 127
;4)If AEXP can be divided by 2 (AEXP<0>=1) then bexp = bexp/2,
;BARGB2 = 1, AARGB<0-2> << 1 and find 23 more bits
;5)Else bexp=(bexp-1)/2, find 24 more bits
;6)BEXP = BEXP + 127
movf AEXP, w ;if zero input then return
btfsc 0x03, 2
retlw 0x00
clrf BARGB0 ;set up all used
clrf BARGB1 ;temporary registers
clrf TEMPB0 ;
clrf TEMPB1 ;
bsf AARGB0, 7 ;make MSB explicit and ignore mantissa sign
addlw -127 ;BEXP = aexp - 127 or aexp - 128
btfss AEXP, 0
addlw -1
movwf BEXP
rlf BEXP, w ;arithmetic right shift of BEXP
rrf BEXP, f
btfss AEXP, 0 ;shift input left if exp can be divided by two
goto FPSQRT24a
bcf 0x03, 0
rlf AARGB1, f
rlf AARGB0, f
bsf BARGB1, 0
FPSQRT24a
movlw 127 ;BEXP = BEXP + 127
addwf BEXP, f
;First find 8 bits of result. This will shift AARGB0 - AARGB1 to TEMPB1
;Then only zeros will be fed instead of AARGB0
movlw 8 ;loop counter
movwf LOOPCOUNT ;
FPSQRT24b
movlw 0x40 ;substract test bit from
subwf AARGB0, f ;current lowest byte
movf BARGB1, w ;and substract current result
btfss 0x03, 0 ;from higher bytes
incfsz BARGB1, w
subwf TEMPB1, w
btfsc 0x03, 0 ;if result = 1 then
movwf TEMPB1 ;store substraction result
rlf BARGB1, f ;shift result into result bytes
rlf BARGB0, f ;
movlw 0x40 ;
btfss BARGB1, 0 ;if result bit = 1 then skip restoration
addwf AARGB0, f ;
bcf 0x03, 0
rlf AARGB1, f ;Shift out next two bits of input
rlf AARGB0, f ;
rlf TEMPB1, f ;
rlf TEMPB0, f ;
rlf AARGB1, f ;
rlf AARGB0, f ;
rlf TEMPB1, f ;
rlf TEMPB0, f ;
decfsz LOOPCOUNT, f ;repeat untill all 12 bits will be found
goto FPSQRT24b
;Find other 7 or 8 bits. Only zeros are fed instead of AARGB0
movlw 7 ;loop counter
btfss AEXP, 0
movlw 8
movwf LOOPCOUNT ;
FPSQRT24d
movf TEMPB1, w ;store one byte of input
movwf AARGB1
bcf 0x03, 0 ;simulate borrow (0x00 - 0x40 = 0xC0)
incfsz BARGB1, w
subwf TEMPB1, f
movf BARGB0, w
btfss 0x03, 0
incfsz BARGB0, w
subwf TEMPB0, w
btfsc 0x03, 0 ;if result = 1 then
movwf TEMPB0 ;store substraction result
rlf BARGB1, f ;shift result into result bytes
rlf BARGB0, f
btfsc BARGB1, 0 ;if result bit = 1 then skip restoration
goto FPSQRT24e
movf AARGB1, w ;restore previous data
movwf TEMPB1 ;
FPSQRT24e
rrf BARGB1, w ;Shift out next two bits of input
rlf TEMPB1, f ;
rlf TEMPB0, f ;
rrf BARGB1, w ;
rlf TEMPB1, f ;
rlf TEMPB0, f ;
decfsz LOOPCOUNT, f ;repeat untill all 12 bits will be found
goto FPSQRT24d
;flag C, TEMPB1 - TEMPB0 contain current input that may be used to find 17th bit for rounding
;Copy BARG to AARG
movf BEXP, w
movwf AEXP
movf BARGB0, w
movwf AARGB0
movf BARGB1, w
movwf AARGB1
bcf AARGB0, 7 ;clear sign bit (overwrites explicit MSB, which is always one)
retlw 0x00
;**********************************************************************
;Last updated 02Jan00