do not edit — generated by btf.
git.druid.rocksindexdruid520jurysrc/isa.c

src/isa.c


/* isa.c: encoding tables and the one decoder everybody uses. */
 
#include <ctype.h>
#include <stdio.h>
#include <string.h>
 
#include "isa.h"
 
/* each table is indexed by the op byte's high nibble. unlisted slots
 * are zero, so name == NULL, which decodes as "bad opcode." */
 
static const opdef NORMAL[16] =
{
	/* 0 */ {"HALT", FMT_NONE, OP_HALT},
	/* 1 */ {"LDI",  FMT_IR,   OP_LDI},
	/* 2 */ {"ADD",  FMT_IR,   OP_ADD},
	/* 3 */ {"SUB",  FMT_IR,   OP_SUB},
	/* 4 */ {"AND",  FMT_IR,   OP_AND},
	/* 5 */ {"OR",   FMT_IR,   OP_OR},
	/* 6 */ {"XOR",  FMT_IR,   OP_XOR},
	/* 7 */ {"CMP",  FMT_IR,   OP_CMP},
	/* 8 */ {"JMP",  FMT_CA,   OP_JCC},   /* name comes from CONDS */
	/* 9 */ {"LD",   FMT_AR,   OP_LD},
	/* a */ {"ST",   FMT_RA,   OP_ST},
	/* b */ {"CALL", FMT_A,    OP_CALL},
	/* c */ {"MODE", FMT_MODE, OP_MODE},
	/* d */ {"PUSH", FMT_R,    OP_PUSH},
	/* e */ {"POP",  FMT_R,    OP_POP},
	/* f */ {"RET",  FMT_NONE, OP_RET}
};
 
static const opdef MODE1[16] =
{
	/* 0 */ {"LDR",   FMT_PR, OP_LDR},
	/* 1 */ {"STR",   FMT_RP, OP_STR},
	/* 2 */ {"JMPR",  FMT_P,  OP_JMPR},
	/* 3 */ {"CALLR", FMT_P,  OP_CALLR},
	/* 4 */ {"INCP",  FMT_P,  OP_INCP},
	/* 5 */ {"DECP",  FMT_P,  OP_DECP}
};
 
static const opdef MODE2[16] =
{
	/* 0 */ {"SHL",  FMT_R, OP_SHL},
	/* 1 */ {"SHR",  FMT_R, OP_SHR},
	/* 2 */ {"ROL",  FMT_R, OP_ROL},
	/* 3 */ {"ROR",  FMT_R, OP_ROR},
	/* 4 */ {"NOT",  FMT_R, OP_NOT},
	/* 5 */ {"NEG",  FMT_R, OP_NEG},
	/* 6 */ {"INC",  FMT_R, OP_INC},
	/* 7 */ {"DEC",  FMT_R, OP_DEC},
	/* 8 */ {"OUT",  FMT_R, OP_OUT},
	/* 9 */ {"OUTC", FMT_R, OP_OUTC}
};
 
static const opdef MODE3[16] =
{
	/* 0 */ {"MOV",  FMT_RR, OP_MOV},
	/* 1 */ {"SWAP", FMT_RR, OP_SWAP},
	/* 2 */ {"ADDR", FMT_RR, OP_ADDR},
	/* 3 */ {"ADCR", FMT_RR, OP_ADCR},
	/* 4 */ {"SUBR", FMT_RR, OP_SUBR},
	/* 5 */ {"SBCR", FMT_RR, OP_SBCR},
	/* 6 */ {"CMPR", FMT_RR, OP_CMPR},
	/* 7 */ {"ANDR", FMT_RR, OP_ANDR},
	/* 8 */ {"ORR",  FMT_RR, OP_ORR},
	/* 9 */ {"XORR", FMT_RR, OP_XORR}
};
 
static const opdef MODE4[16] =
{
	/* 0 */ {"ADC", FMT_IR, OP_ADC},
	/* 1 */ {"SBC", FMT_IR, OP_SBC},
	/* 2 */ {"TST", FMT_IR, OP_TST}
};
 
const opdef* MODES[NMODES] = {NORMAL, MODE1, MODE2, MODE3, MODE4};
 
const char* CONDS[NCONDS] = {"JMP", "JZ", "JNZ", "JC", "JNC", "JN", "JNN"};
 
const char* DECMSG[] =
{
	"ok.", "pc out of range.", "bad opcode.", "bad mode.", "bad register."
};
 
int
sameci(const char* a, const char* b)
{
	while(*a != '\0' && *b != '\0')
	{
		if(toupper((unsigned char)*a) != toupper((unsigned char)*b))
		{
			return 0;
		}
		a = a + 1;
		b = b + 1;
	}
	return *a == '\0' && *b == '\0';
}
 
/* bytes after the op byte */
int
fmtextra(int fmt)
{
	switch(fmt)
	{
		case FMT_IR: case FMT_P: case FMT_PR: case FMT_RP: case FMT_RR:
			return 1;
		case FMT_AR: case FMT_RA: case FMT_CA: case FMT_A:
			return 2;
		default:
			return 0;
	}
}
 
/* decode the instruction at mem[at], mem being len bytes long. fills in
 * *in and returns DEC_OK, or says why the bytes arent an instruction. */
int
isadecode(const unsigned char* mem, unsigned long len, unsigned long at, ins* in)
{
	unsigned long p = at;
	int b;
	int n;
 
	memset(in, 0, sizeof(*in));
	if(p >= len)
	{
		return DEC_SHORT;
	}
	b = mem[p];
	p = p + 1;
 
	if((b >> 4) == 0xC)
	{
		in->mode = b & 0xF;
		if(in->mode < 1 || in->mode >= NMODES)
		{
			return DEC_BADMODE;
		}
		if(p >= len)
		{
			return DEC_SHORT;
		}
		b = mem[p];
		p = p + 1;
	}
 
	in->op = (b >> 4) & 0xF;
	in->nib = b & 0xF;
	in->def = &MODES[in->mode][in->op];
	if(in->def->name == NULL || in->def->fmt == FMT_MODE)
	{
		return DEC_BADOP;
	}
 
	n = fmtextra(in->def->fmt);
	if(p + n > len)
	{
		return DEC_SHORT;
	}
 
	switch(in->def->fmt)
	{
		case FMT_R: case FMT_IR: case FMT_AR: case FMT_RA:
		case FMT_PR: case FMT_RP:
			if(in->nib >= NREGS)
			{
				return DEC_BADREG;
			}
			break;
		case FMT_CA:
			if(in->nib >= NCONDS)
			{
				return DEC_BADOP;
			}
			break;
		default:
			if(in->nib != 0)
			{
				return DEC_BADOP;
			}
			break;
	}
 
	if(n == 1)
	{
		in->val = mem[p];
		in->x = (mem[p] >> 4) & 0xF;
		in->y = mem[p] & 0xF;
	}
	if(n == 2)
	{
		in->val = ((unsigned int)mem[p] << 8) | mem[p + 1];
	}
	if(in->def->fmt == FMT_P || in->def->fmt == FMT_PR || in->def->fmt == FMT_RP ||
	   in->def->fmt == FMT_RR)
	{
		if(in->x >= NREGS || in->y >= NREGS)
		{
			return DEC_BADREG;
		}
	}
 
	in->len = (int)(p + n - at);
	return DEC_OK;
}
 
const char*
isaname(const ins* in)
{
	if(in->def->fmt == FMT_CA)
	{
		return CONDS[in->nib];
	}
	return in->def->name;
}
 
/* an instruction as asm source, asm reads this straight back in.
 * operand order here and in asm.c's parseins have to match. */
void
isafmt(const ins* in, char* buf)
{
	const char* nm = isaname(in);
 
	switch(in->def->fmt)
	{
		case FMT_R:
			sprintf(buf, "%s r%d", nm, in->nib);
			break;
		case FMT_IR:
			sprintf(buf, "%s 0x%02x, r%d", nm, in->val, in->nib);
			break;
		case FMT_AR:
			sprintf(buf, "%s 0x%04x, r%d", nm, in->val, in->nib);
			break;
		case FMT_RA:
			sprintf(buf, "%s r%d, 0x%04x", nm, in->nib, in->val);
			break;
		case FMT_CA: case FMT_A:
			sprintf(buf, "%s 0x%04x", nm, in->val);
			break;
		case FMT_P:
			sprintf(buf, "%s r%d:r%d", nm, in->x, in->y);
			break;
		case FMT_PR:
			sprintf(buf, "%s r%d:r%d, r%d", nm, in->x, in->y, in->nib);
			break;
		case FMT_RP:
			sprintf(buf, "%s r%d, r%d:r%d", nm, in->nib, in->x, in->y);
			break;
		case FMT_RR:
			/* source is the low nibble, dest the high, dest written last */
			sprintf(buf, "%s r%d, r%d", nm, in->y, in->x);
			break;
		default:
			sprintf(buf, "%s", nm);
			break;
	}
}
 
/* look a mnemonic up. MODE isnt findable, asm adds it for you. */
int
isafind(const char* name, int* mode, int* op, int* nib)
{
	int m;
	int o;
	int c;
	const opdef* d;
 
	for(m = 0; m < NMODES; m = m + 1)
	{
		for(o = 0; o < 16; o = o + 1)
		{
			d = &MODES[m][o];
			if(d->name == NULL || d->fmt == FMT_MODE)
			{
				continue;
			}
			if(d->fmt == FMT_CA)
			{
				for(c = 0; c < NCONDS; c = c + 1)
				{
					if(sameci(name, CONDS[c]) != 0)
					{
						*mode = m;
						*op = o;
						*nib = c;
						return 1;
					}
				}
				continue;
			}
			if(sameci(name, d->name) != 0)
			{
				*mode = m;
				*op = o;
				*nib = 0;
				return 1;
			}
		}
	}
	return 0;
}
powered by btf.