Imported slu/mmu/interrupt/register code from WIP memtester program into C template.
[pdp11-modern-c] / pdp11 / pdp11_slu.c
diff --git a/pdp11/pdp11_slu.c b/pdp11/pdp11_slu.c
new file mode 100644 (file)
index 0000000..1d4667c
--- /dev/null
@@ -0,0 +1,132 @@
+// (c) 2020 Aaron Taylor <ataylor at subgeniuskitty dot com>
+// See License.txt file for copyright and license details.
+
+#include <stdarg.h>
+#include <stdint.h>
+#include "pdp11.h"
+
+/*
+ * Polled console I/O
+ */
+
+void
+putch(uint16_t c)
+{
+    while(!(GET(CONSXCSR,SLUXCSR_XMTRDY))) continue;
+    CONSXBUF = c;
+}
+
+uint16_t
+getch(void)
+{
+    while(!(GET(CONSRCSR,SLURCSR_RCVRDY))) continue;
+    return CONSRBUF;
+}
+
+
+/*
+ * Helper functions for use with console IO
+ */
+
+void
+print_string(const char * string)
+{
+    while (*string != '\0') {
+        putch(*string);
+        string++;
+    }
+}
+
+char
+digit_to_ascii(uint16_t digit)
+{
+    if (digit > 15) {
+        print_string("ERROR: Out of range in digit_to_ascii()\r\n");
+        // TODO: How do I want to handle runtime errors?
+        return 0;
+    } else if (digit > 9) {
+        digit -= 10;
+        digit += 'a';
+        return digit;
+    } else {
+        digit += '0';
+        return digit;
+    }
+}
+
+void
+print_uint16_in_octal(uint16_t number)
+{
+    char output[7]; // +6 for digits; +1 for null-term
+    for (int i = 5; i >= 0; i--) {
+        output[i] = digit_to_ascii(number % 8);
+        number = number / 8;
+    }
+    output[6] = '\0';
+    putch('0');
+    print_string(output);
+}
+
+void
+printf(const char * format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    while (*format) {
+        switch (*format) {
+            case '%':
+                format++;
+                switch (*format) {
+                    case 's':
+                        {
+                        char * s = va_arg(ap, char *);
+                        print_string(s);
+                        break;
+                        }
+                    case 'o':
+                        {
+                        uint16_t u = va_arg(ap, unsigned int);
+                        print_uint16_in_octal(u);
+                        break;
+                        }
+                    default:
+                        /* Put it back and look innocent. */
+                        putch('%');
+                        putch(*format);
+                        break;
+                }
+                break;
+            case '\\':
+                format++;
+                switch (*format) {
+                    case 'n':
+                        print_string("\r\n");
+                        break;
+                    case 't':
+                        putch('\t');
+                        break;
+                    case '%':
+                        putch('%');
+                        break;
+                    case '\\':
+                        putch('\\');
+                        break;
+                    default:
+                        /* Maybe this escape wasn't meant for us. */
+                        putch('\\');
+                        putch(*format);
+                        break;
+                }
+                break;
+            case '\n':
+                print_string("\r\n");
+                break;
+            default:
+                putch(*format);
+                break;
+        }
+        format++;
+    }
+    va_end(ap);
+}
+