/* bfin-parse.y ADI Blackfin parser
- Copyright 2005, 2006, 2007
+ Copyright 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#include "as.h"
#include <obstack.h>
-#include "bfin-aux.h" // opcode generating auxiliaries
+#include "bfin-aux.h" /* Opcode generating auxiliaries. */
#include "libbfd.h"
#include "elf/common.h"
#include "elf/bfin.h"
void error (char *format, ...)
{
va_list ap;
- char buffer[2000];
+ static char buffer[2000];
va_start (ap, format);
vsprintf (buffer, format, ap);
va_end (ap);
- as_bad (buffer);
+ as_bad ("%s", buffer);
}
int
}
+/* Check mac option. */
+
+static int
+check_macfunc_option (Macfunc *a, Opt_mode *opt)
+{
+ /* Default option is always valid. */
+ if (opt->mod == 0)
+ return 0;
+
+ if ((a->w == 1 && a->P == 1
+ && opt->mod != M_FU && opt->mod != M_IS && opt->mod != M_IU
+ && opt->mod != M_S2RND && opt->mod != M_ISS2)
+ || (a->w == 1 && a->P == 0
+ && opt->mod != M_FU && opt->mod != M_IS && opt->mod != M_IU
+ && opt->mod != M_T && opt->mod != M_TFU && opt->mod != M_S2RND
+ && opt->mod != M_ISS2 && opt->mod != M_IH)
+ || (a->w == 0 && a->P == 0
+ && opt->mod != M_FU && opt->mod != M_IS && opt->mod != M_W32))
+ return -1;
+
+ return 0;
+}
+
/* Check (vector) mac funcs and ops. */
static int
Macfunc mtmp;
Opt_mode otmp;
+ /* The option mode should be put at the end of the second instruction
+ of the vector except M, which should follow MAC1 instruction. */
+ if (opa->mod != 0)
+ return yyerror ("Bad opt mode");
+
/* If a0macfunc comes before a1macfunc, swap them. */
if (aa->n == 0)
{
if (opb->MM != 0)
return yyerror ("(M) not allowed with A0MAC");
- if (opa->mod != 0)
- return yyerror ("Bad opt mode");
if (ab->n != 0)
return yyerror ("Vector AxMACs can't be same");
}
/* If both ops are one of 0, 1, or 2, we have multiply_halfregs in both
assignment_or_macfuncs. */
- if (aa->op < 3 && aa->op >=0
- && ab->op < 3 && ab->op >= 0)
+ if ((aa->op == 0 || aa->op == 1 || aa->op == 2)
+ && (ab->op == 0 || ab->op == 1 || ab->op == 2))
{
if (check_multiply_halfregs (aa, ab) < 0)
return -1;
if (aa->w && (aa->dst.regno - ab->dst.regno != 1))
return yyerror ("Destination Dregs must differ by one");
}
- /* We assign to full regs, thus obey even/odd rules. */
- else if ((aa->w && aa->P && IS_EVEN (aa->dst))
- || (ab->w && ab->P && !IS_EVEN (ab->dst)))
- return yyerror ("Even/Odd register assignment mismatch");
- /* We assign to half regs, thus obey hi/low rules. */
- else if ( (aa->w && !aa->P && !IS_H (aa->dst))
- || (ab->w && !aa->P && IS_H (ab->dst)))
- return yyerror ("High/Low register assignment mismatch");
+
+ /* Make sure mod flags get ORed, too. */
+ opb->mod |= opa->mod;
+
+ /* Check option. */
+ if (check_macfunc_option (aa, opb) < 0
+ && check_macfunc_option (ab, opb) < 0)
+ return yyerror ("bad option");
/* Make sure first macfunc has got both P flags ORed. */
aa->P |= ab->P;
- /* Make sure mod flags get ORed, too. */
- opb->mod |= opa->mod;
return 0;
}
return 0;
}
+static INSTR_T
+gen_multi_instr_1 (INSTR_T dsp32, INSTR_T dsp16_grp1, INSTR_T dsp16_grp2)
+{
+ int mask1 = dsp32 ? insn_regmask (dsp32->value, dsp32->next->value) : 0;
+ int mask2 = dsp16_grp1 ? insn_regmask (dsp16_grp1->value, 0) : 0;
+ int mask3 = dsp16_grp2 ? insn_regmask (dsp16_grp2->value, 0) : 0;
+
+ if ((mask1 & mask2) || (mask1 & mask3) || (mask2 & mask3))
+ yyerror ("resource conflict in multi-issue instruction");
+
+ /* Anomaly 05000074 */
+ if (ENABLE_AC_05000074
+ && (dsp32->value & 0xf780) == 0xc680
+ && ((dsp16_grp1->value & 0xfe40) == 0x9240
+ || (dsp16_grp1->value & 0xfe08) == 0xba08
+ || (dsp16_grp1->value & 0xfc00) == 0xbc00))
+ yyerror ("anomaly 05000074 - Multi-Issue Instruction with \
+dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported");
+
+ return bfin_gen_multi_instr (dsp32, dsp16_grp1, dsp16_grp2);
+}
+
%}
%union {
if (($1->value & 0xf800) == 0xc000)
{
if (is_group1 ($3) && is_group2 ($5))
- $$ = bfin_gen_multi_instr ($1, $3, $5);
+ $$ = gen_multi_instr_1 ($1, $3, $5);
else if (is_group2 ($3) && is_group1 ($5))
- $$ = bfin_gen_multi_instr ($1, $5, $3);
+ $$ = gen_multi_instr_1 ($1, $5, $3);
else
return yyerror ("Wrong 16 bit instructions groups, slot 2 and slot 3 must be 16-bit instrution group");
}
else if (($3->value & 0xf800) == 0xc000)
{
if (is_group1 ($1) && is_group2 ($5))
- $$ = bfin_gen_multi_instr ($3, $1, $5);
+ $$ = gen_multi_instr_1 ($3, $1, $5);
else if (is_group2 ($1) && is_group1 ($5))
- $$ = bfin_gen_multi_instr ($3, $5, $1);
+ $$ = gen_multi_instr_1 ($3, $5, $1);
else
return yyerror ("Wrong 16 bit instructions groups, slot 1 and slot 3 must be 16-bit instrution group");
}
else if (($5->value & 0xf800) == 0xc000)
{
if (is_group1 ($1) && is_group2 ($3))
- $$ = bfin_gen_multi_instr ($5, $1, $3);
+ $$ = gen_multi_instr_1 ($5, $1, $3);
else if (is_group2 ($1) && is_group1 ($3))
- $$ = bfin_gen_multi_instr ($5, $3, $1);
+ $$ = gen_multi_instr_1 ($5, $3, $1);
else
return yyerror ("Wrong 16 bit instructions groups, slot 1 and slot 2 must be 16-bit instrution group");
}
if (($1->value & 0xf800) == 0xc000)
{
if (is_group1 ($3))
- $$ = bfin_gen_multi_instr ($1, $3, 0);
+ $$ = gen_multi_instr_1 ($1, $3, 0);
else if (is_group2 ($3))
- $$ = bfin_gen_multi_instr ($1, 0, $3);
+ $$ = gen_multi_instr_1 ($1, 0, $3);
else
return yyerror ("Wrong 16 bit instructions groups, slot 2 must be the 16-bit instruction group");
}
else if (($3->value & 0xf800) == 0xc000)
{
if (is_group1 ($1))
- $$ = bfin_gen_multi_instr ($3, $1, 0);
+ $$ = gen_multi_instr_1 ($3, $1, 0);
else if (is_group2 ($1))
- $$ = bfin_gen_multi_instr ($3, 0, $1);
+ $$ = gen_multi_instr_1 ($3, 0, $1);
else
return yyerror ("Wrong 16 bit instructions groups, slot 1 must be the 16-bit instruction group");
}
else if (is_group1 ($1) && is_group2 ($3))
- $$ = bfin_gen_multi_instr (0, $1, $3);
+ $$ = gen_multi_instr_1 (0, $1, $3);
else if (is_group2 ($1) && is_group1 ($3))
- $$ = bfin_gen_multi_instr (0, $3, $1);
+ $$ = gen_multi_instr_1 (0, $3, $1);
else
return yyerror ("Wrong 16 bit instructions groups, slot 1 and slot 2 must be the 16-bit instruction group");
}
int w0 = 0, w1 = 0;
int h00, h10, h01, h11;
+ if (check_macfunc_option (&$1, &$2) < 0)
+ return yyerror ("bad option");
+
if ($1.n == 0)
{
if ($2.MM)
}
| CCREG ASSIGN REG_A _ASSIGN_ASSIGN REG_A
{
- if (!REG_SAME ($3, $5))
+ if ($3.regno == REG_A0 && $5.regno == REG_A1)
{
notethat ("CCflag: CC = A0 == A1\n");
$$ = CCFLAG (0, 0, 5, 0, 0);
}
else
- return yyerror ("CC register expected");
+ return yyerror ("AREGs are in bad order or same");
}
| CCREG ASSIGN REG_A LESS_THAN REG_A
{
- if (!REG_SAME ($3, $5))
+ if ($3.regno == REG_A0 && $5.regno == REG_A1)
{
notethat ("CCflag: CC = A0 < A1\n");
$$ = CCFLAG (0, 0, 6, 0, 0);
}
else
- return yyerror ("Register mismatch");
+ return yyerror ("AREGs are in bad order or same");
}
| CCREG ASSIGN REG LESS_THAN REG iu_or_nothing
{
{
notethat ("CCflag: CC = dpregs == dpregs\n");
$$ = CCFLAG (&$3, $5.regno & CODE_MASK, 0, 0, IS_PREG ($3) ? 1 : 0);
- }
+ }
+ else
+ return yyerror ("Compare only of same register class");
}
| CCREG ASSIGN REG _ASSIGN_ASSIGN expr
{
}
| CCREG ASSIGN REG_A _LESS_THAN_ASSIGN REG_A
{
- if (!REG_SAME ($3, $5))
+ if ($3.regno == REG_A0 && $5.regno == REG_A1)
{
notethat ("CCflag: CC = A0 <= A1\n");
$$ = CCFLAG (0, 0, 7, 0, 0);
}
else
- return yyerror ("CC register expected");
+ return yyerror ("AREGs are in bad order or same");
}
| CCREG ASSIGN REG _LESS_THAN_ASSIGN REG iu_or_nothing
{
if (!IS_H ($1) && $4.MM)
return yyerror ("(M) not allowed with MAC0");
+ if ($4.mod != 0 && $4.mod != M_FU && $4.mod != M_IS
+ && $4.mod != M_IU && $4.mod != M_T && $4.mod != M_TFU
+ && $4.mod != M_S2RND && $4.mod != M_ISS2 && $4.mod != M_IH)
+ return yyerror ("bad option.");
+
if (IS_H ($1))
{
$$ = DSP32MULT (0, $4.MM, $4.mod, 1, 0,
if (IS_EVEN ($1) && $4.MM)
return yyerror ("(M) not allowed with MAC0");
+ if ($4.mod != 0 && $4.mod != M_FU && $4.mod != M_IS
+ && $4.mod != M_S2RND && $4.mod != M_ISS2)
+ return yyerror ("bad option");
+
if (!IS_EVEN ($1))
{
notethat ("dsp32mult: dregs = multiply_halfregs (opt_mode)\n");
else
return yyerror ("Bad shift value or register");
}
- | HALF_REG ASSIGN HALF_REG LESS_LESS expr
- {
- if (IS_UIMM ($5, 4))
- {
- notethat ("dsp32shiftimm: dregs_half = dregs_half << uimm4\n");
- $$ = DSP32SHIFTIMM (0x0, &$1, imm5 ($5), &$3, 2, HL2 ($1, $3));
- }
- else
- return yyerror ("Bad shift value");
- }
| HALF_REG ASSIGN HALF_REG LESS_LESS expr smod
{
if (IS_UIMM ($5, 4))
{
- notethat ("dsp32shiftimm: dregs_half = dregs_half << uimm4\n");
- $$ = DSP32SHIFTIMM (0x0, &$1, imm5 ($5), &$3, $6.s0, HL2 ($1, $3));
+ if ($6.s0)
+ {
+ notethat ("dsp32shiftimm: dregs_half = dregs_half << uimm4 (S)\n");
+ $$ = DSP32SHIFTIMM (0x0, &$1, imm5 ($5), &$3, $6.s0, HL2 ($1, $3));
+ }
+ else
+ {
+ notethat ("dsp32shiftimm: dregs_half = dregs_half << uimm4\n");
+ $$ = DSP32SHIFTIMM (0x0, &$1, imm5 ($5), &$3, 2, HL2 ($1, $3));
+ }
}
else
return yyerror ("Bad shift value");
if (!IS_DREG ($1) && !ispreg)
return yyerror ("Bad destination register for LOAD");
+ if (tmp->type == Expr_Node_Reloc
+ && strcmp (tmp->value.s_value,
+ "_current_shared_library_p5_offset_") != 0)
+ return yyerror ("Plain symbol used as offset");
+
if ($5.r0)
tmp = unary (Expr_Op_Type_NEG, tmp);
assign_macfunc:
REG ASSIGN REG_A
{
+ if (IS_A1 ($3) && IS_EVEN ($1))
+ return yyerror ("Cannot move A1 to even register");
+ else if (!IS_A1 ($3) && !IS_EVEN ($1))
+ return yyerror ("Cannot move A0 to odd register");
+
$$.w = 1;
$$.P = 1;
$$.n = IS_A1 ($3);
$$.dst = $1;
$$.s0.regno = 0;
$$.s1.regno = 0;
-
- if (IS_A1 ($3) && IS_EVEN ($1))
- return yyerror ("Cannot move A1 to even register");
- else if (!IS_A1 ($3) && !IS_EVEN ($1))
- return yyerror ("Cannot move A0 to odd register");
}
| a_macfunc
{
}
| REG ASSIGN LPAREN a_macfunc RPAREN
{
+ if ($4.n && IS_EVEN ($1))
+ return yyerror ("Cannot move A1 to even register");
+ else if (!$4.n && !IS_EVEN ($1))
+ return yyerror ("Cannot move A0 to odd register");
+
$$ = $4;
$$.w = 1;
$$.P = 1;
| HALF_REG ASSIGN LPAREN a_macfunc RPAREN
{
+ if ($4.n && !IS_H ($1))
+ return yyerror ("Cannot move A1 to low half of register");
+ else if (!$4.n && IS_H ($1))
+ return yyerror ("Cannot move A0 to high half of register");
+
$$ = $4;
$$.w = 1;
$$.P = 0;
| HALF_REG ASSIGN REG_A
{
+ if (IS_A1 ($3) && !IS_H ($1))
+ return yyerror ("Cannot move A1 to low half of register");
+ else if (!IS_A1 ($3) && IS_H ($1))
+ return yyerror ("Cannot move A0 to high half of register");
+
$$.w = 1;
$$.P = 0;
$$.n = IS_A1 ($3);
$$.dst = $1;
$$.s0.regno = 0;
$$.s1.regno = 0;
-
- if (IS_A1 ($3) && !IS_H ($1))
- return yyerror ("Cannot move A1 to low half of register");
- else if (!IS_A1 ($3) && IS_H ($1))
- return yyerror ("Cannot move A0 to high half of register");
}
;
break;
default:
- error ("%s:%d: Internal compiler error\n", __FILE__, __LINE__);
+ error ("%s:%d: Internal assembler error\n", __FILE__, __LINE__);
}
return x;
}
x->value.i_value = ~x->value.i_value;
break;
default:
- error ("%s:%d: Internal compiler error\n", __FILE__, __LINE__);
+ error ("%s:%d: Internal assembler error\n", __FILE__, __LINE__);
}
return x;
}