ilo-vm/source/mult-ilo.c

265 lines
7.7 KiB
C
Raw Permalink Normal View History

/***************************************************************
crc's _ _ ___ _
_ __ ___ _ _| | |_ / (_) | ___
| '_ ` _ \| | | | | __| / /| | |/ _ \
| | | | | | |_| | | |_ / / | | | (_) |
|_| |_| |_|\__,_|_|\__/_/ |_|_|\___/
(c) charles childers
This is a special implementation of my ilo computer, with many
copies of ilo running under a single process. Under this you
can quickly switch between ilo instances.
- `bye` will act like `restart` on the current computer
- ctrl+c restarts the current computer
- ctrl+n switches to the next ilo
- ctrl+p switches to the previous ilo
- ctrl+a shuts down mult/ilo
- switching can only be done when the system is waiting for
input
**************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#define V void
#define I int
#define C char
#define ILOS 5
struct termios old_term, new_term;
typedef struct ilo ilo;
struct ilo {
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) */
I a, b, f, s, d, l;
C i[1];
};
struct ilo systems[ILOS];
I cur, cancel;
#define DS v->ds
#define AS v->as
#define SP v->sp
#define RP v->rp
#define IP v->ip
#define M v->m
#define A v->a
#define B v->b
#define S v->s
#define D v->d
#define L v->l
#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 */
V iof(ilo *);
V push(ilo *v, I n) { DS[SP + 1] = n; SP += 1; }
I pop(ilo *v) { SP -= 1; return DS[SP + 1]; }
V load_image(ilo *v) {
v->f = open(v->rom, O_RDONLY, 0666);
if (!v->f) { return; };
read(v->f, &M, 65536 * 4);
close(v->f);
v->i[0] = 32;
IP = SP = RP = 0;
}
V save_image(ilo *v) {
v->f = open(v->rom, O_WRONLY, 0666);
write(v->f, &M, 65536 * 4);
close(v->f);
}
V block_common(ilo *v) {
B = pop(v); /* block buffer */
A = pop(v); /* block number */
lseek(v->f, 4096 * A, SEEK_SET);
}
V read_block(ilo *v) {
v->f = open(v->blocks, O_RDONLY, 0666);
block_common(v);
read(v->f, M + B, 4096);
close(v->f);
}
V write_block(ilo *v) {
v->f = open(v->blocks, O_WRONLY, 0666);
block_common(v);
write(v->f, M + B, 4096);
close(v->f);
}
V save_ip(ilo *v) { RP += 1; R = IP; }
V symmetric(ilo *v) {
if (B >= 0 && N < 0) { T += 1; N -= B; } }
V li(ilo *v) { IP += 1; push(v, M[IP]); }
V du(ilo *v) { push(v, T); }
V dr(ilo *v) { DS[SP] = 0; SP -= 1; }
V sw(ilo *v) { A = T; T = N; N = A; }
V pu(ilo *v) { RP += 1; R = pop(v); }
V po(ilo *v) { push(v, R); RP -= 1; }
V ju(ilo *v) { IP = pop(v) - 1; }
V ca(ilo *v) { save_ip(v); IP = pop(v) - 1; }
V cc(ilo *v) { A = pop(v);
if (pop(v)) { save_ip(v);
IP = A - 1; } }
V cj(ilo *v) { A = pop(v);
if (pop(v)) { IP = A - 1; } }
V re(ilo *v) { IP = R; RP -= 1; }
V eq(ilo *v) { N = (N == T) ? -1 : 0; SP -= 1; }
V ne(ilo *v) { N = (N != T) ? -1 : 0; SP -= 1; }
V lt(ilo *v) { N = (N < T) ? -1 : 0; SP -= 1; }
V gt(ilo *v) { N = (N > T) ? -1 : 0; SP -= 1; }
V fe(ilo *v) { T = M[T]; }
V st(ilo *v) { M[T] = N; SP -= 2; }
V ad(ilo *v) { N += T; SP -= 1; }
V su(ilo *v) { N -= T; SP -= 1; }
V mu(ilo *v) { N *= T; SP -= 1; }
V di(ilo *v) { A = T; B = N;
if (A == 0) { cancel = 1; iof(v); return; }
T = B / A; N = B % A;
symmetric(v); }
V an(ilo *v) { N = T & N; SP -= 1; }
V or(ilo *v) { N = T | N; SP -= 1; }
V xo(ilo *v) { N = T ^ N; SP -= 1; }
V sl(ilo *v) { N = N << T; SP -= 1; }
V sr(ilo *v) { N = N >> T; SP -= 1; }
V cp(ilo *v) { L = pop(v); D = pop(v); S = T; T = -1;
while (L) {
if (M[D] != M[S]) { T = 0; }
L -= 1; S += 1; D += 1; } }
V cy(ilo *v) { L = pop(v); D = pop(v); S = pop(v);
while (L) {
M[D] = M[S];
L -= 1; S += 1; D += 1; } }
V pre(V) { cur -= 1; if (cur < 0) cur = ILOS - 1; }
V nxt(V) { cur += 1; if (cur > (ILOS - 1)) cur = 0; }
V msgs(V) { printf("\n*** SWITCH TO %d ***\n", cur); }
V msgx(V) { printf("\n*** SHUTDOWN REQUESTED ***\n");
tcsetattr(STDIN_FILENO,TCSANOW, &old_term);
exit(1); }
V msgr(V) { printf("\n*** RESTART %d ***\n", cur); }
V ioa(ilo *v) { v->i[0] = (char)pop(v); write(1, &v->i, 1); }
V iob(ilo *v) { read(0, &v->i, 1); push(v, v->i[0]);
if (v->i[0] == 14) { T = 32; nxt(); msgs(); }
if (v->i[0] == 16) { T = 32; pre(); msgs(); }
if (v->i[0] == 3) { T = 32; msgr(); iof(v);
cancel = 1; }
if (v->i[0] == 1) { T = 32; msgx(); }
if (v->i[0] == 8 || v->i[0] == 127) {
v->i[0] = '\b'; write(1, &v->i, 1);
v->i[0] = ' '; write(1, &v->i, 1);
v->i[0] = '\b'; write(1, &v->i, 1);
} else { write(1, &v->i, 1); } }
V ioc(ilo *v) { read_block(v); }
V iod(ilo *v) { write_block(v); }
V ioe(ilo *v) { save_image(v); }
V iof(ilo *v) { load_image(v); IP = -1; }
V iog(ilo *v) { iof(v); }
V ioh(ilo *v) { push(v, SP); push(v, RP); }
V io(ilo *v) {
switch (pop(v)) {
case 0: ioa(v); break; case 1: iob(v); break;
case 2: ioc(v); break; case 3: iod(v); break;
case 4: ioe(v); break; case 5: iof(v); break;
case 6: iog(v); break; case 7: ioh(v); break;
default: break;
}
}
V process(ilo *v, I o) {
switch (o) {
case 0: break; case 1: li(v); break;
case 2: du(v); break; case 3: dr(v); break;
case 4: sw(v); break; case 5: pu(v); break;
case 6: po(v); break; case 7: ju(v); break;
case 8: ca(v); break; case 9: cc(v); break;
case 10: cj(v); break; case 11: re(v); break;
case 12: eq(v); break; case 13: ne(v); break;
case 14: lt(v); break; case 15: gt(v); break;
case 16: fe(v); break; case 17: st(v); break;
case 18: ad(v); break; case 19: su(v); break;
case 20: mu(v); break; case 21: di(v); break;
case 22: an(v); break; case 23: or(v); break;
case 24: xo(v); break; case 25: sl(v); break;
case 26: sr(v); break; case 27: cp(v); break;
case 28: cy(v); break; case 29: io(v); break;
default: break;
}
}
V process_bundle(ilo *v, I opcode) {
if (cancel) return; process(v, opcode & 0xFF);
if (cancel) return; process(v, (opcode >> 8) & 0xFF);
if (cancel) return; process(v, (opcode >> 16) & 0xFF);
if (cancel) return; process(v, (opcode >> 24) & 0xFF);
}
V execute(V) {
ilo *v = &systems[cur];
while (IP < 65536) {
cancel = 0;
process_bundle(v, M[IP]);
IP += 1;
v = &systems[cur];
}
}
V handle_sigint(I sig) {
printf("\n*** SIGINT (%d) : RESTARTING %d ***\n", sig, cur);
cancel = 1;
iof(&systems[cur]);
}
I main(I argc, C **argv) {
ilo *v;
I i;
cur = 0;
for (i = 0; i < ILOS; i++) {
v = &systems[i];
v->blocks = (argc > 1) ? argv[1] : "ilo.blocks";
v->rom = (argc > 2) ? argv[2] : "ilo.rom";
load_image(v);
}
if (signal(SIGINT, handle_sigint) == SIG_ERR) {
perror("signal");
return 1;
}
tcgetattr(STDIN_FILENO, &old_term);
new_term = old_term;
new_term.c_lflag &=(~ICANON & ~ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &new_term);
execute();
tcsetattr(STDIN_FILENO, TCSANOW, &old_term);
return 0;
}