Commit | Line | Data |
---|---|---|
202004d5 AT |
1 | // (c) 2020 Aaron Taylor <ataylor at subgeniuskitty dot com> |
2 | // See License.txt file for copyright and license details. | |
3 | ||
4 | #include <stdarg.h> | |
5 | #include <stdint.h> | |
6 | #include "pdp11.h" | |
7 | ||
8 | /* | |
9 | * Polled console I/O | |
10 | */ | |
11 | ||
12 | void | |
13 | putch(uint16_t c) | |
14 | { | |
15 | while(!(GET(CONSXCSR,SLUXCSR_XMTRDY))) continue; | |
16 | CONSXBUF = c; | |
17 | } | |
18 | ||
19 | uint16_t | |
20 | getch(void) | |
21 | { | |
22 | while(!(GET(CONSRCSR,SLURCSR_RCVRDY))) continue; | |
23 | return CONSRBUF; | |
24 | } | |
25 | ||
26 | ||
27 | /* | |
28 | * Helper functions for use with console IO | |
29 | */ | |
30 | ||
31 | void | |
32 | print_string(const char * string) | |
33 | { | |
34 | while (*string != '\0') { | |
35 | putch(*string); | |
36 | string++; | |
37 | } | |
38 | } | |
39 | ||
40 | char | |
41 | digit_to_ascii(uint16_t digit) | |
42 | { | |
43 | if (digit > 15) { | |
44 | print_string("ERROR: Out of range in digit_to_ascii()\r\n"); | |
45 | // TODO: How do I want to handle runtime errors? | |
46 | return 0; | |
47 | } else if (digit > 9) { | |
48 | digit -= 10; | |
49 | digit += 'a'; | |
50 | return digit; | |
51 | } else { | |
52 | digit += '0'; | |
53 | return digit; | |
54 | } | |
55 | } | |
56 | ||
57 | void | |
58 | print_uint16_in_octal(uint16_t number) | |
59 | { | |
60 | char output[7]; // +6 for digits; +1 for null-term | |
61 | for (int i = 5; i >= 0; i--) { | |
62 | output[i] = digit_to_ascii(number % 8); | |
63 | number = number / 8; | |
64 | } | |
65 | output[6] = '\0'; | |
66 | putch('0'); | |
67 | print_string(output); | |
68 | } | |
69 | ||
70 | void | |
71 | printf(const char * format, ...) | |
72 | { | |
73 | va_list ap; | |
74 | va_start(ap, format); | |
75 | while (*format) { | |
76 | switch (*format) { | |
77 | case '%': | |
78 | format++; | |
79 | switch (*format) { | |
80 | case 's': | |
81 | { | |
82 | char * s = va_arg(ap, char *); | |
83 | print_string(s); | |
84 | break; | |
85 | } | |
86 | case 'o': | |
87 | { | |
88 | uint16_t u = va_arg(ap, unsigned int); | |
89 | print_uint16_in_octal(u); | |
90 | break; | |
91 | } | |
92 | default: | |
93 | /* Put it back and look innocent. */ | |
94 | putch('%'); | |
95 | putch(*format); | |
96 | break; | |
97 | } | |
98 | break; | |
99 | case '\\': | |
100 | format++; | |
101 | switch (*format) { | |
102 | case 'n': | |
103 | print_string("\r\n"); | |
104 | break; | |
105 | case 't': | |
106 | putch('\t'); | |
107 | break; | |
108 | case '%': | |
109 | putch('%'); | |
110 | break; | |
111 | case '\\': | |
112 | putch('\\'); | |
113 | break; | |
114 | default: | |
115 | /* Maybe this escape wasn't meant for us. */ | |
116 | putch('\\'); | |
117 | putch(*format); | |
118 | break; | |
119 | } | |
120 | break; | |
121 | case '\n': | |
122 | print_string("\r\n"); | |
123 | break; | |
124 | default: | |
125 | putch(*format); | |
126 | break; | |
127 | } | |
128 | format++; | |
129 | } | |
130 | va_end(ap); | |
131 | } | |
132 |