Norimasa Okamoto
/
pymite
python-on-a-chip online compiler
Embed:
(wiki syntax)
Show/hide line numbers
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 }
Generated on Tue Jul 12 2022 23:13:47 by 1.7.2