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