/* * Ad-hoc Tcode9 virtual machine * Nils M Holm, 2017, CC0 license * https://creativecommons.org/publicdomain/zero/1.0/ * * Running at about 1/13th of the speed of native * T3X9 output when compiled with clang -O2. */ #include #include #include #include #include #undef DEBUG #define MINSIZE 131072 #define STKLEN 65536 #define byte unsigned char #define sbyte signed char #define cell int byte *M; sbyte *S; cell Red; cell Memsize; void writes(char *s) { write(1, s, strlen(s)); } void wlog(char *s) { write(2, s, strlen(s)); } void fail(char *s) { wlog("tcvm: "); wlog(s); wlog("\n"); _exit(1); } #define BSIZE 1024 char B[BSIZE]; int Fd, C, K; int rdch(void) { if (C >= K) { K = read(Fd, B, BSIZE); C = 0; if (K < 1) return -1; } C = C+1; return B[C-1] & 255; } cell rdwd(void) { cell v; v = rdch(); v = v | (rdch() << 8); v = v | (rdch() << 16); v = v | (rdch() << 24); return v; } void readblk(byte *v, int k) { int i, c; for (i=0; i> 8) & 255; M[a+2] = (w >> 16) & 255; M[a+3] = (w >> 24) & 255; } void push(cell x) { P -= 4; Sw(P, x); } cell pop(void) { P += 4; return w(P-4); } #define a() w(I+1) #define a2() w(I+5) #define s() S[I+1] #define s2() w(I+2) cell memscan(cell p, cell c, cell k) { cell i; for (i=0; i= A) { I += a(); } I += 4; break; case 0x9d: case 0x1d: if (pop() <= A) { I += a(); } I += 4; break; case 0x9e: case 0x1e: push(F); F = P; break; case 0x9f: case 0x1f: F = pop(); I = pop(); break; case 0xa0: exit(s()); break; case 0x20: exit(a()); break; case 0xa1: case 0x21: A = -A; break; case 0xa2: case 0x22: A = ~A; break; case 0xa3: case 0x23: A = 0==A? -1: 0; break; case 0xa4: case 0x24: A = pop() + A; break; case 0xa5: case 0x25: A = pop() - A; break; case 0xa6: case 0x26: A = pop() * A; break; case 0xa7: case 0x27: A = pop() / A; break; case 0xa8: case 0x28: A = pop() % A; break; case 0xa9: case 0x29: A = pop() & A; break; case 0xaa: case 0x2a: A = pop() | A; break; case 0xab: case 0x2b: A = pop() ^ A; break; case 0xac: case 0x2c: A = pop() << A; break; case 0xad: case 0x2d: A = (unsigned) pop() >> A; break; case 0xae: case 0x2e: A = pop() == A? -1: 0; break; case 0xaf: case 0x2f: A = pop() != A? -1: 0; break; case 0xb0: case 0x30: A = pop() < A? -1: 0; break; case 0xb1: case 0x31: A = pop() > A? -1: 0; break; case 0xb2: case 0x32: A = pop() <= A? -1: 0; break; case 0xb3: case 0x33: A = pop() >= A? -1: 0; break; /* case 0xb4: WORD */ /* case 0x34: WORD */ case 0xb5: case 0x35: A = sys_call(M[I+1]); I = pop(); break; default: fail("invalid opcode"); break; }} } int size(void) { int k, n; k = 0; for (I = 0;; I++) { n = 0; switch (M[I]) { case 0x8d: n = s(); I++; break; case 0x0d: n = a(); I += 4; break; case 0x90: case 0x10: I += 4; break; case 0x98: case 0x18: I += a(); I += 4; break; default: return k; } k += n; } return k; } cell main(cell argc, char **argv) { if (argc != 2) fail("usage: tcvm program"); load(argv[1]); run(size()); return 0; }