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