264 lines
7.7 KiB
C
264 lines
7.7 KiB
C
/***************************************************************
|
|
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;
|
|
}
|