diff --git a/mach/vc4/as/mach1.c b/mach/vc4/as/mach1.c index 6e7b6819f..440d7de97 100644 --- a/mach/vc4/as/mach1.c +++ b/mach/vc4/as/mach1.c @@ -19,3 +19,7 @@ extern void mem_instr(quad opcode, int cc, int rd, long offset, int rs); extern void mem_offset_instr(quad opcode, int cc, int rd, int qa, int rb); extern void mem_postincr_instr(quad opcode, int cc, int rd, int rs); extern void mem_address_instr(quad opcode, int rd, struct expr_t* expr); +extern void branch_addcmp_reg_reg_instr(int cc, int rd, int ra, int rs, struct expr_t* expr); +extern void branch_addcmp_lit_reg_instr(int cc, int rd, long va, int rs, struct expr_t* expr); +extern void branch_addcmp_reg_lit_instr(int cc, int rd, int ra, long vs, struct expr_t* expr); +extern void branch_addcmp_lit_lit_instr(int cc, int rd, long va, long vs, struct expr_t* expr); diff --git a/mach/vc4/as/mach2.c b/mach/vc4/as/mach2.c index 2abde7136..8143d080b 100644 --- a/mach/vc4/as/mach2.c +++ b/mach/vc4/as/mach2.c @@ -9,7 +9,7 @@ %token CC %token OP -%token OP_BRANCH +%token OP_BRANCH OP_BRANCHLINK OP_ADDCMPB %token OP_ONEREG %token OP_ONELREG %token OP_ALU diff --git a/mach/vc4/as/mach3.c b/mach/vc4/as/mach3.c index 64b503a98..aba49dca2 100644 --- a/mach/vc4/as/mach3.c +++ b/mach/vc4/as/mach3.c @@ -73,7 +73,8 @@ 0, OP, B16(00000000,00001010), "rti", 0, OP_BRANCH, 0, "b", -0, OP_BRANCH, 1, "bl", +0, OP_BRANCHLINK, 0, "bl", +0, OP_ADDCMPB, 0, "addcmpb", 0, OP_ONELREG, B16(00000000,10000000), "tbb", 0, OP_ONELREG, B16(00000000,10100000), "tbs", diff --git a/mach/vc4/as/mach4.c b/mach/vc4/as/mach4.c index 78c9337c9..e9593e761 100644 --- a/mach/vc4/as/mach4.c +++ b/mach/vc4/as/mach4.c @@ -8,9 +8,26 @@ operation : OP { emit2($1); } - | OP_BRANCH GPR { emit2($1 | ($2<<0)); } - | OP_BRANCH expr { branch_instr($1, ALWAYS, &$2); } - | OP_BRANCH CC expr { branch_instr($1, $2, &$3); } + | OP_BRANCH GPR { emit2(B16(00000000,01000000) | ($2<<0)); } + | OP_BRANCHLINK GPR { emit2(B16(00000000,01100000) | ($2<<0)); } + + | OP_BRANCH expr { branch_instr(0, ALWAYS, &$2); } + | OP_BRANCHLINK expr { branch_instr(1, ALWAYS, &$2); } + | OP_BRANCH CC expr { branch_instr(0, $2, &$3); } + | OP_BRANCHLINK CC expr { branch_instr(1, $2, &$3); } + + | OP_BRANCH GPR ',' GPR ',' expr { branch_addcmp_lit_reg_instr(ALWAYS, 0, $2, $4, &$6); } + | OP_BRANCH CC GPR ',' GPR ',' expr { branch_addcmp_lit_reg_instr($2, 0, $3, $5, &$7); } + | OP_BRANCH GPR ',' '#' absexp ',' expr { branch_addcmp_lit_lit_instr(ALWAYS, 0, $2, $5, &$7); } + | OP_BRANCH CC GPR ',' '#' absexp ',' expr { branch_addcmp_lit_lit_instr($2, 0, $3, $6, &$8); } + | OP_ADDCMPB GPR ',' GPR ',' GPR ',' expr { branch_addcmp_reg_reg_instr(ALWAYS, $2, $4, $6, &$8); } + | OP_ADDCMPB CC GPR ',' GPR ',' GPR ',' expr { branch_addcmp_reg_reg_instr($2, $3, $5, $7, &$9); } + | OP_ADDCMPB GPR ',' '#' absexp ',' GPR ',' expr { branch_addcmp_reg_reg_instr(ALWAYS, $2, $5, $7, &$9); } + | OP_ADDCMPB CC GPR ',' '#' absexp ',' GPR ',' expr { branch_addcmp_reg_reg_instr($2, $3, $6, $8, &$10); } + | OP_ADDCMPB GPR ',' GPR ',' '#' absexp ',' expr { branch_addcmp_reg_lit_instr(ALWAYS, $2, $4, $7, &$9); } + | OP_ADDCMPB CC GPR ',' GPR ',' '#' absexp ',' expr { branch_addcmp_reg_lit_instr($2, $3, $5, $8, &$10); } + | OP_ADDCMPB GPR ',' '#' absexp ',' '#' absexp ',' expr { branch_addcmp_lit_lit_instr(ALWAYS, $2, $5, $8, &$10); } + | OP_ADDCMPB CC GPR ',' '#' absexp ',' '#' absexp ',' expr { branch_addcmp_lit_lit_instr($2, $3, $6, $9, &$11); } | OP_ONELREG GPR { diff --git a/mach/vc4/as/mach5.c b/mach/vc4/as/mach5.c index 265e18f52..768d2eaee 100644 --- a/mach/vc4/as/mach5.c +++ b/mach/vc4/as/mach5.c @@ -388,3 +388,87 @@ void mem_address_instr(quad opcode, int rd, struct expr_t* expr) } } +/* Common code for handling addcmp: merge in as much of expr as will fit to + * the second pair of the addcmp opcode. */ + +static void branch_addcmp_common(quad opcode, int bits, struct expr_t* expr) +{ + quad type = expr->typ & S_TYP; + + switch (pass) + { + case 0: + /* Calculate size of instructions only. */ + + emit2(0); + break; + + case 1: + case 2: + { + if (type != DOTTYP) + serror("can't use this type of branch to jump outside the section"); + + /* The VC4 branch instructions express distance in 2-byte + * words. */ + + int d = (expr->val - DOTVAL-2 + 4) / 2; + + if (!fitx(d, bits)) + serror("target of branch is too far away"); + + emit2(opcode | maskx(d, bits)); + break; + } + } +} + +void branch_addcmp_reg_reg_instr(int cc, int rd, int ra, int rs, struct expr_t* expr) +{ + if ((rd >= 0x10) || (ra >= 0x10) || (rs >= 0x10)) + serror("can only use r0-r15 in this instruction"); + + emit2(B16(10000000,00000000) | (cc<<8) | (ra<<4) | (rd<<0)); + branch_addcmp_common(B16(00000000,00000000) | (rs<<10), 10, expr); +} + +void branch_addcmp_lit_reg_instr(int cc, int rd, long va, int rs, struct expr_t* expr) +{ + if ((rd >= 0x10) || (rs >= 0x10)) + serror("can only use r0-r15 in this instruction"); + + if (!fitx(va, 4)) + serror("value too big to encode into instruction"); + va = maskx(va, 4); + + emit2(B16(10000000,00000000) | (cc<<8) | (va<<4) | (rd<<0)); + branch_addcmp_common(B16(01000000,00000000) | (rs<<10), 10, expr); +} + +void branch_addcmp_reg_lit_instr(int cc, int rd, int ra, long vs, struct expr_t* expr) +{ + if ((rd >= 0x10) || (ra >= 0x10)) + serror("can only use r0-r15 in this instruction"); + + if (!fitx(vs, 6)) + serror("value too big to encode into instruction"); + vs = maskx(vs, 6); + + emit2(B16(10000000,00000000) | (cc<<8) | (ra<<4) | (rd<<0)); + branch_addcmp_common(B16(10000000,00000000) | (vs<<8), 8, expr); +} + +void branch_addcmp_lit_lit_instr(int cc, int rd, long va, long vs, struct expr_t* expr) +{ + if (rd >= 0x10) + serror("can only use r0-r15 in this instruction"); + + if (!fitx(va, 4) || !fitx(vs, 6)) + serror("value too big to encode into instruction"); + va = maskx(va, 4); + vs = maskx(vs, 6); + + emit2(B16(10000000,00000000) | (cc<<8) | (va<<4) | (rd<<0)); + branch_addcmp_common(B16(11000000,00000000) | (vs<<8), 8, expr); +} + diff --git a/mach/vc4/test/opcodes.s b/mach/vc4/test/opcodes.s index a2104fcd7..87a50d070 100644 --- a/mach/vc4/test/opcodes.s +++ b/mach/vc4/test/opcodes.s @@ -353,3 +353,10 @@ near: ldb r0, main stb r0, near stb r0, main + + b.eq r0, r1, near + b r0, r1, near + addcmpb r0, r1, r2, . + addcmpb r0, #1, r2, . + addcmpb r0, r1, #1, . + addcmpb r0, #1, #2, .