summary refs log tree commit diff stats
path: root/tests/tcg/minilib/printf.c
diff options
context:
space:
mode:
authorAlex Bennée <alex.bennee@linaro.org>2019-03-05 11:40:31 +0000
committerAlex Bennée <alex.bennee@linaro.org>2019-03-12 17:05:21 +0000
commita113ec989b74acf6a8eac68bbe41aab141d0235c (patch)
tree672d32e72dca462ad9710f899ad33ae3bc6fe8b7 /tests/tcg/minilib/printf.c
parentd72132c02ebabf0c17986da865e3b15ba4dae1f5 (diff)
downloadfocaccia-qemu-a113ec989b74acf6a8eac68bbe41aab141d0235c.tar.gz
focaccia-qemu-a113ec989b74acf6a8eac68bbe41aab141d0235c.zip
tests/tcg: provide a minilib for system tests
We will likely want a few common functions to make up for the fact we
don't have a libc and we don't want to feel like we are programming by
banging rocks together.

I've purloined the printf function from:

  https://git.virtualopensystems.com/dev/tcg_baremetal_tests

Although I have tweaked the names to avoid confusing GCC about clashing
with builtins.

Cc: Alexander Spyridakis <a.spyridakis@virtualopensystems.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Diffstat (limited to 'tests/tcg/minilib/printf.c')
-rw-r--r--tests/tcg/minilib/printf.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/tests/tcg/minilib/printf.c b/tests/tcg/minilib/printf.c
new file mode 100644
index 0000000000..121620cb16
--- /dev/null
+++ b/tests/tcg/minilib/printf.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015 Virtual Open Systems SAS
+ * Author: Alexander Spyridakis <a.spyridakis@virtualopensystems.com>
+ *
+ * printf based on implementation by Kevin Wolf <kwolf@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#include "minilib.h"
+
+typedef __builtin_va_list   va_list;
+#define va_start(ap, X)     __builtin_va_start(ap, X)
+#define va_arg(ap, type)    __builtin_va_arg(ap, type)
+#define va_end(ap)          __builtin_va_end(ap)
+
+static void print_str(char *s)
+{
+    while (*s) {
+        __sys_outc(*s++);
+    }
+}
+
+static void print_num(unsigned long long value, int base)
+{
+    char digits[] = "0123456789abcdef";
+    char buf[32];
+    int i = sizeof(buf) - 2, j;
+
+    /* Set the buffer to 0. See problem of before. */
+    for (j = 0; j < 32; j++) {
+        buf[j] = 0;
+    }
+
+    do {
+        buf[i--] = digits[value % base];
+        value /= base;
+    } while (value);
+
+    print_str(&buf[i + 1]);
+}
+
+void ml_printf(const char *fmt, ...)
+{
+    va_list ap;
+    char *str;
+    int base;
+    int has_long;
+    int alt_form;
+    unsigned long long val;
+
+    va_start(ap, fmt);
+
+    for (; *fmt; fmt++) {
+        if (*fmt != '%') {
+            __sys_outc(*fmt);
+            continue;
+        }
+        fmt++;
+
+        if (*fmt == '#') {
+            fmt++;
+            alt_form = 1;
+        } else {
+            alt_form = 0;
+        }
+
+        if (*fmt == 'l') {
+            fmt++;
+            if (*fmt == 'l') {
+                fmt++;
+                has_long = 2;
+            } else {
+                has_long = 1;
+            }
+        } else {
+            has_long = 0;
+        }
+
+        switch (*fmt) {
+        case 'x':
+        case 'p':
+            base = 16;
+            goto convert_number;
+        case 'd':
+        case 'i':
+        case 'u':
+            base = 10;
+            goto convert_number;
+        case 'o':
+            base = 8;
+            goto convert_number;
+
+        convert_number:
+            switch (has_long) {
+            case 0:
+                val = va_arg(ap, unsigned int);
+                break;
+            case 1:
+                val = va_arg(ap, unsigned long);
+                break;
+            case 2:
+                val = va_arg(ap, unsigned long long);
+                break;
+            }
+
+            if (alt_form && base == 16) {
+                print_str("0x");
+            }
+
+            print_num(val, base);
+            break;
+
+        case 's':
+            str = va_arg(ap, char*);
+            print_str(str);
+            break;
+        case '%':
+            __sys_outc(*fmt);
+            break;
+        default:
+            __sys_outc('%');
+            __sys_outc(*fmt);
+            break;
+        }
+    }
+
+    va_end(ap);
+}