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;
100 #define SDCC_FLOAT_LIB
102 static bit continue_float;
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
112 static data unsigned int i2bcd_tmp; // slow 32 int conversion needs temp space
119 #define PRINTF_FAST printf_fast
122 void PRINTF_FAST(code char *fmt, ...) reentrant
124 fmt; /* supress unreferenced variable warning */
129 mov a, _bp // r0 will point to va_args (stack)
131 mov r0, a // r0 points to MSB of fmt
134 mov dpl, @r0 // dptr has address of fmt
140 movc a, @a+dptr // get next byte of fmt string
142 //cjne a, #'%', printf_normal
143 cjne a, #37, printf_normal
151 clr _field_width_flag
152 mov r1, #_field_width
161 movc a, @a+dptr // get next byte of data format
164 /* parse and consume the field width digits, even if */
165 /* we don't build the code to make use of them */
172 setb _field_width_flag
180 sjmp printf_format_loop
188 //cjne a, #'l', printf_format_h
189 cjne a, #108, printf_format_h
191 sjmp printf_format_loop
194 //cjne a, #'h', printf_format_s
195 cjne a, #104, printf_format_s
197 sjmp printf_format_loop
200 //cjne a, #'s', printf_format_d
201 cjne a, #115, printf_format_d
205 //cjne a, #'d', printf_format_u
206 cjne a, #100, printf_format_u
211 //cjne a, #'u', printf_format_c
212 cjne a, #117, 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
224 //cjne a, #'x', printf_format_f
225 cjne a, #120, printf_format_f
230 //cjne a, #'f', printf_format_dot
231 cjne a, #102, printf_format_dot
236 //cjne a, #'.', printf_normal
237 cjne a, #46, printf_normal
240 mov r1, #ar3 // parse frac field, but discard if FIXED4
242 mov r1, #_frac_field_width
246 sjmp printf_format_loop
252 ljmp printf_main_loop
262 /* print a string... just grab each byte with __gptrget */
263 /* the user much pass a 24 bit generic pointer */
266 push dph // save addr in fmt onto stack
268 mov b, @r0 // b has type of address (generic *)
272 mov dpl, @r0 // dptr has address of user's string
276 jnb _field_width_flag, printf_str_loop
285 jnz printf_str_fw_loop
290 #endif // FIELD_WIDTH
299 pop dpl // restore addr withing fmt
301 ljmp printf_main_loop
310 /* printing in hex is easy because sdcc pushes the LSB first */
314 jb _short_flag, printf_hex_end
316 jnb _long_flag, printf_hex_end
321 ljmp printf_main_loop
324 lcall printf_phex_msn
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 */
351 jnb acc.7, printf_uint /* check if negative */
353 mov a, r1 /* invert integer */
357 jb _short_flag, printf_uint
362 jnb _long_flag, printf_uint
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 */
380 jb _short_flag, printf_uint_ck8
381 jnb _long_flag, printf_uint_ck16
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 */
387 jnz printf_uint_begin
389 jnz printf_uint_begin
392 jnz printf_ld_in_hex // print long integer as hex
393 mov a, r4 // rather than just the low 16 bits
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 */
401 jnz printf_uint_begin
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! */
407 jnz printf_uint_begin
409 jnb _field_width_flag, printf_uint_zero
420 jnb _continue_float, 0001$
424 ljmp printf_main_loop
431 lcall printf_int2bcd // bcd number in r3/r2/r7/r6/r5
435 jnb _field_width_flag, printf_uifw_end
439 jnb _long_flag, printf_uifw_16
462 jb _short_flag, printf_uifw_8
481 ;r1 has the number of digits for the number
483 mov c, _negative_flag
488 #ifndef PUTCHAR_CALLEE_SAVES
498 #ifndef PUTCHAR_CALLEE_SAVES
510 #endif // FIELD_WIDTH
514 jnb _negative_flag, printf_uint_pos
515 #ifdef PUTCHAR_CALLEE_SAVES
537 #endif // PUTCHAR_CALLEE_SAVES
540 jb _short_flag, printf_uint8
542 jnb _long_flag, printf_uint16
550 lcall printf_phex_msn
552 lcall printf_phex_lsn
554 lcall printf_phex_msn
556 lcall printf_phex_lsn
559 lcall printf_phex_msn
571 lcall printf_phex_lsn
573 lcall printf_phex_msn
581 lcall printf_phex_lsn
583 lcall printf_phex_msn
585 lcall printf_phex_lsn
590 jnb _continue_float, 0002$
594 ljmp printf_main_loop
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.
612 jnb _field_width_flag, print_float_begin
620 push ar0 // keep r0 safe, will need it again
621 lcall printf_get_float
623 mov a, #158 // check for large float we can't print
625 jnc print_float_size_ok
626 printf_float_too_big:
627 // TODO: should print some sort of overflow error??
629 ljmp printf_format_loop
638 jnz printf_float_too_big
640 lcall printf_uint // print the integer portion
644 // now that the integer part is printed, we need to refetch the
645 // float from the va_args and extract the fractional part
647 lcall printf_get_float
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)
659 print_float_lshift_loop:
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)
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
685 mov dptr, #_frac2bcd // FLOAT_FIXED4 version (14 entries)
686 print_float_frac_loop:
693 jnc print_float_frac_skip
704 print_float_frac_skip:
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
714 setb _print_zero_flag
716 lcall printf_phex_msn
718 lcall printf_phex_lsn
720 lcall printf_phex_msn
722 lcall printf_phex_lsn
726 ljmp printf_main_loop
728 #else // not FLOAT_FIXED4
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.
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.
752 subb a, _frac_field_width
754 jnc print_float_begin
756 sjmp print_float_begin
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
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
773 mov dptr, #_float_range_table
775 print_float_default_loop:
783 jnc print_float_default_done
785 djnz r5, print_float_default_loop
786 print_float_default_done:
787 mov _frac_field_width, r5
790 #endif // not FLOAT_DEFAULT_FRAC_DIGITS
793 push ar0 // keep r0 safe, will need it again
794 lcall printf_get_float
798 cjne a, #126, print_float_frac_lshift
799 sjmp print_float_frac // input between 0.5 to 0.9999
801 print_float_frac_lshift:
802 jc print_float_frac_rshift
803 //Acc (exponent) is greater than 126 (input >= 1.0)
806 print_float_lshift_loop:
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)
825 // Convert the fraction in r4/r3/r2/r1 into 8 BCD digits in r0/r7/r6/r5
832 mov dptr, #_frac2bcd // FLOAT version (27 entries)
833 print_float_frac_loop:
846 jnc print_float_frac_skip
867 print_float_frac_skip:
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.
876 mov r4, #0x50 // r4/r3/r2/r1 = 0.5 (bcd rounding)
880 mov a, _frac_field_width
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
887 add a, r1 // add rounding to fractional part
889 mov _float_frac_bcd+3, a // and store it for later use
893 mov _float_frac_bcd+2, a
897 mov _float_frac_bcd+1, a
901 mov _float_frac_bcd+0, a
902 mov sign_b, c // keep fractional carry in sign_b
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.
910 lcall printf_get_float
913 mov a, #158 // check for large float we can't print
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
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
940 jc printf_float_too_big
945 jnz printf_float_too_big
948 lcall printf_uint // print the integer portion
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.
955 jb _field_width_flag, print_float_do_frac
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
969 mov a, _frac_field_width
975 setb _print_zero_flag
976 print_float_do_frac_loop:
979 lcall get_float_frac_digit
980 lcall printf_phex_lsn
982 cjne a, _frac_field_width, print_float_do_frac_loop
986 ljmp printf_main_loop
990 // acc=1 for tenths, acc=2 for hundredths, etc
991 get_float_frac_digit:
996 add a, #_float_frac_bcd
999 jb psw.5, get_float_frac_digit_done
1001 get_float_frac_digit_done:
1008 #endif // end of normal FLOAT code (not FLOAT_FIXED4)
1011 // These helper functions are used, regardless of which type of
1012 // FLOAT code is used.
1017 lcall pm2_entry_phex
1019 lcall pm2_entry_cout
1022 lcall pm2_entry_cout
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
1039 mov _negative_flag, c
1041 jz printf_get_float_2
1068 /* read an integer into r1/r2/r3/r4, and msb into r5 */
1074 jb _short_flag, printf_get_done
1079 jnb _long_flag, printf_get_done
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.
1116 jnb _short_flag, printf_i2bcd_16 // if 8 bit int, we're done
1123 mov dptr, #_int2bcd_2
1139 mov dptr, #_int2bcd_3
1157 jb _long_flag, printf_i2bcd_32 // if 16 bit int, we're done
1166 mov dptr, #_int2bcd_4
1191 mov dptr, #_int2bcd_5
1218 mov dptr, #_int2bcd_6
1220 lcall printf_bcd_add10 // saves 27 bytes, costs 5 cycles
1226 mov dptr, #_int2bcd_7
1260 #else // not FAST_INTEGER
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.
1273 jb _short_flag, printf_int2bcd_begin
1275 jnb _long_flag, printf_int2bcd_begin
1277 printf_int2bcd_begin:
1283 mov (_i2bcd_tmp + 0), a
1284 mov (_i2bcd_tmp + 1), a
1299 jnc print_i2bcd_skip
1317 addc a, (_i2bcd_tmp + 0)
1319 mov (_i2bcd_tmp + 0), a
1322 addc a, (_i2bcd_tmp + 1)
1324 mov (_i2bcd_tmp + 1), a
1331 djnz b, printf_i2bcd_loop
1332 mov r2, (_i2bcd_tmp + 0)
1333 mov r3, (_i2bcd_tmp + 1)
1340 jb _short_flag, printf_int2bcd_begin
1342 printf_int2bcd_begin:
1356 jnc printf_i2bcd_add_skip
1372 printf_i2bcd_add_skip:
1376 djnz b, printf_i2bcd_loop
1382 #endif // not FAST_INTEGER
1400 lcall printf_putchar
1404 jnz printf_space_loop
1412 /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
1419 jnb _print_zero_flag, printf_ret
1421 setb _print_zero_flag
1427 #ifdef PUTCHAR_CALLEE_SAVES
1447 /* print a zero if all the calls to print the digits ended up */
1448 /* being leading zeros */
1451 jb _print_zero_flag, printf_ret
1464 * for ($d=0; $d < 8; $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++) {
1471 * (((16 ** $d) * $i) / (10 ** ($p * 2))) % 100;
1472 * print ", " if $i < 15;
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};
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};
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};
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};
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};
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};
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};
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};
1549 #else // not FAST_INTEGER
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;
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;
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
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
1628 #endif // not FAST_INTEGER
1634 #ifndef FLOAT_FIXED4
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;
1644 * printf "\t\t// %.15f %.8f\n", $f, $sum;
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
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??
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[] = {
1702 #else // using FLOAT_FIXED4
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;
1712 * printf "\t\t// %.15f %.4f\n", $f, $sum;
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
1734 #endif // FLOAT_FIXED4