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

Subversion Repositories ft816float

[/] [ft816float/] [trunk/] [software/] [_sprtflt.asm] - Blame information for rev 87

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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