qemu/tests/tcg/mips/mips64-dspr2/printf.c
<<
>>
Prefs
   1
   2typedef unsigned long va_list;
   3
   4#define ACC    4
   5#define __read(source)                    \
   6({ va_list __res;                    \
   7    __asm__ __volatile__(                \
   8        "move\t%0, " #source "\n\t"        \
   9        : "=r" (__res));            \
  10    __res;                        \
  11})
  12
  13enum format_type {
  14    FORMAT_TYPE_NONE,
  15    FORMAT_TYPE_HEX,
  16    FORMAT_TYPE_ULONG,
  17    FORMAT_TYPE_FLOAT
  18};
  19
  20struct printf_spec {
  21    char    type;
  22};
  23
  24static int format_decode(char *fmt, struct printf_spec *spec)
  25{
  26    char *start = fmt;
  27
  28    for (; *fmt ; ++fmt) {
  29        if (*fmt == '%') {
  30            break;
  31        }
  32    }
  33
  34    switch (*++fmt) {
  35    case 'x':
  36        spec->type = FORMAT_TYPE_HEX;
  37        break;
  38
  39    case 'd':
  40        spec->type = FORMAT_TYPE_ULONG;
  41        break;
  42
  43    case 'f':
  44        spec->type = FORMAT_TYPE_FLOAT;
  45        break;
  46
  47    default:
  48        spec->type = FORMAT_TYPE_NONE;
  49    }
  50
  51    return ++fmt - start;
  52}
  53
  54void *memcpy(void *dest, void *src, int n)
  55{
  56    int i;
  57    char *s = src;
  58    char *d = dest;
  59
  60    for (i = 0; i < n; i++) {
  61        d[i] = s[i];
  62    }
  63    return dest;
  64}
  65
  66char *number(char *buf, va_list num)
  67{
  68    int i;
  69    char *str = buf;
  70    static char digits[16] = "0123456789abcdef";
  71    str = str + sizeof(num) * 2;
  72
  73    for (i = 0; i < sizeof(num) * 2; i++) {
  74        *--str = digits[num & 15];
  75        num >>= 4;
  76    }
  77
  78    return buf + sizeof(num) * 2;
  79}
  80
  81char *__number(char *buf, va_list num)
  82{
  83    int i;
  84    va_list mm = num;
  85    char *str = buf;
  86
  87    if (!num) {
  88        *str++ = '0';
  89        return str;
  90    }
  91
  92    for (i = 0; mm; mm = mm/10, i++) {
  93        /* Do nothing. */
  94    }
  95
  96    str = str + i;
  97
  98    while (num) {
  99        *--str = num % 10 + 48;
 100        num = num / 10;
 101    }
 102
 103    return str + i;
 104}
 105
 106va_list modf(va_list args, va_list *integer, va_list *num)
 107{
 108    int i;
 109    double dot_v = 0;
 110    va_list E, DOT, DOT_V;
 111
 112    if (!args) {
 113        return 0;
 114    }
 115
 116    for (i = 0, args = args << 1 >> 1; i < 52; i++) {
 117        if ((args >> i) & 0x1) {
 118            break;
 119        }
 120    }
 121
 122    *integer = 0;
 123
 124    if ((args >> 56 != 0x3f) || (args >> 52 == 0x3ff)) {
 125        E = (args >> 52) - 1023;
 126        DOT = 52 - E - i;
 127        DOT_V = args << (12 + E) >> (12 + E) >> i;
 128        *integer = ((args << 12 >> 12) >> (i + DOT)) | (1 << E);
 129    } else {
 130        E = ~((args >> 52) - 1023) + 1;
 131        DOT_V = args << 12 >> 12;
 132
 133        dot_v += 1.0 / (1 << E);
 134
 135        for (i = 1; i <= 16; i++) {
 136            if ((DOT_V >> (52 - i)) & 0x1) {
 137                dot_v += 1.0 / (1 << E + i);
 138            }
 139        }
 140
 141        for (i = 1, E = 0; i <= ACC; i++) {
 142            dot_v *= 10;
 143            if (!(va_list)dot_v) {
 144                E++;
 145            }
 146    }
 147
 148    *num = E;
 149
 150    return dot_v;
 151    }
 152
 153    if (args & 0xf) {
 154        for (i = 1; i <= 16; i++) {
 155            if ((DOT_V >> (DOT - i)) & 0x1) {
 156                dot_v += 1.0 / (1 << i);
 157            }
 158        }
 159
 160        for (i = 1, E = 0; i <= ACC; i++) {
 161            dot_v *= 10;
 162            if (!(va_list)dot_v) {
 163                E++;
 164            }
 165        }
 166
 167        *num = E;
 168
 169        return dot_v;
 170    } else if (DOT) {
 171        for (i = 1; i <= DOT; i++) {
 172            if ((DOT_V >> (DOT - i)) & 0x1) {
 173                dot_v += 1.0 / (1 << i);
 174            }
 175        }
 176
 177        for (i = 1; i <= ACC; i++) {
 178            dot_v = dot_v * 10;
 179        }
 180
 181    return dot_v;
 182    }
 183
 184    return 0;
 185}
 186
 187int vsnprintf(char *buf, int size, char *fmt, va_list args)
 188{
 189    char *str, *mm;
 190    struct printf_spec spec = {0};
 191
 192    str = mm = buf;
 193
 194    while (*fmt) {
 195        char *old_fmt = fmt;
 196        int read = format_decode(fmt, &spec);
 197
 198        fmt += read;
 199
 200        switch (spec.type) {
 201        case FORMAT_TYPE_NONE: {
 202            memcpy(str, old_fmt, read);
 203            str += read;
 204            break;
 205        }
 206        case FORMAT_TYPE_HEX: {
 207            memcpy(str, old_fmt, read);
 208            str = number(str + read, args);
 209            for (; *mm ; ++mm) {
 210                if (*mm == '%') {
 211                    *mm = '0';
 212                break;
 213                }
 214            }
 215        break;
 216        }
 217        case FORMAT_TYPE_ULONG: {
 218            memcpy(str, old_fmt, read - 2);
 219            str = __number(str + read - 2, args);
 220            break;
 221        }
 222        case FORMAT_TYPE_FLOAT: {
 223            va_list integer, dot_v, num;
 224            dot_v = modf(args, &integer, &num);
 225            memcpy(str, old_fmt, read - 2);
 226            str += read - 2;
 227            if ((args >> 63 & 0x1)) {
 228                *str++ = '-';
 229            }
 230            str = __number(str, integer);
 231            if (dot_v) {
 232                *str++ = '.';
 233                while (num--) {
 234                    *str++ = '0';
 235                }
 236                str = __number(str, dot_v);
 237            }
 238            break;
 239        }
 240        }
 241    }
 242    *str = '\0';
 243
 244    return str - buf;
 245}
 246
 247static void serial_out(char *str)
 248{
 249    while (*str) {
 250        *(char *)0xffffffffb80003f8 = *str++;
 251    }
 252}
 253
 254int vprintf(char *fmt, va_list args)
 255{
 256    int printed_len = 0;
 257    static char printf_buf[512];
 258    printed_len = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args);
 259    serial_out(printf_buf);
 260    return printed_len;
 261}
 262
 263int printf(char *fmt, ...)
 264{
 265    return vprintf(fmt, __read($5));
 266}
 267