* configure.in: added missing mcs51 in status output
[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         ljmp    printf_format_loop
940 print_float_size_ok:
941         push    dpl
942         lcall   fs_rshift_a
943         pop     dpl
944         jnb     sign_b, print_float_do_int
945         // if we get here, the fractional round off caused the
946         // integer part to increment.  Add 1 for a proper result
947         mov     a, r1
948         add     a, #1
949         mov     r1, a
950         clr     a
951         addc    a, r2
952         mov     r2, a
953 #ifdef LONG
954         clr     a
955         addc    a, r3
956         mov     r3, a
957         clr     a
958         addc    a, r4
959         mov     r4, a
960 #endif
961         jc      printf_float_too_big
962 print_float_do_int:
963 #ifndef LONG
964         mov     a, r3
965         orl     a, r4
966         jnz     printf_float_too_big
967 #endif
968         setb    _continue_float
969         lcall   printf_uint             // print the integer portion
970
971
972 print_float_frac_width:
973         // Now all we have to do is output the fractional digits that
974         // were previous computed and stored in memory.
975 #ifdef FIELD_WIDTH
976         jb      _field_width_flag, print_float_do_frac
977 #endif
978 #ifndef DO_NOT_TRIM_TRAILING_ZEROS 
979         // if the user did not explicitly set a
980         // field width, trim off trailing zeros
981 print_float_frac_trim:
982         mov     a, _frac_field_width
983         jz      print_float_do_frac
984         lcall   get_float_frac_digit
985         jnz     print_float_do_frac
986         djnz    _frac_field_width, print_float_frac_trim
987 #endif
988
989 print_float_do_frac:
990         mov     a, _frac_field_width
991         jz      print_float_done
992         //mov   a, #'.'
993         mov     a, #0x2E
994         lcall   printf_putchar
995         mov     r0, #0
996         setb    _print_zero_flag
997 print_float_do_frac_loop:
998         inc     r0
999         mov     a, r0
1000         lcall   get_float_frac_digit
1001         lcall   printf_phex_lsn
1002         mov     a, r0
1003         cjne    a, _frac_field_width, print_float_do_frac_loop
1004
1005 print_float_done:
1006         pop     ar0
1007         ljmp    printf_main_loop
1008
1009
1010
1011         // acc=1 for tenths, acc=2 for hundredths, etc
1012 get_float_frac_digit:
1013         dec     a
1014         clr     c
1015         rrc     a
1016         mov     psw.5, c
1017         add     a, #_float_frac_bcd
1018         mov     r1, a
1019         mov     a, @r1
1020         jb      psw.5, get_float_frac_digit_done
1021         swap    a
1022 get_float_frac_digit_done:
1023         anl     a, #15
1024         ret
1025
1026
1027
1028
1029 #endif // end of normal FLOAT code (not FLOAT_FIXED4)
1030
1031
1032 // These helper functions are used, regardless of which type of
1033 // FLOAT code is used.
1034
1035 #if 0
1036 pm2_print_float:
1037          mov    a, r7
1038          lcall  pm2_entry_phex
1039          mov    a, #0x20
1040          lcall  pm2_entry_cout
1041          lcall  _print_r4321
1042          mov    a, #0x20
1043          lcall  pm2_entry_cout
1044          ret
1045 #endif
1046
1047         // Fetch a float from the va_args and put it into
1048         // r7(exp) r4/r3/r2(mant) and also clear r1 and preset
1049         // the flags
1050 printf_get_float:
1051         mov     a, @r0
1052         dec     r0
1053         mov     r1, a
1054         mov     a, @r0
1055         dec     r0
1056         mov     r4, a
1057         rlc     a
1058         mov     a, r1
1059         rlc     a
1060         mov     _negative_flag, c
1061         mov     r7, a
1062         jz      printf_get_float_2
1063         orl     ar4, #0x80
1064 printf_get_float_2:
1065         mov     a, @r0
1066         dec     r0
1067         mov     r3, a
1068         mov     a, @r0
1069         dec     r0
1070         mov     r2, a
1071         mov     r1, #0
1072         clr     _short_flag
1073         setb    _long_flag
1074         ret
1075 #endif // FLOAT
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089         /* read an integer into r1/r2/r3/r4, and msb into r5 */
1090 printf_get_int:
1091         mov     a, @r0
1092         mov     r1, a
1093         mov     r5, a
1094         dec     r0
1095         jb      _short_flag, printf_get_done
1096         mov     r2, ar1
1097         mov     a, @r0
1098         mov     r1, a
1099         dec     r0
1100         jnb     _long_flag, printf_get_done
1101         mov     r4, ar2
1102         mov     r3, ar1
1103         mov     a, @r0
1104         mov     r2, a
1105         dec     r0
1106         mov     a, @r0
1107         mov     r1, a
1108         dec     r0
1109 printf_get_done:
1110         ret
1111
1112
1113
1114
1115
1116 #ifdef FAST_INTEGER
1117
1118         /* convert binary number in r4/r3/r2/r1 into bcd packed number
1119          * in r3/r2/r7/r6/r5.  The input number is destroyed in the
1120          * process, to avoid needing extra memory for the result (and
1121          * r1 gets used for temporary storage).  dptr is overwritten,
1122          * but r0 is not changed.
1123          */
1124
1125 printf_int2bcd:
1126         mov     a, r1
1127         mov     b, #100
1128         div     ab
1129         mov     r6, a
1130         mov     a, #10
1131         xch     a, b
1132         div     ab
1133         swap    a
1134         orl     a, b
1135         mov     r5, a
1136
1137         jnb     _short_flag, printf_i2bcd_16    // if 8 bit int, we're done
1138         ret
1139
1140 printf_i2bcd_16:
1141         mov     a, r2
1142         anl     a, #0x0F
1143         mov     r1, a
1144         mov     dptr, #_int2bcd_2
1145         movc    a, @a+dptr
1146         add     a, r5
1147         da      a
1148         mov     r5, a
1149         mov     a, r1
1150         orl     a, #16
1151         movc    a, @a+dptr
1152         addc    a, r6
1153         da      a
1154         mov     r6, a
1155
1156         mov     a, r2
1157         swap    a
1158         anl     a, #0x0F
1159         mov     r1, a
1160         mov     dptr, #_int2bcd_3
1161         movc    a, @a+dptr
1162         add     a, r5
1163         da      a
1164         mov     r5, a
1165         mov     a, r1
1166         orl     a, #16
1167         movc    a, @a+dptr
1168         addc    a, r6
1169         da      a
1170         mov     r6, a
1171         mov     a, r1
1172         orl     a, #32
1173         movc    a, @a+dptr
1174         addc    a, #0
1175         da      a
1176         mov     r7, a
1177
1178         jb      _long_flag, printf_i2bcd_32     // if 16 bit int, we're done
1179         ret
1180
1181 printf_i2bcd_32:
1182
1183 #ifdef LONG
1184         mov     a, r3
1185         anl     a, #0x0F
1186         mov     r1, a
1187         mov     dptr, #_int2bcd_4
1188         movc    a, @a+dptr
1189         add     a, r5
1190         da      a
1191         mov     r5, a
1192         mov     a, r1
1193         orl     a, #16
1194         movc    a, @a+dptr
1195         addc    a, r6
1196         da      a
1197         mov     r6, a
1198         mov     a, r1
1199         orl     a, #32
1200         movc    a, @a+dptr
1201         addc    a, r7
1202         da      a
1203         mov     r7, a
1204         clr     a
1205         addc    a, #0
1206         mov     r2, a
1207
1208         mov     a, r3
1209         swap    a
1210         anl     a, #0x0F
1211         mov     r1, a
1212         mov     dptr, #_int2bcd_5
1213         movc    a, @a+dptr
1214         add     a, r5
1215         da      a
1216         mov     r5, a
1217         mov     a, r1
1218         orl     a, #16
1219         movc    a, @a+dptr
1220         addc    a, r6
1221         da      a
1222         mov     r6, a
1223         mov     a, r1
1224         orl     a, #32
1225         movc    a, @a+dptr
1226         addc    a, r7
1227         da      a
1228         mov     r7, a
1229         mov     a, r1
1230         orl     a, #48
1231         movc    a, @a+dptr
1232         addc    a, r2
1233         da      a
1234         mov     r2, a
1235
1236         mov     a, r4
1237         anl     a, #0x0F
1238         mov     r1, a
1239         mov     dptr, #_int2bcd_6
1240         mov     r3, #0
1241         lcall   printf_bcd_add10        // saves 27 bytes, costs 5 cycles
1242
1243         mov     a, r4
1244         swap    a
1245         anl     a, #0x0F
1246         mov     r1, a
1247         mov     dptr, #_int2bcd_7
1248 printf_bcd_add10:
1249         movc    a, @a+dptr
1250         add     a, r5
1251         da      a
1252         mov     r5, a
1253         mov     a, r1
1254         orl     a, #16
1255         movc    a, @a+dptr
1256         addc    a, r6
1257         da      a
1258         mov     r6, a
1259         mov     a, r1
1260         orl     a, #32
1261         movc    a, @a+dptr
1262         addc    a, r7
1263         da      a
1264         mov     r7, a
1265         mov     a, r1
1266         orl     a, #48
1267         movc    a, @a+dptr
1268         addc    a, r2
1269         da      a
1270         mov     r2, a
1271         mov     a, r1
1272         orl     a, #64
1273         movc    a, @a+dptr
1274         addc    a, r3
1275         da      a
1276         mov     r3, a
1277 #endif // LONG
1278         ret
1279
1280
1281 #else // not FAST_INTEGER
1282
1283         /* convert binary number in r4/r3/r2/r1 into bcd packed number
1284          * in r3/r2/r7/r6/r5.  The input number is destroyed in the
1285          * process, to avoid needing extra memory for the result (and
1286          * r1 gets used for temporary storage).  dptr is overwritten,
1287          * but r0 is not changed.
1288          */
1289
1290 #ifdef LONG
1291
1292 printf_int2bcd:
1293         mov     a, #8
1294         jb      _short_flag, printf_int2bcd_begin
1295         mov     a, #16
1296         jnb     _long_flag, printf_int2bcd_begin
1297         mov     a, #32
1298 printf_int2bcd_begin:
1299         mov     b, a
1300         clr     a
1301         mov     r5, a
1302         mov     r6, a
1303         mov     r7, a
1304         mov     (_i2bcd_tmp + 0), a
1305         mov     (_i2bcd_tmp + 1), a
1306         mov     dptr, #_int2bcd
1307 printf_i2bcd_loop:
1308         mov     a, r4
1309         rrc     a
1310         mov     r4, a
1311         mov     a, r3
1312         rrc     a
1313         mov     r3, a
1314         mov     a, r2
1315         rrc     a
1316         mov     r2, a
1317         mov     a, r1
1318         rrc     a
1319         mov     r1, a
1320         jnc     print_i2bcd_skip
1321         clr     a
1322         movc    a, @a+dptr
1323         add     a, r5
1324         da      a
1325         mov     r5, a
1326         mov     a, #1
1327         movc    a, @a+dptr
1328         addc    a, r6
1329         da      a
1330         mov     r6, a
1331         mov     a, #2
1332         movc    a, @a+dptr
1333         addc    a, r7
1334         da      a
1335         mov     r7, a
1336         mov     a, #3
1337         movc    a, @a+dptr
1338         addc    a, (_i2bcd_tmp + 0)
1339         da      a
1340         mov     (_i2bcd_tmp + 0), a
1341         mov     a, #4
1342         movc    a, @a+dptr
1343         addc    a, (_i2bcd_tmp + 1)
1344         da      a
1345         mov     (_i2bcd_tmp + 1), a
1346 print_i2bcd_skip:
1347         inc     dptr
1348         inc     dptr
1349         inc     dptr
1350         inc     dptr
1351         inc     dptr
1352         djnz    b, printf_i2bcd_loop
1353         mov     r2, (_i2bcd_tmp + 0)
1354         mov     r3, (_i2bcd_tmp + 1)
1355         ret
1356
1357 #else //  not LONG
1358
1359 printf_int2bcd:
1360         mov     a, #8
1361         jb      _short_flag, printf_int2bcd_begin
1362         mov     a, #16
1363 printf_int2bcd_begin:
1364         mov     b, a
1365         clr     a
1366         mov     r5, a
1367         mov     r6, a
1368         mov     r7, a
1369         mov     dptr, #_int2bcd
1370 printf_i2bcd_loop:
1371         mov     a, r2
1372         rrc     a
1373         mov     r2, a
1374         mov     a, r1
1375         rrc     a
1376         mov     r1, a
1377         jnc     printf_i2bcd_add_skip
1378         clr     a
1379         movc    a, @a+dptr
1380         add     a, r5
1381         da      a
1382         mov     r5, a
1383         mov     a, #1
1384         movc    a, @a+dptr
1385         addc    a, r6
1386         da      a
1387         mov     r6, a
1388         mov     a, #2
1389         movc    a, @a+dptr
1390         addc    a, r7
1391         da      a
1392         mov     r7, a
1393 printf_i2bcd_add_skip:
1394         inc     dptr
1395         inc     dptr
1396         inc     dptr
1397         djnz    b, printf_i2bcd_loop
1398         ret
1399
1400 #endif // not LONG
1401
1402
1403 #endif // not FAST_INTEGER
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417 #ifdef FIELD_WIDTH
1418 printf_space_loop:
1419         //mov   a, #' '
1420         mov     a, #32
1421         jnb     _leading_zero_flag, printf_space_output
1422         //mov   a, #'0'
1423         mov     a, #48
1424 printf_space_output:
1425         lcall   printf_putchar
1426         dec     _field_width
1427 printf_space:
1428         mov     a, _field_width
1429         jnz     printf_space_loop
1430         ret
1431 #endif
1432
1433
1434
1435
1436
1437         /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
1438
1439 printf_phex_msn:
1440         swap    a
1441 printf_phex_lsn:
1442         anl     a, #15
1443         jnz     printf_phex_ok
1444         jnb     _print_zero_flag, printf_ret
1445 printf_phex_ok:
1446         setb    _print_zero_flag
1447         add     a, #0x90
1448         da      a
1449         addc    a, #0x40
1450         da      a
1451 printf_putchar:
1452 #ifdef PUTCHAR_CALLEE_SAVES
1453         push    dph
1454         push    dpl
1455         mov     dpl, a
1456         lcall   _putchar
1457         pop     dpl
1458         pop     dph
1459 #else
1460         push    dph
1461         push    dpl
1462         push    ar0
1463         mov     dpl, a
1464         lcall   _putchar
1465         pop     ar0
1466         pop     dpl
1467         pop     dph
1468 #endif
1469 printf_ret:
1470         ret
1471
1472         /* print a zero if all the calls to print the digits ended up */
1473         /* being leading zeros */
1474
1475 printf_zero:
1476         jb      _print_zero_flag, printf_ret
1477         //mov   a, #'0'
1478         mov     a, #48
1479         ljmp    printf_putchar
1480   
1481 printf_end:
1482         _endasm;
1483 }
1484
1485
1486 #ifdef FAST_INTEGER
1487 /*
1488  * #! /usr/bin/perl
1489  * for ($d=0; $d < 8; $d++) {
1490  *      $n = 16 ** $d;
1491  *      for ($p=0; $p < 5; $p++) {
1492  *              last unless (((16 ** $d) * 15) / (10 ** ($p * 2))) % 100;
1493  *              printf "code unsigned char int2bcd_%d_%d[15] = {", $d, $p;
1494  *              for ($i=0; $i < 16; $i++) {
1495  *                      printf "0x%02d",
1496  *                         (((16 ** $d) * $i) / (10 ** ($p * 2))) % 100;
1497  *                      print ", " if $i < 15;
1498  *              }
1499  *              print "};\n";
1500  *      }
1501  * }
1502  */
1503
1504 #if 0
1505 static code unsigned char int2bcd_0[] = {
1506 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1507 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1508
1509 static code unsigned char int2bcd_1[] = {
1510 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1511 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1512 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1513 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02};
1514 #endif
1515
1516 static code unsigned char int2bcd_2[] = {
1517 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1518 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1519 0x00, 0x02, 0x05, 0x07, 0x10, 0x12, 0x15, 0x17,
1520 0x20, 0x23, 0x25, 0x28, 0x30, 0x33, 0x35, 0x38};
1521
1522 static code unsigned char int2bcd_3[] = {
1523 0x00, 0x96, 0x92, 0x88, 0x84, 0x80, 0x76, 0x72,
1524 0x68, 0x64, 0x60, 0x56, 0x52, 0x48, 0x44, 0x40,
1525 0x00, 0x40, 0x81, 0x22, 0x63, 0x04, 0x45, 0x86,
1526 0x27, 0x68, 0x09, 0x50, 0x91, 0x32, 0x73, 0x14,
1527 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02,
1528 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06};
1529
1530 #ifdef LONG
1531 static code unsigned char int2bcd_4[] = {
1532 0x00, 0x36, 0x72, 0x08, 0x44, 0x80, 0x16, 0x52,
1533 0x88, 0x24, 0x60, 0x96, 0x32, 0x68, 0x04, 0x40,
1534 0x00, 0x55, 0x10, 0x66, 0x21, 0x76, 0x32, 0x87,
1535 0x42, 0x98, 0x53, 0x08, 0x64, 0x19, 0x75, 0x30,
1536 0x00, 0x06, 0x13, 0x19, 0x26, 0x32, 0x39, 0x45,
1537 0x52, 0x58, 0x65, 0x72, 0x78, 0x85, 0x91, 0x98};
1538
1539 static code unsigned char int2bcd_5[] = {
1540 0x00, 0x76, 0x52, 0x28, 0x04, 0x80, 0x56, 0x32,
1541 0x08, 0x84, 0x60, 0x36, 0x12, 0x88, 0x64, 0x40,
1542 0x00, 0x85, 0x71, 0x57, 0x43, 0x28, 0x14, 0x00,
1543 0x86, 0x71, 0x57, 0x43, 0x29, 0x14, 0x00, 0x86,
1544 0x00, 0x04, 0x09, 0x14, 0x19, 0x24, 0x29, 0x34,
1545 0x38, 0x43, 0x48, 0x53, 0x58, 0x63, 0x68, 0x72,
1546 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1547 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1548
1549 static code unsigned char int2bcd_6[] = {
1550 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1551 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1552 0x00, 0x72, 0x44, 0x16, 0x88, 0x60, 0x32, 0x05,
1553 0x77, 0x49, 0x21, 0x93, 0x65, 0x38, 0x10, 0x82,
1554 0x00, 0x77, 0x55, 0x33, 0x10, 0x88, 0x66, 0x44,
1555 0x21, 0x99, 0x77, 0x54, 0x32, 0x10, 0x88, 0x65,
1556 0x00, 0x16, 0x33, 0x50, 0x67, 0x83, 0x00, 0x17,
1557 0x34, 0x50, 0x67, 0x84, 0x01, 0x18, 0x34, 0x51,
1558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
1559 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02};
1560
1561 static code unsigned char int2bcd_7[] = {
1562 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1563 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1564 0x00, 0x54, 0x09, 0x63, 0x18, 0x72, 0x27, 0x81,
1565 0x36, 0x91, 0x45, 0x00, 0x54, 0x09, 0x63, 0x18,
1566 0x00, 0x43, 0x87, 0x30, 0x74, 0x17, 0x61, 0x04,
1567 0x48, 0x91, 0x35, 0x79, 0x22, 0x66, 0x09, 0x53,
1568 0x00, 0x68, 0x36, 0x05, 0x73, 0x42, 0x10, 0x79,
1569 0x47, 0x15, 0x84, 0x52, 0x21, 0x89, 0x58, 0x26,
1570 0x00, 0x02, 0x05, 0x08, 0x10, 0x13, 0x16, 0x18,
1571 0x21, 0x24, 0x26, 0x29, 0x32, 0x34, 0x37, 0x40};
1572 #endif // LONG
1573
1574 #else // not FAST_INTEGER
1575
1576 /*
1577  * #! /usr/bin/perl
1578  * print "code unsigned char int2bcd[] = {\n";
1579  * for ($i=0, $n=1; $i<32; $i++, $n*=2) {
1580  *      $r = sprintf "%010u", $n;
1581  *      $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1582  *      printf "0x%02d, 0x%02d, 0x%02d, 0x%02d, 0x%02d", $5, $4, $3, $2, $1;
1583  *      print ',' if $i < 31;
1584  *      printf "\t\t// %10u\n", $n;
1585  * }
1586  * print "}\ncode unsigned char int2bcd[] = {\n";
1587  * for ($i=0, $n=1; $i<16; $i++, $n*=2) {
1588  *      $r = sprintf "%06u", $n;
1589  *      $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1590  *      printf "0x%02d, 0x%02d, 0x%02d", $3, $2, $1;
1591  *      print ',' if $i < 15;
1592  *      printf "\t\t// %10u\n", $n;
1593  * }
1594  * print "};\n";
1595 */
1596
1597 #ifdef LONG
1598 static code unsigned char int2bcd[] = {
1599 0x01, 0x00, 0x00, 0x00, 0x00,           //          1
1600 0x02, 0x00, 0x00, 0x00, 0x00,           //          2
1601 0x04, 0x00, 0x00, 0x00, 0x00,           //          4
1602 0x08, 0x00, 0x00, 0x00, 0x00,           //          8
1603 0x16, 0x00, 0x00, 0x00, 0x00,           //         16
1604 0x32, 0x00, 0x00, 0x00, 0x00,           //         32
1605 0x64, 0x00, 0x00, 0x00, 0x00,           //         64
1606 0x28, 0x01, 0x00, 0x00, 0x00,           //        128
1607 0x56, 0x02, 0x00, 0x00, 0x00,           //        256
1608 0x12, 0x05, 0x00, 0x00, 0x00,           //        512
1609 0x24, 0x10, 0x00, 0x00, 0x00,           //       1024
1610 0x48, 0x20, 0x00, 0x00, 0x00,           //       2048
1611 0x96, 0x40, 0x00, 0x00, 0x00,           //       4096
1612 0x92, 0x81, 0x00, 0x00, 0x00,           //       8192
1613 0x84, 0x63, 0x01, 0x00, 0x00,           //      16384
1614 0x68, 0x27, 0x03, 0x00, 0x00,           //      32768
1615 0x36, 0x55, 0x06, 0x00, 0x00,           //      65536
1616 0x72, 0x10, 0x13, 0x00, 0x00,           //     131072
1617 0x44, 0x21, 0x26, 0x00, 0x00,           //     262144
1618 0x88, 0x42, 0x52, 0x00, 0x00,           //     524288
1619 0x76, 0x85, 0x04, 0x01, 0x00,           //    1048576
1620 0x52, 0x71, 0x09, 0x02, 0x00,           //    2097152
1621 0x04, 0x43, 0x19, 0x04, 0x00,           //    4194304
1622 0x08, 0x86, 0x38, 0x08, 0x00,           //    8388608
1623 0x16, 0x72, 0x77, 0x16, 0x00,           //   16777216
1624 0x32, 0x44, 0x55, 0x33, 0x00,           //   33554432
1625 0x64, 0x88, 0x10, 0x67, 0x00,           //   67108864
1626 0x28, 0x77, 0x21, 0x34, 0x01,           //  134217728
1627 0x56, 0x54, 0x43, 0x68, 0x02,           //  268435456
1628 0x12, 0x09, 0x87, 0x36, 0x05,           //  536870912
1629 0x24, 0x18, 0x74, 0x73, 0x10,           // 1073741824
1630 0x48, 0x36, 0x48, 0x47, 0x21            // 2147483648
1631 };
1632 #else // not LONG
1633 static code unsigned char int2bcd[] = {
1634 0x01, 0x00, 0x00,               //          1
1635 0x02, 0x00, 0x00,               //          2
1636 0x04, 0x00, 0x00,               //          4
1637 0x08, 0x00, 0x00,               //          8
1638 0x16, 0x00, 0x00,               //         16
1639 0x32, 0x00, 0x00,               //         32
1640 0x64, 0x00, 0x00,               //         64
1641 0x28, 0x01, 0x00,               //        128
1642 0x56, 0x02, 0x00,               //        256
1643 0x12, 0x05, 0x00,               //        512
1644 0x24, 0x10, 0x00,               //       1024
1645 0x48, 0x20, 0x00,               //       2048
1646 0x96, 0x40, 0x00,               //       4096
1647 0x92, 0x81, 0x00,               //       8192
1648 0x84, 0x63, 0x01,               //      16384
1649 0x68, 0x27, 0x03                //      32768
1650 };
1651 #endif // not LONG
1652
1653 #endif // not FAST_INTEGER
1654
1655
1656
1657
1658 #ifdef FLOAT
1659 #ifndef FLOAT_FIXED4
1660
1661 /*
1662  * #! /usr/bin/perl
1663  * for ($i=0, $f=0.5; $i<24; $i++) {
1664  *      $r = sprintf "%.8f", $f;
1665  *      $r =~ /0\.([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1666  *      printf "0x%02d, 0x%02d, 0x%02d, 0x%02d", $4, $3, $2, $1;
1667  *      print ',' if $i < 23;
1668  *      $sum += $r;
1669  *      printf "\t\t// %.15f  %.8f\n", $f, $sum;
1670  *      $f /= 2;
1671  * }
1672  */
1673
1674 static code unsigned char frac2bcd[] = {
1675 0x00, 0x00, 0x00, 0x50,         // 0.500000000000000  0.50000000
1676 0x00, 0x00, 0x00, 0x25,         // 0.250000000000000  0.75000000
1677 0x00, 0x00, 0x50, 0x12,         // 0.125000000000000  0.87500000
1678 0x00, 0x00, 0x25, 0x06,         // 0.062500000000000  0.93750000
1679 0x00, 0x50, 0x12, 0x03,         // 0.031250000000000  0.96875000
1680 0x00, 0x25, 0x56, 0x01,         // 0.015625000000000  0.98437500
1681 0x50, 0x12, 0x78, 0x00,         // 0.007812500000000  0.99218750
1682 0x25, 0x06, 0x39, 0x00,         // 0.003906250000000  0.99609375
1683 0x12, 0x53, 0x19, 0x00,         // 0.001953125000000  0.99804687
1684 0x56, 0x76, 0x09, 0x00,         // 0.000976562500000  0.99902343
1685 0x28, 0x88, 0x04, 0x00,         // 0.000488281250000  0.99951171
1686 0x14, 0x44, 0x02, 0x00,         // 0.000244140625000  0.99975585
1687 0x07, 0x22, 0x01, 0x00,         // 0.000122070312500  0.99987792
1688 0x04, 0x61, 0x00, 0x00,         // 0.000061035156250  0.99993896
1689 0x52, 0x30, 0x00, 0x00,         // 0.000030517578125  0.99996948
1690 0x26, 0x15, 0x00, 0x00,         // 0.000015258789062  0.99998474
1691 0x63, 0x07, 0x00, 0x00,         // 0.000007629394531  0.99999237
1692 0x81, 0x03, 0x00, 0x00,         // 0.000003814697266  0.99999618
1693 0x91, 0x01, 0x00, 0x00,         // 0.000001907348633  0.99999809
1694 0x95, 0x00, 0x00, 0x00,         // 0.000000953674316  0.99999904
1695 0x48, 0x00, 0x00, 0x00,         // 0.000000476837158  0.99999952
1696 0x24, 0x00, 0x00, 0x00,         // 0.000000238418579  0.99999976
1697 0x12, 0x00, 0x00, 0x00,         // 0.000000119209290  0.99999988
1698 0x06, 0x00, 0x00, 0x00,         // 0.000000059604645  0.99999994
1699 0x03, 0x00, 0x00, 0x00,         // 0.000000029802322  0.99999997
1700 0x01, 0x00, 0x00, 0x00,         // 0.000000014901161  0.99999998
1701 0x01, 0x00, 0x00, 0x00          // 0.000000007450581  0.99999999
1702 };
1703
1704 #ifndef FLOAT_DEFAULT_FRAC_DIGITS
1705 // TODO: Perhaps these should be tweaked a bit to take round up
1706 // effects into account... or maybe give more default digits??
1707 // Range                #digits
1708 // 0.0001 - 0.0009999   7
1709 // 0.001 - 0.009999     6       0.001 = 0x3A83126F  3A83
1710 // 0.01 - 0.09999       5       0.01  = 0x3C23D70A  3C23
1711 // 0.1 - 9.9999         4       0.1   = 0x3DCCCCCD, 3DCC
1712 // 10.0 - 99.99         3       10.0  = 0x41200000  4120
1713 // 100.0 - 999.99       2       100.0 = 0x42C80000  42C8
1714 // 1000 - 9999.9        1       1000  = 0x447A0000  447A
1715 // 10000+               0       10000 = 0x461C4000  461C
1716 static code unsigned int float_range_table[] = {
1717 65536 - 0x3A83,
1718 65536 - 0x3C23,
1719 65536 - 0x3DCC,
1720 65536 - 0x4120,
1721 65536 - 0x42C8,
1722 65536 - 0x447A,
1723 65536 - 0x461C
1724 };
1725 #endif
1726
1727 #else // using FLOAT_FIXED4
1728
1729 /*
1730 * #! /usr/bin/perl
1731 *     for ($i=0, $f=0.5; $i<14; $i++) {
1732 *     $r = sprintf "%.4f", $f;
1733 *     $r =~ /0\.([0-9][0-9])([0-9][0-9])/;
1734 *     printf "0x%02d, 0x%02d", $2, $1;
1735 *     print ',' if $i < 13;
1736 *     $sum += $r;
1737 *     printf "\t\t// %.15f  %.4f\n", $f, $sum;
1738 *     $f /= 2;
1739 * }
1740 */
1741
1742 static code unsigned char frac2bcd[] = {
1743 0x00, 0x50,             // 0.500000000000000  0.5000
1744 0x00, 0x25,             // 0.250000000000000  0.7500
1745 0x50, 0x12,             // 0.125000000000000  0.8750
1746 0x25, 0x06,             // 0.062500000000000  0.9375
1747 0x12, 0x03,             // 0.031250000000000  0.9687
1748 0x56, 0x01,             // 0.015625000000000  0.9843
1749 0x78, 0x00,             // 0.007812500000000  0.9921
1750 0x39, 0x00,             // 0.003906250000000  0.9960
1751 0x20, 0x00,             // 0.001953125000000  0.9980
1752 0x10, 0x00,             // 0.000976562500000  0.9990
1753 0x05, 0x00,             // 0.000488281250000  0.9995
1754 0x02, 0x00,             // 0.000244140625000  0.9997
1755 0x01, 0x00,             // 0.000122070312500  0.9998
1756 0x01, 0x00              // 0.000061035156250  0.9999
1757 };
1758
1759 #endif // FLOAT_FIXED4
1760 #endif // FLOAT
1761
1762
1763 #endif // defines compatible with printf_fast
1764