2024-05-23 15:32:54 +02:00
|
|
|
/***************************************************************
|
|
|
|
crc's _ _
|
|
|
|
(_) | ___
|
|
|
|
| | |/ _ \ a tiny virtual computer
|
|
|
|
| | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
|
|
|
|
|_|_|\___/ ilo.c (c) charles childers
|
|
|
|
**************************************************************/
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdlib.h>
|
2024-05-29 17:41:28 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <termios.h>
|
|
|
|
#include <unistd.h>
|
2024-05-23 15:32:54 +02:00
|
|
|
|
|
|
|
#define T ds[sp] /* Top of Data Stack */
|
|
|
|
#define N ds[sp-1] /* Next on Data Stack */
|
|
|
|
#define R as[rp] /* Top of Address Stack */
|
|
|
|
#define V void
|
|
|
|
#define I int
|
|
|
|
#define C char
|
|
|
|
|
|
|
|
I ip, /* instruction pointer */
|
|
|
|
sp, /* data stack pointer */
|
|
|
|
rp, /* address stack pointer */
|
|
|
|
ds[33], /* data stack */
|
|
|
|
as[257], /* address stack */
|
|
|
|
m[65536]; /* memory */
|
|
|
|
|
|
|
|
C *blocks, /* name of block file (ilo.blocks) */
|
|
|
|
*rom; /* name of image (ilo.rom) */
|
|
|
|
|
|
|
|
/* the other variables are used by the various
|
|
|
|
functions for misc. purposes */
|
|
|
|
|
|
|
|
I a, b, f, s, d, l;
|
|
|
|
C i[1];
|
|
|
|
|
2024-05-29 17:41:28 +02:00
|
|
|
struct termios ot, nt;
|
|
|
|
|
|
|
|
V it() {
|
|
|
|
tcgetattr(STDIN_FILENO, &ot);
|
|
|
|
nt = ot;
|
|
|
|
nt.c_lflag &=(~ICANON & ~ECHO);
|
|
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &nt);
|
|
|
|
}
|
|
|
|
V rt() { tcsetattr(STDIN_FILENO, TCSANOW, &ot); }
|
|
|
|
|
|
|
|
|
2024-05-23 15:32:54 +02:00
|
|
|
V p(char *s) { while(*s) putchar(*s++); }
|
|
|
|
V e(char *s) { p("E:"); p(s); p("\n"); exit(1); }
|
|
|
|
V dso() { if ((sp + 1) > 32) { e("DSO"); } }
|
|
|
|
V dsu() { if ((sp - 1) < 0) { e("DSU"); } }
|
|
|
|
V rso() { if ((rp + 1) > 256) { e("RSO"); } }
|
|
|
|
V rsu() { if ((rp - 1) < 0) { e("RSU"); } }
|
|
|
|
V dbz() { if (T == 0) { e("DBZ"); } }
|
|
|
|
V mem() { if (T < 0 || T > 65535) { e("MEM"); } }
|
|
|
|
V uli() { if (f == -1) { e("ULI"); } }
|
|
|
|
V usi() { if (f == -1) { e("URI"); } }
|
|
|
|
V urb() { if (f == -1) { e("URB"); } }
|
|
|
|
V uwb() { if (f == -1) { e("UWB"); } }
|
2024-05-29 17:41:28 +02:00
|
|
|
|
2024-05-23 15:32:54 +02:00
|
|
|
V push(I v) { dso(); ds[sp + 1] = v; sp += 1; }
|
|
|
|
I pop() { dsu(); sp -= 1; return ds[sp + 1]; }
|
|
|
|
|
|
|
|
V load_image() {
|
|
|
|
f = open(rom, O_RDONLY, 0666);
|
|
|
|
uli();
|
2024-05-29 17:41:28 +02:00
|
|
|
if (read(f, &m, 65536 * 4) < 0) { uli(); }
|
2024-05-23 15:32:54 +02:00
|
|
|
close(f);
|
|
|
|
ip = sp = rp = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
V save_image() {
|
|
|
|
f = open(rom, O_WRONLY, 0666);
|
|
|
|
usi();
|
2024-05-29 17:41:28 +02:00
|
|
|
if (write(f, &m, 65536 * 4) < 0) { usi(); }
|
2024-05-23 15:32:54 +02:00
|
|
|
close(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
V block_common() {
|
|
|
|
b = pop(); /* block buffer */
|
|
|
|
a = pop(); /* block number */
|
2024-05-29 17:41:28 +02:00
|
|
|
if (lseek(f, 4096 * a, SEEK_SET) < 0) { e("LSEEK"); };
|
2024-05-23 15:32:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
V read_block() {
|
|
|
|
f = open(blocks, O_RDONLY, 0666);
|
|
|
|
urb();
|
|
|
|
block_common();
|
2024-05-29 17:41:28 +02:00
|
|
|
if (read(f, m + b, 4096) < 0) { urb(); }
|
2024-05-23 15:32:54 +02:00
|
|
|
close(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
V write_block() {
|
|
|
|
f = open(blocks, O_WRONLY, 0666);
|
|
|
|
uwb();
|
|
|
|
block_common();
|
2024-05-29 17:41:28 +02:00
|
|
|
if (write(f, m + b, 4096) < 0) { uwb(); }
|
2024-05-23 15:32:54 +02:00
|
|
|
close(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
V save_ip() { rso(); rp += 1; R = ip; }
|
|
|
|
V symmetric() { if (b >= 0 && N < 0) { T += 1; N -= b; } }
|
2024-05-29 17:41:28 +02:00
|
|
|
V emit() { if (write(1, &i, 1) < 0) { exit(1); }; }
|
|
|
|
V bs() { i[0] = '\b'; emit();
|
|
|
|
i[0] = ' '; emit();
|
|
|
|
i[0] = '\b'; emit(); }
|
2024-05-23 15:32:54 +02:00
|
|
|
|
|
|
|
V li() { ip += 1; push(m[ip]); }
|
|
|
|
V du() { push(T); }
|
|
|
|
V dr() { ds[sp] = 0; sp -= 1; }
|
|
|
|
V sw() { a = T; T = N; N = a; }
|
|
|
|
V pu() { rso(); rp += 1; R = pop(); }
|
|
|
|
V po() { rsu(); push(R); rp -= 1; }
|
|
|
|
V ju() { ip = pop() - 1; }
|
|
|
|
V ca() { save_ip(); ip = pop() - 1; }
|
|
|
|
V cc() { a = pop(); if (pop()) { save_ip(); ip = a - 1; } }
|
|
|
|
V cj() { a = pop(); if (pop()) { ip = a - 1; } }
|
|
|
|
V re() { rsu(); ip = R; rp -= 1; }
|
|
|
|
V eq() { N = (N == T) ? -1 : 0; sp -= 1; }
|
|
|
|
V ne() { N = (N != T) ? -1 : 0; sp -= 1; }
|
|
|
|
V lt() { N = (N < T) ? -1 : 0; sp -= 1; }
|
|
|
|
V gt() { N = (N > T) ? -1 : 0; sp -= 1; }
|
|
|
|
V fe() { mem(); T = m[T]; }
|
|
|
|
V st() { mem(); m[T] = N; sp -= 2; }
|
|
|
|
V ad() { N += T; sp -= 1; }
|
|
|
|
V su() { N -= T; sp -= 1; }
|
|
|
|
V mu() { N *= T; sp -= 1; }
|
|
|
|
V di() { dbz();
|
|
|
|
a = T; b = N; T = b / a; N = b % a; symmetric(); }
|
|
|
|
V an() { N = T & N; sp -= 1; }
|
|
|
|
V or() { N = T | N; sp -= 1; }
|
|
|
|
V xo() { N = T ^ N; sp -= 1; }
|
|
|
|
V sl() { N = N << T; sp -= 1; }
|
|
|
|
V sr() { N = N >> T; sp -= 1; }
|
2024-05-29 17:41:28 +02:00
|
|
|
V cp() { size_t l = pop() * 4;
|
|
|
|
void *d = m + pop();
|
|
|
|
void *s = m + pop();
|
|
|
|
push((memcmp(s, d, l) == 0) ? -1 : 0);
|
|
|
|
}
|
|
|
|
V cy() { size_t l = pop() * 4;
|
|
|
|
void *d = m + pop();
|
|
|
|
void *s = m + pop();
|
|
|
|
memmove(d, s, l);
|
|
|
|
}
|
|
|
|
V ioa() { i[0] = (char)pop(); emit(); }
|
|
|
|
V iob() { if (read(0, &i, 1) < 0) { rt(); exit(1); }; push(i[0]);
|
|
|
|
(i[0] == 8 || i[0] == 127) ? bs() : emit(); }
|
2024-05-23 15:32:54 +02:00
|
|
|
V ioc() { read_block(); }
|
|
|
|
V iod() { write_block(); }
|
|
|
|
V ioe() { save_image(); }
|
|
|
|
V iof() { load_image(); ip = -1; }
|
|
|
|
V iog() { ip = 65536; }
|
|
|
|
V ioh() { push(sp); push(rp); }
|
|
|
|
V io() {
|
|
|
|
switch (pop()) {
|
|
|
|
case 0: ioa(); break; case 1: iob(); break;
|
|
|
|
case 2: ioc(); break; case 3: iod(); break;
|
|
|
|
case 4: ioe(); break; case 5: iof(); break;
|
|
|
|
case 6: iog(); break; case 7: ioh(); break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Using a switch here instead of a jump table to avoid */
|
|
|
|
/* some issues w/relocation stuff when building w/o libc */
|
|
|
|
|
|
|
|
V process(I o) {
|
|
|
|
switch (o) {
|
|
|
|
case 0: break; case 1: li(); break;
|
|
|
|
case 2: du(); break; case 3: dr(); break;
|
|
|
|
case 4: sw(); break; case 5: pu(); break;
|
|
|
|
case 6: po(); break; case 7: ju(); break;
|
|
|
|
case 8: ca(); break; case 9: cc(); break;
|
|
|
|
case 10: cj(); break; case 11: re(); break;
|
|
|
|
case 12: eq(); break; case 13: ne(); break;
|
|
|
|
case 14: lt(); break; case 15: gt(); break;
|
|
|
|
case 16: fe(); break; case 17: st(); break;
|
|
|
|
case 18: ad(); break; case 19: su(); break;
|
|
|
|
case 20: mu(); break; case 21: di(); break;
|
|
|
|
case 22: an(); break; case 23: or(); break;
|
|
|
|
case 24: xo(); break; case 25: sl(); break;
|
|
|
|
case 26: sr(); break; case 27: cp(); break;
|
|
|
|
case 28: cy(); break; case 29: io(); break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define INST(n) ((opcode >> n) & 0xFF) != 0
|
|
|
|
|
|
|
|
V process_bundle(I opcode) {
|
|
|
|
if (INST(0)) process(opcode & 0xFF);
|
|
|
|
if (INST(8)) process((opcode >> 8) & 0xFF);
|
|
|
|
if (INST(16)) process((opcode >> 16) & 0xFF);
|
|
|
|
if (INST(24)) process((opcode >> 24) & 0xFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
V execute() {
|
|
|
|
while (ip < 65536) {
|
|
|
|
process_bundle(m[ip]);
|
|
|
|
ip += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
V add_restrictions() {
|
|
|
|
#ifdef __OpenBSD__
|
|
|
|
unveil(blocks, "rw");
|
|
|
|
unveil(rom, "rw");
|
2024-05-29 17:41:28 +02:00
|
|
|
unveil(NULL, NULL);
|
|
|
|
pledge("stdio rpath wpath tty", NULL);
|
2024-05-23 15:32:54 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
I main(I argc, C **argv) {
|
|
|
|
blocks = (argc > 1) ? argv[1] : "ilo.blocks";
|
|
|
|
rom = (argc > 2) ? argv[2] : "ilo.rom";
|
|
|
|
add_restrictions();
|
2024-05-29 17:41:28 +02:00
|
|
|
it(); load_image(); execute(); rt();
|
2024-05-23 15:32:54 +02:00
|
|
|
return 0;
|
|
|
|
}
|