; 32bit Floating point package for the 8051 ; This version is for the ASM51 assembler by Metalink Corporation (very similar to ASM51 from Intel) ; By Jerson Fernandes ; email : jerson@vsnl.com ; jerson@geocities.com ; From : Bombay in India ; floating point format ; exponent, 24 bits mantissa ; xxxxxxxx, S.xxxxxxx xxxxxxxx xxxxxxxx ; stored internally from right to left ; ZERO = 00 000000 ; MAX float = FF 7FFFFF 6.80564693E+38 ; MIN float = 01 000000 1.17549435E-38 ; Int2Float converts the input number to float at Aarg ; Float2Int converts the A register to integer @ Aarg $title(32 bit floating point package for 8051) $mod51 FPPush Macro FPreg mov a,FPreg ;save the result push acc mov a,FPreg+1 push acc mov a,FPreg+2 push acc mov a,FPreg+3 push acc endm FPPop Macro FPreg pop acc ;retrieve A mov FPreg+3,a pop acc mov FPreg+2,a pop acc mov FPreg+1,a pop acc mov FPreg,a endm DSEG ;--- This will allow you to link in the library on the DSEGment ;--- The ORG 8 directive has been used to test the module as a standalone program ;--- You may remove it when you want to assemble this into a library org 8 ;======= Floating point variables =========== float_arg equ 3 ;3 bytes mantissa float_exp equ 1 ;1 byte exponent expbias equ 128 ;exponent bias Quo: ds float_arg ;holds quotient of divide Aarg: ds float_arg Aexp: ds float_exp Barg: ds float_arg Bexp: ds float_exp Aext: ds 1 ;extension for Aarg Aext2: ds 1 ;for holding the aligned bit ;======= Floating point variables =========== ;--- Again, like before, this TOS (top of Stack) pointer is used just because this is a standalone program ;--- Not needed when you make this into a library. ;--- Just make sure your main program has declared enough room for the stack to grow TOS: CSEG ;--- will allow the linker to stack this code in the code segment ;--- The ORG 0 directive has been used to test the module as a standalone program ;--- You may remove it when you want to assemble this into a library org 0 ;--- This segment is to test the functionality of the library ;--- It is not part of the library and can be modified as per your needs ;example code for 1+10 ;** example code to check 5020 = (1000*1000)/50000 + 5000 ;*** Well - it works for me!! start: mov sp,#TOS ;point to the top of stack mov Aarg,#low 1000 ;define a 24 bit integer value +1000 mov Aarg+1,#high 1000 mov Aarg+2,#0 acall int2float ; acall copy_ab ;copy it to floating B register ; mov Aarg,#low 1000 ;define 24 bit integer value +1000 mov Aarg+1,#high 1000 mov Aarg+2,#0 acall int2float ; acall fpmul32 ;multiply A & B ; FPPush Aarg mov Aarg,#low 50000 mov Aarg+1,#high 50000 mov Aarg+2,#0 acall int2float acall copy_ab ;B = 50000 ; FPPop Aarg ; lcall fpdiv32 ; A / B ; acall copy_ab ;copy the result to B ; mov Aarg,#low 5000 mov Aarg+1,#high 5000 ;Add 5000 mov Aarg+2,#0 acall int2float ; lcall fpAdd32 ; ; Now convert the result to 24 bit integer lcall float2int sjmp $ ;======================================================================== ; 32bit Floating point package for the 8051 ; floating point format ; exponent, 24 bits mantissa ; xxxxxxxx, S.xxxxxxx xxxxxxxx xxxxxxxx ; stored internally from right to left ;Copy ArgA to ArgB Copy_AB:mov r7,#float_arg mov r0,#Aarg mov r1,#Barg copy_AB_5: mov a,@r0 mov @r1,a inc r0 inc r1 djnz r7,copy_AB_5 mov Bexp,Aexp ret ;Copy ArgB to ArgA Copy_BA:mov r7,#float_arg mov r0,#Barg mov r1,#Aarg copy_BA_5: mov a,@r0 mov @r1,a inc r0 inc r1 djnz r7,copy_BA_5 mov Aexp,Bexp ret ;Swap A and B registers ; Swap_AB: mov r0,#Aarg mov r1,#Barg mov r2,#Float_Arg ;counter Sw10: xch a,@r0 ; [r0] -> A xch a,@r1 ; [r1] <-> A xch a,@r0 ; [r0] <- A inc r0 inc r1 djnz r2,Sw10 ; xch a,Aexp xch a,Bexp xch a,Aexp ret ;Negate mantissa ; INPUT R0 - pointer to the mantissa LSB to negate ; OUTPUT negated mantissa ; Negate: mov a,@r0 cpl a add a,#1 ;2s complement mov @r0,a inc r0 mov a,@r0 cpl a addc a,#0 mov @r0,a inc r0 mov a,@r0 cpl a addc a,#0 mov @r0,a ret ; Convert a integer to a floating point number ; Input - 24 bit signed integer @ Aarg ; Output- 32 bit floating point number @ Aarg int2float: ; Normalize the 24 bit signed integer in Aarg Normalize: mov r6,#24 ;exponent counter mov a,Aarg+2 ;extract sign anl a,#80h mov r5,a ;keep in R5 jz norm5 ;negative number make +ve as we have the sign mov r0,#Aarg lcall Negate Norm5: mov r0,#Aarg+2 mov a,@r0 orl a,#0 jnz Norm10 ;the highest 8 are 0, shift 8 mov a,#0 xch a,Aarg xch a,Aarg+1 xch a,Aarg+2 clr c mov a,r6 subb a,#8 mov r6,a ;update the exponent ; jz Norm0 ;if no more exponent, its zero (0) jnc Norm5 ;continue if still more is left of the exponent ; Norm10:mov a,@r0 ;read the msb jb Acc.7,Norm_end ;shift one bit left mov a,Aarg clr c rlc a mov Aarg,a mov a,Aarg+1 rlc a mov Aarg+1,a mov a,Aarg+2 rlc a mov Aarg+2,a djnz r6,Norm10 ;note the shift in the exponent too Norm_end: mov a,#expbias add a,r6 mov Aexp,a ;now make the msbit implicit and put in the sign there mov a,r5 orl a,#7fh anl a,Aarg+2 mov Aarg+2,a ;sign is always for int2float ret Norm0: mov Aexp,a ret ; Float to integer conversion routine ; Input - floating point number in Aarg,Aexp ; Output- 24 bit signed integer in Aarg float2int: mov a,Aexp clr c subb a,#expbias jc res0 ;result is 0 cjne a,#24,$+3 ;overflow,return a 0 int jnc res0 mov r6,a ;keep the exponent here ;find out how much to shift the float to get our int mov a,#24 clr c subb a,r6 mov r6,a ;take out the sign and make msb explicit mov a,Aarg+2 ;keep in R5 mov r5,a orl a,#80h mov Aarg+2,a ;explicit msb ;now shift the float to form the int flint10: mov a,r6 ;if exp >= 8, shift bytes clr c subb a,#9 jnc flint20 ;now do bit shifts flint15: clr c mov a,Aarg+2 rrc a mov Aarg+2,a mov a,Aarg+1 rrc a mov Aarg+1,a mov a,Aarg+0 rrc a mov Aarg+0,a djnz r6,flint15 ;we're done getting the int,restore the sign mov a,r5 anl a,#80h jz flint30 ;restore the negative number mov r0,#Aarg lcall Negate flint30:ret flint20: ;shift right 8 bits clr a xch a,Aarg+2 xch a,Aarg+1 xch a,Aarg+0 ;and adjust the exp counter in r6 mov a,r6 subb a,#8 mov r6,a sjmp flint10 res0: clr a mov Aarg+0,a mov Aarg+1,a mov Aarg+2,a ret ;Floating point divide ; Input - Arg 1 in Aarg, Aexp ; - Arg 2 in Barg, Bexp ; Output- Divide arg1 by arg2 ; - result in Aarg ; Temp - R5 resulting sign ; acc for dividend is ; Aarg[2,1,0],Quo[2,1,0] msb first fpdiv32: ;check if Bexp == 0 mov a,Bexp jnz fpd10 ajmp fpdivz fpd10: mov a,Aarg+2 ;extract resulting sign xrl a,Barg+2 anl a,#80h ;keep the sign bit here mov r5,a ;make the msb explicit in args mov a,#80h orl a,Aarg+2 mov Aarg+2,a mov a,#80h orl a,Barg+2 mov Barg+2,a ;if A>= 1; clr c mov a,Barg+2 rrc a mov Barg+2,a mov a,Barg+1 rrc a mov Barg+1,a mov a,Barg rrc a mov Barg,a ; Bexp ++; inc Bexp djnz ExpCtr,fpAWhile fpA40: ;check if the XOR sign is -ve mov a,XORsign jz fpA50 mov r0,#Barg lcall Negate fpA50: ;add A = A+B mov r0,#Aarg mov r1,#Barg mov r2,#Float_arg ;counter clr c fpA45: mov a,@r0 addc a,@r1 mov @r0,a inc r0 inc r1 djnz r2,fpA45 ; ;done with addition mov a,XORsign ; is XOR sign +ve? jnz fpAneg ;Positive number jnc fpA70 fpA60: ;if Cy is left over, shift the Aarg and correct the exponent mov a,Aarg+2 rrc a mov Aarg+2,a mov a,Aarg+1 rrc a mov Aarg+1,a mov a,Aarg rrc a mov Aarg,a ; Aexp ++; inc Aexp ; fpA70: mov a,Aarg+2 anl a,#7fh orl a,Asign mov Aarg+2,a ; put in the sign ret fpA80: acall fpANrm sjmp fpA70 fpAneg: jc fpA80 ; mov r0,#Aarg lcall Negate ; mov a,Aarg+2 orl a,#80h mov Aarg+2,a fpANrm: ;Normalize the result mov a,Aarg+2 ;read the msb jb Acc.7,fpANrmEnd ;shift one bit left mov a,Aarg clr c rlc a mov Aarg,a mov a,Aarg+1 rlc a mov Aarg+1,a mov a,Aarg+2 rlc a mov Aarg+2,a ; dec Aexp ; mov a,Aexp cjne a,#expbias,fpANrm fpANrmEnd: ret end