Add compare-and-branch instructions.

--HG--
branch : dtrg-videocore
This commit is contained in:
David Given 2013-05-19 18:40:19 +01:00
parent 80afe75c9b
commit 4f15423d63
6 changed files with 118 additions and 5 deletions

View 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);

View 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

View 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",

View 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
{

View 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);
}

View 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, .