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