#include "vm.h" static u8 end[1024]; u32 ninst; Inst *inst; REG R; #define OP(fn) void fn(void) #define B(r) *((i8*)(R.r)) #define F(r) ((WORD*)(R.r)) #define A(r) ((Array*)(R.r)) #define P(r) *((WORD**)(R.r)) #define W(r) *((WORD*)(R.r)) #define T(r) *((void**)(R.r)) #define JMP(r) R.PC = *(Inst**)(R.r) void printbin(u8 x) { u8 arr[8] = { [0] = x & 128, [1] = x & 64, [2] = x & 32, [3] = x & 16, [4] = x & 8, [5] = x & 4, [6] = x & 2, [7] = x & 1, }; printf("op %x %d: ",x, x); printf("%d%d ", arr[0]!=0,arr[1]!=0); printf("%d%d%d ", arr[2]!=0,arr[3]!=0,arr[4]!=0); printf("%d%d%d\n", arr[5]!=0,arr[6]!=0,arr[7]!=0); } u8 rd1(FILE *f) { u8 v = 0; assert(fread(&v, 1, 1, f) == 1); return v; } u16 rd2(FILE *f) { u16 v = 0; assert(fread(&v, 1, 2, f) == 2); return v; } WORD rd4(FILE *f) { i32 v = 0; assert(fread(&v, 1, 4, f) == 4); return v; } void newstack(int sz) { Stack *s = calloc(1, sizeof(s)+sz); R.EX = s->stack; R.TS = s->stack + sz; R.SP = s->fu + sz; R.FP = s->fu; } void initprog(int ss) { newstack(ss); WORD *p = (WORD*)&R.FP[32]; *p = (WORD)&end; } OP(nop) {} OP(jmp) {JMP(d);} OP(lea) {W(d) = (WORD)R.s;} OP(movw) {W(d) = W(s);} OP(movm) {memmove(R.d,R.s,W(m));} OP(addw) {W(d) = W(m) + W(s);} OP(subw) {W(d) = W(m) - W(s);} OP(mulw) {W(d) = W(m) * W(s);} OP(beqw) {if(W(s) == W(m)) JMP(d);} OP(bneqw) {if(W(s) != W(m)) JMP(d);} OP(ltw) {W(d) = (W(s) < W(m));} OP(leqw) {W(d) = (W(s) <= W(m));} OP(eqw) {W(d) = (W(s) == W(m));} OP(neqw) {W(d) = (W(s) != W(m));} OP(frame){ Stack *s; Frame *f; int sz; sz = W(s); s = calloc(1, sizeof(Stack) + sz); s->sz = sz; s->SP = R.SP; s->TS = R.TS; s->EX = R.EX; f = s->fr; R.s = f; R.EX = s; R.TS = s->stack + sizeof(Stack)+sz; R.SP = s->fu + sz; T(d) = R.s; } OP(call){ Frame *f = T(s); f->lr = R.PC; f->fp = R.FP; R.FP = (u8*)f; JMP(d); } OP(ret) { Frame *f = (Frame*)R.FP; R.FP = f->fp; if(R.FP == NULL){ printf("result %ld\n", W(d)); WORD *p = end; exit(0); } R.SP = (u8*)f; R.PC = f->lr; u8 *x = (u8*)f-IBY2WD*4; Stack *s = x; R.SP = s->SP; R.TS = s->TS; R.EX = s->EX; free(s); } OP(len){ Array *a = A(s); W(d) = a->len; } OP(array){ WORD *s = R.s; WORD m = W(m); WORD *d = R.d; if(m){ *d = (WORD)&d[ArrHead/IBY2WD]; memcpy(d+1, s+1, m-IBY2WD); }else assert(0); } OP(slice){ WORD s1 = W(s); WORD s2 = W(m); Array *a = A(d); if(s2 == -1) s2 = a->len; assert(s1 >= 0 && s1 < a->len); assert(s2 >= 0 && s2 <= a->len); assert(s1 < s2); Array d = *a; d.len = s2 - s1; d.cap = s2 - s1; d.arr = a->arr + s1*a->size; *a = d; } static void (*optab[])(void) = { [INOP] = nop, [ILEA] = lea, [IFRAME] = frame, [ICALL] = call, [IJMP] = jmp, [IRET] = ret, [ILEN] = len, [ISLICE] = slice, [IARRAY] = array, [IADDW] = addw, [ISUBW] = subw, [IMOVW] = movw, [IMULW] = mulw, [IMOVM] = movm, [IBEQW] = beqw, [IBNEQW] = bneqw, [IEQW] = eqw, [INEQW] = neqw, [ILEQW] = leqw, [ILTW] = ltw, }; void xec(void) { while(1){ Inst in = *R.PC; u8 op = in.op; if(dec[in.add] == 0){ printbin(in.add); exit(1); } if(optab[in.op]==0){ printf("op 0X%x %d\n", in.op, in.op); exit(1); } dec[in.add](); R.PC++; optab[op](); } } void bpatch(Inst *i) { static int tab[IEND] = { [ICALL]=1,[IBEQW]=1,[IBNEQW]=1,[IJMP]=1, }; if(tab[i->op] == 0) return; assert(i->d.imm >= 0 && i->d.imm < ninst); i->d.imm = (WORD)&inst[i->d.imm]; return; } void rdinst(FILE *f, Inst *in) { in->op = rd1(f); assert(in->op != EOF); in->add = rd1(f); switch(in->add & ARM) { case AXIMM: case AXINF: case AXINM: in->reg = rd4(f); break; } switch(UXSRC(in->add)) { case SRC(AFP): case SRC(AMP): case SRC(AIMM): in->s.ind = rd4(f); break; case SRC(AIND|AFP): case SRC(AIND|AMP): in->s.f = rd2(f); in->s.s = rd2(f); break; } switch(UXDST(in->add)) { case DST(AFP): case DST(AMP): in->d.ind = rd4(f); break; case DST(AIMM): in->d.ind = rd4(f); bpatch(in); break; case DST(AIND|AFP): case DST(AIND|AMP): in->d.f = rd2(f); in->d.s = rd2(f); break; } } void load(char *fname) { FILE *f = fopen(fname, "r"); assert(f != 0); initprog(1024); ninst = rd4(f); inst = calloc(sizeof(Inst), ninst); for(u32 i = 0; i < ninst; ++i){ rdinst(f, inst+i); } R.PC = inst; fclose(f); } int main(int argc, char *argv[]) { load(argv[1]); xec(); }