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