Add qemu 2.4.0
[kvmfornfv.git] / qemu / tests / tcg / mips / mips64-dsp / printf.c
diff --git a/qemu/tests/tcg/mips/mips64-dsp/printf.c b/qemu/tests/tcg/mips/mips64-dsp/printf.c
new file mode 100644 (file)
index 0000000..cf8676d
--- /dev/null
@@ -0,0 +1,266 @@
+
+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));
+}