shithub: scc

ref: 44f728861fa35ba070e36bb60c2694e7e979a37f
dir: /src/cmd/as/target/x86/ins.c/

View raw version
#include <stdlib.h>
#include <string.h>

#include <scc/scc.h>

#include "../../as.h"
#include "proc.h"

#define addrbyte(mod, reg, rm) ((mod) << 6 | (reg) << 3 | (rm))

/*
 * This implementation is based in:
 *	- x86 Opcode Structure and Instruction Overview - Fraunhofer-Institut
 *        fÜr kommunikation, informationsverarbeitung und ergonomie fkie.
 *	- Intel® 64 and IA-32 Architectures Software Developer’s Manual.
 *	- Encoding Real x86 Instructions - CIS-77 lectures.
 */
enum addr_mode {
	MEM_MODE   = 0,
	MEM8_MODE  = 1,
	MEM16_MODE = 2,
	REG_MODE   = 3,
};

static int
getclass(Node *np)
{
	if (np->addr != AREG)
		return 0;

	switch (np->sym->value) {
	case AREG_AL:
	case AREG_AH:
	case AREG_BL:
	case AREG_BH:
	case AREG_CL:
	case AREG_CH:
	case AREG_DL:
	case AREG_DH:
		return R8CLASS;

	case AREG_AX:
	case AREG_BX:
	case AREG_CX:
	case AREG_DX:
	case AREG_DI:
	case AREG_SI:
	case AREG_SP:
	case AREG_BP:
		return R16CLASS;

	case AREG_CS:
	case AREG_DS:
	case AREG_SS:
	case AREG_ES:
	case AREG_FS:
	case AREG_GS:

	case AREG_EFLAGS:
	case AREG_CF:
	case AREG_PF:
	case AREG_AF:
	case AREG_ZF:
	case AREG_SF:
	case AREG_TF:
	case AREG_IF:
	case AREG_DF:
	case AREG_OF:
	case AREG_IOPL:
	case AREG_NT:
	case AREG_RF:
	case AREG_VM:
	case AREG_AC:
	case AREG_VIF:
	case AREG_VIP:
	case AREG_ID:

	case AREG_EAX:
	case AREG_RAX:

	case AREG_EBX:
	case AREG_RBX:

	case AREG_ECX:
	case AREG_RCX:

	case AREG_EDX:
	case AREG_RDX:

	case AREG_SIL:
	case AREG_ESI:
	case AREG_RSI:
	case AREG_DIL:
	case AREG_EDI:
	case AREG_RDI:

	case AREG_SPL:
	case AREG_ESP:
	case AREG_RSP:

	case AREG_BPL:
	case AREG_EBP:
	case AREG_RBP:

	case AREG_R0:
	case AREG_MM0:
	case AREG_R1:
	case AREG_MM1:
	case AREG_R2:
	case AREG_MM2:
	case AREG_R3:
	case AREG_MM3:
	case AREG_R4:
	case AREG_MM4:
	case AREG_R5:
	case AREG_MM5:
	case AREG_R6:
	case AREG_MM6:
	case AREG_R7:
	case AREG_MM7:

	case AREG_R8:
	case AREG_R8L:
	case AREG_R8W:
	case AREG_R9:
	case AREG_R9L:
	case AREG_R9W:
	case AREG_R10:
	case AREG_R10L:
	case AREG_R10W:
	case AREG_R11:
	case AREG_R11L:
	case AREG_R11W:
	case AREG_R12:
	case AREG_R12L:
	case AREG_R12W:
	case AREG_R13:
	case AREG_R13L:
	case AREG_R13W:
	case AREG_R14:
	case AREG_R14L:
	case AREG_R14W:
	case AREG_R15:
	case AREG_R15L:
	case AREG_R15W:

	case AREG_XMM0:
	case AREG_XMM1:
	case AREG_XMM2:
	case AREG_XMM3:
	case AREG_XMM4:
	case AREG_XMM5:
	case AREG_XMM6:
	case AREG_XMM7:
	case AREG_XMM8:
	case AREG_XMM9:
	case AREG_XMM10:
	case AREG_XMM11:
	case AREG_XMM12:
	case AREG_XMM13:
	case AREG_XMM14:
	case AREG_XMM15:

	case AREG_YMM0:
	case AREG_YMM1:
	case AREG_YMM2:
	case AREG_YMM3:
	case AREG_YMM4:
	case AREG_YMM5:
	case AREG_YMM6:
	case AREG_YMM7:
	case AREG_YMM8:
	case AREG_YMM9:
	case AREG_YMM10:
	case AREG_YMM11:
	case AREG_YMM12:
	case AREG_YMM13:
	case AREG_YMM14:
	case AREG_YMM15:

	case AREG_MXCSR:
		return 0;
	default:
		abort();
	}
}

int
match(Op *op, Node **args)
{
	unsigned char *p;
	int arg, class, rep, opt;
	Node *np;

	if (!op->args)
		return args == NULL;

	opt = rep = 0;
	for (p = op->args; arg = *p; ++p) {
		if (rep)
			--p;
		if ((np = *args++) == NULL)
			return (rep|opt) != 0;

		switch (arg) {
		case AOPT:
			opt = 1;
			break;
		case AREP:
			rep = 1;
			break;
		case AREG_R8CLASS:
			class = R8CLASS;
			goto check_class;
		case AREG_R16CLASS:
			class = R16CLASS;
		check_class:
			if ((getclass(np) & class) == 0)
				return 0;
			break;
		case AIMM8:
		case AIMM16:
		case AIMM32:
		case AIMM64:
			if (np->addr != AIMM)
				return 0;
			if (toobig(np, arg))
				error("overflow in immediate operand");
			break;
		case ASYM:
			if (np->addr != AIMM || np->op != IDEN)
				return 0;
			break;
		case ADIRECT:
		case ASTR:
			if (np->addr != arg)
				return 0;
			break;
		default:
			abort();
		}
	}

	return *args == NULL;
}

Node *
moperand(void)
{
}

static int
reg8toint(Node *np)
{
	switch (np->sym->value) {
	case AREG_AL: return 0;
	case AREG_CL: return 1;
	case AREG_DL: return 2;
	case AREG_BL: return 3;
	case AREG_AH: return 4;
	case AREG_CH: return 5;
	case AREG_DH: return 6;
	case AREG_BH: return 7;
	default:      abort();
	}
}

static int
reg16toint(Node *np)
{
	switch (np->sym->value) {
	case AREG_AX: return 0;
	case AREG_CX: return 1;
	case AREG_DX: return 2;
	case AREG_BX: return 3;
	case AREG_SP: return 4;
	case AREG_BP: return 5;
	case AREG_SI: return 6;
	case AREG_DI: return 7;
	default:	abort();
	}
}

static int
reg32toint(Node *np)
{
	switch (np->sym->value) {
	case AREG_EAX: return 0;
	case AREG_ECX: return 1;
	case AREG_EDX: return 2;
	case AREG_EBX: return 3;
	case AREG_ESP: return 4;
	case AREG_EBP: return 5;
	case AREG_ESI: return 6;
	case AREG_EDI: return 7;
	default:	abort();
	}
}

void
reg8_reg8(Op *op, Node **args)
{
	int src, dst;
	char buf[op->size];

	src = reg8toint(args[0]);
	dst = reg8toint(args[1]);
	memcpy(buf, op->bytes, op->size - 1);
	buf[op->size - 1] = addrbyte(REG_MODE, src, dst);
	emit(buf, op->size);
}

void
imm8_reg8(Op *op, Node **args)
{
	int src, dst;
	char buf[op->size];

	src = (*args)->sym->value;
	dst = reg8toint(args[1]);
	memcpy(buf, op->bytes, op->size - 2);
	buf[op->size - 2] = addrbyte(REG_MODE, 0, dst);
	buf[op->size - 1] = src;
	emit(buf, op->size);
}


void
reg16_reg16(Op *op, Node **args)
{
	int src, dst;
	char buf[op->size];

	src = reg16toint(args[0]);
	dst = reg16toint(args[1]);
	memcpy(buf, op->bytes, op->size - 1);
	buf[op->size - 1] = addrbyte(REG_MODE, src, dst);
	emit(buf, op->size);
}


void
reg32_reg32(Op *op, Node **args)
{
	int src, dst;
	char buf[op->size];

	src = reg32toint(args[0]);
	dst = reg32toint(args[1]);
	memcpy(buf, op->bytes, op->size - 1);
	buf[op->size - 1] = addrbyte(REG_MODE, src, dst);
	emit(buf, op->size);
}