URL
https://opencores.org/ocsvn/ft816float/ft816float/trunk
Subversion Repositories ft816float
[/] [ft816float/] [trunk/] [software/] [FloatToString.asm] - Rev 88
Compare with Previous | Blame | View Log
code;==============================================================================; Decimal-Floating point to string conversion routine.;; Modifies; _fpWork work area; Register Usage:; fp0 = input decimal-float to convert; fp1 = constant holder, 1.0, 10.0; fp2 = 1.0e<fp0 exponent> value for conversion; fp3 = holds digit value during significand conversion; a0 = pointer to string buffer, updated to point to NULL at end of string; a1 = pointer to "Nan" or "Inf" message string; d0 = temporary; d1 = digit value during exponent, significand conversion; d6 = exponent;==============================================================================align 4_dfOne dc.l $25ff0000,$00000000,$00000000_dfTen dc.l $2600C000,$00000000,$00000000_dfMil dc.l $2606DDFA,$1C000000,$00000000_msgNan dc.b "NaN",0_msgInf dc.b "Inf",0even;------------------------------------------------------------------------------; Check for the special Nan and infinity values. Output the appropriate string.;; Modifies; _fpWork area; a0; Parameters:; fp0 = dbl;------------------------------------------------------------------------------_CheckNan:link a2,#-12movem.l d0/a1,(sp)move.l _canary,8(sp)fmove.x fp0,_fpWorkmove.b _fpWork,d0 ; get sign+comboandi.b #$7C,d0 ; mask for combo bitscmpi.b #$7C,d0 ; is it the Nan combo?bne .notNanlea _msgNan,a1 ; output "Nan"bra .outStr.notNancmpi.b #$78,d0 ; is it infinity combo?bne .notInflea _msgInf,a1.outStrmove.b (a1)+,(a0)+ ; output "Inf"move.b (a1)+,(a0)+move.b (a1)+,(a0)+clr.b (a0)movem.l (sp),d0/a1cchk 8(sp)unlk a2ori #1,ccr ; set carry and returnrts.notInfmovem.l (sp),d0/a1cchk 8(sp)unlk a2andi #$FE,ccr ; clear carry and returnrts;------------------------------------------------------------------------------; Check for a zero value. Output a single "0" if zero,;; Modifies:; a0; Parameters:; fp0 = dbl;------------------------------------------------------------------------------_CheckZero:ftst fp0 ; check if number is zerofbne .0003move.b #'0',(a0)+ ; if zero output "0"clr.b (a0)ori #4,ccr ; set zfrts.0003andi #$FB,ccr ; clear zfrts;------------------------------------------------------------------------------; Check for a negative number. This includes Nans and Infinities. Output a "-"; if negative.;; Modifies; a0; Parameters:; fp0 = dbl;------------------------------------------------------------------------------_CheckNegative:ftst fp0 ; is number negative?fbge .0002move.b #'-',(a0)+ ; yes, output '-'fneg fp0 ; make fp0 positive.0002rts;------------------------------------------------------------------------------; Make the input value larger so that digits may appear before the decimal; point.;; Modifies:; fp0,fp1,d6; Parameters:; fp0 = dbl;------------------------------------------------------------------------------; if (dbl < 1.0) {; while (dbl < 1.0) {; dbl *= 1000000.0;; exp -= 6;; }; }_MakeBig:fmove.w #1,fp1.0002fcmp fp1,fp0 ; is fp0 > 1?fbge .0001 ; yes, returnfscale.l #6,fp0 ; multiply fp0 by a millionsubi.w #6,d6 ; decrement exponent by sixbra .0002 ; keep trying until number is > 1.0001rts;------------------------------------------------------------------------------; Create a number dbl2 on the same order of magnitude as dbl, but; less than dbl. The number will be 1.0e<dbl's exponent>;; Modifies:; d6,fp2; Parameters:; fp0 = dbl;------------------------------------------------------------------------------; // The following is similar to using log10() and pow() functions.; // Now dbl is >= 1.0; // Create a number dbl2 on the same order of magnitude as dbl, but; // less than dbl.; dbl2 = 1.0;; dbla = dbl2;; if (dbl > dbl2) { // dbl > 1.0 ?; while (dbl2 <= dbl) {; dbla = dbl2;; dbl2 *= 10.0; // increase power of 10; exp++;; }; // The above loop goes one too far, we want the last value less; // than dbl.; dbl2 = dbla;; exp--;; }_LessThanDbl:fmove.w #1,fp2 ; setup fp2 = 1fcmp fp2,fp0 ; if (dbl > dbl2)fble .0004.0006fcmp fp0,fp2 ; while (dbl2 <= dbl)fbgt .0005fscale.w #1,fp2 ; dbl2 *= 10 (increase exponent by one)addi.w #1,d6 ; exp++bra .0006.0005fscale.l #-1,fp2 ; dbl2 /= 10 (decrease exponent by one)subi.w #1,d6 ; exp--;.0004; fmove.x fp0,_fpWork ; debugging; fmove.x fp2,_fpWork+12rts;------------------------------------------------------------------------------; Compute the number of digits before the decimal point.;; Modifies:; d0,d6,_digits_before_decpt; Parameters:; d6 = exponent;------------------------------------------------------------------------------; if (exp >= 0 && exp < 6) {; digits_before_decpt = exp+1;; exp = 0;; }; else if (exp >= -7); digits_before_decpt = 1;; else; digits_before_decpt = -1;_ComputeDigitsBeforeDecpt:move.l d0,-(a7)tst.w d6bmi .0007cmpi.w #6,d6bge .0007move.w d6,d0addi.w #1,d0move.w d0,_digits_before_decptclr.w d6move.l (a7)+,d0rts.0007cmpi.w #-7,d6blt .0009move.w #1,_digits_before_decptmove.l (a7)+,d0rts.0009move.w #-1,_digits_before_decptmove.l (a7)+,d0rts;------------------------------------------------------------------------------; Spit out a leading zero before the decimal point for a small number.;; Modifies:; a0; Parameters:; d6 = exponent;------------------------------------------------------------------------------; if (exp < -7) {; buf[ndx] = '0';; ndx++;; buf[ndx] = '.';; ndx++;; }_LeadingZero:cmpi.w #-7,d6bge .0010move.b #'0',(a0)+move.b #'.',(a0)+.0010rts;------------------------------------------------------------------------------; Extract the digits of the significand.;; Modifies:; _precision variable; Register Usage; d0 = counter; d1 = digit; fp0 = dbl; fp2 = dbl2; fp3 = digit as decimal float; fp7 = dbla; Parameters:; fp0, fp2;------------------------------------------------------------------------------; // Now loop processing one digit at a time.; for (nn = 0; nn < 25 && precision > 0; nn++) {; digit = 0;; dbla = dbl;; // dbl is on the same order of magnitude as dbl2 so; // a repeated subtract can be used to find the digit.; while (dbl >= dbl2) {; dbl -= dbl2;; digit++;; }; buf[ndx] = digit + '0';; // Now go back and perform just a single subtract and; // a multiply to find out how much to reduce dbl by.; // This should improve the accuracy; if (digit > 2); dbl = dbla - dbl2 * digit;; ndx++;; digits_before_decpt--;; if (digits_before_decpt==0) {; buf[ndx] = '.';; ndx++;; }; else if (digits_before_decpt < 0); precision--;; // Shift the next digit to be tested into position.; dbl *= 10.0;; }_SpitOutDigits:link a2,#-24move.l _canary,20(sp)fmove.x fp7,(sp)movem.l d0/d1,12(sp)move.w #24,d0 ; d0 = nn.0017tst.l _precisionble .0011moveq #0,d1 ; digit = 0fmove fp0,fp7 ; dbla = dbl.0013fcmp fp2,fp0fblt .0012fsub fp2,fp0 ; dbl -= dbl2addi.b #1,d1 ; digit++bra .0013.0012addi.b #'0',d1 ; convert digit to asciimove.b d1,(a0)+ ; and storesubi.b #'0',d1 ; d1 = binary digit again; cmpi.b #2,d1; ble .0014; ext.w d1; ext.l d1; fmove.l d1,fp3 ; fp3 = digit; fmul fp2,fp3 ; fp3 = dbl2 * digit; fmove fp7,fp0; fsub fp3,fp0 ; dbl = dbla - dbl2 * digit.0014subi.w #1,_digits_before_decptbne .0015move.b #'.',(a0)+.0015tst.w _digits_before_decptbge .0016subi.l #1,_precision.0016fscale.l #-1,fp2 ; dbl *= 10.0dbra d0,.0017.0011movem.l 12(sp),d0/d1fmove.x (sp),fp7cchk 20(sp)unlk a2rts;------------------------------------------------------------------------------; If the number ends in a decimal point, trim off the point.;; Registers Modified:; none; Parameters:; a0 = pointer to end of number; Returns:; a0 = updated to point just past last digit.;------------------------------------------------------------------------------_TrimTrailingPoint:cmpi.b #'.',-1(a0)bne .0001clr.b -(a0)rts.0001cmpi.b #'.',(a0)bne .0002cmpi.b #0,1(a0)bne .0002clr.b (a0)subq #1,a0.0002rts;------------------------------------------------------------------------------; If the number ends in .0 get rid of the .0;; Registers Modified:; none; Parameters:; a0 = pointer to last digits of number; Returns:; a0 = updated to point just past last digit.;------------------------------------------------------------------------------_TrimDotZero:tst.b (a0)bne .0004cmpi.b #'0',-1(a0)bne .0004cmpi.b #'.',-2(a0)bne .0004clr.b -2(a0)subq #2,a0.0004rts;------------------------------------------------------------------------------; Trim trailing zeros from the number. Generally there is no need to display; trailing zeros.; Turns a number like 652.000000000000000000000 into 650.0;; Registers Modified:; none; Parameters:; a0 = pointer to last digits of number; Returns:; a0 = updated to point just past last digit.;------------------------------------------------------------------------------; // Trim trailing zeros from the number; do {; ndx--;; } while(buf[ndx]=='0');; ndx++;_TrimTrailingZeros:.0018cmpi.b #'0',-(a0) ; if the last digit was a zero, backupbeq .0018addq #1,a0 ; now advance by onemove.b #0,(a0) ; NULL terminate stringrts;------------------------------------------------------------------------------; Output 'e+' or 'e-';; Registers Modified:; d6.w (if negative); Parameters:; a0 = pointer to last digits of number; Returns:; a0 = updated to point just past '+' or '-'.;------------------------------------------------------------------------------; // Spit out +/-E; buf[ndx] = E;; ndx++;; if (exp < 0) {; buf[ndx]='-';; ndx++;; exp = -exp;; }; else {; buf[ndx]='+';; ndx++;; }_SpitOutE:move.b _E,(a0)+tst.w d6bge .0021move.b #'-',(a0)+neg.w d6bra .0022.0021move.b #'+',(a0)+.0022rts;------------------------------------------------------------------------------; Extract a single digit of the exponent. Extract works from the leftmost digit; to the rightmost.;; Register Usage; d2 = history of zeros; d3 = digit; Modifies; d2,d6,a0; Parameter; d1.w = power of ten; d6.w = exponent;------------------------------------------------------------------------------_ExtExpDigit:move.l d3,-(a7)ext.l d6 ; make d6 a longdivu d1,d6 ; divide by power of tenmove.b d6,d3 ; d3 = quotient (0 to 9)swap d6 ; d6 = remainder, setup for next digitor.b d3,d2tst.b d3bne .0003tst.b d2beq .0004.0003addi.b #'0',d3 ; convert to asciimove.b d3,(a0)+.0004move.l (a7)+,d3rts;------------------------------------------------------------------------------; Extract all the digits of the exponent.;; Register Usage; d1 = power of 10; d2 = history of zeros; Parameters; a0 = pointer to string buffer; d6 = exponent;------------------------------------------------------------------------------; // If the number is times 10^0 don't output the exponent; if (exp==0) {; buf[ndx]='\0';; goto prt;; }_ExtExpDigits:move.l d1,-(a7)tst.w d6 ; is exponent zero?beq .0002bsr _SpitOutE ; exponent is non-zero e+clr.b d2 ; d2 = history of zerosmove.w #1000,d1bsr _ExtExpDigitmove.w #100,d1bsr _ExtExpDigitmove.w #10,d1bsr _ExtExpDigitmove.w #1,d1bsr _ExtExpDigit.0002:move.l (a7)+,d1move.b #0,(a0) ; NULL terminate stringrts ; and return;------------------------------------------------------------------------------; Pad the left side of the output string.;; Modifies:; d0,d1,d2,d3;------------------------------------------------------------------------------; // pad left; if (width > 0) {; if (ndx < width) {; for (nn = 39; nn >= width-ndx; nn--); buf[nn] = buf[nn-(width-ndx)];; for (; nn >= 0; nn--); buf[nn] = ' ';; }; }_PadLeft:movem.l d0/d1/d2/d3,-(a7)tst.b _widthble .0041move.l a0,d0sub.l #_fpBuf,d0 ; d0 = ndxcmp.b _width,d0bge .0041move.w #49,d1 ; d1 = nn.0040move.b _width,d2ext.w d2sub.w d0,d2 ; d2 = width-ndxcmp.w d2,d1blt .0039move.w d1,d3 ; d3 = nnsub.w d2,d3 ; d3 = nn-(width-ndx)move.b (a0,d3.w),(a0,d1.w)subi.w #1,d1bra .0040.0039tst.w d1bmi .0041move.b #' ',(a0,d1.w)subi.w #1,d1bra .0039.0041movem.l (a7)+,d0/d1/d2/d3rts;------------------------------------------------------------------------------; Pad the right side of the output string.;; Parameters:; a0 = pointer to end of string; Modifies:; none; Returns:; none;------------------------------------------------------------------------------; // pad right; if (width < 0) {; width = -width;; while (ndx < width) {; buf[ndx]=' ';; ndx++;; }; buf[ndx]='\0';; }; return (ndx);_PadRight:move.l d0,-(a7)tst.b _widthbpl .0042neg.b _widthmove.l a0,d0sub.l #_fpBuf,d0 ; d0 = ndx.0044cmp.b _width,d0bge .0043move.b #' ',(a0,d0.w)addi.w #1,d0bra .0044.0043move.b #0,(a0,d0.w).0042move.l (a7)+,d0rts;------------------------------------------------------------------------------; Output a string representation of a decimal floating point number to a; buffer.;; Register Usage; a0 = pointer to string buffer; d6 = exponent; Modifies:; a0 = points to end of string; Parameters:; fp0 = number to convert; Returns:; none;------------------------------------------------------------------------------_FloatToString:move.l d6,-(a7)bsr _CheckNegative ; is number negative?bsr _CheckZero ; check for zerobeq .0001 ; branch since already output "0"bsr _CheckNan ; check for Nan or infinitybcs .0001 ; branch if nan/inf string output; Now the fun beginsclr.l d6 ; exponent = 0bsr _MakeBigbsr _LessThanDblbsr _ComputeDigitsBeforeDecptbsr _LeadingZerobsr _SpitOutDigitsbsr _TrimTrailingZerosbsr _TrimTrailingPointbsr _TrimDotZerobsr _ExtExpDigits ; extract exponent digitsbsr _PadLeft ; pad the number to the left or rightbsr _PadRight.0001move.l (a7)+,d6rts
