shithub: scc

ref: a926e8f5971ee8598fc7083ad9911da0c23fc76d
dir: /src/cmd/as/target/powerpc/ins.c/

View raw version
#include <stdlib.h>

#include <scc/scc.h>

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

/*
 * This code is derived from PowerISA_V2.06B_V2_PUBLIC document.
 * All the names used in the specification are preserved in
 * this code.
 */

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

	switch (np->sym->value) {
	case AREG_R0:
	case AREG_R1:
	case AREG_R2:
	case AREG_R3:
	case AREG_R4:
	case AREG_R5:
	case AREG_R6:
	case AREG_R7:
	case AREG_R8:
	case AREG_R9:
	case AREG_R10:
	case AREG_R11:
	case AREG_R12:
	case AREG_R13:
	case AREG_R14:
	case AREG_R15:
	case AREG_R16:
	case AREG_R17:
	case AREG_R18:
	case AREG_R19:
	case AREG_R20:
	case AREG_R21:
	case AREG_R22:
	case AREG_R23:
	case AREG_R24:
	case AREG_R25:
	case AREG_R26:
	case AREG_R27:
	case AREG_R29:
	case AREG_R30:
	case AREG_R31:
		return GPRSCLASS;
	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_GPRSCLASS:
			class = GPRSCLASS;
		check_class:
			if ((getclass(np) & class) == 0)
				return 0;
			break;
		case AIMM2:
		case AIMM5:
		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)
{
	abort();
}

static void
emit_packed(unsigned long ins)
{
	char buff[4];

	if (endian == BIG_ENDIAN) {
		buff[0] = ins >> 24;
		buff[1] = ins >> 16;
		buff[2] = ins >> 8;
		buff[3] = ins;
	} else {
		buff[0] = ins;
		buff[1] = ins >> 8;
		buff[2] = ins >> 16;
		buff[3] = ins >> 24;
	}

	emit(buff, 4);
}

void
i_form(Op *op, Node **args)
{
	unsigned long ins, opcd, li, aa, lk;
	long long dst;
	long long max = 1l << 23;
	long long min = -(1l << 23);

	opcd = op->bytes[0];
	aa = op->bytes[1];
	lk = op->bytes[2];

	dst = args[0]->sym->value;
	if (dst & 0x3)
		error("unaligned branch");
	if (aa)
		dst -= cursec->curpc - 4;
	if (dst < min || dst > max)
		error("out of range branch");

	li = dst;
	li >>= 2;
	ins = opcd<<26 | li<<2 | aa<<1 | lk;
	emit_packed(ins);
}

void
b_form(Op *op, Node **args)
{
	unsigned long ins, opcd, bo, bi, bd, aa, lk;
	long long dst;
	long long max = 1l << 13;
	long long min = -(1l << 13);

	opcd = op->bytes[0];
	aa = op->bytes[1];
	lk = op->bytes[2];

	bo = args[0]->sym->value;
	bi = args[1]->sym->value;

	dst = args[2]->sym->value;
	if (dst & 0x3)
		error("unaligned branch");
	if (aa)
		dst -= cursec->curpc - 4;

	if (dst < min || dst > max)
		error("out of range branch");
	bd = dst;
	bd >>= 2;

	ins = opcd<<26 | bo<<21 | bi<<16 | bd<<11 | aa<<1 | lk;
	emit_packed(ins);
}

void
sc_form(Op *op, Node **args)
{
	abort();
}

void
d_form(Op *op, Node **args)
{
	abort();
}

void
ds_form(Op *op, Node **args)
{
	abort();
}

void
dq_form(Op *op, Node **args)
{
	abort();
}

void
x_form(Op *op, Node **args)
{
	abort();
}

void
xl_form(Op *op, Node **args)
{
	unsigned long ins, bo, bi, bh, lk;
	unsigned long opcd1, opcd2;
	long long dst;

	opcd1 = op->bytes[0];
	opcd2 = op->bytes[1]<<8 | op->bytes[2];
	lk = op->bytes[3];

	bo = args[0]->sym->value;
	bi = args[1]->sym->value;
	bh = args[2]->sym->value;

	ins = opcd1<<26 | bo<<21 | bi<<16 | bh<<11 | opcd2<<1 | lk;
	emit_packed(ins);
}

void
xfx_form(Op *op, Node **args)
{
	abort();
}

void
xlfdorm_form(Op *op, Node **args)
{
	abort();
}

void
xx1_form(Op *op, Node **args)
{
	abort();
}

void
xx2_form(Op *op, Node **args)
{
	abort();
}

void
xx3_form(Op *op, Node **args)
{
	abort();
}

void
xx4_form(Op *op, Node **args)
{
	abort();
}

void
xs_form(Op *op, Node **args)
{
	abort();
}

void
xo_form(Op *op, Node **args)
{
	abort();
}

void
a_form(Op *op, Node **args)
{
	abort();
}

void
m_form(Op *op, Node **args)
{
	abort();
}

void
md_form(Op *op, Node **args)
{
	abort();
}

void
mds_form(Op *op, Node **args)
{
	abort();
}

void
va_form(Op *op, Node **args)
{
	abort();
}

void
vc_form(Op *op, Node **args)
{
	abort();
}

void
vx_form(Op *op, Node **args)
{
	abort();
}

void
evs_form(Op *op, Node **args)
{
	abort();
}

void
z22_form(Op *op, Node **args)
{
	abort();
}

void
z23_form(Op *op, Node **args)
{
	abort();
}