/* 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
if (opt->mod == 0)
return 0;
- if ((a->op == 3 && a->w == 1 && a->P == 1
- && opt->mod != M_FU && opt->mod != M_S2RND && opt->mod != M_ISS2)
- || (a->op == 3 && 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_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)
- || (a->w == 1 && a->P == 1
- && opt->mod != M_FU && opt->mod != M_IS && opt->mod != M_S2RND
- && opt->mod != M_ISS2)
+ 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))
+ && 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;
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;
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");
}
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;
}