// A VM that runs the Sieve of Eratosthenes. int main() { // RAM FOR VM int run,ip; int opcode,b,c,d,j; int reg[256]; int ram[10000]; // WORK SPACE int i,found; char buf[256]; // HARDCODE SIEVE PROGRAM struct PROG SIEVE[] = { /* Constants and Parameters */ {LOADIMMEDIATE,'A', 1}, {LOADIMMEDIATE,'Z', 0}, {LOADIMMEDIATE,'N', 100}, /* Make all numbers between 2 and n valid. */ {LOADIMMEDIATE,'I', 2}, {LABEL,1}, {GT, 2, 'I', 'N'}, {STOREINDIRECT,'I', 'A'}, {ADD, 'I', 'A'}, {JMP,1}, /* Go over all p values between 2 and n. */ {LABEL,2}, {LOADIMMEDIATE,'I', 2}, {LABEL,3}, {GT, 4, 'I', 'N'}, /* If p is still valid, then it is a prime - print it. */ {LOADINDIRECT, 'F', 'I'}, {NE, 5, 'F', 'A'}, {PRINT, 'I'}, /* Delete all numbers: p, 2p, 3p, ... until n by making them invalid. */ {LOADREGISTER, 'K', 'I'}, {LABEL,6}, {GT, 7, 'K', 'N'}, {STOREINDIRECT,'K', 'Z'}, {ADD,'K','I'}, {JMP, 6}, {LABEL,7}, {LABEL,5}, {ADD, 'I', 'A'}, {JMP, 3}, {LABEL,4}, {HALT} }; // HARDCODED PROGRAM THAT DOES AN EMPTY LOOP A MILLION TIMES struct PROG MILLIONLOOP[] = { {LOADIMMEDIATE,'A', 1,0}, // A = 1 {LOADIMMEDIATE,'Z', 0,0}, // Z = 0 {LOADIMMEDIATE,'S',1000000,0}, // S = 1000000 {LOADIMMEDIATE,'I', 0,0}, // I = 0 {LABEL,1,0,0}, // LABEL 1 {GT, 2, 'I', 'S'}, // IF I > S GOTO LABEL 2 {ADD, 'I', 'A',0}, // I = I + A {JMP, 1,0,0}, // GOTO LABEL 1 {LABEL,2,0,0}, // LABEL 2 {HALT, 0,0,0} // HALT }; struct PROG *p=NULL; // POINT TO PROGRAM TO RUN p = SIEVE; // LINKER ip = 0; run = 1; while ( run ) { // FETCH opcode = p[ip].a; b = p[ip].b; c = p[ip].c; d = p[ip].d; if (opcode == HALT) break; if (opcode >= NE && opcode <= JMP) { i = 0; found = 0; while( p[i].a ) { if ( p[i].a == LABEL && p[i].b == p[ip].b) { p[ip].j = i; found = 1; break; } i++; } if (found == 0) { printf("Cannot Link: #%04d: %d %d %d %d\n",ip,p[ip].a,p[ip].b,p[ip].c,p[ip].d); return 0; } } ip++; } // DISASSEMBLER printf("START\n"); ip = 0; run = 1; while ( run ) { // FETCH opcode = p[ip].a; b = p[ip].b; c = p[ip].c; d = p[ip].d; // NEXT INSTRUCTION ip++; // DECODE AND DISASSEMBLE switch(opcode) { // OPERAND LABEL case LABEL: printf("%s %d\n",defines[opcode],b); break; case JMP: printf("\t"); printf("%s %d\n",defines[opcode],b); break; // OPERAND LABEL REGISTER REGISTER case LT: case LE: case EQ: case GE: case GT: case NE: printf("\t"); sprintf(buf,"%s %d",defines[opcode],b); printf("%-16s\t%c\t%c\n",buf,c,d); break; // OPERAND case HALT: run = 0; case NOP: printf("\t"); printf("%-16s\n",defines[opcode]); break; // OPERAND INTEGER case LOADIMMEDIATE: printf("\t"); printf("%-16s\t%c\t%d\n",defines[opcode],b,c); break; // OPERAND REG case PRINT: printf("\t"); printf("%-16s\t%c\n",defines[opcode],b); break; // OPERAND REG REG case ADD: case LOADREGISTER: case STOREINDIRECT: case LOADINDIRECT: printf("\t"); printf("%-16s\t%c\t%c\n",defines[opcode],b,c); break; // UNHANDLED default: printf("xx\t"); printf("%-16s\t%d\t%d\t%d\n",defines[opcode],b,c,d); break; } } printf("\n"); // VIRTUAL MACHINE // PROGRAM EXECUTION printf("OUTPUT\n"); ip = 0; run = 1; while ( run ) { // FETCH opcode = p[ip].a; b = p[ip].b; c = p[ip].c; d = p[ip].d; j = p[ip].j; // NEXT INSTRUCTION ip++; // DECODE AND EXECUTE switch(opcode) { case HALT: run = 0; break; case NOP: case LABEL: break; case PRINT: printf(" %d",reg[b]); break; case LOADREGISTER: reg[b] = reg[c]; break; case LOADIMMEDIATE: reg[b] = c; break; case LOADABSOLUTE: reg[b] = ram[c]; break; case LOADINDIRECT: reg[b] = ram[reg[c]]; break; case STOREABSOLUTE: ram[b] = reg[c]; break; case STOREINDIRECT: ram[reg[b]] = reg[c]; break; case ADD: reg[b] += reg[c]; break; case JMP: ip = j; break; case LT: if (reg[c] < reg[d] ) ip = j; break; case LE: if (reg[c] <= reg[d] ) ip = j; break; case EQ: if (reg[c] == reg[d] ) ip = j; break; case GE: if (reg[c] >= reg[d] ) ip = j; break; case GT: if (reg[c] > reg[d] ) ip = j; break; case NE: if (reg[c] != reg[d] ) ip = j; break; default: printf("illegal opcode %d\n",opcode); run = 0; break; } } printf("\n"); return 0; }