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