fix float overflow checki in printf_fast_f, bug #1525093
[fw/sdcc] / device / lib / printf_fast.c
1 /* Fast printf routine for use with sdcc/mcs51
2  * Copyright (c) 2004, Paul Stoffregen, paul@pjrc.com
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18
19 /******************************************************************/
20 /**                                                              **/
21 /**    Major features.  These determine what capabilities your   **/
22 /**    compiled printf_fast will have.                           **/
23 /**                                                              **/
24 /******************************************************************/
25
26 // Include support for 32 bit base 10 integers (%ld and %lu).  Without
27 // this, you won't be able to print 32 bit integers as base 10.  They
28 // will appear in hexadecimal.
29 #define LONG
30
31 // Include support for floating point numbers (%f).  Don't forget to
32 // enable LONG above, if you want to print floats greater than
33 // 65535.997.  You can have 6 good digits after the decimal point,
34 // or an 8th if a small error is ok.  +/- 2^32 to 1/10^8 isn't the
35 // full dynamic range of 32 bit floats, but it covers the most
36 // commonly used range.  Adds about 500-600 bytes of code.
37 //#define FLOAT
38
39 // Include support for minimum field widths (%8d, %20s, %12.5f)
40 #define FIELD_WIDTH
41
42 // Include fast integer conversion.  Without this, a compact but slower
43 // algorithm is used to convert integers (%d, %u, int part of %f).
44 // Even the slow algorithm is much faster than a typical C implementation
45 // based on repetitive division by 10.  If you enable this, you get an
46 // extremely fast version (only 8 table lookups and 8 adds to convert a
47 // 32 bit integer), but it costs extra code space for larger lookup
48 // tables and optimized non-looping code.
49 #define FAST_INTEGER
50
51
52 /******************************************************************/
53 /**                                                              **/
54 /**    Minor tweaks.  These provide small code savings, with     **/
55 /**    a partial loss of functionality.                          **/
56 /**                                                              **/
57 /******************************************************************/
58
59
60 // If you enabled FLOAT, enabling this replaces the normal %f float
61 // output with a very compact version that always prints 4 fractional
62 // digits and does not have round off.  Zero will print as "0.0000",
63 // and 1.999997 will print as "1.9999" (not rounded up to 2).  The
64 // 4th digit is not accurate (+/- 2).  This simpler version also
65 // avoids using 5 bytes of internal data memory.  Code size is about
66 // 240 bytes less.
67 //#define FLOAT_FIXED4
68
69 // If you used FLOAT (not FLOAT_FIXED4), this will remove the smart
70 // default number of digits code.  When you use "%f" without a field
71 // width, normally the smart default width code chooses a good number
72 // of digits based on size of the number.  If you enabled FIELD_WIDTH
73 // and use a number, like "%.5f", this smart default code is never
74 // used anyway.  Saves about 40 bytes of code.
75 //#define FLOAT_DEFAULT_FRAC_DIGITS 6
76
77 // If you used FLOAT (not FLOAT_FIXED4) and you do not specify a
78 // field width, normally trailing zeros are trimmed.  Using this
79 // removes that feature (saves only a few bytes).
80 //#define DO_NOT_TRIM_TRAILING_ZEROS
81
82 // Omit saving and restoring registers when calling putchar().  If you
83 // are desparate for a little more code space, this will give you a
84 // small savings.  You MUST define putchar() with #pragma callee_saves,
85 // or implement it in assembly and avoid changing the registers.
86 //#define PUTCHAR_CALLEE_SAVES
87
88
89 /* extern void putchar(char ); */
90
91 // Warning: using static/global variables makes these functions NON-reentrant!
92 // reentrant keyword is only used for parameter passing method
93
94 static bit long_flag, short_flag, print_zero_flag, negative_flag;
95
96 #ifdef FIELD_WIDTH
97 static bit field_width_flag;
98 static bit leading_zero_flag;
99 static data unsigned char field_width;
100 #endif
101
102 #ifdef FLOAT
103 #define SDCC_FLOAT_LIB
104 #include <float.h>
105 static bit continue_float;
106 #ifndef FLOAT_FIXED4
107 static data unsigned char frac_field_width;
108 static data unsigned char float_frac_bcd[4];
109 // TODO: can float_frac_bcd be overlaid with temps used by trig functions
110 #endif
111 #endif
112
113 #ifndef FAST_INTEGER
114 #ifdef LONG
115 static data unsigned int i2bcd_tmp;  // slow 32 int conversion needs temp space
116 #endif
117 #endif
118
119
120
121 #ifndef PRINTF_FAST
122 #define PRINTF_FAST printf_fast
123 #endif
124
125
126 #if !defined(SDCC_mcs51) || defined(SDCC_USE_XSTACK) || defined(_SDCC_NO_ASM_LIB_FUNCS)
127 // Does printf_fast really work on ds390 and ds400?
128 // If it does, enable them in the line above
129 #if defined(SDCC_USE_XSTACK)
130 #warning "printf_fast not built, does not support --xstack"
131 #elif defined(_SDCC_NO_ASM_LIB_FUNCS)
132 #warning "printf_fast not built, _SDCC_NO_ASM_LIB_FUNCS defined"
133 #endif
134 #else // defines are compatible with printf_fast
135
136
137 void PRINTF_FAST(code char *fmt, ...) reentrant
138 {
139         fmt;    /* suppress unreferenced variable warning */
140
141         _asm
142
143 printf_begin:
144         mov     a, _bp          // r0 will point to va_args (stack)
145         add     a, #253
146         mov     r0, a           // r0 points to MSB of fmt
147         mov     dph, @r0
148         dec     r0
149         mov     dpl, @r0        // dptr has address of fmt
150         dec     r0
151
152
153 printf_main_loop:
154         clr     a
155         movc    a, @a+dptr      // get next byte of fmt string
156         inc     dptr
157         //cjne  a, #'%', printf_normal
158         cjne    a, #37, printf_normal
159
160 printf_format:
161         clr     _long_flag
162         clr     _short_flag
163         clr     _print_zero_flag
164         clr     _negative_flag
165 #ifdef FIELD_WIDTH
166         clr     _field_width_flag
167         clr     _leading_zero_flag
168         mov     r1, #_field_width
169         mov     @r1, #0
170 #endif
171 #ifdef FLOAT
172         clr     _continue_float
173 #endif
174
175 printf_format_loop:
176         clr     a
177         movc    a, @a+dptr      // get next byte of data format
178         inc     dptr
179
180         /* parse and consume the field width digits, even if */
181         /* we don't build the code to make use of them */
182         add     a, #198
183         jc      printf_nondigit1
184         add     a, #10
185         jnc     printf_nondigit2
186 #ifdef FIELD_WIDTH
187 printf_digit:
188         jnz     printf_digit_2
189         cjne    a, _field_width, printf_digit_2
190         setb    _leading_zero_flag
191 printf_digit_2:
192         setb    _field_width_flag
193         mov     r2, a
194         mov     a, @r1
195         mov     b, #10
196         mul     ab
197         add     a, r2
198         mov     @r1, a
199 #endif
200         sjmp    printf_format_loop
201 printf_nondigit1:
202         add     a, #10
203 printf_nondigit2:
204         add     a, #48
205
206
207 printf_format_l:
208         //cjne  a, #'l', printf_format_h
209         cjne    a, #108, printf_format_h
210         setb    _long_flag
211         sjmp    printf_format_loop
212
213 printf_format_h:
214         //cjne  a, #'h', printf_format_s
215         cjne    a, #104, printf_format_s
216         setb    _short_flag
217         sjmp    printf_format_loop
218
219 printf_format_s:
220         //cjne  a, #'s', printf_format_d
221         cjne    a, #115, printf_format_d
222         ljmp    printf_string
223
224 printf_format_d:
225         //cjne  a, #'d', printf_format_u
226         cjne    a, #100, printf_format_u
227         lcall   printf_get_int
228         ljmp    printf_int
229
230 printf_format_u:
231         //cjne  a, #'u', printf_format_c
232         cjne    a, #117, printf_format_c
233         lcall   printf_get_int
234         ljmp    printf_uint
235
236 printf_format_c:
237         //cjne  a, #'c', printf_format_x
238         cjne    a, #99, printf_format_x
239         mov     a, @r0          // Acc has the character to print
240         dec     r0
241         sjmp    printf_char
242
243 printf_format_x:
244         //cjne  a, #'x', printf_format_f
245         cjne    a, #120, printf_format_f
246         ljmp    printf_hex
247
248 printf_format_f:
249 #ifdef FLOAT
250         //cjne  a, #'f', printf_format_dot
251         cjne    a, #102, printf_format_dot
252         ljmp    print_float
253 #endif
254
255 printf_format_dot:
256         //cjne  a, #'.', printf_normal
257         cjne    a, #46, printf_normal
258 #ifdef FLOAT
259 #ifdef FLOAT_FIXED4
260         mov     r1, #ar3        // parse frac field, but discard if FIXED4
261 #else
262         mov     r1, #_frac_field_width
263         mov     @r1, #0
264 #endif
265 #endif
266         sjmp    printf_format_loop
267
268 printf_normal:
269         jz      printf_eot
270 printf_char:
271         lcall   printf_putchar
272         ljmp    printf_main_loop
273
274 printf_eot:
275         ljmp    printf_end
276
277
278
279
280
281
282         /* print a string... just grab each byte with __gptrget */
283         /* the user much pass a 24 bit generic pointer */
284
285 printf_string:
286         push    dph             // save addr in fmt onto stack
287         push    dpl
288         mov     b, @r0          // b has type of address (generic *)
289         dec     r0
290         mov     dph, @r0
291         dec     r0
292         mov     dpl, @r0        // dptr has address of user's string
293         dec     r0
294
295 #ifdef FIELD_WIDTH
296         jnb     _field_width_flag, printf_str_loop
297         clr     _leading_zero_flag      // never leading zeros for strings
298         push    dpl
299         push    dph
300 printf_str_fw_loop:
301         lcall   __gptrget
302         jz      printf_str_space
303         inc     dptr
304         dec     _field_width
305         mov     a, _field_width
306         jnz     printf_str_fw_loop
307 printf_str_space:
308         lcall   printf_space
309         pop     dph
310         pop     dpl
311 #endif // FIELD_WIDTH
312
313 printf_str_loop:
314         lcall   __gptrget
315         jz      printf_str_done
316         inc     dptr
317         lcall   printf_putchar
318         sjmp    printf_str_loop
319 printf_str_done:
320         pop     dpl             // restore addr withing fmt
321         pop     dph
322         ljmp    printf_main_loop
323
324
325
326
327
328
329
330
331         /* printing in hex is easy because sdcc pushes the LSB first */
332
333 printf_hex:
334         lcall   printf_hex8
335         jb      _short_flag, printf_hex_end
336         lcall   printf_hex8
337         jnb     _long_flag, printf_hex_end
338         lcall   printf_hex8
339         lcall   printf_hex8
340 printf_hex_end:
341         lcall   printf_zero
342         ljmp    printf_main_loop
343 printf_hex8:
344         mov     a, @r0
345         lcall   printf_phex_msn
346         mov     a, @r0
347         dec     r0
348         ljmp    printf_phex_lsn
349
350
351 #ifndef LONG
352 printf_ld_in_hex:
353         //mov   a, #'0'
354         mov     a, #48
355         lcall   printf_putchar
356         //mov   a, #'x'
357         mov     a, #120
358         lcall   printf_putchar
359         mov     a, r0
360         add     a, #4
361         mov     r0, a
362         sjmp    printf_hex
363 #endif
364
365
366         /* printing an integer is not so easy.  For a signed int */
367         /* check if it is negative and print the minus sign and */
368         /* invert it to a positive integer */
369
370 printf_int:
371         mov     a, r5
372         jnb     acc.7, printf_uint      /* check if negative */
373         setb    _negative_flag
374         mov     a, r1                   /* invert integer */
375         cpl     a
376         add     a, #1
377         mov     r1, a
378         jb      _short_flag, printf_uint
379         mov     a, r2
380         cpl     a
381         addc    a, #0
382         mov     r2, a
383         jnb     _long_flag, printf_uint
384         mov     a, r3
385         cpl     a
386         addc    a, #0
387         mov     r3, a
388         mov     a, r4
389         cpl     a
390         addc    a, #0
391         mov     r4, a
392
393
394         /* printing integers is a lot of work... because it takes so */
395         /* long, the first thing to do is make sure we're doing as */
396         /* little work as possible, then convert the binary int to */
397         /* packed BCD, and finally print each digit of the BCD number */
398
399 printf_uint:
400
401         jb      _short_flag, printf_uint_ck8
402         jnb     _long_flag, printf_uint_ck16
403 printf_uint_ck32:
404         /* it's a 32 bit int... but if the upper 16 bits are zero */
405         /* we can treat it like a 16 bit integer and convert much faster */
406 #ifdef LONG
407         mov     a, r3
408         jnz     printf_uint_begin
409         mov     a, r4
410         jnz     printf_uint_begin
411 #else
412         mov     a, r3
413         jnz     printf_ld_in_hex        // print long integer as hex
414         mov     a, r4                   // rather than just the low 16 bits
415         jnz     printf_ld_in_hex
416 #endif
417         clr     _long_flag
418 printf_uint_ck16:
419         /* it's a 16 bit int... but if the upper 8 bits are zero */
420         /* we can treat it like a 8 bit integer and convert much faster */
421         mov     a, r2
422         jnz     printf_uint_begin
423         setb    _short_flag
424 printf_uint_ck8:
425         /* it's an 8 bit int... if it's zero, it's a lot faster to just */
426         /* print the digit zero and skip all the hard work! */
427         mov     a, r1
428         jnz     printf_uint_begin
429 #ifdef FIELD_WIDTH
430         jnb     _field_width_flag, printf_uint_zero
431         mov     a, _field_width
432         jz      printf_uint_zero
433         dec     _field_width
434         lcall   printf_space
435 #endif
436 printf_uint_zero:
437         //mov   a, #'0'
438         mov     a, #48
439         lcall   printf_putchar
440 #ifdef FLOAT
441         jnb     _continue_float, 0001$
442         ret
443 0001$:
444 #endif
445         ljmp    printf_main_loop
446
447
448
449 printf_uint_begin:
450         push    dpl
451         push    dph
452         lcall   printf_int2bcd          // bcd number in r3/r2/r7/r6/r5
453 printf_uint_2:
454
455 #ifdef FIELD_WIDTH
456         jnb     _field_width_flag, printf_uifw_end
457 #ifdef LONG
458 printf_uifw_32:
459         mov     r1, #10
460         jnb     _long_flag, printf_uifw_16
461         mov     a, r3
462         anl     a, #0xF0
463         jnz     printf_uifw_sub
464         dec     r1
465         mov     a, r3
466         anl     a, #0x0F
467         jnz     printf_uifw_sub
468         dec     r1
469         mov     a, r2
470         anl     a, #0xF0
471         jnz     printf_uifw_sub
472         dec     r1
473         mov     a, r2
474         anl     a, #0x0F
475         jnz     printf_uifw_sub
476         dec     r1
477         mov     a, r7
478         anl     a, #0xF0
479         jnz     printf_uifw_sub
480 #endif // LONG
481 printf_uifw_16:
482         mov     r1, #5
483         jb      _short_flag, printf_uifw_8
484         mov     a, r7
485         anl     a, #0x0F
486         jnz     printf_uifw_sub
487         dec     r1
488         mov     a, r6
489         anl     a, #0xF0
490         jnz     printf_uifw_sub
491 printf_uifw_8:
492         mov     r1, #3
493         mov     a, r6
494         anl     a, #0x0F
495         jnz     printf_uifw_sub
496         dec     r1
497         mov     a, r5
498         anl     a, #0xF0
499         jnz     printf_uifw_sub
500         dec     r1
501 printf_uifw_sub:
502         ;r1 has the number of digits for the number
503         mov     a, _field_width
504         mov     c, _negative_flag
505         subb    a, r1
506         jc      printf_uifw_end
507         mov     _field_width, a
508
509 #ifndef PUTCHAR_CALLEE_SAVES
510 #ifdef LONG
511         push    ar3
512         push    ar2
513 #endif
514         push    ar7
515         push    ar6
516         push    ar5
517 #endif
518         lcall   printf_space
519 #ifndef PUTCHAR_CALLEE_SAVES
520         pop     ar5
521         pop     ar6
522         pop     ar7
523 #ifdef LONG
524         pop     ar2
525         pop     ar3
526 #endif
527 #endif
528
529
530 printf_uifw_end:
531 #endif // FIELD_WIDTH
532
533
534 printf_uint_doit:
535         jnb     _negative_flag, printf_uint_pos
536 #ifdef PUTCHAR_CALLEE_SAVES
537         //mov   a, #'-'
538         mov     a, #45
539         lcall   printf_putchar
540 #else
541 #ifdef LONG
542         push    ar3
543         push    ar2
544 #endif
545         push    ar7
546         push    ar6
547         push    ar5
548         //mov   a, #'-'
549         mov     a, #45
550         lcall   printf_putchar
551         pop     ar5
552         pop     ar6
553         pop     ar7
554 #ifdef LONG
555         pop     ar2
556         pop     ar3
557 #endif
558 #endif // PUTCHAR_CALLEE_SAVES
559
560 printf_uint_pos:
561         jb      _short_flag, printf_uint8
562 #ifdef LONG
563         jnb     _long_flag, printf_uint16
564 printf_uint32:
565         push    ar5
566         push    ar6
567         push    ar7
568         mov     dpl, r2
569         mov     a, r3
570         mov     dph, a
571         lcall   printf_phex_msn
572         mov     a, dph
573         lcall   printf_phex_lsn
574         mov     a, dpl
575         lcall   printf_phex_msn
576         mov     a, dpl
577         lcall   printf_phex_lsn
578         pop     acc
579         mov     dpl, a
580         lcall   printf_phex_msn
581         mov     a, dpl
582         pop     dph
583         pop     dpl
584         sjmp    printf_uint16a
585 #endif // LONG
586
587 printf_uint16:
588         mov     dpl, r5
589         mov     dph, r6
590         mov     a, r7
591 printf_uint16a:
592         lcall   printf_phex_lsn
593         mov     a, dph
594         lcall   printf_phex_msn
595         mov     a, dph
596         sjmp    printf_uint8a
597
598 printf_uint8:
599         mov     dpl, r5
600         mov     a, r6
601 printf_uint8a:
602         lcall   printf_phex_lsn
603         mov     a, dpl
604         lcall   printf_phex_msn
605         mov     a, dpl
606         lcall   printf_phex_lsn
607         lcall   printf_zero
608         pop     dph
609         pop     dpl
610 #ifdef FLOAT
611         jnb     _continue_float, 0002$
612         ret
613 0002$:
614 #endif
615         ljmp    printf_main_loop
616
617
618
619
620
621
622
623
624 #ifdef FLOAT
625 #ifdef FLOAT_FIXED4
626         // Print a float the easy way.  First, extract the integer part and
627         // use the integer printing code.  Then extract the fractional part,
628         // convert each bit to 4 digit BCD, and print the BCD sum.  Absolutely
629         // no field width control, always 4 digits printed past the decimal
630         // point.  No round off.  1.9999987 prints as 1.9999, not 2.0000.
631 print_float:
632 #ifdef FIELD_WIDTH
633         jnb     _field_width_flag, print_float_begin
634         mov     a, _field_width
635         add     a, #251
636         mov     _field_width, a
637         jc      print_float_begin
638         mov     _field_width, #0
639 #endif
640 print_float_begin:
641         push    ar0             // keep r0 safe, will need it again
642         lcall   printf_get_float
643         clr     c
644         mov     a, #158                 // check for large float we can't print
645         subb    a, r7
646         jnc     print_float_size_ok
647 printf_float_too_big:
648         // TODO: should print some sort of overflow error??
649         pop     ar0
650         ljmp    printf_format_loop
651 print_float_size_ok:
652         push    dpl
653         lcall   fs_rshift_a
654         pop     dpl
655         setb    _continue_float
656 #ifndef LONG
657         mov     a, r3
658         orl     a, r4
659         jnz     printf_float_too_big
660 #endif
661         lcall   printf_uint             // print the integer portion
662         //mov   a, #'.'
663         mov     a, #0x2E
664         lcall   printf_putchar
665         // now that the integer part is printed, we need to refetch the
666         // float from the va_args and extract the fractional part
667         pop     ar0
668         lcall   printf_get_float
669         push    ar0
670         push    dpl
671         push    dph
672         mov     a, r7
673         cjne    a, #126, print_float_frac_lshift
674         sjmp    print_float_frac // input between 0.5 to 0.9999
675 print_float_frac_lshift:
676         jc      print_float_frac_rshift
677         //Acc (exponent) is greater than 126 (input >= 1.0)
678         add     a, #130
679         mov     r5, a
680 print_float_lshift_loop:
681         clr     c
682         mov     a, r2
683         rlc     a
684         mov     r2, a
685         mov     a, r3
686         rlc     a
687         mov     r3, a
688         mov     a, r4
689         rlc     a
690         mov     r4, a
691         djnz    r5, print_float_lshift_loop
692         sjmp    print_float_frac
693 print_float_frac_rshift:
694         //Acc (exponent) is less than 126 (input < 0.5)
695         cpl     a
696         add     a, #127
697         lcall   fs_rshift_a
698 print_float_frac:
699         // now we've got the fractional part, so now is the time to
700         // convert to BCD... just convert each bit to BCD using a
701         // lookup table and BCD sum them together
702         mov     r7, #14
703         clr     a
704         mov     r6, a
705         mov     r5, a
706         mov     dptr, #_frac2bcd        // FLOAT_FIXED4 version (14 entries)
707 print_float_frac_loop:
708         mov     a, r3
709         rlc     a
710         mov     r3, a
711         mov     a, r4
712         rlc     a
713         mov     r4, a
714         jnc     print_float_frac_skip
715         clr     a
716         movc    a, @a+dptr
717         add     a, r5
718         da      a
719         mov     r5, a
720         mov     a, #1
721         movc    a, @a+dptr
722         addc    a, r6
723         da      a
724         mov     r6, a
725 print_float_frac_skip:
726         inc     dptr
727         inc     dptr
728         djnz    r7, print_float_frac_loop
729         // the BCD sum is in dptr, so all we've got to do is output
730         // all 4 digits.  No trailing zero suppression, no nice round
731         // off (impossible to change the integer part since we already
732         // printed it).
733         mov     dph, r6
734         mov     dpl, r5
735         setb    _print_zero_flag
736         mov     a, dph
737         lcall   printf_phex_msn
738         mov     a, dph
739         lcall   printf_phex_lsn
740         mov     a, dpl
741         lcall   printf_phex_msn
742         mov     a, dpl
743         lcall   printf_phex_lsn
744         pop     dph
745         pop     dpl
746         pop     ar0
747         ljmp    printf_main_loop
748
749 #else // not FLOAT_FIXED4
750
751
752
753
754 print_float:
755         // Print a float the not-as-easy way, with a configurable number of
756         // fractional digits (up to 8) and proper round-off (up to 7 digits).
757         // First, extract the fractional part, convert to BCD, and then add
758         // the scaled round-off.  Store the rounded fractional digits and
759         // their carry.  Then extract the integer portion, increment it if
760         // the rounding caused a carry.  Use the integer printing to output
761         // the integer, and then output the stored fractional digits.  This
762         // approach requires 5 bytes of internal RAM to store the 8 fractional
763         // digits and the number of them we'll actually print.  This code is
764         // a couple hundred bytes larger and a bit slower than the FIXED4
765         // version, but it gives very nice results.
766 print_float_1:
767 #ifdef FIELD_WIDTH
768         jnb     _field_width_flag, print_float_default_width
769         // The caller specified exact field width, so use it.  Need to
770         // convert the whole float digits into the integer portion only.
771         mov     a, _field_width
772         setb    c
773         subb    a, _frac_field_width
774         mov     _field_width, a
775         jnc     print_float_begin
776         mov     _field_width, #0
777         sjmp    print_float_begin
778 #endif
779 print_float_default_width:
780         // The caller didn't specify field width (or FIELD_WIDTH is
781         // not defined so it's ignored).  We've still got to know
782         // how many fractional digits are going to print, so we can
783         // round off properly.
784 #ifdef FLOAT_DEFAULT_FRAC_DIGITS
785         mov     _frac_field_width, #FLOAT_DEFAULT_FRAC_DIGITS
786 #else
787         // default fractional field width (between 0 to 7)
788         // attempt to scale the default number of fractional digits
789         // based on the magnitude of the float
790         mov     ar1, r0         // r0 points to first byte of float
791         dec     r1              // r1 points to second byte of float
792         mov     r6, dpl
793         mov     r7, dph
794         mov     dptr, #_float_range_table
795         mov     r5, #7
796 print_float_default_loop:
797         clr     a
798         movc    a, @a+dptr
799         add     a, @r1
800         inc     dptr
801         clr     a
802         movc    a, @a+dptr
803         addc    a, @r0
804         jnc     print_float_default_done
805         inc     dptr
806         djnz    r5, print_float_default_loop
807 print_float_default_done:
808         mov     _frac_field_width, r5
809         mov     dpl, r6
810         mov     dph, r7
811 #endif // not FLOAT_DEFAULT_FRAC_DIGITS
812
813 print_float_begin:
814         push    ar0                     // keep r0 safe, will need it again
815         lcall   printf_get_float
816         push    dpl
817         push    dph
818         mov     a, r7
819         cjne    a, #126, print_float_frac_lshift
820         sjmp    print_float_frac        // input between 0.5 to 0.9999
821
822 print_float_frac_lshift:
823         jc      print_float_frac_rshift
824         //Acc (exponent) is greater than 126 (input >= 1.0)
825         add     a, #130
826         mov     r5, a
827 print_float_lshift_loop:
828         clr     c
829         mov     a, r2
830         rlc     a
831         mov     r2, a
832         mov     a, r3
833         rlc     a
834         mov     r3, a
835         mov     a, r4
836         rlc     a
837         mov     r4, a
838         djnz    r5, print_float_lshift_loop
839         sjmp    print_float_frac
840 print_float_frac_rshift:
841         //Acc (exponent) is less than 126 (input < 0.5)
842         cpl     a
843         add     a, #127
844         lcall   fs_rshift_a
845 print_float_frac:
846         // Convert the fraction in r4/r3/r2/r1 into 8 BCD digits in r0/r7/r6/r5
847         mov     b, #27
848         clr     a
849         mov     r0, a
850         mov     r7, a
851         mov     r6, a
852         mov     r5, a
853         mov     dptr, #_frac2bcd        // FLOAT version (27 entries)
854 print_float_frac_loop:
855         mov     a, r1
856         rlc     a
857         mov     r1, a
858         mov     a, r2
859         rlc     a
860         mov     r2, a
861         mov     a, r3
862         rlc     a
863         mov     r3, a
864         mov     a, r4
865         rlc     a
866         mov     r4, a
867         jnc     print_float_frac_skip
868         clr     a
869         movc    a, @a+dptr
870         add     a, r5
871         da      a
872         mov     r5, a
873         mov     a, #1
874         movc    a, @a+dptr
875         addc    a, r6
876         da      a
877         mov     r6, a
878         mov     a, #2
879         movc    a, @a+dptr
880         addc    a, r7
881         da      a
882         mov     r7, a
883         mov     a, #3
884         movc    a, @a+dptr
885         addc    a, r0
886         da      a
887         mov     r0, a
888 print_float_frac_skip:
889         inc     dptr
890         inc     dptr
891         inc     dptr
892         inc     dptr
893         djnz    b, print_float_frac_loop
894 print_float_frac_roundoff:
895         // Now it's time to round-off the BCD digits to the desired precision.
896         clr     a
897         mov     r4, #0x50               // r4/r3/r2/r1 = 0.5 (bcd rounding)
898         mov     r3, a
899         mov     r2, a
900         mov     r1, a
901         mov     a, _frac_field_width
902         rl      a
903         rl      a
904         anl     a, #0xFC
905         mov     dph, r0                 // fs_rshift_a will overwrite r0 & dpl
906         lcall   fs_rshift_a             // divide r4/r3/r2/r1 by 10^frac_field_width
907         mov     a, r5
908         add     a, r1                   // add rounding to fractional part
909         da      a
910         mov     _float_frac_bcd+3, a    // and store it for later use
911         mov     a, r6
912         addc    a, r2
913         da      a
914         mov     _float_frac_bcd+2, a
915         mov     a, r7
916         addc    a, r3
917         da      a
918         mov     _float_frac_bcd+1, a
919         mov     a, dph
920         addc    a, r4
921         da      a
922         mov     _float_frac_bcd+0, a
923         mov     sign_b, c               // keep fractional carry in sign_b
924         pop     dph
925         pop     dpl
926 print_float_int:
927         // Time to work on the integer portion... fetch the float again, check
928         // size (exponent), scale to integer, add the fraction's carry, and
929         // let the integer printing code do all the work.
930         pop     ar0
931         lcall   printf_get_float
932         push    ar0
933         clr     c
934         mov     a, #158                 // check for large float we can't print
935         subb    a, r7
936         jnc     print_float_size_ok
937 printf_float_too_big:
938         // TODO: should print some sort of overflow error??
939         pop     ar0
940         ljmp    printf_format_loop
941 print_float_size_ok:
942         push    dpl
943         lcall   fs_rshift_a
944         pop     dpl
945         jnb     sign_b, print_float_do_int
946         // if we get here, the fractional round off caused the
947         // integer part to increment.  Add 1 for a proper result
948         mov     a, r1
949         add     a, #1
950         mov     r1, a
951         clr     a
952         addc    a, r2
953         mov     r2, a
954 #ifdef LONG
955         clr     a
956         addc    a, r3
957         mov     r3, a
958         clr     a
959         addc    a, r4
960         mov     r4, a
961 #endif
962         jc      printf_float_too_big
963 print_float_do_int:
964 #ifndef LONG
965         mov     a, r3
966         orl     a, r4
967         jnz     printf_float_too_big
968 #endif
969         setb    _continue_float
970         lcall   printf_uint             // print the integer portion
971
972
973 print_float_frac_width:
974         // Now all we have to do is output the fractional digits that
975         // were previous computed and stored in memory.
976 #ifdef FIELD_WIDTH
977         jb      _field_width_flag, print_float_do_frac
978 #endif
979 #ifndef DO_NOT_TRIM_TRAILING_ZEROS 
980         // if the user did not explicitly set a
981         // field width, trim off trailing zeros
982 print_float_frac_trim:
983         mov     a, _frac_field_width
984         jz      print_float_do_frac
985         lcall   get_float_frac_digit
986         jnz     print_float_do_frac
987         djnz    _frac_field_width, print_float_frac_trim
988 #endif
989
990 print_float_do_frac:
991         mov     a, _frac_field_width
992         jz      print_float_done
993         //mov   a, #'.'
994         mov     a, #0x2E
995         lcall   printf_putchar
996         mov     r0, #0
997         setb    _print_zero_flag
998 print_float_do_frac_loop:
999         inc     r0
1000         mov     a, r0
1001         lcall   get_float_frac_digit
1002         lcall   printf_phex_lsn
1003         mov     a, r0
1004         cjne    a, _frac_field_width, print_float_do_frac_loop
1005
1006 print_float_done:
1007         pop     ar0
1008         ljmp    printf_main_loop
1009
1010
1011
1012         // acc=1 for tenths, acc=2 for hundredths, etc
1013 get_float_frac_digit:
1014         dec     a
1015         clr     c
1016         rrc     a
1017         mov     psw.5, c
1018         add     a, #_float_frac_bcd
1019         mov     r1, a
1020         mov     a, @r1
1021         jb      psw.5, get_float_frac_digit_done
1022         swap    a
1023 get_float_frac_digit_done:
1024         anl     a, #15
1025         ret
1026
1027
1028
1029
1030 #endif // end of normal FLOAT code (not FLOAT_FIXED4)
1031
1032
1033 // These helper functions are used, regardless of which type of
1034 // FLOAT code is used.
1035
1036 #if 0
1037 pm2_print_float:
1038          mov    a, r7
1039          lcall  pm2_entry_phex
1040          mov    a, #0x20
1041          lcall  pm2_entry_cout
1042          lcall  _print_r4321
1043          mov    a, #0x20
1044          lcall  pm2_entry_cout
1045          ret
1046 #endif
1047
1048         // Fetch a float from the va_args and put it into
1049         // r7(exp) r4/r3/r2(mant) and also clear r1 and preset
1050         // the flags
1051 printf_get_float:
1052         mov     a, @r0
1053         dec     r0
1054         mov     r1, a
1055         mov     a, @r0
1056         dec     r0
1057         mov     r4, a
1058         rlc     a
1059         mov     a, r1
1060         rlc     a
1061         mov     _negative_flag, c
1062         mov     r7, a
1063         jz      printf_get_float_2
1064         orl     ar4, #0x80
1065 printf_get_float_2:
1066         mov     a, @r0
1067         dec     r0
1068         mov     r3, a
1069         mov     a, @r0
1070         dec     r0
1071         mov     r2, a
1072         mov     r1, #0
1073         clr     _short_flag
1074         setb    _long_flag
1075         ret
1076 #endif // FLOAT
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090         /* read an integer into r1/r2/r3/r4, and msb into r5 */
1091 printf_get_int:
1092         mov     a, @r0
1093         mov     r1, a
1094         mov     r5, a
1095         dec     r0
1096         jb      _short_flag, printf_get_done
1097         mov     r2, ar1
1098         mov     a, @r0
1099         mov     r1, a
1100         dec     r0
1101         jnb     _long_flag, printf_get_done
1102         mov     r4, ar2
1103         mov     r3, ar1
1104         mov     a, @r0
1105         mov     r2, a
1106         dec     r0
1107         mov     a, @r0
1108         mov     r1, a
1109         dec     r0
1110 printf_get_done:
1111         ret
1112
1113
1114
1115
1116
1117 #ifdef FAST_INTEGER
1118
1119         /* convert binary number in r4/r3/r2/r1 into bcd packed number
1120          * in r3/r2/r7/r6/r5.  The input number is destroyed in the
1121          * process, to avoid needing extra memory for the result (and
1122          * r1 gets used for temporary storage).  dptr is overwritten,
1123          * but r0 is not changed.
1124          */
1125
1126 printf_int2bcd:
1127         mov     a, r1
1128         mov     b, #100
1129         div     ab
1130         mov     r6, a
1131         mov     a, #10
1132         xch     a, b
1133         div     ab
1134         swap    a
1135         orl     a, b
1136         mov     r5, a
1137
1138         jnb     _short_flag, printf_i2bcd_16    // if 8 bit int, we're done
1139         ret
1140
1141 printf_i2bcd_16:
1142         mov     a, r2
1143         anl     a, #0x0F
1144         mov     r1, a
1145         mov     dptr, #_int2bcd_2
1146         movc    a, @a+dptr
1147         add     a, r5
1148         da      a
1149         mov     r5, a
1150         mov     a, r1
1151         orl     a, #16
1152         movc    a, @a+dptr
1153         addc    a, r6
1154         da      a
1155         mov     r6, a
1156
1157         mov     a, r2
1158         swap    a
1159         anl     a, #0x0F
1160         mov     r1, a
1161         mov     dptr, #_int2bcd_3
1162         movc    a, @a+dptr
1163         add     a, r5
1164         da      a
1165         mov     r5, a
1166         mov     a, r1
1167         orl     a, #16
1168         movc    a, @a+dptr
1169         addc    a, r6
1170         da      a
1171         mov     r6, a
1172         mov     a, r1
1173         orl     a, #32
1174         movc    a, @a+dptr
1175         addc    a, #0
1176         da      a
1177         mov     r7, a
1178
1179         jb      _long_flag, printf_i2bcd_32     // if 16 bit int, we're done
1180         ret
1181
1182 printf_i2bcd_32:
1183
1184 #ifdef LONG
1185         mov     a, r3
1186         anl     a, #0x0F
1187         mov     r1, a
1188         mov     dptr, #_int2bcd_4
1189         movc    a, @a+dptr
1190         add     a, r5
1191         da      a
1192         mov     r5, a
1193         mov     a, r1
1194         orl     a, #16
1195         movc    a, @a+dptr
1196         addc    a, r6
1197         da      a
1198         mov     r6, a
1199         mov     a, r1
1200         orl     a, #32
1201         movc    a, @a+dptr
1202         addc    a, r7
1203         da      a
1204         mov     r7, a
1205         clr     a
1206         addc    a, #0
1207         mov     r2, a
1208
1209         mov     a, r3
1210         swap    a
1211         anl     a, #0x0F
1212         mov     r1, a
1213         mov     dptr, #_int2bcd_5
1214         movc    a, @a+dptr
1215         add     a, r5
1216         da      a
1217         mov     r5, a
1218         mov     a, r1
1219         orl     a, #16
1220         movc    a, @a+dptr
1221         addc    a, r6
1222         da      a
1223         mov     r6, a
1224         mov     a, r1
1225         orl     a, #32
1226         movc    a, @a+dptr
1227         addc    a, r7
1228         da      a
1229         mov     r7, a
1230         mov     a, r1
1231         orl     a, #48
1232         movc    a, @a+dptr
1233         addc    a, r2
1234         da      a
1235         mov     r2, a
1236
1237         mov     a, r4
1238         anl     a, #0x0F
1239         mov     r1, a
1240         mov     dptr, #_int2bcd_6
1241         mov     r3, #0
1242         lcall   printf_bcd_add10        // saves 27 bytes, costs 5 cycles
1243
1244         mov     a, r4
1245         swap    a
1246         anl     a, #0x0F
1247         mov     r1, a
1248         mov     dptr, #_int2bcd_7
1249 printf_bcd_add10:
1250         movc    a, @a+dptr
1251         add     a, r5
1252         da      a
1253         mov     r5, a
1254         mov     a, r1
1255         orl     a, #16
1256         movc    a, @a+dptr
1257         addc    a, r6
1258         da      a
1259         mov     r6, a
1260         mov     a, r1
1261         orl     a, #32
1262         movc    a, @a+dptr
1263         addc    a, r7
1264         da      a
1265         mov     r7, a
1266         mov     a, r1
1267         orl     a, #48
1268         movc    a, @a+dptr
1269         addc    a, r2
1270         da      a
1271         mov     r2, a
1272         mov     a, r1
1273         orl     a, #64
1274         movc    a, @a+dptr
1275         addc    a, r3
1276         da      a
1277         mov     r3, a
1278 #endif // LONG
1279         ret
1280
1281
1282 #else // not FAST_INTEGER
1283
1284         /* convert binary number in r4/r3/r2/r1 into bcd packed number
1285          * in r3/r2/r7/r6/r5.  The input number is destroyed in the
1286          * process, to avoid needing extra memory for the result (and
1287          * r1 gets used for temporary storage).  dptr is overwritten,
1288          * but r0 is not changed.
1289          */
1290
1291 #ifdef LONG
1292
1293 printf_int2bcd:
1294         mov     a, #8
1295         jb      _short_flag, printf_int2bcd_begin
1296         mov     a, #16
1297         jnb     _long_flag, printf_int2bcd_begin
1298         mov     a, #32
1299 printf_int2bcd_begin:
1300         mov     b, a
1301         clr     a
1302         mov     r5, a
1303         mov     r6, a
1304         mov     r7, a
1305         mov     (_i2bcd_tmp + 0), a
1306         mov     (_i2bcd_tmp + 1), a
1307         mov     dptr, #_int2bcd
1308 printf_i2bcd_loop:
1309         mov     a, r4
1310         rrc     a
1311         mov     r4, a
1312         mov     a, r3
1313         rrc     a
1314         mov     r3, a
1315         mov     a, r2
1316         rrc     a
1317         mov     r2, a
1318         mov     a, r1
1319         rrc     a
1320         mov     r1, a
1321         jnc     print_i2bcd_skip
1322         clr     a
1323         movc    a, @a+dptr
1324         add     a, r5
1325         da      a
1326         mov     r5, a
1327         mov     a, #1
1328         movc    a, @a+dptr
1329         addc    a, r6
1330         da      a
1331         mov     r6, a
1332         mov     a, #2
1333         movc    a, @a+dptr
1334         addc    a, r7
1335         da      a
1336         mov     r7, a
1337         mov     a, #3
1338         movc    a, @a+dptr
1339         addc    a, (_i2bcd_tmp + 0)
1340         da      a
1341         mov     (_i2bcd_tmp + 0), a
1342         mov     a, #4
1343         movc    a, @a+dptr
1344         addc    a, (_i2bcd_tmp + 1)
1345         da      a
1346         mov     (_i2bcd_tmp + 1), a
1347 print_i2bcd_skip:
1348         inc     dptr
1349         inc     dptr
1350         inc     dptr
1351         inc     dptr
1352         inc     dptr
1353         djnz    b, printf_i2bcd_loop
1354         mov     r2, (_i2bcd_tmp + 0)
1355         mov     r3, (_i2bcd_tmp + 1)
1356         ret
1357
1358 #else //  not LONG
1359
1360 printf_int2bcd:
1361         mov     a, #8
1362         jb      _short_flag, printf_int2bcd_begin
1363         mov     a, #16
1364 printf_int2bcd_begin:
1365         mov     b, a
1366         clr     a
1367         mov     r5, a
1368         mov     r6, a
1369         mov     r7, a
1370         mov     dptr, #_int2bcd
1371 printf_i2bcd_loop:
1372         mov     a, r2
1373         rrc     a
1374         mov     r2, a
1375         mov     a, r1
1376         rrc     a
1377         mov     r1, a
1378         jnc     printf_i2bcd_add_skip
1379         clr     a
1380         movc    a, @a+dptr
1381         add     a, r5
1382         da      a
1383         mov     r5, a
1384         mov     a, #1
1385         movc    a, @a+dptr
1386         addc    a, r6
1387         da      a
1388         mov     r6, a
1389         mov     a, #2
1390         movc    a, @a+dptr
1391         addc    a, r7
1392         da      a
1393         mov     r7, a
1394 printf_i2bcd_add_skip:
1395         inc     dptr
1396         inc     dptr
1397         inc     dptr
1398         djnz    b, printf_i2bcd_loop
1399         ret
1400
1401 #endif // not LONG
1402
1403
1404 #endif // not FAST_INTEGER
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418 #ifdef FIELD_WIDTH
1419 printf_space_loop:
1420         //mov   a, #' '
1421         mov     a, #32
1422         jnb     _leading_zero_flag, printf_space_output
1423         //mov   a, #'0'
1424         mov     a, #48
1425 printf_space_output:
1426         lcall   printf_putchar
1427         dec     _field_width
1428 printf_space:
1429         mov     a, _field_width
1430         jnz     printf_space_loop
1431         ret
1432 #endif
1433
1434
1435
1436
1437
1438         /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
1439
1440 printf_phex_msn:
1441         swap    a
1442 printf_phex_lsn:
1443         anl     a, #15
1444         jnz     printf_phex_ok
1445         jnb     _print_zero_flag, printf_ret
1446 printf_phex_ok:
1447         setb    _print_zero_flag
1448         add     a, #0x90
1449         da      a
1450         addc    a, #0x40
1451         da      a
1452 printf_putchar:
1453 #ifdef PUTCHAR_CALLEE_SAVES
1454         push    dph
1455         push    dpl
1456         mov     dpl, a
1457         lcall   _putchar
1458         pop     dpl
1459         pop     dph
1460 #else
1461         push    dph
1462         push    dpl
1463         push    ar0
1464         mov     dpl, a
1465         lcall   _putchar
1466         pop     ar0
1467         pop     dpl
1468         pop     dph
1469 #endif
1470 printf_ret:
1471         ret
1472
1473         /* print a zero if all the calls to print the digits ended up */
1474         /* being leading zeros */
1475
1476 printf_zero:
1477         jb      _print_zero_flag, printf_ret
1478         //mov   a, #'0'
1479         mov     a, #48
1480         ljmp    printf_putchar
1481   
1482 printf_end:
1483         _endasm;
1484 }
1485
1486
1487 #ifdef FAST_INTEGER
1488 /*
1489  * #! /usr/bin/perl
1490  * for ($d=0; $d < 8; $d++) {
1491  *      $n = 16 ** $d;
1492  *      for ($p=0; $p < 5; $p++) {
1493  *              last unless (((16 ** $d) * 15) / (10 ** ($p * 2))) % 100;
1494  *              printf "code unsigned char int2bcd_%d_%d[15] = {", $d, $p;
1495  *              for ($i=0; $i < 16; $i++) {
1496  *                      printf "0x%02d",
1497  *                         (((16 ** $d) * $i) / (10 ** ($p * 2))) % 100;
1498  *                      print ", " if $i < 15;
1499  *              }
1500  *              print "};\n";
1501  *      }
1502  * }
1503  */
1504
1505 #if 0
1506 static code unsigned char int2bcd_0[] = {
1507 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1508 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1509
1510 static code unsigned char int2bcd_1[] = {
1511 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1512 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1513 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1514 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02};
1515 #endif
1516
1517 static code unsigned char int2bcd_2[] = {
1518 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1519 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1520 0x00, 0x02, 0x05, 0x07, 0x10, 0x12, 0x15, 0x17,
1521 0x20, 0x23, 0x25, 0x28, 0x30, 0x33, 0x35, 0x38};
1522
1523 static code unsigned char int2bcd_3[] = {
1524 0x00, 0x96, 0x92, 0x88, 0x84, 0x80, 0x76, 0x72,
1525 0x68, 0x64, 0x60, 0x56, 0x52, 0x48, 0x44, 0x40,
1526 0x00, 0x40, 0x81, 0x22, 0x63, 0x04, 0x45, 0x86,
1527 0x27, 0x68, 0x09, 0x50, 0x91, 0x32, 0x73, 0x14,
1528 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02,
1529 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06};
1530
1531 #ifdef LONG
1532 static code unsigned char int2bcd_4[] = {
1533 0x00, 0x36, 0x72, 0x08, 0x44, 0x80, 0x16, 0x52,
1534 0x88, 0x24, 0x60, 0x96, 0x32, 0x68, 0x04, 0x40,
1535 0x00, 0x55, 0x10, 0x66, 0x21, 0x76, 0x32, 0x87,
1536 0x42, 0x98, 0x53, 0x08, 0x64, 0x19, 0x75, 0x30,
1537 0x00, 0x06, 0x13, 0x19, 0x26, 0x32, 0x39, 0x45,
1538 0x52, 0x58, 0x65, 0x72, 0x78, 0x85, 0x91, 0x98};
1539
1540 static code unsigned char int2bcd_5[] = {
1541 0x00, 0x76, 0x52, 0x28, 0x04, 0x80, 0x56, 0x32,
1542 0x08, 0x84, 0x60, 0x36, 0x12, 0x88, 0x64, 0x40,
1543 0x00, 0x85, 0x71, 0x57, 0x43, 0x28, 0x14, 0x00,
1544 0x86, 0x71, 0x57, 0x43, 0x29, 0x14, 0x00, 0x86,
1545 0x00, 0x04, 0x09, 0x14, 0x19, 0x24, 0x29, 0x34,
1546 0x38, 0x43, 0x48, 0x53, 0x58, 0x63, 0x68, 0x72,
1547 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1548 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1549
1550 static code unsigned char int2bcd_6[] = {
1551 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1552 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1553 0x00, 0x72, 0x44, 0x16, 0x88, 0x60, 0x32, 0x05,
1554 0x77, 0x49, 0x21, 0x93, 0x65, 0x38, 0x10, 0x82,
1555 0x00, 0x77, 0x55, 0x33, 0x10, 0x88, 0x66, 0x44,
1556 0x21, 0x99, 0x77, 0x54, 0x32, 0x10, 0x88, 0x65,
1557 0x00, 0x16, 0x33, 0x50, 0x67, 0x83, 0x00, 0x17,
1558 0x34, 0x50, 0x67, 0x84, 0x01, 0x18, 0x34, 0x51,
1559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
1560 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02};
1561
1562 static code unsigned char int2bcd_7[] = {
1563 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1564 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1565 0x00, 0x54, 0x09, 0x63, 0x18, 0x72, 0x27, 0x81,
1566 0x36, 0x91, 0x45, 0x00, 0x54, 0x09, 0x63, 0x18,
1567 0x00, 0x43, 0x87, 0x30, 0x74, 0x17, 0x61, 0x04,
1568 0x48, 0x91, 0x35, 0x79, 0x22, 0x66, 0x09, 0x53,
1569 0x00, 0x68, 0x36, 0x05, 0x73, 0x42, 0x10, 0x79,
1570 0x47, 0x15, 0x84, 0x52, 0x21, 0x89, 0x58, 0x26,
1571 0x00, 0x02, 0x05, 0x08, 0x10, 0x13, 0x16, 0x18,
1572 0x21, 0x24, 0x26, 0x29, 0x32, 0x34, 0x37, 0x40};
1573 #endif // LONG
1574
1575 #else // not FAST_INTEGER
1576
1577 /*
1578  * #! /usr/bin/perl
1579  * print "code unsigned char int2bcd[] = {\n";
1580  * for ($i=0, $n=1; $i<32; $i++, $n*=2) {
1581  *      $r = sprintf "%010u", $n;
1582  *      $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1583  *      printf "0x%02d, 0x%02d, 0x%02d, 0x%02d, 0x%02d", $5, $4, $3, $2, $1;
1584  *      print ',' if $i < 31;
1585  *      printf "\t\t// %10u\n", $n;
1586  * }
1587  * print "}\ncode unsigned char int2bcd[] = {\n";
1588  * for ($i=0, $n=1; $i<16; $i++, $n*=2) {
1589  *      $r = sprintf "%06u", $n;
1590  *      $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1591  *      printf "0x%02d, 0x%02d, 0x%02d", $3, $2, $1;
1592  *      print ',' if $i < 15;
1593  *      printf "\t\t// %10u\n", $n;
1594  * }
1595  * print "};\n";
1596 */
1597
1598 #ifdef LONG
1599 static code unsigned char int2bcd[] = {
1600 0x01, 0x00, 0x00, 0x00, 0x00,           //          1
1601 0x02, 0x00, 0x00, 0x00, 0x00,           //          2
1602 0x04, 0x00, 0x00, 0x00, 0x00,           //          4
1603 0x08, 0x00, 0x00, 0x00, 0x00,           //          8
1604 0x16, 0x00, 0x00, 0x00, 0x00,           //         16
1605 0x32, 0x00, 0x00, 0x00, 0x00,           //         32
1606 0x64, 0x00, 0x00, 0x00, 0x00,           //         64
1607 0x28, 0x01, 0x00, 0x00, 0x00,           //        128
1608 0x56, 0x02, 0x00, 0x00, 0x00,           //        256
1609 0x12, 0x05, 0x00, 0x00, 0x00,           //        512
1610 0x24, 0x10, 0x00, 0x00, 0x00,           //       1024
1611 0x48, 0x20, 0x00, 0x00, 0x00,           //       2048
1612 0x96, 0x40, 0x00, 0x00, 0x00,           //       4096
1613 0x92, 0x81, 0x00, 0x00, 0x00,           //       8192
1614 0x84, 0x63, 0x01, 0x00, 0x00,           //      16384
1615 0x68, 0x27, 0x03, 0x00, 0x00,           //      32768
1616 0x36, 0x55, 0x06, 0x00, 0x00,           //      65536
1617 0x72, 0x10, 0x13, 0x00, 0x00,           //     131072
1618 0x44, 0x21, 0x26, 0x00, 0x00,           //     262144
1619 0x88, 0x42, 0x52, 0x00, 0x00,           //     524288
1620 0x76, 0x85, 0x04, 0x01, 0x00,           //    1048576
1621 0x52, 0x71, 0x09, 0x02, 0x00,           //    2097152
1622 0x04, 0x43, 0x19, 0x04, 0x00,           //    4194304
1623 0x08, 0x86, 0x38, 0x08, 0x00,           //    8388608
1624 0x16, 0x72, 0x77, 0x16, 0x00,           //   16777216
1625 0x32, 0x44, 0x55, 0x33, 0x00,           //   33554432
1626 0x64, 0x88, 0x10, 0x67, 0x00,           //   67108864
1627 0x28, 0x77, 0x21, 0x34, 0x01,           //  134217728
1628 0x56, 0x54, 0x43, 0x68, 0x02,           //  268435456
1629 0x12, 0x09, 0x87, 0x36, 0x05,           //  536870912
1630 0x24, 0x18, 0x74, 0x73, 0x10,           // 1073741824
1631 0x48, 0x36, 0x48, 0x47, 0x21            // 2147483648
1632 };
1633 #else // not LONG
1634 static code unsigned char int2bcd[] = {
1635 0x01, 0x00, 0x00,               //          1
1636 0x02, 0x00, 0x00,               //          2
1637 0x04, 0x00, 0x00,               //          4
1638 0x08, 0x00, 0x00,               //          8
1639 0x16, 0x00, 0x00,               //         16
1640 0x32, 0x00, 0x00,               //         32
1641 0x64, 0x00, 0x00,               //         64
1642 0x28, 0x01, 0x00,               //        128
1643 0x56, 0x02, 0x00,               //        256
1644 0x12, 0x05, 0x00,               //        512
1645 0x24, 0x10, 0x00,               //       1024
1646 0x48, 0x20, 0x00,               //       2048
1647 0x96, 0x40, 0x00,               //       4096
1648 0x92, 0x81, 0x00,               //       8192
1649 0x84, 0x63, 0x01,               //      16384
1650 0x68, 0x27, 0x03                //      32768
1651 };
1652 #endif // not LONG
1653
1654 #endif // not FAST_INTEGER
1655
1656
1657
1658
1659 #ifdef FLOAT
1660 #ifndef FLOAT_FIXED4
1661
1662 /*
1663  * #! /usr/bin/perl
1664  * for ($i=0, $f=0.5; $i<24; $i++) {
1665  *      $r = sprintf "%.8f", $f;
1666  *      $r =~ /0\.([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1667  *      printf "0x%02d, 0x%02d, 0x%02d, 0x%02d", $4, $3, $2, $1;
1668  *      print ',' if $i < 23;
1669  *      $sum += $r;
1670  *      printf "\t\t// %.15f  %.8f\n", $f, $sum;
1671  *      $f /= 2;
1672  * }
1673  */
1674
1675 static code unsigned char frac2bcd[] = {
1676 0x00, 0x00, 0x00, 0x50,         // 0.500000000000000  0.50000000
1677 0x00, 0x00, 0x00, 0x25,         // 0.250000000000000  0.75000000
1678 0x00, 0x00, 0x50, 0x12,         // 0.125000000000000  0.87500000
1679 0x00, 0x00, 0x25, 0x06,         // 0.062500000000000  0.93750000
1680 0x00, 0x50, 0x12, 0x03,         // 0.031250000000000  0.96875000
1681 0x00, 0x25, 0x56, 0x01,         // 0.015625000000000  0.98437500
1682 0x50, 0x12, 0x78, 0x00,         // 0.007812500000000  0.99218750
1683 0x25, 0x06, 0x39, 0x00,         // 0.003906250000000  0.99609375
1684 0x12, 0x53, 0x19, 0x00,         // 0.001953125000000  0.99804687
1685 0x56, 0x76, 0x09, 0x00,         // 0.000976562500000  0.99902343
1686 0x28, 0x88, 0x04, 0x00,         // 0.000488281250000  0.99951171
1687 0x14, 0x44, 0x02, 0x00,         // 0.000244140625000  0.99975585
1688 0x07, 0x22, 0x01, 0x00,         // 0.000122070312500  0.99987792
1689 0x04, 0x61, 0x00, 0x00,         // 0.000061035156250  0.99993896
1690 0x52, 0x30, 0x00, 0x00,         // 0.000030517578125  0.99996948
1691 0x26, 0x15, 0x00, 0x00,         // 0.000015258789062  0.99998474
1692 0x63, 0x07, 0x00, 0x00,         // 0.000007629394531  0.99999237
1693 0x81, 0x03, 0x00, 0x00,         // 0.000003814697266  0.99999618
1694 0x91, 0x01, 0x00, 0x00,         // 0.000001907348633  0.99999809
1695 0x95, 0x00, 0x00, 0x00,         // 0.000000953674316  0.99999904
1696 0x48, 0x00, 0x00, 0x00,         // 0.000000476837158  0.99999952
1697 0x24, 0x00, 0x00, 0x00,         // 0.000000238418579  0.99999976
1698 0x12, 0x00, 0x00, 0x00,         // 0.000000119209290  0.99999988
1699 0x06, 0x00, 0x00, 0x00,         // 0.000000059604645  0.99999994
1700 0x03, 0x00, 0x00, 0x00,         // 0.000000029802322  0.99999997
1701 0x01, 0x00, 0x00, 0x00,         // 0.000000014901161  0.99999998
1702 0x01, 0x00, 0x00, 0x00          // 0.000000007450581  0.99999999
1703 };
1704
1705 #ifndef FLOAT_DEFAULT_FRAC_DIGITS
1706 // TODO: Perhaps these should be tweaked a bit to take round up
1707 // effects into account... or maybe give more default digits??
1708 // Range                #digits
1709 // 0.0001 - 0.0009999   7
1710 // 0.001 - 0.009999     6       0.001 = 0x3A83126F  3A83
1711 // 0.01 - 0.09999       5       0.01  = 0x3C23D70A  3C23
1712 // 0.1 - 9.9999         4       0.1   = 0x3DCCCCCD, 3DCC
1713 // 10.0 - 99.99         3       10.0  = 0x41200000  4120
1714 // 100.0 - 999.99       2       100.0 = 0x42C80000  42C8
1715 // 1000 - 9999.9        1       1000  = 0x447A0000  447A
1716 // 10000+               0       10000 = 0x461C4000  461C
1717 static code unsigned int float_range_table[] = {
1718 65536 - 0x3A83,
1719 65536 - 0x3C23,
1720 65536 - 0x3DCC,
1721 65536 - 0x4120,
1722 65536 - 0x42C8,
1723 65536 - 0x447A,
1724 65536 - 0x461C
1725 };
1726 #endif
1727
1728 #else // using FLOAT_FIXED4
1729
1730 /*
1731 * #! /usr/bin/perl
1732 *     for ($i=0, $f=0.5; $i<14; $i++) {
1733 *     $r = sprintf "%.4f", $f;
1734 *     $r =~ /0\.([0-9][0-9])([0-9][0-9])/;
1735 *     printf "0x%02d, 0x%02d", $2, $1;
1736 *     print ',' if $i < 13;
1737 *     $sum += $r;
1738 *     printf "\t\t// %.15f  %.4f\n", $f, $sum;
1739 *     $f /= 2;
1740 * }
1741 */
1742
1743 static code unsigned char frac2bcd[] = {
1744 0x00, 0x50,             // 0.500000000000000  0.5000
1745 0x00, 0x25,             // 0.250000000000000  0.7500
1746 0x50, 0x12,             // 0.125000000000000  0.8750
1747 0x25, 0x06,             // 0.062500000000000  0.9375
1748 0x12, 0x03,             // 0.031250000000000  0.9687
1749 0x56, 0x01,             // 0.015625000000000  0.9843
1750 0x78, 0x00,             // 0.007812500000000  0.9921
1751 0x39, 0x00,             // 0.003906250000000  0.9960
1752 0x20, 0x00,             // 0.001953125000000  0.9980
1753 0x10, 0x00,             // 0.000976562500000  0.9990
1754 0x05, 0x00,             // 0.000488281250000  0.9995
1755 0x02, 0x00,             // 0.000244140625000  0.9997
1756 0x01, 0x00,             // 0.000122070312500  0.9998
1757 0x01, 0x00              // 0.000061035156250  0.9999
1758 };
1759
1760 #endif // FLOAT_FIXED4
1761 #endif // FLOAT
1762
1763
1764 #endif // defines compatible with printf_fast
1765