OpenCores
URL https://opencores.org/ocsvn/ft816float/ft816float/trunk

Subversion Repositories ft816float

[/] [ft816float/] [trunk/] [software/] [FloatToString.asm] - Blame information for rev 88

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 88 robfinch
        code
2
;==============================================================================
3
; Decimal-Floating point to string conversion routine.
4
;
5
; Modifies
6
;               _fpWork work area
7
; Register Usage:
8
;       fp0 = input decimal-float to convert
9
;               fp1 = constant holder, 1.0, 10.0
10
;               fp2 = 1.0e value for conversion
11
;               fp3 = holds digit value during significand conversion
12
;       a0 = pointer to string buffer, updated to point to NULL at end of string
13
;               a1 = pointer to "Nan" or "Inf" message string
14
;               d0 = temporary
15
;               d1 = digit value during exponent, significand conversion
16
;       d6 = exponent
17
;==============================================================================
18
        align 4
19
_dfOne  dc.l $25ff0000,$00000000,$00000000
20
_dfTen  dc.l $2600C000,$00000000,$00000000
21
_dfMil  dc.l $2606DDFA,$1C000000,$00000000
22
 
23
_msgNan dc.b "NaN",0
24
_msgInf dc.b "Inf",0
25
        even
26
 
27
;------------------------------------------------------------------------------
28
; Check for the special Nan and infinity values. Output the appropriate string.
29
;
30
; Modifies
31
;               _fpWork area
32
;               a0
33
; Parameters:
34
;               fp0 = dbl
35
;------------------------------------------------------------------------------
36
 
37
_CheckNan:
38
        link a2,#-12
39
        movem.l d0/a1,(sp)
40
        move.l _canary,8(sp)
41
        fmove.x fp0,_fpWork
42
        move.b _fpWork,d0                               ; get sign+combo
43
        andi.b #$7C,d0                                  ; mask for combo bits
44
        cmpi.b #$7C,d0                                  ; is it the Nan combo?
45
        bne .notNan
46
        lea _msgNan,a1                                  ; output "Nan"
47
        bra .outStr
48
.notNan
49
        cmpi.b #$78,d0                                  ; is it infinity combo?
50
        bne .notInf
51
        lea _msgInf,a1
52
.outStr
53
        move.b (a1)+,(a0)+                      ; output "Inf"
54
        move.b (a1)+,(a0)+
55
        move.b (a1)+,(a0)+
56
        clr.b (a0)
57
        movem.l (sp),d0/a1
58
        cchk 8(sp)
59
        unlk a2
60
        ori #1,ccr                                                      ; set carry and return
61
        rts
62
.notInf
63
        movem.l (sp),d0/a1
64
        cchk 8(sp)
65
        unlk a2
66
        andi #$FE,ccr                                           ; clear carry and return
67
        rts
68
 
69
;------------------------------------------------------------------------------
70
; Check for a zero value. Output a single "0" if zero,
71
;
72
; Modifies:
73
;               a0
74
; Parameters:
75
;               fp0 = dbl
76
;------------------------------------------------------------------------------
77
 
78
_CheckZero:
79
        ftst fp0                                                                ; check if number is zero
80
        fbne .0003
81
        move.b #'0',(a0)+                               ; if zero output "0"
82
        clr.b (a0)
83
        ori #4,ccr                                                      ; set zf
84
        rts
85
.0003
86
        andi #$FB,ccr                                           ; clear zf
87
        rts
88
 
89
;------------------------------------------------------------------------------
90
; Check for a negative number. This includes Nans and Infinities. Output a "-"
91
; if negative.
92
;
93
;       Modifies
94
;               a0
95
; Parameters:
96
;               fp0 = dbl
97
;------------------------------------------------------------------------------
98
 
99
_CheckNegative:
100
        ftst fp0                                                                ; is number negative?
101
        fbge .0002
102
        move.b #'-',(a0)+                               ; yes, output '-'
103
        fneg fp0                                                                ; make fp0 positive
104
.0002
105
        rts
106
 
107
;------------------------------------------------------------------------------
108
; Make the input value larger so that digits may appear before the decimal
109
; point.
110
;
111
; Modifies:
112
;               fp0,fp1,d6
113
; Parameters:
114
;               fp0 = dbl
115
;------------------------------------------------------------------------------
116
 
117
;       if (dbl < 1.0) {
118
;               while (dbl < 1.0) {
119
;                       dbl *= 1000000.0;
120
;                       exp -= 6;
121
;               }
122
;       }
123
 
124
_MakeBig:
125
        fmove.w #1,fp1
126
.0002
127
        fcmp fp1,fp0                                            ; is fp0 > 1?
128
        fbge .0001                                                      ; yes, return
129
        fscale.l #6,fp0                                 ; multiply fp0 by a million
130
        subi.w #6,d6                                            ; decrement exponent by six
131
        bra .0002                                                               ; keep trying until number is > 1
132
.0001
133
        rts
134
 
135
;------------------------------------------------------------------------------
136
;       Create a number dbl2 on the same order of magnitude as dbl, but
137
;       less than dbl. The number will be 1.0e
138
;
139
; Modifies:
140
;               d6,fp2
141
; Parameters:
142
;               fp0 = dbl
143
;------------------------------------------------------------------------------
144
 
145
;       // The following is similar to using log10() and pow() functions.
146
;       // Now dbl is >= 1.0
147
;       // Create a number dbl2 on the same order of magnitude as dbl, but
148
;       // less than dbl.
149
;       dbl2 = 1.0;
150
;       dbla = dbl2;
151
;       if (dbl > dbl2) {       // dbl > 1.0 ?
152
;               while (dbl2 <= dbl) {
153
;                       dbla = dbl2;
154
;                       dbl2 *= 10.0;   // increase power of 10
155
;                       exp++;
156
;               }
157
;               // The above loop goes one too far, we want the last value less
158
;               // than dbl.
159
;               dbl2 = dbla;
160
;               exp--;
161
;       }
162
 
163
_LessThanDbl:
164
        fmove.w #1,fp2                  ; setup fp2 = 1
165
        fcmp fp2,fp0                            ; if (dbl > dbl2)
166
        fble .0004
167
.0006
168
        fcmp fp0,fp2                            ; while (dbl2 <= dbl)
169
        fbgt .0005
170
        fscale.w #1,fp2                 ; dbl2 *= 10 (increase exponent by one)
171
        addi.w #1,d6                            ; exp++
172
        bra .0006
173
.0005
174
        fscale.l #-1,fp2                ; dbl2 /= 10 (decrease exponent by one)
175
        subi.w #1,d6                            ; exp--;
176
.0004
177
;       fmove.x fp0,_fpWork     ; debugging
178
;       fmove.x fp2,_fpWork+12
179
        rts
180
 
181
;------------------------------------------------------------------------------
182
; Compute the number of digits before the decimal point.
183
;
184
; Modifies:
185
;               d0,d6,_digits_before_decpt
186
; Parameters:
187
;               d6 = exponent
188
;------------------------------------------------------------------------------
189
 
190
; if (exp >= 0 && exp < 6) {
191
;   digits_before_decpt = exp+1;
192
;               exp = 0;
193
;       }
194
;       else if (exp >= -7)
195
;               digits_before_decpt = 1;
196
;       else
197
;               digits_before_decpt = -1;
198
 
199
_ComputeDigitsBeforeDecpt:
200
        move.l d0,-(a7)
201
        tst.w d6
202
        bmi .0007
203
        cmpi.w #6,d6
204
        bge .0007
205
        move.w d6,d0
206
        addi.w #1,d0
207
        move.w d0,_digits_before_decpt
208
        clr.w d6
209
        move.l (a7)+,d0
210
        rts
211
.0007
212
        cmpi.w #-7,d6
213
        blt .0009
214
        move.w #1,_digits_before_decpt
215
        move.l (a7)+,d0
216
        rts
217
.0009
218
        move.w #-1,_digits_before_decpt
219
        move.l (a7)+,d0
220
        rts
221
 
222
;------------------------------------------------------------------------------
223
;       Spit out a leading zero before the decimal point for a small number.
224
;
225
; Modifies:
226
;               a0
227
; Parameters:
228
;               d6 = exponent
229
;------------------------------------------------------------------------------
230
 
231
;  if (exp < -7) {
232
;                buf[ndx] = '0';
233
;                ndx++;
234
;    buf[ndx] = '.';
235
;    ndx++;
236
;  }
237
 
238
_LeadingZero:
239
        cmpi.w #-7,d6
240
        bge .0010
241
        move.b #'0',(a0)+
242
        move.b #'.',(a0)+
243
.0010
244
        rts
245
 
246
;------------------------------------------------------------------------------
247
; Extract the digits of the significand.
248
;
249
; Modifies:
250
;               _precision variable
251
; Register Usage
252
;               d0 = counter
253
;               d1 = digit
254
;               fp0 = dbl
255
;               fp2 = dbl2
256
;               fp3 = digit as decimal float
257
;               fp7 = dbla
258
; Parameters:
259
;               fp0, fp2
260
;------------------------------------------------------------------------------
261
 
262
;       // Now loop processing one digit at a time.
263
;  for (nn = 0; nn < 25 && precision > 0; nn++) {
264
;    digit = 0;
265
;               dbla = dbl;
266
;               // dbl is on the same order of magnitude as dbl2 so
267
;               // a repeated subtract can be used to find the digit.
268
;    while (dbl >= dbl2) {
269
;      dbl -= dbl2;
270
;      digit++;
271
;    }
272
;    buf[ndx] = digit + '0';
273
;               // Now go back and perform just a single subtract and
274
;               // a multiply to find out how much to reduce dbl by.
275
;               // This should improve the accuracy
276
;               if (digit > 2)
277
;                       dbl = dbla - dbl2 * digit;
278
;    ndx++;
279
;    digits_before_decpt--;
280
;    if (digits_before_decpt==0) {
281
;                       buf[ndx] = '.';
282
;                       ndx++;
283
;    }
284
;    else if (digits_before_decpt < 0)
285
;      precision--;
286
;               // Shift the next digit to be tested into position.
287
;    dbl *= 10.0;
288
;  }
289
 
290
_SpitOutDigits:
291
        link a2,#-24
292
        move.l _canary,20(sp)
293
        fmove.x fp7,(sp)
294
        movem.l d0/d1,12(sp)
295
        move.w #24,d0                   ; d0 = nn
296
.0017
297
        tst.l _precision
298
        ble .0011
299
        moveq #0,d1                             ; digit = 0
300
        fmove fp0,fp7                   ; dbla = dbl
301
.0013
302
        fcmp fp2,fp0
303
        fblt .0012
304
        fsub fp2,fp0                    ; dbl -= dbl2
305
        addi.b #1,d1                    ; digit++
306
        bra .0013
307
.0012
308
        addi.b #'0',d1          ; convert digit to ascii
309
        move.b d1,(a0)+         ; and store
310
        subi.b #'0',d1          ; d1 = binary digit again
311
;       cmpi.b #2,d1
312
;       ble .0014
313
 
314
;       ext.w d1
315
;       ext.l d1
316
;       fmove.l d1,fp3          ; fp3 = digit
317
;       fmul fp2,fp3                    ; fp3 = dbl2 * digit
318
;       fmove fp7,fp0
319
;       fsub fp3,fp0                    ; dbl = dbla - dbl2 * digit
320
.0014
321
        subi.w #1,_digits_before_decpt
322
        bne .0015
323
        move.b #'.',(a0)+
324
.0015
325
        tst.w _digits_before_decpt
326
        bge .0016
327
        subi.l #1,_precision
328
.0016
329
        fscale.l #-1,fp2                ; dbl *= 10.0
330
        dbra d0,.0017
331
.0011
332
        movem.l 12(sp),d0/d1
333
        fmove.x (sp),fp7
334
        cchk 20(sp)
335
        unlk a2
336
        rts
337
 
338
;------------------------------------------------------------------------------
339
; If the number ends in a decimal point, trim off the point.
340
;
341
; Registers Modified:
342
;               none
343
; Parameters:
344
;               a0 = pointer to end of number
345
; Returns:
346
;               a0 = updated to point just past last digit.
347
;------------------------------------------------------------------------------
348
 
349
_TrimTrailingPoint:
350
        cmpi.b #'.',-1(a0)
351
        bne .0001
352
        clr.b -(a0)
353
        rts
354
.0001
355
        cmpi.b #'.',(a0)
356
        bne .0002
357
        cmpi.b #0,1(a0)
358
        bne .0002
359
        clr.b (a0)
360
        subq #1,a0
361
.0002
362
        rts
363
 
364
;------------------------------------------------------------------------------
365
; If the number ends in .0 get rid of the .0
366
;
367
; Registers Modified:
368
;               none
369
; Parameters:
370
;               a0 = pointer to last digits of number
371
; Returns:
372
;               a0 = updated to point just past last digit.
373
;------------------------------------------------------------------------------
374
 
375
_TrimDotZero:
376
        tst.b (a0)
377
        bne .0004
378
        cmpi.b #'0',-1(a0)
379
        bne .0004
380
        cmpi.b #'.',-2(a0)
381
        bne .0004
382
        clr.b -2(a0)
383
        subq #2,a0
384
.0004
385
        rts
386
 
387
;------------------------------------------------------------------------------
388
; Trim trailing zeros from the number. Generally there is no need to display
389
; trailing zeros.
390
; Turns a number like 652.000000000000000000000 into 650.0
391
;
392
; Registers Modified:
393
;               none
394
; Parameters:
395
;               a0 = pointer to last digits of number
396
; Returns:
397
;               a0 = updated to point just past last digit.
398
;------------------------------------------------------------------------------
399
 
400
;       // Trim trailing zeros from the number
401
;  do {
402
;      ndx--;
403
;  } while(buf[ndx]=='0');
404
;  ndx++;
405
 
406
_TrimTrailingZeros:
407
.0018
408
        cmpi.b #'0',-(a0)               ; if the last digit was a zero, backup
409
        beq .0018
410
        addq #1,a0                                      ; now advance by one
411
        move.b #0,(a0)                  ; NULL terminate string
412
        rts
413
 
414
;------------------------------------------------------------------------------
415
; Output 'e+' or 'e-'
416
;
417
; Registers Modified:
418
;               d6.w (if negative)
419
; Parameters:
420
;               a0 = pointer to last digits of number
421
; Returns:
422
;               a0 = updated to point just past '+' or '-'.
423
;------------------------------------------------------------------------------
424
 
425
;       // Spit out +/-E
426
;  buf[ndx] = E;
427
;  ndx++;
428
;  if (exp < 0) {
429
;    buf[ndx]='-';
430
;    ndx++;
431
;    exp = -exp;
432
;  }
433
;  else {
434
;               buf[ndx]='+';
435
;               ndx++;
436
;  }
437
 
438
_SpitOutE:
439
        move.b _E,(a0)+
440
        tst.w d6
441
        bge .0021
442
        move.b #'-',(a0)+
443
        neg.w d6
444
        bra .0022
445
.0021
446
        move.b #'+',(a0)+
447
.0022
448
        rts
449
 
450
;------------------------------------------------------------------------------
451
; Extract a single digit of the exponent. Extract works from the leftmost digit
452
; to the rightmost.
453
;
454
; Register Usage
455
;               d2 = history of zeros
456
;               d3 = digit
457
; Modifies
458
;               d2,d6,a0
459
; Parameter
460
;       d1.w = power of ten
461
;               d6.w = exponent
462
;------------------------------------------------------------------------------
463
 
464
_ExtExpDigit:
465
        move.l d3,-(a7)
466
        ext.l d6                                ; make d6 a long
467
        divu d1,d6                      ; divide by power of ten
468
        move.b d6,d3            ; d3 = quotient (0 to 9)
469
        swap d6                                 ; d6 = remainder, setup for next digit
470
        or.b d3,d2
471
        tst.b d3
472
        bne .0003
473
        tst.b d2
474
        beq .0004
475
.0003
476
        addi.b #'0',d3  ; convert to ascii
477
        move.b d3,(a0)+
478
.0004
479
        move.l (a7)+,d3
480
        rts
481
 
482
;------------------------------------------------------------------------------
483
; Extract all the digits of the exponent.
484
;
485
; Register Usage
486
;               d1 = power of 10
487
;               d2 = history of zeros
488
; Parameters
489
;               a0 = pointer to string buffer
490
;               d6 = exponent
491
;------------------------------------------------------------------------------
492
 
493
;       // If the number is times 10^0 don't output the exponent
494
;  if (exp==0) {
495
;    buf[ndx]='\0';
496
;    goto prt;
497
;  }
498
 
499
_ExtExpDigits:
500
        move.l d1,-(a7)
501
        tst.w d6                                                        ; is exponent zero?
502
        beq .0002
503
        bsr _SpitOutE                                   ; exponent is non-zero e+
504
        clr.b d2                                                        ; d2 = history of zeros
505
        move.w #1000,d1
506
        bsr _ExtExpDigit
507
        move.w #100,d1
508
        bsr _ExtExpDigit
509
        move.w #10,d1
510
        bsr _ExtExpDigit
511
        move.w #1,d1
512
        bsr _ExtExpDigit
513
.0002:
514
        move.l (a7)+,d1
515
        move.b #0,(a0)                          ; NULL terminate string
516
        rts                                                                             ; and return
517
 
518
;------------------------------------------------------------------------------
519
; Pad the left side of the output string.
520
;
521
; Modifies:
522
;               d0,d1,d2,d3
523
;------------------------------------------------------------------------------
524
 
525
;  // pad left
526
;  if (width > 0) {
527
;    if (ndx < width) {
528
;      for (nn = 39; nn >= width-ndx; nn--)
529
;        buf[nn] = buf[nn-(width-ndx)];
530
;      for (; nn >= 0; nn--)
531
;        buf[nn] = ' ';
532
;    }
533
;  }
534
 
535
_PadLeft:
536
        movem.l d0/d1/d2/d3,-(a7)
537
        tst.b _width
538
        ble .0041
539
        move.l a0,d0
540
        sub.l #_fpBuf,d0        ; d0 = ndx
541
        cmp.b _width,d0
542
        bge .0041
543
        move.w #49,d1                   ; d1 = nn
544
.0040
545
        move.b _width,d2
546
        ext.w d2
547
        sub.w d0,d2                             ; d2 = width-ndx
548
        cmp.w d2,d1
549
        blt .0039
550
        move.w d1,d3                    ; d3 = nn
551
        sub.w d2,d3                             ; d3 = nn-(width-ndx)
552
        move.b (a0,d3.w),(a0,d1.w)
553
        subi.w #1,d1
554
        bra .0040
555
.0039
556
        tst.w d1
557
        bmi .0041
558
        move.b #' ',(a0,d1.w)
559
        subi.w #1,d1
560
        bra .0039
561
.0041
562
        movem.l (a7)+,d0/d1/d2/d3
563
        rts
564
 
565
;------------------------------------------------------------------------------
566
; Pad the right side of the output string.
567
;
568
; Parameters:
569
;               a0 = pointer to end of string
570
; Modifies:
571
;               none
572
; Returns:
573
;               none
574
;------------------------------------------------------------------------------
575
 
576
;  // pad right
577
;  if (width < 0) {
578
;    width = -width;
579
;    while (ndx < width) {
580
;      buf[ndx]=' ';
581
;      ndx++;
582
;    }
583
;    buf[ndx]='\0';
584
;  }
585
;  return (ndx);
586
 
587
_PadRight:
588
        move.l d0,-(a7)
589
        tst.b _width
590
        bpl .0042
591
        neg.b _width
592
        move.l a0,d0
593
        sub.l #_fpBuf,d0        ; d0 = ndx
594
.0044
595
        cmp.b _width,d0
596
        bge .0043
597
        move.b #' ',(a0,d0.w)
598
        addi.w #1,d0
599
        bra .0044
600
.0043
601
        move.b #0,(a0,d0.w)
602
.0042
603
        move.l (a7)+,d0
604
        rts
605
 
606
;------------------------------------------------------------------------------
607
; Output a string representation of a decimal floating point number to a
608
; buffer.
609
;
610
; Register Usage
611
;               a0 = pointer to string buffer
612
;               d6 = exponent
613
; Modifies:
614
;               a0 = points to end of string
615
; Parameters:
616
;               fp0 = number to convert
617
; Returns:
618
;               none
619
;------------------------------------------------------------------------------
620
 
621
_FloatToString:
622
        move.l d6,-(a7)
623
        bsr _CheckNegative                      ; is number negative?
624
        bsr _CheckZero                                  ; check for zero
625
        beq .0001                                                               ; branch since already output "0"
626
        bsr _CheckNan                                           ; check for Nan or infinity
627
        bcs .0001                                                               ; branch if nan/inf string output
628
        ; Now the fun begins
629
        clr.l d6                                                                ; exponent = 0
630
        bsr _MakeBig
631
        bsr _LessThanDbl
632
        bsr _ComputeDigitsBeforeDecpt
633
        bsr _LeadingZero
634
        bsr _SpitOutDigits
635
        bsr _TrimTrailingZeros
636
        bsr _TrimTrailingPoint
637
        bsr _TrimDotZero
638
        bsr _ExtExpDigits                               ; extract exponent digits
639
        bsr _PadLeft                                            ; pad the number to the left or right
640
        bsr _PadRight
641
.0001
642
        move.l (a7)+,d6
643
        rts
644
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.