scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

commit 4caf226e95bfddbbe1b76b54bfb915e8ed95e3c5
parent 2c1b957c0bd9ff6b3cdc02c5efae1f3f1a637c52
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Thu, 19 Sep 2019 20:39:11 +0200

[as/powerpc] Add Branch instructions

Diffstat:
Msrc/cmd/as/target/powerpc/ins.c | 91++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/cmd/as/target/powerpc/powerpc.c | 2+-
Msrc/cmd/as/target/powerpc/powerpc.dat | 10++++++++++
Msrc/cmd/as/target/powerpc/powerpc64.c | 51+++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/cmd/as/target/powerpc/proc.h | 2++
Atests/as/execute/powerpc.s | 4++++
6 files changed, 154 insertions(+), 6 deletions(-)

diff --git a/src/cmd/as/target/powerpc/ins.c b/src/cmd/as/target/powerpc/ins.c @@ -50,9 +50,59 @@ getclass(Node *np) } 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 @@ moperand(void) 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 diff --git 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 diff --git 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 diff --git 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; + } } diff --git a/src/cmd/as/target/powerpc/proc.h b/src/cmd/as/target/powerpc/proc.h @@ -31,6 +31,8 @@ enum args { AREG_R29, AREG_R30, AREG_R31, + + AREG_GPRSCLASS, /* register class for GPRS registers */ }; enum class { diff --git a/tests/as/execute/powerpc.s b/tests/as/execute/powerpc.s @@ -0,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