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