/*************************************************************** crc's _ _ (_) | ___ | | |/ _ \ a tiny virtual computer | | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC |_|_|\___/ ilo.c (c) charles childers ilo-fast.c modifications (c) 2024 Christopher Leonard Recommended compiler flags: -O3 -fomit-frame-pointer -funroll-loops -march=native -ftree-vectorize **************************************************************/ #include #include #include #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 static void #define I int #define C char static C *blocks, /* name of block file (ilo.blocks) */ *rom; /* name of image (ilo.rom) */ #define push(v) { ds[sp + 1] = (v); sp += 1; } #define pop() ( sp -= 1, ds[sp + 1] ) #define load_image() { \ f = open(rom, O_RDONLY, 0666); \ if (!f) { return; }; \ read(f, &m, 65536 * 4); \ close(f); \ ip = sp = rp = 0; \ } #define save_image() { \ f = open(rom, O_WRONLY, 0666); \ write(f, &m, 65536 * 4); \ close(f); \ } #define block_common() { \ b = pop(); /* block buffer */ \ a = pop(); /* block number */ \ lseek(f, 4096 * a, SEEK_SET); \ } #define read_block() { \ f = open(blocks, O_RDONLY, 0666); \ block_common(); \ read(f, m + b, 4096); \ close(f); \ } #define write_block() { \ f = open(blocks, O_WRONLY, 0666); \ block_common(); \ write(f, m + b, 4096); \ close(f); \ } #define save_ip() { rp += 1; R = ip; } #define symmetric() { if (b >= 0 && N < 0) { T += 1; N -= b; } } #define li() { ip += 1; push(m[ip]); } #define du() { push(T); } #define dr() { ds[sp] = 0; sp -= 1; } #define sw() { a = T; T = N; N = a; } #define pu() { rp += 1; R = pop(); } #define po() { push(R); rp -= 1; } #define ju() { ip = pop() - 1; } #define ca() { save_ip(); ip = pop() - 1; } #define cc() { a = pop(); if (pop()) { save_ip(); ip = a - 1; } } #define cj() { a = pop(); if (pop()) { ip = a - 1; } } #define re() { ip = R; rp -= 1; } #define eq() { N = (N == T) ? -1 : 0; sp -= 1; } #define ne() { N = (N != T) ? -1 : 0; sp -= 1; } #define lt() { N = (N < T) ? -1 : 0; sp -= 1; } #define gt() { N = (N > T) ? -1 : 0; sp -= 1; } #define fe() { T = m[T]; } #define st() { m[T] = N; sp -= 2; } #define ad() { N += T; sp -= 1; } #define su() { N -= T; sp -= 1; } #define mu() { N *= T; sp -= 1; } #define di() { a = T; b = N; T = b / a; N = b % a; symmetric(); } #define an() { N = T & N; sp -= 1; } #define or() { N = T | N; sp -= 1; } #define xo() { N = T ^ N; sp -= 1; } #define sl() { N = N << T; sp -= 1; } #define sr() { N = N >> T; sp -= 1; } #define cp() { l = pop(); d = pop(); s = T; T = -1; \ while (l) { if (m[d] != m[s]) { T = 0; } \ l -= 1; s += 1; d += 1; } } #define cy() { l = pop(); d = pop(); s = pop(); \ while (l) { m[d] = m[s]; l -= 1; s += 1; d += 1; } } #define ioa() { i[0] = (char)pop(); write(1, &i, 1); } #define iob() { read(0, &i, 1); push(i[0]); } #define ioc() { read_block(); } #define iod() { write_block(); } #define ioe() { save_image(); } #define iof() { load_image(); ip = -1; } #define iog() { ip = 65536; } #define ioh() { push(sp); push(rp); } #define 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 execute() { I ip, /* instruction pointer */ sp, /* data stack pointer */ rp, /* address stack pointer */ ds[33], /* data stack */ as[257], /* address stack */ m[65536]; /* memory */ /* the other variables are used by the various functions for misc. purposes */ I a, b, f, s, d, l; C i[1]; load_image(); for (; ip < 65536; ip++) { I opcode = m[ip]; I bundle; for (bundle = 0; bundle < 4; bundle++) { I o = (opcode >> (8*bundle)) & 0xFF; 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; } } } #if 0 #ifndef NOSTDLIB for (; sp > 0; sp -= 1) printf(" %d", ds[sp]); printf("\n"); #endif #endif } I main(I argc, C **argv) { #ifndef NOSTDLIB blocks = (argc > 1) ? argv[1] : "ilo.blocks"; rom = (argc > 2) ? argv[2] : "ilo.rom"; #else blocks = "ilo.blocks"; rom = "ilo.rom"; #endif execute(); return 0; }