// ============================================================= // 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 #include #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(); }