shithub: apl10

ref: 7b65afc1ad13f3859eca6eadaa2c45d864320304
dir: /opcodes.c/

View raw version
#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);
}