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