python-on-a-chip online compiler

Dependencies:   mbed TSI

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sli.c Source File

sli.c

Go to the documentation of this file.
00001 /*
00002 # This file is Copyright 2002 Dean Hall.
00003 # This file is part of the PyMite VM.
00004 # This file is licensed under the MIT License.
00005 # See the LICENSE file for details.
00006 */
00007 
00008 
00009 #undef __FILE_ID__
00010 #define __FILE_ID__ 0x11
00011 
00012 
00013 /**
00014  * \file
00015  * \brief Standard Library Interface
00016  *
00017  * PyMite requires a few functions from a few different
00018  * standard C libraries (memory, string, etc).
00019  */
00020 
00021 
00022 #include "pm.h"
00023 
00024 
00025 /** use Duff's Device or simple for-loop for memcpy. */
00026 #define USE_DUFFS_DEVICE    0
00027 
00028 
00029 #if !HAVE_STRING_H
00030 
00031 void *
00032 sli_memcpy(unsigned char *to, unsigned char const *from, unsigned int n)
00033 {
00034     unsigned char *tobak;
00035 
00036     /* Store init value of to */
00037     tobak = to;
00038 
00039 #if USE_DUFFS_DEVICE
00040     if (n > 0)
00041     {
00042         switch (n & 0x7)
00043             do
00044             {
00045             case 0:
00046                 *to++ = *from++;
00047             case 7:
00048                 *to++ = *from++;
00049             case 6:
00050                 *to++ = *from++;
00051             case 5:
00052                 *to++ = *from++;
00053             case 4:
00054                 *to++ = *from++;
00055             case 3:
00056                 *to++ = *from++;
00057             case 2:
00058                 *to++ = *from++;
00059             case 1:
00060                 *to++ = *from++;
00061             }
00062             while ((n -= 8) > 0);
00063     }
00064 #else
00065     for (; n > 0; n--)
00066     {
00067         *to = *from;
00068         from++;
00069         to++;
00070     }
00071 #endif /* USE_DUFFS_DEVICE */
00072     return tobak;
00073 }
00074 
00075 
00076 int
00077 sli_strlen(char const *s)
00078 {
00079     char const *si = s;
00080     int len = 0;
00081 
00082     while (*si++)
00083     {
00084         len++;
00085     }
00086     return len;
00087 }
00088 
00089 
00090 int
00091 sli_strcmp(char const *s1, char const *s2)
00092 {
00093     /* While not at either strings' end and they're same */
00094     while ((*s1 != C_NULL) && (*s2 != C_NULL) && (*s1 == *s2))
00095     {
00096         s1++;
00097         s2++;
00098     }
00099 
00100     /* Return string difference */
00101     return *s1 - *s2;
00102 }
00103 
00104 
00105 int
00106 sli_strncmp(char const *s1, char const *s2, unsigned int n)
00107 {
00108     unsigned int i = 0;
00109 
00110     if (n == 0)
00111     {
00112         return 0;
00113     }
00114 
00115     /* Scan n bytes in string */
00116     for (i = 0; i < n; i++)
00117     {
00118         /* If bytes differ, return difference */
00119         if (s1[i] != s2[i])
00120         {
00121             return s1[i] - s2[i];
00122         }
00123     }
00124     return 0;
00125 }
00126 
00127 #endif /* HAVE_STRING_H */
00128 
00129 
00130 /*
00131  * This function is moved outside of HAVE_STRING_H because the one in string.h
00132  * will not accept a null value for the second arg
00133  */
00134 void
00135 sli_memset(unsigned char *dest, char const val, unsigned int n)
00136 {
00137     unsigned int i;
00138 
00139     for (i = 0; i < n; i++)
00140     {
00141         *dest = (unsigned char)val;
00142         dest++;
00143     }
00144 }
00145 
00146 void
00147 sli_puts(uint8_t * s)
00148 {
00149     uint8_t *ps = s;
00150     uint8_t c;
00151 
00152     c = *ps;
00153     ps++;
00154     while (c != '\0')
00155     {
00156         plat_putByte(c);
00157         c = *ps;
00158         ps++;
00159     }
00160 }
00161 
00162 
00163 PmReturn_t
00164 sli_ltoa10(int32_t value, uint8_t *buf, uint8_t buflen)
00165 {
00166     int32_t const decimal_places[] = { 1000000000, 100000000, 10000000, 1000000,
00167                                        100000, 10000, 1000, 100, 10, 1 };
00168     int32_t decimal_place;
00169     int32_t number;
00170     uint8_t c;
00171     uint8_t printed_one = C_FALSE;
00172     uint8_t i;
00173     uint8_t j;
00174     PmReturn_t retval = PM_RET_OK;
00175 
00176     C_ASSERT(buflen >= 12);
00177 
00178     number = value;
00179     if (number == 0)
00180     {
00181         buf[0] = '0';
00182         buf[1] = '\0';
00183         return retval;
00184     }
00185 
00186     /* Special case (can't convert it to positive value) */
00187     if (number == -2147483648)
00188     {
00189         sli_memcpy(buf, (unsigned char *)"-2147483648", 11);
00190         return PM_RET_OK;
00191     }
00192 
00193     j = 0;
00194     if (number < 0)
00195     {
00196         buf[0] = '-';
00197         j++;
00198         number = -number;
00199     }
00200 
00201     for (i = 0; i < 10; i++)
00202     {
00203         decimal_place = decimal_places[i];
00204         c = '0';
00205         while (number >= decimal_place)
00206         {
00207             number -= decimal_place;
00208             c++;
00209         }
00210         if ((c != '0') || printed_one)
00211         {
00212             buf[j++] = c;
00213             printed_one = C_TRUE;
00214         }
00215     }
00216     buf[j] = '\0';
00217 
00218     return retval;
00219 }
00220 
00221 char const * const hexChars = "0123456789abcdef";
00222 
00223 /* MUST show leading zeros because callers don't keep track */
00224 PmReturn_t
00225 sli_btoa16(uint8_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase)
00226 {
00227     C_ASSERT(buflen >= 3);
00228 
00229     if (upperCase) upperCase = 'A' - 'a';
00230 
00231     buf[0] = (value >> 4) > 9 
00232              ? hexChars[value >> 4] + upperCase
00233              : hexChars[value >> 4];
00234     buf[1] = (value & 0x0F) > 9
00235              ? hexChars[value & 0x0F] + upperCase
00236              : hexChars[value & 0x0F];
00237     buf[2] = '\0';
00238 
00239     return PM_RET_OK;
00240 }
00241 
00242 
00243 /* Does NOT show leading zeroes */
00244 PmReturn_t
00245 sli_ltoa16(int32_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase)
00246 {
00247     int8_t i;
00248     uint8_t j = 0;
00249     uint8_t showZero = C_FALSE;
00250     uint8_t nibble;
00251 
00252     C_ASSERT(buflen >= 9);
00253 
00254     if (upperCase) upperCase = 'A' - 'a';
00255 
00256     for (i = 28; i >= 0; i -= 4)
00257     {
00258         nibble = ((value >> i) & 0xF);
00259         if ((nibble == 0) && !showZero) continue;
00260         buf[j++] = (nibble > 9) 
00261                    ? hexChars[nibble] + upperCase
00262                    : hexChars[nibble];
00263         showZero = C_TRUE;
00264     }
00265     buf[j] = '\0';
00266 
00267     return PM_RET_OK;
00268 }
00269 
00270 
00271 PmReturn_t
00272 sli_ptoa16(intptr_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase)
00273 {
00274     PmReturn_t retval;
00275     int8_t i;
00276     int8_t j;
00277 
00278     C_ASSERT(buflen >= 2 * sizeof(intptr_t) + 1);
00279 
00280     /* Print the hex value, most significant byte first */
00281     for (j = 0, i = 8 * sizeof(intptr_t) - 8; i >= 0; i -= 8, j += 2)
00282     {
00283         retval = sli_btoa16((value >> i) & 0xFF, &buf[j], buflen - j, upperCase);
00284         PM_BREAK_IF_ERROR(retval);
00285     }
00286 
00287     return retval;
00288 }
00289 
00290 
00291 typedef union {
00292     int32_t L;
00293     float F;
00294 } LF_t;
00295 
00296 
00297 /* The buf MUST be at least 15 bytes long */
00298 PmReturn_t
00299 sli_ftoa(float f, uint8_t *buf, uint8_t buflen)
00300 {
00301     uint32_t mantissa, int_part, frac_part;
00302     int16_t exp2;
00303     LF_t x;
00304     uint8_t *p;
00305     int8_t adj = 0;
00306     PmReturn_t retval = PM_RET_OK;
00307 
00308     C_ASSERT(buflen >= 15);
00309 
00310     if (f == 0.0)
00311     {
00312         buf[0] = '0';
00313         buf[1] = '.';
00314         buf[2] = '0';
00315         buf[3] = '\0';
00316         return PM_RET_OK;
00317     }
00318     x.F = f;
00319 
00320     exp2 = (0xFF & (x.L >> 23)) - 127;
00321     mantissa = (x.L & 0xFFFFFF) | 0x800000;
00322     frac_part = 0;
00323     int_part = 0;
00324     p = buf;
00325 
00326     /* Adjust large exponents using the approximation: 2**10 == k*10**3 */
00327     while (exp2 >= 31)
00328     {
00329         /* Reduce the binary exponent here (incr the decimal exponent below) */
00330         exp2 -=  10;
00331         adj++;
00332 
00333         /*
00334          * To use the approximation above, the mantissa must be multiplied by k
00335          * where k = 1.024 ~= (1 + 12583/(2**19))
00336          * Divide first to avoid integer overflow (the mantissa is 24 bits)
00337          */
00338         mantissa += ((mantissa >> 6) * 12583) >> 13;
00339     }
00340 
00341     if (exp2 < -23)
00342     {
00343         // Unable to handle large negative exponents at this time
00344         *p++ = '?';
00345         return PM_RET_OK;
00346     }
00347     else if (exp2 >= 23)
00348     {
00349         int_part = mantissa << (exp2 - 23);
00350     }
00351     else if (exp2 >= 0)
00352     {
00353         int_part = mantissa >> (23 - exp2);
00354         frac_part = (mantissa << (exp2 + 1)) & 0xFFFFFF;
00355     }
00356     else /* if (exp2 < 0) */
00357     {
00358         frac_part = (mantissa & 0xFFFFFF) >> -(exp2 + 1);
00359     }
00360 
00361     if (x.L < 0)
00362     {
00363         *p++ = '-';
00364     }
00365 
00366     if (int_part == 0)
00367     {
00368         *p++ = '0';
00369     }
00370     else
00371     {
00372         retval = sli_ltoa10(int_part, p, buflen - (p - buf));
00373         PM_RETURN_IF_ERROR(retval);
00374         while (*p) p++;
00375     }
00376     *p++ = '.';
00377 
00378     if (frac_part == 0)
00379     {
00380         *p++ = '0';
00381     }
00382     else
00383     {
00384         char m, max;
00385 
00386         max = buflen - (p - buf) - 1;
00387         if (max > 6)
00388         {
00389             max = 6;
00390         }
00391 
00392         /* Print fractional part */
00393         for (m = 0; m < max; m++)
00394         {
00395             frac_part *= 10;
00396             *p++ = '0' + (frac_part >> 24);
00397             frac_part &= 0xFFFFFF;
00398         }
00399 
00400         /* Remove ending zeroes */
00401         //for (--p; p[0] == '0' && p[-1] != '.'; --p);
00402         //++p;
00403     }
00404 
00405     /*
00406      * If the exponent is large (adjustment took place above),
00407      * normalize the string to scientific notation
00408      */
00409     if (adj != 0)
00410     {
00411         uint8_t i;
00412 
00413         /* Shift chars to make room for the new decimal point */
00414         i = (p - buf + 1);
00415         i = (i > (buflen - 1)) ? buflen - 1 : i;
00416         for (; i > 1; i--)
00417         {
00418             buf[i] = buf[i-1];
00419         }
00420 
00421         /* Find the index of the old decimal point */
00422         for (i = 6; (buf[i] != '.') && (i < 15); i++);
00423 
00424         /* Set the new decimal point (normalized) */
00425         buf[1] = '.';
00426 
00427         /*
00428          * Adjust the decimal exponent (3 decimal places for every 10 bits)
00429          * and add the amount for the normalization
00430          */
00431         p = &buf[8];
00432         *p++ = 'e';
00433         *p++ = '+';
00434         retval = sli_ltoa10(3 * adj + (i - 2), p, buflen - (p - buf));
00435         PM_RETURN_IF_ERROR(retval);
00436         while (*p) p++;
00437     }
00438 
00439     *p = '\0';
00440 
00441     return PM_RET_OK;
00442 }