Add compare-and-branch instructions.
authorDavid Given <dg@cowlark.com>
Sun, 19 May 2013 17:40:19 +0000 (18:40 +0100)
committerDavid Given <dg@cowlark.com>
Sun, 19 May 2013 17:40:19 +0000 (18:40 +0100)
--HG--
branch : dtrg-videocore

mach/vc4/as/mach1.c
mach/vc4/as/mach2.c
mach/vc4/as/mach3.c
mach/vc4/as/mach4.c
mach/vc4/as/mach5.c
mach/vc4/test/opcodes.s

index 6e7b681..440d7de 100644 (file)
@@ -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);
index 2abde71..8143d08 100644 (file)
@@ -9,7 +9,7 @@
 %token <y_word> CC
 
 %token <y_word> OP
-%token <y_word> OP_BRANCH
+%token <y_word> OP_BRANCH OP_BRANCHLINK OP_ADDCMPB
 %token <y_word> OP_ONEREG
 %token <y_word> OP_ONELREG
 %token <y_word> OP_ALU
index 64b503a..aba49dc 100644 (file)
@@ -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",
index 78c9337..e9593e7 100644 (file)
@@ -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
        {
index 265e18f..768d2ea 100644 (file)
@@ -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);
+}
+
index a2104fc..87a50d0 100644 (file)
@@ -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, .