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