+// (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);
+}
+