yo-compiler/vm/vm.c
2024-11-04 02:11:36 +09:00

283 lines
4.3 KiB
C

#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();
}