183 lines
4.9 KiB
C
183 lines
4.9 KiB
C
/***************************************************************
|
|
crc's _ _
|
|
(_) | ___
|
|
| | |/ _ \ a tiny virtual computer
|
|
| | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
|
|
|_|_|\___/ ilo.c (c) charles childers
|
|
**************************************************************/
|
|
|
|
/* cc -lpthread ilo-pthread.c -o ilo */
|
|
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#include <stdlib.h>
|
|
|
|
int ip, sp, rp, data[33], address[257], memory[65536];
|
|
int a, b, t, fp, block, buffer, src, dest, len;
|
|
char *blocks, *rom, iob[2];
|
|
|
|
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
#define T data[sp]
|
|
#define N data[sp-1]
|
|
#define R address[rp]
|
|
#define V void
|
|
|
|
int pop() { return data[(--sp) + 1]; }
|
|
V push(int value) { data[++sp] = value; }
|
|
|
|
V prepare_vm() { ip = sp = rp = 0; }
|
|
|
|
V load_image() {
|
|
fp = open(rom, O_RDONLY, 0666);
|
|
if (!fp) { return; };
|
|
read(fp, &memory, 65536 * 4);
|
|
close(fp);
|
|
prepare_vm();
|
|
}
|
|
|
|
V save_image() {
|
|
fp = open(rom, O_WRONLY, 0666);
|
|
write(fp, &memory, 65536 * 4);
|
|
close(fp);
|
|
}
|
|
|
|
V read_block() {
|
|
buffer = pop();
|
|
block = pop();
|
|
fp = open(blocks, O_RDONLY, 0666);
|
|
lseek(fp, 4096 * block, SEEK_SET);
|
|
read(fp, memory + buffer, 4096);
|
|
close(fp);
|
|
}
|
|
|
|
V write_block() {
|
|
buffer = pop();
|
|
block = pop();
|
|
fp = open(blocks, O_WRONLY, 0666);
|
|
lseek(fp, 4096 * block, SEEK_SET);
|
|
write(fp, memory + buffer, 4096);
|
|
close(fp);
|
|
}
|
|
|
|
V li() { ip++; push(memory[ip]); }
|
|
V du() { push(T); }
|
|
V dr() { data[sp] = 0; sp--; }
|
|
V sw() { a = T; T = N; N = a; }
|
|
V pu() { rp++; R = pop(); }
|
|
V po() { push(R); rp--; }
|
|
V ju() { ip = pop() - 1; }
|
|
V ca() { rp++; R = ip; ip = pop() - 1; }
|
|
V cc() { t = pop(); if (pop()) { rp++; R = ip; ip = t - 1; } }
|
|
V cj() { t = pop(); if (pop()) { ip = t - 1; } }
|
|
V re() { ip = R; rp--; }
|
|
V eq() { N = (N == T) ? -1 : 0; sp--; }
|
|
V ne() { N = (N != T) ? -1 : 0; sp--; }
|
|
V lt() { N = (N < T) ? -1 : 0; sp--; }
|
|
V gt() { N = (N > T) ? -1 : 0; sp--; }
|
|
V fe() { T = memory[T]; }
|
|
V st() { memory[T] = N; sp--; sp--; }
|
|
V ad() { N += T; sp--; }
|
|
V su() { N -= T; sp--; }
|
|
V mu() { N *= T; sp--; }
|
|
V di() { a = T; b = N; T = b / a; N = b % a; }
|
|
V an() { N = T & N; sp--; }
|
|
V or() { N = T | N; sp--; }
|
|
V xo() { N = T ^ N; sp--; }
|
|
V sl() { N = N << T; sp--; }
|
|
V sr() { N = N >> T; sp--; }
|
|
V cp() { len = pop(); dest = pop(); src = pop(); push(-1);
|
|
while (len) {
|
|
if (memory[dest] != memory[src]) T = 0;
|
|
len -= 1; src += 1; dest += 1;
|
|
}
|
|
}
|
|
V cy() { len = pop(); dest = pop(); src = pop();
|
|
while (len) {
|
|
memory[dest] = memory[src];
|
|
len -= 1; src += 1; dest += 1;
|
|
}
|
|
}
|
|
V io() {
|
|
switch (pop()) {
|
|
case 0:
|
|
iob[0] = pop(); write(1, &iob, 1);
|
|
break;
|
|
case 1: push(getchar()); break;
|
|
case 2: read_block(); break;
|
|
case 3: write_block(); break;
|
|
case 4: save_image(); break;
|
|
case 5: load_image(); ip = -1; break;
|
|
case 6: ip = 65536; exit(0); break;
|
|
case 7: push(sp); push(rp); break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
V process(int 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;
|
|
}
|
|
}
|
|
|
|
V process_bundle(int opcode) {
|
|
process(opcode & 0xFF);
|
|
process((opcode >> 8) & 0xFF);
|
|
process((opcode >> 16) & 0xFF);
|
|
process((opcode >> 24) & 0xFF);
|
|
}
|
|
|
|
V *execute(V *unused) {
|
|
while (ip < 65536) {
|
|
pthread_mutex_lock(&mutex);
|
|
process_bundle(memory[ip]);
|
|
ip++;
|
|
pthread_mutex_unlock(&mutex);
|
|
pthread_yield();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
V *guard(V *unused) {
|
|
while (1) {
|
|
if (sp < 0) { printf("E: data stack underflow\n"); exit(1); }
|
|
if (sp > 31) { printf("E: data stack overflow\n"); exit(2); }
|
|
if (rp < 0) { printf("E: address stack underflow\n"); exit(3); }
|
|
if (rp > 255) { printf("E: address stack overflow\n"); exit(4); }
|
|
pthread_yield();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
blocks = (argc > 1) ? argv[1] : "ilo.blocks";
|
|
rom = (argc > 2) ? argv[2] : "ilo.rom";
|
|
load_image();
|
|
|
|
pthread_t cpu, stack_guard;
|
|
int e1 = pthread_create(&cpu, NULL, execute, NULL);
|
|
int e2 = pthread_create(&stack_guard, NULL, guard, NULL);
|
|
// while(1) {pthread_yield();};
|
|
|
|
if (!e2) {
|
|
pthread_join(stack_guard, NULL);
|
|
pthread_join(cpu, NULL);
|
|
}
|
|
}
|