ref: 7b65afc1ad13f3859eca6eadaa2c45d864320304
dir: /opcodes.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "dat.h"
#include "fns.h"
char *regnames[Reg_max] = {
[RegIp] = "ip",
[RegMod] = "mod",
[RegFunc] = "func",
[RegSp] = "sp",
[RegFp] = "fp",
[RegX] = "x",
[RegY] = "y",
[RegF] = "f",
[RegG] = "g",
[RegR] = "r",
[RegT] = "t",
};
OpcodeSpec optab[O_max] = {
[Onop] = {"nop", 0},
[Oexit] = {"exit", 0},
[Ocall] = {"call", 1},
[Oreturn] = {"return", 0},
[Omov] = {"mov", 2},
[Olocals] = {"locals", 1},
[Oscalnum] = {"scalnum", 2},
[Odisplay] = {"display", 1},
};
void
encodeinstr(ParsedInstr *p, Label *labels, uvlong nlabels)
{
/* Encoding:
* 1 byte opcode
* optional 1 byte argument info
* optional 1st arg
* optional 2nd arg
*/
u8int *d = p->buf;
*d++ = p->opcode;
if(optab[p->opcode].args > 0){
u8int info = 0;
info |= (p->args[0].tag & 0xF) << 0;
info |= (p->args[1].tag & 0xF) << 4;
*d++ = info;
int l;
for(int i = 0; i < optab[p->opcode].args; i++){
OpArg arg = p->args[i];
switch(arg.tag){
case OAlabel:
for(l = 0; l < nlabels; l++){
if(strcmp(arg.cp, labels[l].name) == 0){
d += write8u(d, labels[l].coffset);
break;
}
}
if(l == nlabels)
sysfatal("Undefined label %s", arg.cp);
break;
case OAreg:
d += write1u(d, arg.u64);
break;
case OAlocal1:
d += write1u(d, arg.u64);
break;
case OAlocal2:
d += write2u(d, arg.u64);
break;
case OAlocal4:
d += write4u(d, arg.u64);
break;
case OAlocal8:
d += write8u(d, arg.u64);
break;
case OAnum1:
d += write1s(d, arg.s64);
break;
case OAnum2:
d += write2s(d, arg.s64);
break;
case OAnum4:
d += write4s(d, arg.s64);
break;
case OAnum8:
d += write8s(d, arg.s64);
break;
default:
sysfatal("missing case in encodeinstr: %d", p->args[i].tag);
}
}
}
p->len = d - p->buf;
}
void
encodelabel(ParsedInstr *p, Label *labels, uvlong nlabels)
{
int islabel = 0;
for(int i = 0; i < optab[p->opcode].args; i++){
if(p->args[i].tag == OAlabel)
islabel = 1;
}
if(islabel)
encodeinstr(p, labels, nlabels);
}
void
decodeinstr(u8int *d, ParsedInstr *p, Label *labels, uvlong nlabels)
{
u8int *c = d;
int fast = (labels == nil);
p->opcode = *c++;
int args = optab[p->opcode].args;
if(args){
u8int info = *c++;
for(int i = 0; i < args; i++){
p->args[i].tag = info & 0xF;
info = info >> 4;
u64int u64;
int l;
switch(p->args[i].tag){
case OAlabel:
u64 = read8u(c);
c += 8;
if(fast){
p->args[i].u64 = u64;
}else{
for(l = 0; l < nlabels; l++){
if(labels[l].coffset == u64)
break;
}
if(l == nlabels)
sysfatal("couldn't find label at offset %ulld", u64);
p->args[i].cp = strdup(labels[l].name);
}
break;
case OAreg:
p->args[i].u64 = read1u(c);
c += 1;
break;
case OAlocal1:
p->args[i].u64 = read1u(c);
c += 1;
break;
case OAlocal2:
p->args[i].u64 = read2u(c);
c += 2;
break;
case OAlocal4:
p->args[i].u64 = read4u(c);
c += 4;
break;
case OAlocal8:
p->args[i].u64 = read8u(c);
c += 8;
break;
case OAnum1:
p->args[i].s64 = read1s(c);
c += 1;
break;
case OAnum2:
p->args[i].s64 = read2s(c);
c += 2;
break;
case OAnum4:
p->args[i].s64 = read4s(c);
c += 4;
break;
case OAnum8:
p->args[i].s64 = read8s(c);
c += 8;
break;
default:
sysfatal("missing case in decodeinstr: %d", p->args[i].tag);
}
}
}
p->len = c - d;
if(!fast)
memcpy(p->buf, d, p->len);
}