| |
| typedef unsigned long va_list; |
| |
| #define ACC 4 |
| #define __read(source) \ |
| ({ va_list __res; \ |
| __asm__ __volatile__( \ |
| "move\t%0, " #source "\n\t" \ |
| : "=r" (__res)); \ |
| __res; \ |
| }) |
| |
| enum format_type { |
| FORMAT_TYPE_NONE, |
| FORMAT_TYPE_HEX, |
| FORMAT_TYPE_ULONG, |
| FORMAT_TYPE_FLOAT |
| }; |
| |
| struct printf_spec { |
| char type; |
| }; |
| |
| static int format_decode(char *fmt, struct printf_spec *spec) |
| { |
| char *start = fmt; |
| |
| for (; *fmt ; ++fmt) { |
| if (*fmt == '%') { |
| break; |
| } |
| } |
| |
| switch (*++fmt) { |
| case 'x': |
| spec->type = FORMAT_TYPE_HEX; |
| break; |
| |
| case 'd': |
| spec->type = FORMAT_TYPE_ULONG; |
| break; |
| |
| case 'f': |
| spec->type = FORMAT_TYPE_FLOAT; |
| break; |
| |
| default: |
| spec->type = FORMAT_TYPE_NONE; |
| } |
| |
| return ++fmt - start; |
| } |
| |
| void *memcpy(void *dest, void *src, int n) |
| { |
| int i; |
| char *s = src; |
| char *d = dest; |
| |
| for (i = 0; i < n; i++) { |
| d[i] = s[i]; |
| } |
| return dest; |
| } |
| |
| char *number(char *buf, va_list num) |
| { |
| int i; |
| char *str = buf; |
| static char digits[16] = "0123456789abcdef"; |
| str = str + sizeof(num) * 2; |
| |
| for (i = 0; i < sizeof(num) * 2; i++) { |
| *--str = digits[num & 15]; |
| num >>= 4; |
| } |
| |
| return buf + sizeof(num) * 2; |
| } |
| |
| char *__number(char *buf, va_list num) |
| { |
| int i; |
| va_list mm = num; |
| char *str = buf; |
| |
| if (!num) { |
| *str++ = '0'; |
| return str; |
| } |
| |
| for (i = 0; mm; mm = mm/10, i++) { |
| /* Do nothing. */ |
| } |
| |
| str = str + i; |
| |
| while (num) { |
| *--str = num % 10 + 48; |
| num = num / 10; |
| } |
| |
| return str + i; |
| } |
| |
| va_list modf(va_list args, va_list *integer, va_list *num) |
| { |
| int i; |
| double dot_v = 0; |
| va_list E, DOT, DOT_V; |
| |
| if (!args) { |
| return 0; |
| } |
| |
| for (i = 0, args = args << 1 >> 1; i < 52; i++) { |
| if ((args >> i) & 0x1) { |
| break; |
| } |
| } |
| |
| *integer = 0; |
| |
| if ((args >> 56 != 0x3f) || (args >> 52 == 0x3ff)) { |
| E = (args >> 52) - 1023; |
| DOT = 52 - E - i; |
| DOT_V = args << (12 + E) >> (12 + E) >> i; |
| *integer = ((args << 12 >> 12) >> (i + DOT)) | (1 << E); |
| } else { |
| E = ~((args >> 52) - 1023) + 1; |
| DOT_V = args << 12 >> 12; |
| |
| dot_v += 1.0 / (1 << E); |
| |
| for (i = 1; i <= 16; i++) { |
| if ((DOT_V >> (52 - i)) & 0x1) { |
| dot_v += 1.0 / (1 << E + i); |
| } |
| } |
| |
| for (i = 1, E = 0; i <= ACC; i++) { |
| dot_v *= 10; |
| if (!(va_list)dot_v) { |
| E++; |
| } |
| } |
| |
| *num = E; |
| |
| return dot_v; |
| } |
| |
| if (args & 0xf) { |
| for (i = 1; i <= 16; i++) { |
| if ((DOT_V >> (DOT - i)) & 0x1) { |
| dot_v += 1.0 / (1 << i); |
| } |
| } |
| |
| for (i = 1, E = 0; i <= ACC; i++) { |
| dot_v *= 10; |
| if (!(va_list)dot_v) { |
| E++; |
| } |
| } |
| |
| *num = E; |
| |
| return dot_v; |
| } else if (DOT) { |
| for (i = 1; i <= DOT; i++) { |
| if ((DOT_V >> (DOT - i)) & 0x1) { |
| dot_v += 1.0 / (1 << i); |
| } |
| } |
| |
| for (i = 1; i <= ACC; i++) { |
| dot_v = dot_v * 10; |
| } |
| |
| return dot_v; |
| } |
| |
| return 0; |
| } |
| |
| int vsnprintf(char *buf, int size, char *fmt, va_list args) |
| { |
| char *str, *mm; |
| struct printf_spec spec = {0}; |
| |
| str = mm = buf; |
| |
| while (*fmt) { |
| char *old_fmt = fmt; |
| int read = format_decode(fmt, &spec); |
| |
| fmt += read; |
| |
| switch (spec.type) { |
| case FORMAT_TYPE_NONE: { |
| memcpy(str, old_fmt, read); |
| str += read; |
| break; |
| } |
| case FORMAT_TYPE_HEX: { |
| memcpy(str, old_fmt, read); |
| str = number(str + read, args); |
| for (; *mm ; ++mm) { |
| if (*mm == '%') { |
| *mm = '0'; |
| break; |
| } |
| } |
| break; |
| } |
| case FORMAT_TYPE_ULONG: { |
| memcpy(str, old_fmt, read - 2); |
| str = __number(str + read - 2, args); |
| break; |
| } |
| case FORMAT_TYPE_FLOAT: { |
| va_list integer, dot_v, num; |
| dot_v = modf(args, &integer, &num); |
| memcpy(str, old_fmt, read - 2); |
| str += read - 2; |
| if ((args >> 63 & 0x1)) { |
| *str++ = '-'; |
| } |
| str = __number(str, integer); |
| if (dot_v) { |
| *str++ = '.'; |
| while (num--) { |
| *str++ = '0'; |
| } |
| str = __number(str, dot_v); |
| } |
| break; |
| } |
| } |
| } |
| *str = '\0'; |
| |
| return str - buf; |
| } |
| |
| static void serial_out(char *str) |
| { |
| while (*str) { |
| *(char *)0xffffffffb80003f8 = *str++; |
| } |
| } |
| |
| int vprintf(char *fmt, va_list args) |
| { |
| int printed_len = 0; |
| static char printf_buf[512]; |
| printed_len = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args); |
| serial_out(printf_buf); |
| return printed_len; |
| } |
| |
| int printf(char *fmt, ...) |
| { |
| return vprintf(fmt, __read($5)); |
| } |