shithub: scc

Download patch

ref: 1f43b75a1163e7edec45e03d2905f4abcb105506
parent: 45a5271ae24937f5d96724db3d3da898a56e106e
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Thu Sep 19 16:39:11 EDT 2019

[as/powerpc] Add Branch instructions

--- a/src/cmd/as/target/powerpc/ins.c
+++ b/src/cmd/as/target/powerpc/ins.c
@@ -50,9 +50,59 @@
 }
 
 int
-match(Op *Op, Node **args)
+match(Op *op, Node **args)
 {
-	return 0;
+	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 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 *
@@ -61,10 +111,45 @@
 	abort();
 }
 
+static void
+pack_emit(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)
 {
-	abort();
+	unsigned long ins, opcd, li, aa, lk;
+	unsigned long long dst;
+
+	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;
+	li = dst >> 2;
+
+	ins = opcd<<26 | li<<2 | aa<<1 | lk;
+	pack_emit(ins);
 }
 
 void
--- a/src/cmd/as/target/powerpc/powerpc.c
+++ b/src/cmd/as/target/powerpc/powerpc.c
@@ -6,7 +6,7 @@
 #include "proc.h"
 
 TUINT maxaddr = 0xFFFF;
-int endian = LITTLE_ENDIAN;
+int endian = BIG_ENDIAN;
 int left2right = 0;
 
 void
--- a/src/cmd/as/target/powerpc/powerpc.dat
+++ b/src/cmd/as/target/powerpc/powerpc.dat
@@ -35,3 +35,13 @@
 .ALIGN	imm16+	0	none	align	POWERPC,POWERPC64
 .END	none	0	none	end	POWERPC,POWERPC64
 .INCLUDE	string	0	none	include	POWERPC,POWERPC64
+
+# Branch instructions
+B	imm32	4	18,0,0	i_form	POWERPC
+B	imm64	4	18,0,0	i_form	POWERPC64
+BA	imm32	4	18,1,0	i_form	POWERPC
+BA	imm64	4	18,1,0	i_form	POWERPC64
+BL	imm32	4	18,0,1	i_form	POWERPC
+BL	imm64	4	18,0,1	i_form	POWERPC64
+BLA	imm32	4	18,1,1	i_form	POWERPC
+BLA	imm64	4	18,1,1	i_form	POWERPC64
--- a/src/cmd/as/target/powerpc/powerpc64.c
+++ b/src/cmd/as/target/powerpc/powerpc64.c
@@ -3,13 +3,60 @@
 #include <scc/scc.h>
 
 #include "../../as.h"
+#include "proc.h"
 
 TUINT maxaddr = 0xFFFF;
-int endian = LITTLE_ENDIAN;
+int endian = BIG_ENDIAN;
 int left2right = 0;
-#include "proc.h"
 
 void
 iarch(void)
 {
+	static struct {
+		char *name;
+		char type;
+	} regs[] = {
+		"R0", AREG_R0,
+		"R1", AREG_R1,
+		"R2", AREG_R2,
+		"R3", AREG_R3,
+		"R4", AREG_R4,
+		"R5", AREG_R5,
+		"R6", AREG_R6,
+		"R7", AREG_R7,
+		"R8", AREG_R8,
+		"R9", AREG_R9,
+
+		"R10", AREG_R10,
+		"R11", AREG_R11,
+		"R12", AREG_R12,
+		"R13", AREG_R13,
+		"R14", AREG_R14,
+		"R15", AREG_R15,
+		"R16", AREG_R16,
+		"R17", AREG_R17,
+		"R18", AREG_R18,
+		"R19", AREG_R19,
+
+		"R20", AREG_R20,
+		"R21", AREG_R21,
+		"R22", AREG_R22,
+		"R23", AREG_R23,
+		"R24", AREG_R24,
+		"R25", AREG_R25,
+		"R26", AREG_R26,
+		"R27", AREG_R27,
+		"R28", AREG_R28,
+		"R29", AREG_R29,
+		"R30", AREG_R30,
+		"R31", AREG_R31,
+
+		NULL
+	}, *bp;
+
+	for (bp = regs; bp->name; ++bp) {
+		Symbol *sym = lookup(bp->name);
+		sym->flags = FREG;
+		sym->value = bp->type;
+	}
 }
--- a/src/cmd/as/target/powerpc/proc.h
+++ b/src/cmd/as/target/powerpc/proc.h
@@ -31,6 +31,8 @@
 	AREG_R29,
 	AREG_R30,
 	AREG_R31,
+
+	AREG_GPRSCLASS,   /* register class for GPRS registers */
 };
 
 enum class {
--- /dev/null
+++ b/tests/as/execute/powerpc.s
@@ -1,0 +1,4 @@
+	B	$L1	/ 48 00 00 0C
+	BA	$L1	/ 48 00 00 0E
+	BL	$L1	/ 48 00 00 0D
+L1:	BLA	$L1	/ 48 00 00 07