1 /* Fast printf routine for use with sdcc/mcs51
2 * Copyright (c) 2004, Paul Stoffregen, paul@pjrc.com
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.
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.
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.
19 /******************************************************************/
21 /** Major features. These determine what capabilities your **/
22 /** comiled printf_fast will have. **/
24 /******************************************************************/
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.
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.
39 // Include support for minimum field widths (%8d, %20s, %12.5f)
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.
52 /******************************************************************/
54 /** Minor tweaks. These provide small code savings, with **/
55 /** a partial loss of functionality. **/
57 /******************************************************************/
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
67 //#define FLOAT_FIXED4
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
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
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
89 /* extern void putchar(char ); */
92 static bit long_flag, short_flag, print_zero_flag, negative_flag;
95 static bit field_width_flag;
96 static data unsigned char field_width;
101 static bit continue_float;
103 static data unsigned char frac_field_width;
104 static data unsigned char float_frac_bcd[4];
105 // TODO: can float_frac_bcd be overlaid with temps used by trig functions
111 static data unsigned int i2bcd_tmp; // slow 32 int conversion needs temp space
117 void printf_fast(code char *fmt, ...) reentrant
119 fmt; /* supress unreferenced variable warning */
124 mov a, _bp // r0 will point to va_args (stack)
126 mov r0, a // r0 points to MSB of fmt
129 mov dpl, @r0 // dptr has address of fmt
135 movc a, @a+dptr // get next byte of fmt string
137 //cjne a, #'%', printf_normal
138 cjne a, #37, printf_normal
146 clr _field_width_flag
147 mov r1, #_field_width
156 movc a, @a+dptr // get next byte of data format
159 /* parse and consume the field width digits, even if */
160 /* we don't build the code to make use of them */
167 setb _field_width_flag
175 sjmp printf_format_loop
183 //cjne a, #'l', printf_format_h
184 cjne a, #108, printf_format_h
186 sjmp printf_format_loop
189 //cjne a, #'h', printf_format_s
190 cjne a, #104, printf_format_s
192 sjmp printf_format_loop
195 //cjne a, #'s', printf_format_d
196 cjne a, #115, printf_format_d
200 //cjne a, #'d', printf_format_u
201 cjne a, #100, printf_format_u
206 //cjne a, #'u', printf_format_c
207 cjne a, #117, printf_format_c
212 //cjne a, #'c', printf_format_x
213 cjne a, #99, printf_format_x
214 mov a, @r0 // Acc has the character to print
219 //cjne a, #'x', printf_format_f
220 cjne a, #120, printf_format_f
225 //cjne a, #'f', printf_format_dot
226 cjne a, #102, printf_format_dot
231 //cjne a, #'.', printf_normal
232 cjne a, #46, printf_normal
235 mov r1, #ar3 // parse frac field, but discard if FIXED4
237 mov r1, #_frac_field_width
241 sjmp printf_format_loop
247 ljmp printf_main_loop
257 /* print a string... just grab each byte with __gptrget */
258 /* the user much pass a 24 bit generic pointer */
261 push dph // save addr in fmt onto stack
263 mov b, @r0 // b has type of address (generic *)
267 mov dpl, @r0 // dptr has address of user's string
271 jnb _field_width_flag, printf_str_loop
280 jnz printf_str_fw_loop
285 #endif // FIELD_WIDTH
294 pop dpl // restore addr withing fmt
296 ljmp printf_main_loop
305 /* printing in hex is easy because sdcc pushes the LSB first */
309 jb _short_flag, printf_hex_end
311 jnb _long_flag, printf_hex_end
316 ljmp printf_main_loop
319 lcall printf_phex_msn
340 /* printing an integer is not so easy. For a signed int */
341 /* check if it is negative and print the minus sign and */
342 /* invert it to a positive integer */
346 jnb acc.7, printf_uint /* check if negative */
348 mov a, r1 /* invert integer */
352 jb _short_flag, printf_uint
357 jnb _long_flag, printf_uint
368 /* printing integers is a lot of work... because it takes so */
369 /* long, the first thing to do is make sure we're doing as */
370 /* little work as possible, then convert the binary int to */
371 /* packed BCD, and finally print each digit of the BCD number */
375 jb _short_flag, printf_uint_ck8
376 jnb _long_flag, printf_uint_ck16
378 /* it's a 32 bit int... but if the upper 16 bits are zero */
379 /* we can treat it like a 16 bit integer and convert much faster */
382 jnz printf_uint_begin
384 jnz printf_uint_begin
387 jnz printf_ld_in_hex // print long integer as hex
388 mov a, r4 // rather than just the low 16 bits
393 /* it's a 16 bit int... but if the upper 8 bits are zero */
394 /* we can treat it like a 8 bit integer and convert much faster */
396 jnz printf_uint_begin
399 /* it's an 8 bit int... if it's zero, it's a lot faster to just */
400 /* print the digit zero and skip all the hard work! */
402 jnz printf_uint_begin
404 jnb _field_width_flag, printf_uint_zero
415 jnb _continue_float, 0001$
419 ljmp printf_main_loop
426 lcall printf_int2bcd // bcd number in r3/r2/r7/r6/r5
430 jnb _field_width_flag, printf_uifw_end
434 jnb _long_flag, printf_uifw_16
457 jb _short_flag, printf_uifw_8
476 ;r1 has the number of digits for the number
478 mov c, _negative_flag
483 #ifndef PUTCHAR_CALLEE_SAVES
493 #ifndef PUTCHAR_CALLEE_SAVES
505 #endif // FIELD_WIDTH
509 jnb _negative_flag, printf_uint_pos
510 #ifdef PUTCHAR_CALLEE_SAVES
532 #endif // PUTCHAR_CALLEE_SAVES
535 jb _short_flag, printf_uint8
537 jnb _long_flag, printf_uint16
545 lcall printf_phex_msn
547 lcall printf_phex_lsn
549 lcall printf_phex_msn
551 lcall printf_phex_lsn
554 lcall printf_phex_msn
566 lcall printf_phex_lsn
568 lcall printf_phex_msn
576 lcall printf_phex_lsn
578 lcall printf_phex_msn
580 lcall printf_phex_lsn
585 jnb _continue_float, 0002$
589 ljmp printf_main_loop
600 // Print a float the easy way. First, extract the integer part and
601 // use the integer printing code. Then extract the fractional part,
602 // convert each bit to 4 digit BCD, and print the BCD sum. Absolutely
603 // no field width control, always 4 digits printed past the decimal
604 // point. No round off. 1.9999987 prints as 1.9999, not 2.0000.
607 jnb _field_width_flag, print_float_begin
615 mov exp_b, r0 // keep r0 safe, will need it again
616 lcall printf_get_float
618 mov a, #158 // check for large float we can't print
620 jnc print_float_size_ok
621 printf_float_too_big:
622 // TODO: should print some sort of overflow error??
623 ljmp printf_format_loop
630 jnz printf_float_too_big
632 lcall printf_uint // print the integer portion
636 // now that the integer part is printed, we need to refetch the
637 // float from the va_args and extract the fractional part
639 lcall printf_get_float
642 cjne a, #126, print_float_frac_lshift
643 sjmp print_float_frac // input between 0.5 to 0.9999
644 print_float_frac_lshift:
645 jc print_float_frac_rshift
646 //Acc (exponent) is greater than 126 (input >= 1.0)
649 print_float_lshift_loop:
660 djnz r5, print_float_lshift_loop
661 sjmp print_float_frac
662 print_float_frac_rshift:
663 //Acc (exponent) is less than 126 (input < 0.5)
668 // now we've got the fractional part, so now is the time to
669 // convert to BCD... just convert each bit to BCD using a
670 // lookup table and BCD sum them together
677 mov dptr, #_frac2bcd // FLOAT_FIXED4 version (14 entries)
678 print_float_frac_loop:
685 jnc print_float_frac_skip
696 print_float_frac_skip:
699 djnz r7, print_float_frac_loop
700 // the BCD sum is in dptr, so all we've got to do is output
701 // all 4 digits. No trailing zero suppression, no nice round
702 // off (impossible to change the integer part since we already
706 setb _print_zero_flag
708 lcall printf_phex_msn
710 lcall printf_phex_lsn
712 lcall printf_phex_msn
714 lcall printf_phex_lsn
718 ljmp printf_main_loop
720 #else // not FLOAT_FIXED4
726 // Print a float the not-as-easy way, with a configurable number of
727 // fractional digits (up to 8) and proper round-off (up to 7 digits).
728 // First, extract the fractional part, convert to BCD, and then add
729 // the scaled round-off. Store the rounded fractional digits and
730 // their carry. Then extract the integer portion, increment it if
731 // the rounding caused a carry. Use the integer printing to output
732 // the integer, and then output the stored fractional digits. This
733 // approach requires 5 bytes of internal RAM to store the 8 fractional
734 // digits and the number of them we'll actually print. This code is
735 // a couple hundred bytes larger and a bit slower than the FIXED4
736 // version, but it gives very nice results.
739 jnb _field_width_flag, print_float_default_width
740 // The caller specified exact field width, so use it. Need to
741 // convert the whole float digits into the integer portion only.
744 subb a, _frac_field_width
746 jnc print_float_begin
748 sjmp print_float_begin
750 print_float_default_width:
751 // The caller didn't specify field width (or FIELD_WIDTH is
752 // not defined so it's ignored). We've still got to know
753 // how many fractional digits are going to print, so we can
754 // round off properly.
755 #ifdef FLOAT_DEFAULT_FRAC_DIGITS
756 mov _frac_field_width, #FLOAT_DEFAULT_FRAC_DIGITS
758 // default fractional field width (between 0 to 7)
759 // attempt to scale the default number of fractional digits
760 // based on the magnitude of the float
761 mov ar1, r0 // r0 points to first byte of float
762 dec r1 // r1 points to second byte of float
765 mov dptr, #_float_range_table
767 print_float_default_loop:
775 jnc print_float_default_done
777 djnz r5, print_float_default_loop
778 print_float_default_done:
779 mov _frac_field_width, r5
782 #endif // not FLOAT_DEFAULT_FRAC_DIGITS
785 push ar0 // keep r0 safe, will need it again
786 lcall printf_get_float
788 cjne a, #126, print_float_frac_lshift
789 sjmp print_float_frac // input between 0.5 to 0.9999
791 print_float_frac_lshift:
792 jc print_float_frac_rshift
793 //Acc (exponent) is greater than 126 (input >= 1.0)
796 print_float_lshift_loop:
807 djnz r5, print_float_lshift_loop
808 sjmp print_float_frac
809 print_float_frac_rshift:
810 //Acc (exponent) is less than 126 (input < 0.5)
815 // Convert the fraction in r4/r3/r2/r1 into 8 BCD digits in exb_b/r7/r6/r5
824 mov dptr, #_frac2bcd // FLOAT version (27 entries)
825 print_float_frac_loop:
838 jnc print_float_frac_skip
859 print_float_frac_skip:
864 djnz b, print_float_frac_loop
867 print_float_frac_roundoff:
868 // Now it's time to round-off the BCD digits to the desired precision.
870 mov r4, #0x50 // r4/r3/r2/r1 = 0.5 (bcd rounding)
874 mov a, _frac_field_width
878 lcall __fs_rshift_a // divide r4/r3/r2/r1 by 10^frac_field_width
880 add a, r1 // add rounding to fractional part
882 mov _float_frac_bcd+3, a // and store it for later use
886 mov _float_frac_bcd+2, a
890 mov _float_frac_bcd+1, a
894 mov _float_frac_bcd+0, a
895 mov sign_b, c // keep fractional carry in sign_b
897 // Time to work on the integer portion... fetch the float again, check
898 // size (exponent), scale to integer, add the fraction's carry, and
899 // let the integer printing code do all the work.
901 lcall printf_get_float
904 mov a, #158 // check for large float we can't print
906 jnc print_float_size_ok
907 printf_float_too_big:
908 // TODO: should print some sort of overflow error??
909 ljmp printf_format_loop
912 jnb sign_b, print_float_do_int
913 // if we get here, the fractional round off caused the
914 // integer part to increment. Add 1 for a proper result
929 jc printf_float_too_big
934 jnz printf_float_too_big
937 lcall printf_uint // print the integer portion
940 print_float_frac_width:
941 // Now all we have to do is output the fractional digits that
942 // were previous computed and stored in memory.
944 jb _field_width_flag, print_float_do_frac
946 #ifndef DO_NOT_TRIM_TRAILING_ZEROS
947 // if the user did not explicitly set a
948 // field width, trim off trailing zeros
949 print_float_frac_trim:
950 mov a, _frac_field_width
951 jz print_float_do_frac
952 lcall get_float_frac_digit
953 jnz print_float_do_frac
954 djnz _frac_field_width, print_float_frac_trim
958 mov a, _frac_field_width
964 setb _print_zero_flag
965 print_float_do_frac_loop:
968 lcall get_float_frac_digit
969 lcall printf_phex_lsn
971 cjne a, _frac_field_width, print_float_do_frac_loop
975 ljmp printf_main_loop
979 // acc=1 for tenths, acc=2 for hundredths, etc
980 get_float_frac_digit:
985 add a, #_float_frac_bcd
988 jb psw.5, get_float_frac_digit_done
990 get_float_frac_digit_done:
997 #endif // end of normal FLOAT code (not FLOAT_FIXED4)
1000 // These helper functions are used, regardless of which type of
1001 // FLOAT code is used.
1006 lcall pm2_entry_phex
1008 lcall pm2_entry_cout
1011 lcall pm2_entry_cout
1015 // Fetch a float from the va_args and put it into
1016 // exp_a/r4/r3/r2 and also clear r1 and preset
1028 mov _negative_flag, c
1030 jz printf_get_float_2
1057 /* read an integer into r1/r2/r3/r4, and msb into r5 */
1063 jb _short_flag, printf_get_done
1068 jnb _long_flag, printf_get_done
1086 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1087 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1088 * process, to avoid needing extra memory for the result (and
1089 * r1 gets used for temporary storage). dptr is overwritten,
1090 * but r0 is not changed.
1105 jnb _short_flag, printf_i2bcd_16 // if 8 bit int, we're done
1112 mov dptr, #_int2bcd_2
1128 mov dptr, #_int2bcd_3
1146 jb _long_flag, printf_i2bcd_32 // if 16 bit int, we're done
1155 mov dptr, #_int2bcd_4
1180 mov dptr, #_int2bcd_5
1207 mov dptr, #_int2bcd_6
1209 lcall printf_bcd_add10 // saves 27 bytes, costs 5 cycles
1215 mov dptr, #_int2bcd_7
1249 #else // not FAST_INTEGER
1251 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1252 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1253 * process, to avoid needing extra memory for the result (and
1254 * r1 gets used for temporary storage). dptr is overwritten,
1255 * but r0 is not changed.
1262 jb _short_flag, printf_int2bcd_begin
1264 jnb _long_flag, printf_int2bcd_begin
1266 printf_int2bcd_begin:
1272 mov (_i2bcd_tmp + 0), a
1273 mov (_i2bcd_tmp + 1), a
1288 jnc print_i2bcd_skip
1306 addc a, (_i2bcd_tmp + 0)
1308 mov (_i2bcd_tmp + 0), a
1311 addc a, (_i2bcd_tmp + 1)
1313 mov (_i2bcd_tmp + 1), a
1320 djnz b, printf_i2bcd_loop
1321 mov r2, (_i2bcd_tmp + 0)
1322 mov r3, (_i2bcd_tmp + 1)
1329 jb _short_flag, printf_int2bcd_begin
1331 printf_int2bcd_begin:
1345 jnc printf_i2bcd_add_skip
1361 printf_i2bcd_add_skip:
1365 djnz b, printf_i2bcd_loop
1371 #endif // not FAST_INTEGER
1389 lcall printf_putchar
1393 jnz printf_space_loop
1401 /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
1408 jnb _print_zero_flag, printf_ret
1410 setb _print_zero_flag
1416 #ifdef PUTCHAR_CALLEE_SAVES
1436 /* print a zero if all the calls to print the digits ended up */
1437 /* being leading zeros */
1440 jb _print_zero_flag, printf_ret
1453 * for ($d=0; $d < 8; $d++) {
1455 * for ($p=0; $p < 5; $p++) {
1456 * last unless (((16 ** $d) * 15) / (10 ** ($p * 2))) % 100;
1457 * printf "code unsigned char int2bcd_%d_%d[15] = {", $d, $p;
1458 * for ($i=0; $i < 16; $i++) {
1460 * (((16 ** $d) * $i) / (10 ** ($p * 2))) % 100;
1461 * print ", " if $i < 15;
1469 code unsigned char int2bcd_0[] = {
1470 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1471 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1473 code unsigned char int2bcd_1[] = {
1474 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1475 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1476 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1477 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02};
1480 code unsigned char int2bcd_2[] = {
1481 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1482 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1483 0x00, 0x02, 0x05, 0x07, 0x10, 0x12, 0x15, 0x17,
1484 0x20, 0x23, 0x25, 0x28, 0x30, 0x33, 0x35, 0x38};
1486 code unsigned char int2bcd_3[] = {
1487 0x00, 0x96, 0x92, 0x88, 0x84, 0x80, 0x76, 0x72,
1488 0x68, 0x64, 0x60, 0x56, 0x52, 0x48, 0x44, 0x40,
1489 0x00, 0x40, 0x81, 0x22, 0x63, 0x04, 0x45, 0x86,
1490 0x27, 0x68, 0x09, 0x50, 0x91, 0x32, 0x73, 0x14,
1491 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02,
1492 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06};
1495 code unsigned char int2bcd_4[] = {
1496 0x00, 0x36, 0x72, 0x08, 0x44, 0x80, 0x16, 0x52,
1497 0x88, 0x24, 0x60, 0x96, 0x32, 0x68, 0x04, 0x40,
1498 0x00, 0x55, 0x10, 0x66, 0x21, 0x76, 0x32, 0x87,
1499 0x42, 0x98, 0x53, 0x08, 0x64, 0x19, 0x75, 0x30,
1500 0x00, 0x06, 0x13, 0x19, 0x26, 0x32, 0x39, 0x45,
1501 0x52, 0x58, 0x65, 0x72, 0x78, 0x85, 0x91, 0x98};
1503 code unsigned char int2bcd_5[] = {
1504 0x00, 0x76, 0x52, 0x28, 0x04, 0x80, 0x56, 0x32,
1505 0x08, 0x84, 0x60, 0x36, 0x12, 0x88, 0x64, 0x40,
1506 0x00, 0x85, 0x71, 0x57, 0x43, 0x28, 0x14, 0x00,
1507 0x86, 0x71, 0x57, 0x43, 0x29, 0x14, 0x00, 0x86,
1508 0x00, 0x04, 0x09, 0x14, 0x19, 0x24, 0x29, 0x34,
1509 0x38, 0x43, 0x48, 0x53, 0x58, 0x63, 0x68, 0x72,
1510 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1511 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1513 code unsigned char int2bcd_6[] = {
1514 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1515 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1516 0x00, 0x72, 0x44, 0x16, 0x88, 0x60, 0x32, 0x05,
1517 0x77, 0x49, 0x21, 0x93, 0x65, 0x38, 0x10, 0x82,
1518 0x00, 0x77, 0x55, 0x33, 0x10, 0x88, 0x66, 0x44,
1519 0x21, 0x99, 0x77, 0x54, 0x32, 0x10, 0x88, 0x65,
1520 0x00, 0x16, 0x33, 0x50, 0x67, 0x83, 0x00, 0x17,
1521 0x34, 0x50, 0x67, 0x84, 0x01, 0x18, 0x34, 0x51,
1522 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
1523 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02};
1525 code unsigned char int2bcd_7[] = {
1526 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1527 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1528 0x00, 0x54, 0x09, 0x63, 0x18, 0x72, 0x27, 0x81,
1529 0x36, 0x91, 0x45, 0x00, 0x54, 0x09, 0x63, 0x18,
1530 0x00, 0x43, 0x87, 0x30, 0x74, 0x17, 0x61, 0x04,
1531 0x48, 0x91, 0x35, 0x79, 0x22, 0x66, 0x09, 0x53,
1532 0x00, 0x68, 0x36, 0x05, 0x73, 0x42, 0x10, 0x79,
1533 0x47, 0x15, 0x84, 0x52, 0x21, 0x89, 0x58, 0x26,
1534 0x00, 0x02, 0x05, 0x08, 0x10, 0x13, 0x16, 0x18,
1535 0x21, 0x24, 0x26, 0x29, 0x32, 0x34, 0x37, 0x40};
1538 #else // not FAST_INTEGER
1542 * print "code unsigned char int2bcd[] = {\n";
1543 * for ($i=0, $n=1; $i<32; $i++, $n*=2) {
1544 * $r = sprintf "%010u", $n;
1545 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1546 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d, 0x%02d", $5, $4, $3, $2, $1;
1547 * print ',' if $i < 31;
1548 * printf "\t\t// %10u\n", $n;
1550 * print "}\ncode unsigned char int2bcd[] = {\n";
1551 * for ($i=0, $n=1; $i<16; $i++, $n*=2) {
1552 * $r = sprintf "%06u", $n;
1553 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1554 * printf "0x%02d, 0x%02d, 0x%02d", $3, $2, $1;
1555 * print ',' if $i < 15;
1556 * printf "\t\t// %10u\n", $n;
1562 code unsigned char int2bcd[] = {
1563 0x01, 0x00, 0x00, 0x00, 0x00, // 1
1564 0x02, 0x00, 0x00, 0x00, 0x00, // 2
1565 0x04, 0x00, 0x00, 0x00, 0x00, // 4
1566 0x08, 0x00, 0x00, 0x00, 0x00, // 8
1567 0x16, 0x00, 0x00, 0x00, 0x00, // 16
1568 0x32, 0x00, 0x00, 0x00, 0x00, // 32
1569 0x64, 0x00, 0x00, 0x00, 0x00, // 64
1570 0x28, 0x01, 0x00, 0x00, 0x00, // 128
1571 0x56, 0x02, 0x00, 0x00, 0x00, // 256
1572 0x12, 0x05, 0x00, 0x00, 0x00, // 512
1573 0x24, 0x10, 0x00, 0x00, 0x00, // 1024
1574 0x48, 0x20, 0x00, 0x00, 0x00, // 2048
1575 0x96, 0x40, 0x00, 0x00, 0x00, // 4096
1576 0x92, 0x81, 0x00, 0x00, 0x00, // 8192
1577 0x84, 0x63, 0x01, 0x00, 0x00, // 16384
1578 0x68, 0x27, 0x03, 0x00, 0x00, // 32768
1579 0x36, 0x55, 0x06, 0x00, 0x00, // 65536
1580 0x72, 0x10, 0x13, 0x00, 0x00, // 131072
1581 0x44, 0x21, 0x26, 0x00, 0x00, // 262144
1582 0x88, 0x42, 0x52, 0x00, 0x00, // 524288
1583 0x76, 0x85, 0x04, 0x01, 0x00, // 1048576
1584 0x52, 0x71, 0x09, 0x02, 0x00, // 2097152
1585 0x04, 0x43, 0x19, 0x04, 0x00, // 4194304
1586 0x08, 0x86, 0x38, 0x08, 0x00, // 8388608
1587 0x16, 0x72, 0x77, 0x16, 0x00, // 16777216
1588 0x32, 0x44, 0x55, 0x33, 0x00, // 33554432
1589 0x64, 0x88, 0x10, 0x67, 0x00, // 67108864
1590 0x28, 0x77, 0x21, 0x34, 0x01, // 134217728
1591 0x56, 0x54, 0x43, 0x68, 0x02, // 268435456
1592 0x12, 0x09, 0x87, 0x36, 0x05, // 536870912
1593 0x24, 0x18, 0x74, 0x73, 0x10, // 1073741824
1594 0x48, 0x36, 0x48, 0x47, 0x21 // 2147483648
1597 code unsigned char int2bcd[] = {
1598 0x01, 0x00, 0x00, // 1
1599 0x02, 0x00, 0x00, // 2
1600 0x04, 0x00, 0x00, // 4
1601 0x08, 0x00, 0x00, // 8
1602 0x16, 0x00, 0x00, // 16
1603 0x32, 0x00, 0x00, // 32
1604 0x64, 0x00, 0x00, // 64
1605 0x28, 0x01, 0x00, // 128
1606 0x56, 0x02, 0x00, // 256
1607 0x12, 0x05, 0x00, // 512
1608 0x24, 0x10, 0x00, // 1024
1609 0x48, 0x20, 0x00, // 2048
1610 0x96, 0x40, 0x00, // 4096
1611 0x92, 0x81, 0x00, // 8192
1612 0x84, 0x63, 0x01, // 16384
1613 0x68, 0x27, 0x03 // 32768
1617 #endif // not FAST_INTEGER
1623 #ifndef FLOAT_FIXED4
1627 * for ($i=0, $f=0.5; $i<24; $i++) {
1628 * $r = sprintf "%.8f", $f;
1629 * $r =~ /0\.([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1630 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d", $4, $3, $2, $1;
1631 * print ',' if $i < 23;
1633 * printf "\t\t// %.15f %.8f\n", $f, $sum;
1638 code unsigned char frac2bcd[] = {
1639 0x00, 0x00, 0x00, 0x50, // 0.500000000000000 0.50000000
1640 0x00, 0x00, 0x00, 0x25, // 0.250000000000000 0.75000000
1641 0x00, 0x00, 0x50, 0x12, // 0.125000000000000 0.87500000
1642 0x00, 0x00, 0x25, 0x06, // 0.062500000000000 0.93750000
1643 0x00, 0x50, 0x12, 0x03, // 0.031250000000000 0.96875000
1644 0x00, 0x25, 0x56, 0x01, // 0.015625000000000 0.98437500
1645 0x50, 0x12, 0x78, 0x00, // 0.007812500000000 0.99218750
1646 0x25, 0x06, 0x39, 0x00, // 0.003906250000000 0.99609375
1647 0x12, 0x53, 0x19, 0x00, // 0.001953125000000 0.99804687
1648 0x56, 0x76, 0x09, 0x00, // 0.000976562500000 0.99902343
1649 0x28, 0x88, 0x04, 0x00, // 0.000488281250000 0.99951171
1650 0x14, 0x44, 0x02, 0x00, // 0.000244140625000 0.99975585
1651 0x07, 0x22, 0x01, 0x00, // 0.000122070312500 0.99987792
1652 0x04, 0x61, 0x00, 0x00, // 0.000061035156250 0.99993896
1653 0x52, 0x30, 0x00, 0x00, // 0.000030517578125 0.99996948
1654 0x26, 0x15, 0x00, 0x00, // 0.000015258789062 0.99998474
1655 0x63, 0x07, 0x00, 0x00, // 0.000007629394531 0.99999237
1656 0x81, 0x03, 0x00, 0x00, // 0.000003814697266 0.99999618
1657 0x91, 0x01, 0x00, 0x00, // 0.000001907348633 0.99999809
1658 0x95, 0x00, 0x00, 0x00, // 0.000000953674316 0.99999904
1659 0x48, 0x00, 0x00, 0x00, // 0.000000476837158 0.99999952
1660 0x24, 0x00, 0x00, 0x00, // 0.000000238418579 0.99999976
1661 0x12, 0x00, 0x00, 0x00, // 0.000000119209290 0.99999988
1662 0x06, 0x00, 0x00, 0x00, // 0.000000059604645 0.99999994
1663 0x03, 0x00, 0x00, 0x00, // 0.000000029802322 0.99999997
1664 0x01, 0x00, 0x00, 0x00, // 0.000000014901161 0.99999998
1665 0x01, 0x00, 0x00, 0x00 // 0.000000007450581 0.99999999
1668 #ifndef FLOAT_DEFAULT_FRAC_DIGITS
1669 // TODO: Perhaps these should be tweaked a bit to take round up
1670 // effects into account... or maybe give more default digits??
1672 // 0.0001 - 0.0009999 7
1673 // 0.001 - 0.009999 6 0.001 = 0x3A83126F 3A83
1674 // 0.01 - 0.09999 5 0.01 = 0x3C23D70A 3C23
1675 // 0.1 - 9.9999 4 0.1 = 0x3DCCCCCD, 3DCC
1676 // 10.0 - 99.99 3 10.0 = 0x41200000 4120
1677 // 100.0 - 999.99 2 100.0 = 0x42C80000 42C8
1678 // 1000 - 9999.9 1 1000 = 0x447A0000 447A
1679 // 10000+ 0 10000 = 0x461C4000 461C
1680 code unsigned int float_range_table[] = {
1691 #else // using FLOAT_FIXED4
1695 * for ($i=0, $f=0.5; $i<14; $i++) {
1696 * $r = sprintf "%.4f", $f;
1697 * $r =~ /0\.([0-9][0-9])([0-9][0-9])/;
1698 * printf "0x%02d, 0x%02d", $2, $1;
1699 * print ',' if $i < 13;
1701 * printf "\t\t// %.15f %.4f\n", $f, $sum;
1706 code unsigned char frac2bcd[] = {
1707 0x00, 0x50, // 0.500000000000000 0.5000
1708 0x00, 0x25, // 0.250000000000000 0.7500
1709 0x50, 0x12, // 0.125000000000000 0.8750
1710 0x25, 0x06, // 0.062500000000000 0.9375
1711 0x12, 0x03, // 0.031250000000000 0.9687
1712 0x56, 0x01, // 0.015625000000000 0.9843
1713 0x78, 0x00, // 0.007812500000000 0.9921
1714 0x39, 0x00, // 0.003906250000000 0.9960
1715 0x20, 0x00, // 0.001953125000000 0.9980
1716 0x10, 0x00, // 0.000976562500000 0.9990
1717 0x05, 0x00, // 0.000488281250000 0.9995
1718 0x02, 0x00, // 0.000244140625000 0.9997
1719 0x01, 0x00, // 0.000122070312500 0.9998
1720 0x01, 0x00 // 0.000061035156250 0.9999
1723 #endif // FLOAT_FIXED4