ilo-vm/source/ilo-teensy41.ino

267 lines
6.9 KiB
C++

// =============================================================
// crc's _ _
// (_) | ___
// | | |/ _ \ a tiny virtual computer
// | | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
// |_|_|\___/ ilo-teensy41.ino (c) charles childers
// ============================================================
// This is an ilo for the Teensy 4.1. It derives from the
// ilo-banked.c, as with the DOS & Mac System 5/6/7 ports.
//
// Requirements:
//
// - Teensy 4.1
// - FAT formatted SD card containing these files:
// - ilo.rom (the system image)
// - ilo.blo (the data blocks)
// - A serial terminal interface
//
// ============================================================
#include <SD.h>
#include <TimeLib.h>
#define VERBOSE
#define SLICES 64
#define SLICESIZE (65536/SLICES)
int ip, sp, rp, data[33], address[257];
char *blocks, *rom;
extern int image[];
int *memory[SLICES];
#define TOS data[sp]
#define NOS data[sp-1]
#define TORS address[rp]
#define I int
#define V void
I pop() { sp--; return data[sp + 1]; }
V push(int value) { sp++; data[sp] = value; }
V store(int a, int v) {
int slice = a / SLICESIZE;
int actual = a - (slice * SLICESIZE);
memory[slice][actual] = v;
}
int fetch(int a) {
int slice = a / SLICESIZE;
int actual = a - (slice * SLICESIZE);
return memory[slice][actual];
}
V xlog(const char *s, int eol) {
#ifdef VERBOSE
if (eol)
Serial.println(s);
else
Serial.print(s);
#endif
}
V load_image() {
File rom = SD.open("ilo.rom", FILE_READ);
int data;
xlog("ilo: load rom", 1);
for (int x = 0; x < 65536; x++) {
data = 0;
rom.read(&data, 4);
store(x, data);
if ((x % 1024) == 0) xlog(".", 0);
}
rom.close();
delay(10);
xlog("\nilo: rom loaded", 1);
}
V prepare_vm() {
for (ip = 0; ip < 32; ip++) data[ip] = 0;
for (ip = 0; ip < 128; ip++) address[ip] = 0;
ip = sp = rp = 0;
}
V read_block() {
File blocks = SD.open("ilo.blo", FILE_READ);
int data;
int buf = pop();
int blk = pop();
blocks.seek(4096 * blk);
for (int x = 0; x < 1024; x++) {
data = 0;
blocks.read(&data, 4);
store(buf + x, data);
}
blocks.close();
delay(10);
}
V write_block() {
File blocks = SD.open("ilo.blo", FILE_WRITE);
int data;
int buf = pop();
int blk = pop();
blocks.seek(4096 * blk);
for (int x = 0; x < 1024; x++) {
data = fetch(buf + x);
blocks.write(&data, 4);
}
blocks.close();
delay(10);
}
int led = 13;
V teensy_io() {
int a, b, c, d, e, f;
switch (pop()) {
case 1: digitalWrite(pop(), HIGH);
break;
case 2: digitalWrite(pop(), LOW);
break;
case 3: a = pop();
b = pop();
pinMode(b, a);
break;
case 4: digitalRead(pop()) ? push(-1) : push(0);
break;
case 10: delay(pop());
break;
case 11: delayMicroseconds(pop());
break;
case 12: delayNanoseconds(pop());
break;
case 20: push(hour());
break;
case 21: push(minute());
break;
case 22: push(second());
break;
case 23: push(day());
break;
case 24: push(month());
break;
case 25: push(year());
break;
}
}
V process(int o) {
int a, b, target, flag;
int src, dest, len, kkk;
char outstr[2] = {'a', 0};
switch (o) {
case 0: break;
case 1: ip++; push(fetch(ip)); break;
case 2: push(TOS); break;
case 3: data[sp] = 0; sp--; break;
case 4: a = TOS; TOS = NOS; NOS = a; break;
case 5: rp++; TORS = pop(); break;
case 6: push(TORS); rp--; break;
case 7: ip = pop() - 1; break;
case 8: rp++; TORS = ip; ip = pop() - 1; break;
case 9: target = pop(); flag = pop();
if (flag != 0) { rp++; TORS = ip; ip = target - 1; }
break;
case 10: target = pop(); flag = pop();
if (flag != 0) ip = target - 1; break;
case 11: ip = TORS; rp--; break;
case 12: NOS = (NOS == TOS) ? -1 : 0; sp--; break;
case 13: NOS = (NOS != TOS) ? -1 : 0; sp--; break;
case 14: NOS = (NOS < TOS) ? -1 : 0; sp--; break;
case 15: NOS = (NOS > TOS) ? -1 : 0; sp--; break;
case 16: TOS = fetch(TOS); break;
case 17: store(TOS, NOS); sp--; sp--; break;
case 18: NOS += TOS; sp--; break;
case 19: NOS -= TOS; sp--; break;
case 20: NOS *= TOS; sp--; break;
case 21: a = TOS; b = NOS; TOS = b / a; NOS = b % a; break;
case 22: NOS = TOS & NOS; sp--; break;
case 23: NOS = TOS | NOS; sp--; break;
case 24: NOS = TOS ^ NOS; sp--; break;
case 25: NOS = NOS << TOS; sp--; break;
case 26: NOS = NOS >> TOS; sp--; break;
case 27: len = pop(); dest = pop();
src = pop(); flag = -1;
while (len) {
if (fetch(dest) != fetch(src)) flag = 0;
len -= 1; src += 1; dest += 1;
}; push(flag); break;
case 28: len = pop(); dest = pop();
src = pop();
while (len) {
store(dest, fetch(src));
len -= 1; src += 1; dest += 1;
}; break;
case 29: switch (pop()) {
case 0: outstr[0] = pop(); Serial.print(outstr);
if (outstr[0] == 10) { outstr[0] = 13; Serial.print(outstr); } break;
case 1: kkk = 0; while (kkk <= 0) { kkk = Serial.read(); }
outstr[0] = kkk; Serial.print(outstr);
if (kkk == 13) { kkk = 10; }
push(kkk); break;
case 2: read_block(); break;
case 3: write_block(); break;
case 4: break;
case 5: ip = -1; break;
case 6: ip = 65536; break;
case 7: push(sp); push(rp); break;
case 100: teensy_io(); break;
default: break;
} break;
default: break;
}
}
V execute() {
int opcode, o;
ip = 0;
while (ip < 65536) {
opcode = fetch(ip);
o = opcode & 0xFF; if (o) process(o);
o = (opcode >> 8) & 0xFF; if (o) process(o);
o = (opcode >> 16) & 0xFF; if (o) process(o);
o = (opcode >> 24) & 0xFF; if (o) process(o);
ip++;
}
}
// the setup routine runs once when you press reset:
V setup() {
Serial.begin(9600);
xlog("ilo: prepare memory", 1);
int i;
for (i = 0; i < SLICES; i++)
memory[i] = (int *)malloc(SLICESIZE * sizeof(int));
xlog("ilo: prepare i/o pins", 1);
pinMode(led, OUTPUT);
xlog("ilo: check for SD card", 1);
if (!SD.begin(BUILTIN_SDCARD)) {
xlog("!!!! card failed, or not present; check SD card and restart", 1);
while (1);
}
xlog("ilo: check for ilo.rom", 1);
if (!SD.exists("ilo.rom")) {
xlog("!!!! missing ilo.rom; check SD card and restart", 1);
while (1);
}
xlog("ilo: check for ilo.blo", 1);
if (!SD.exists("ilo.blo")) {
xlog("!!!! missing ilo.blo; check SD card and restart", 1);
while (1);
}
}
// the loop routine runs over and over again forever:
V loop() {
prepare_vm();
load_image();
execute();
}