ref: 7b65afc1ad13f3859eca6eadaa2c45d864320304
dir: /vm.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "dat.h"
#include "fns.h"
static VM *vm;
static void _Noreturn
usage(void)
{
fprint(2, "usage: apl/vm objfile\n");
exits("usage");
}
static void
initvm(void)
{
vm = mallocz(sizeof(VM), 1);
}
static void
loadmod(char *file)
{
Biobuf *b = Bopen(file, OREAD);
if(b == nil)
sysfatal("open: %r");
Module *m = mallocz(sizeof(Module), 1);
for(int n = 0; n < nelem(objparts); n++)
objparts[n].read(m, b, 0);
Bterm(b);
vm->nmods++;
vm->mods = realloc(vm->mods, vm->nmods * sizeof(*vm->mods));
vm->mods[vm->nmods-1] = m;
}
static void
stackgrow(uvlong n)
{
vm->regs[RegSp].u64 += n;
if(vm->regs[RegSp].u64 > nelem(vm->stack))
sysfatal("APL stack overflow");
}
static uvlong
findlabel(char *name)
{
Module *m = vm->mods[vm->regs[RegMod].u64];
for(int i = 0; i < m->nlabels; i++){
if(strcmp(name, m->labels[i].name) == 0)
return m->labels[i].coffset;
}
sysfatal("Failed to find label %s", name);
}
static Word *
getaddr(OpArg *a)
{
switch(a->tag){
case OAlabel:
case OAnum1:
case OAnum2:
case OAnum4:
case OAnum8:
return (Word*)&a->u64;
case OAreg:
return &vm->regs[a->u64];
case OAlocal1:
case OAlocal2:
case OAlocal4:
case OAlocal8:
if((a->u64+1) > (vm->regs[RegSp].u64 - vm->regs[RegFp].u64))
sysfatal("Use of unallocated local: %%%ulld\n", a->u64);
return &vm->stack[vm->regs[RegFp].u64+a->u64];
default:
sysfatal("unhandled case in getaddr: %d", a->tag);
}
}
static void
interpret(void)
{
ParsedInstr instr;
vm->regs[RegMod].u64 = 0;
u8int *code = vm->mods[vm->regs[RegMod].u64]->code;
vm->regs[RegIp].u64 = findlabel("main");
Word *src, *dst;
u64int sp;
for(;;){
decodeinstr(code + vm->regs[RegIp].u64, &instr, nil, 0);
vm->regs[RegIp].u64 += instr.len;
switch(instr.opcode){
case Onop:
break;
case Oexit:
exits(nil);
break;
case Ocall:
sp = vm->regs[RegSp].u64;
stackgrow(Reg_save);
memcpy(vm->stack+sp, vm->regs, Reg_save * sizeof(*vm->regs));
vm->regs[RegIp].u64 = instr.args[0].u64;
vm->regs[RegFp].u64 = vm->regs[RegSp].u64;
break;
case Oreturn:
if(vm->regs[RegFp].u64 == 0)
sysfatal("APL stack underflow");
sp = vm->regs[RegFp].u64 - Reg_save;
memcpy(vm->regs, vm->stack + sp, Reg_save * sizeof(*vm->regs));
vm->regs[RegSp].u64 = sp;
break;
case Omov:
src = getaddr(&instr.args[0]);
dst = getaddr(&instr.args[1]);
memcpy(dst, src, sizeof(Word));
break;
case Olocals:
stackgrow(instr.args[0].s64);
break;
case Oscalnum:
case Odisplay:
default:
sysfatal("missing case in interpret: %s", optab[instr.opcode].name);
}
}
}
void
main(int argc, char *argv[])
{
char *objfile;
ARGBEGIN{
default:
usage();
}ARGEND;
if(argc != 1)
usage();
objfile = *argv;
initvm();
loadmod(objfile);
interpret();
}