Imported slu/mmu/interrupt/register code from WIP memtester program into C template.
[pdp11-modern-c] / pdp11 / pdp11_slu.c
// (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);
}