/* bfin-parse.y ADI Blackfin parser
- Copyright 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 2005-2019 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 "libbfd.h"
#include "elf/common.h"
#include "elf/bfin.h"
static Expr_Node *binary (Expr_Op_Type, Expr_Node *, Expr_Node *);
static Expr_Node *unary (Expr_Op_Type, Expr_Node *);
-static void notethat (char *, ...);
+static void notethat (const char *, ...);
-char *current_inputline;
extern char *yytext;
-int yyerror (char *);
+int yyerror (const char *);
-void error (char *format, ...)
+/* Used to set SRCx fields to all 1s as described in the PRM. */
+static Register reg7 = {REG_R7, 0};
+
+void error (const char *format, ...)
{
va_list ap;
static char buffer[2000];
}
int
-yyerror (char *msg)
+yyerror (const char *msg)
{
if (msg[0] == '\0')
error ("%s", msg);
#define uimm5(x) EXPR_VALUE (x)
#define imm6(x) EXPR_VALUE (x)
#define imm7(x) EXPR_VALUE (x)
+#define uimm8(x) EXPR_VALUE (x)
#define imm16(x) EXPR_VALUE (x)
#define uimm16s4(x) ((EXPR_VALUE (x)) >> 2)
#define uimm16(x) EXPR_VALUE (x)
aa->s1.regno |= (ab->s1.regno & CODE_MASK);
}
- if (aa->w == ab->w && aa->P != ab->P)
+ if (aa->w == ab->w && aa->P != ab->P)
+ return yyerror ("Destination Dreg sizes (full or half) must match");
+
+ if (aa->w && ab->w)
{
- return yyerror ("macfuncs must differ");
- if (aa->w && (aa->dst.regno - ab->dst.regno != 1))
- return yyerror ("Destination Dregs must differ by one");
+ if (aa->P && (aa->dst.regno - ab->dst.regno) != 1)
+ return yyerror ("Destination Dregs (full) must differ by one");
+ if (!aa->P && aa->dst.regno != ab->dst.regno)
+ return yyerror ("Destination Dregs (half) must match");
}
/* Make sure mod flags get ORed, too. */
return 0;
}
+static int
+is_store (INSTR_T x)
+{
+ if (!x)
+ return 0;
+
+ if ((x->value & 0xf000) == 0x8000)
+ {
+ int aop = ((x->value >> 9) & 0x3);
+ int w = ((x->value >> 11) & 0x1);
+ if (!w || aop == 3)
+ return 0;
+ return 1;
+ }
+
+ if (((x->value & 0xFF60) == 0x9E60) || /* dagMODim_0 */
+ ((x->value & 0xFFF0) == 0x9F60)) /* dagMODik_0 */
+ return 0;
+
+ /* decode_dspLDST_0 */
+ if ((x->value & 0xFC00) == 0x9C00)
+ {
+ int w = ((x->value >> 9) & 0x1);
+ if (w)
+ return 1;
+ }
+
+ return 0;
+}
+
static INSTR_T
gen_multi_instr_1 (INSTR_T dsp32, INSTR_T dsp16_grp1, INSTR_T dsp16_grp2)
{
yyerror ("anomaly 05000074 - Multi-Issue Instruction with \
dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported");
+ if (is_store (dsp16_grp1) && is_store (dsp16_grp2))
+ yyerror ("Only one instruction in multi-issue instruction can be a store");
+
return bfin_gen_multi_instr (dsp32, dsp16_grp1, dsp16_grp2);
}
/* Vector Specific. */
%token BYTEOP16P BYTEOP16M
-%token BYTEOP1P BYTEOP2P BYTEOP2M BYTEOP3P
+%token BYTEOP1P BYTEOP2P BYTEOP3P
%token BYTEUNPACK BYTEPACK
%token PACK
%token SAA
else if (is_group2 ($3) && is_group1 ($5))
$$ = 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");
+ return yyerror ("Wrong 16 bit instructions groups, slot 2 and slot 3 must be 16-bit instruction group");
}
else if (($3->value & 0xf800) == 0xc000)
{
else if (is_group2 ($1) && is_group1 ($5))
$$ = 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");
+ return yyerror ("Wrong 16 bit instructions groups, slot 1 and slot 3 must be 16-bit instruction group");
}
else if (($5->value & 0xf800) == 0xc000)
{
else if (is_group2 ($1) && is_group1 ($3))
$$ = 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");
+ return yyerror ("Wrong 16 bit instructions groups, slot 1 and slot 2 must be 16-bit instruction group");
}
else
error ("\nIllegal Multi Issue Construct, at least any one of the slot must be DSP32 instruction group\n");
if (IS_DREG ($1) && !IS_A1 ($4) && IS_A1 ($5))
{
notethat ("dsp32alu: dregs = ( A0 += A1 )\n");
- $$ = DSP32ALU (11, 0, 0, &$1, 0, 0, 0, 0, 0);
+ $$ = DSP32ALU (11, 0, 0, &$1, ®7, ®7, 0, 0, 0);
}
else
return yyerror ("Register mismatch");
if (!IS_A1 ($4) && IS_A1 ($5))
{
notethat ("dsp32alu: dregs_half = ( A0 += A1 )\n");
- $$ = DSP32ALU (11, IS_H ($1), 0, &$1, 0, 0, 0, 0, 1);
+ $$ = DSP32ALU (11, IS_H ($1), 0, &$1, ®7, ®7, 0, 0, 1);
}
else
return yyerror ("Register mismatch");
{
if (!IS_DREG ($2) || !IS_DREG ($4))
return yyerror ("Dregs expected");
+ else if (REG_SAME ($2, $4))
+ return yyerror ("Illegal dest register combination");
else if (!valid_dreg_pair (&$9, $11))
return yyerror ("Bad dreg pair");
else if (!valid_dreg_pair (&$13, $15))
return yyerror ("Bad dreg pair");
else
{
- notethat ("dsp32alu: (dregs , dregs ) = BYTEOP16P (dregs_pair , dregs_pair ) (half)\n");
+ notethat ("dsp32alu: (dregs , dregs ) = BYTEOP16P (dregs_pair , dregs_pair ) (aligndir)\n");
$$ = DSP32ALU (21, 0, &$2, &$4, &$9, &$13, $17.r0, 0, 0);
}
}
{
if (!IS_DREG ($2) || !IS_DREG ($4))
return yyerror ("Dregs expected");
+ else if (REG_SAME ($2, $4))
+ return yyerror ("Illegal dest register combination");
else if (!valid_dreg_pair (&$9, $11))
return yyerror ("Bad dreg pair");
else if (!valid_dreg_pair (&$13, $15))
{
if (!IS_DREG ($2) || !IS_DREG ($4))
return yyerror ("Dregs expected");
+ else if (REG_SAME ($2, $4))
+ return yyerror ("Illegal dest register combination");
else if (!valid_dreg_pair (&$8, $10))
return yyerror ("Bad dreg pair");
else
}
| LPAREN REG COMMA REG RPAREN ASSIGN SEARCH REG LPAREN searchmod RPAREN
{
+ if (REG_SAME ($2, $4))
+ return yyerror ("Illegal dest register combination");
+
if (IS_DREG ($2) && IS_DREG ($4) && IS_DREG ($8))
{
notethat ("dsp32alu: (dregs , dregs ) = SEARCH dregs (searchmod)\n");
| REG ASSIGN A_ONE_DOT_L PLUS A_ONE_DOT_H COMMA
REG ASSIGN A_ZERO_DOT_L PLUS A_ZERO_DOT_H
{
+ if (REG_SAME ($1, $7))
+ return yyerror ("Illegal dest register combination");
+
if (IS_DREG ($1) && IS_DREG ($7))
{
notethat ("dsp32alu: dregs = A1.l + A1.h, dregs = A0.l + A0.h \n");
- $$ = DSP32ALU (12, 0, &$1, &$7, 0, 0, 0, 0, 1);
+ $$ = DSP32ALU (12, 0, &$1, &$7, ®7, ®7, 0, 0, 1);
}
else
return yyerror ("Register mismatch");
| REG ASSIGN REG_A PLUS REG_A COMMA REG ASSIGN REG_A MINUS REG_A amod1
{
+ if (REG_SAME ($1, $7))
+ return yyerror ("Resource conflict in dest reg");
+
if (IS_DREG ($1) && IS_DREG ($7) && !REG_SAME ($3, $5)
&& IS_A1 ($9) && !IS_A1 ($11))
{
notethat ("dsp32alu: dregs = A1 + A0 , dregs = A1 - A0 (amod1)\n");
- $$ = DSP32ALU (17, 0, &$1, &$7, 0, 0, $12.s0, $12.x0, 0);
+ $$ = DSP32ALU (17, 0, &$1, &$7, ®7, ®7, $12.s0, $12.x0, 0);
}
else if (IS_DREG ($1) && IS_DREG ($7) && !REG_SAME ($3, $5)
&& !IS_A1 ($9) && IS_A1 ($11))
{
notethat ("dsp32alu: dregs = A0 + A1 , dregs = A0 - A1 (amod1)\n");
- $$ = DSP32ALU (17, 0, &$1, &$7, 0, 0, $12.s0, $12.x0, 1);
+ $$ = DSP32ALU (17, 0, &$1, &$7, ®7, ®7, $12.s0, $12.x0, 1);
}
else
return yyerror ("Register mismatch");
if (!IS_DREG ($1) || !IS_DREG ($3) || !IS_DREG ($5) || !IS_DREG ($7))
return yyerror ("Dregs expected");
+ if (REG_SAME ($1, $7))
+ return yyerror ("Resource conflict in dest reg");
if ($4.r0 == 1 && $10.r0 == 2)
{
| a_assign ABS REG_A
{
notethat ("dsp32alu: Ax = ABS Ax\n");
- $$ = DSP32ALU (16, IS_A1 ($1), 0, 0, 0, 0, 0, 0, IS_A1 ($3));
+ $$ = DSP32ALU (16, IS_A1 ($1), 0, 0, ®7, ®7, 0, 0, IS_A1 ($3));
}
| A_ZERO_DOT_L ASSIGN HALF_REG
{
}
}
- | REG ASSIGN BYTEOP2M LPAREN REG COLON expr COMMA REG COLON expr RPAREN
- rnd_op
- {
- if (!IS_DREG ($1))
- return yyerror ("Dregs expected");
- else if (!valid_dreg_pair (&$5, $7))
- return yyerror ("Bad dreg pair");
- else if (!valid_dreg_pair (&$9, $11))
- return yyerror ("Bad dreg pair");
- else
- {
- notethat ("dsp32alu: dregs = BYTEOP2P (dregs_pair , dregs_pair ) (rnd_op)\n");
- $$ = DSP32ALU (22, $13.r0, 0, &$1, &$5, &$9, $13.s0, 0, $13.x0);
- }
- }
-
| REG ASSIGN BYTEOP3P LPAREN REG COLON expr COMMA REG COLON expr RPAREN
b3_op
{
| a_assign MINUS REG_A
{
notethat ("dsp32alu: Ax = - Ax\n");
- $$ = DSP32ALU (14, IS_A1 ($1), 0, 0, 0, 0, 0, 0, IS_A1 ($3));
+ $$ = DSP32ALU (14, IS_A1 ($1), 0, 0, ®7, ®7, 0, 0, IS_A1 ($3));
}
| HALF_REG ASSIGN HALF_REG plus_minus HALF_REG amod1
{
if (EXPR_VALUE ($3) == 0 && !REG_SAME ($1, $2))
{
notethat ("dsp32alu: A1 = A0 = 0\n");
- $$ = DSP32ALU (8, 0, 0, 0, 0, 0, 0, 0, 2);
+ $$ = DSP32ALU (8, 0, 0, 0, ®7, ®7, 0, 0, 2);
}
else
return yyerror ("Bad value, 0 expected");
if (REG_SAME ($1, $2))
{
notethat ("dsp32alu: Ax = Ax (S)\n");
- $$ = DSP32ALU (8, 0, 0, 0, 0, 0, 1, 0, IS_A1 ($1));
+ $$ = DSP32ALU (8, 0, 0, 0, ®7, ®7, 1, 0, IS_A1 ($1));
}
else
return yyerror ("Registers must be equal");
if (!REG_SAME ($1, $2))
{
notethat ("dsp32alu: An = Am\n");
- $$ = DSP32ALU (8, 0, 0, 0, 0, 0, IS_A1 ($1), 0, 3);
+ $$ = DSP32ALU (8, 0, 0, 0, ®7, ®7, IS_A1 ($1), 0, 3);
}
else
return yyerror ("Accu reg arguments must differ");
if (IS_DREG ($1) && $3.regno == REG_A0x)
{
notethat ("dsp32alu: dregs_lo = A0.x\n");
- $$ = DSP32ALU (10, 0, 0, &$1, 0, 0, 0, 0, 0);
+ $$ = DSP32ALU (10, 0, 0, &$1, ®7, ®7, 0, 0, 0);
}
else if (IS_DREG ($1) && $3.regno == REG_A1x)
{
notethat ("dsp32alu: dregs_lo = A1.x\n");
- $$ = DSP32ALU (10, 0, 0, &$1, 0, 0, 0, 0, 1);
+ $$ = DSP32ALU (10, 0, 0, &$1, ®7, ®7, 0, 0, 1);
}
else
return yyerror ("Register mismatch");
if (REG_SAME ($1, $3) && REG_SAME ($5, $7) && !REG_SAME ($1, $5))
{
notethat ("dsp32alu: A1 = ABS A1 , A0 = ABS A0\n");
- $$ = DSP32ALU (16, 0, 0, 0, 0, 0, 0, 0, 3);
+ $$ = DSP32ALU (16, 0, 0, 0, ®7, ®7, 0, 0, 3);
}
else
return yyerror ("Register mismatch");
if (REG_SAME ($1, $3) && REG_SAME ($5, $7) && !REG_SAME ($1, $5))
{
notethat ("dsp32alu: A1 = - A1 , A0 = - A0\n");
- $$ = DSP32ALU (14, 0, 0, 0, 0, 0, 0, 0, 3);
+ $$ = DSP32ALU (14, 0, 0, 0, ®7, ®7, 0, 0, 3);
}
else
return yyerror ("Register mismatch");
if (!IS_A1 ($1) && IS_A1 ($2))
{
notethat ("dsp32alu: A0 -= A1\n");
- $$ = DSP32ALU (11, 0, 0, 0, 0, 0, $3.r0, 0, 3);
+ $$ = DSP32ALU (11, 0, 0, 0, ®7, ®7, $3.r0, 0, 3);
}
else
return yyerror ("Register mismatch");
if (!IS_A1 ($1) && IS_A1 ($3))
{
notethat ("dsp32alu: A0 += A1 (W32)\n");
- $$ = DSP32ALU (11, 0, 0, 0, 0, 0, $4.r0, 0, 2);
+ $$ = DSP32ALU (11, 0, 0, 0, ®7, ®7, $4.r0, 0, 2);
}
else
return yyerror ("Register mismatch");
if (REG_SAME ($1, $2) && REG_SAME ($7, $8) && !REG_SAME ($1, $7))
{
notethat ("dsp32alu: A1 = A1 (S) , A0 = A0 (S)\n");
- $$ = DSP32ALU (8, 0, 0, 0, 0, 0, 1, 0, 2);
+ $$ = DSP32ALU (8, 0, 0, 0, ®7, ®7, 1, 0, 2);
}
else
return yyerror ("Register mismatch");
|| (IS_DAGREG ($1) && IS_DAGREG ($3))
|| (IS_GENREG ($1) && $3.regno == REG_USP)
|| ($1.regno == REG_USP && IS_GENREG ($3))
+ || ($1.regno == REG_USP && $3.regno == REG_USP)
|| (IS_DREG ($1) && IS_SYSREG ($3))
|| (IS_PREG ($1) && IS_SYSREG ($3))
- || (IS_SYSREG ($1) && IS_DREG ($3))
- || (IS_SYSREG ($1) && IS_PREG ($3))
+ || (IS_SYSREG ($1) && IS_GENREG ($3))
+ || (IS_ALLREG ($1) && IS_EMUDAT ($3))
+ || (IS_EMUDAT ($1) && IS_ALLREG ($3))
|| (IS_SYSREG ($1) && $3.regno == REG_USP))
{
$$ = bfin_gen_regmv (&$3, &$1);
}
else
- return yyerror ("Register mismatch");
+ return yyerror ("Unsupported register move");
}
| CCREG ASSIGN REG
$$ = bfin_gen_cc2dreg (1, &$3);
}
else
- return yyerror ("Register mismatch");
+ return yyerror ("Only 'CC = Dreg' supported");
}
| REG ASSIGN CCREG
$$ = bfin_gen_cc2dreg (0, &$1);
}
else
- return yyerror ("Register mismatch");
+ return yyerror ("Only 'Dreg = CC' supported");
}
| CCREG _ASSIGN_BANG CCREG
| BITMUX LPAREN REG COMMA REG COMMA REG_A RPAREN asr_asl
{
+ if (REG_SAME ($3, $5))
+ return yyerror ("Illegal source register combination");
+
if (IS_DREG ($3) && IS_DREG ($5) && !IS_A1 ($7))
{
notethat ("dsp32shift: BITMUX (dregs , dregs , A0) (ASR)\n");
{
if (IS_PREG ($3))
{
+ if ($3.regno == REG_SP || $3.regno == REG_FP)
+ return yyerror ("Bad register for TESTSET");
+
notethat ("ProgCtrl: TESTSET (pregs )\n");
$$ = PROGCTRL (11, $3.regno & CODE_MASK);
}
}
/* LOOP_BEGIN. */
+ | LOOP_BEGIN NUMBER
+ {
+ Expr_Node_Value val;
+ val.i_value = $2;
+ Expr_Node *tmp = Expr_Node_Create (Expr_Node_Constant, val, NULL, NULL);
+ bfin_loop_attempt_create_label (tmp, 1);
+ if (!IS_RELOC (tmp))
+ return yyerror ("Invalid expression in LOOP_BEGIN statement");
+ bfin_loop_beginend (tmp, 1);
+ $$ = 0;
+ }
| LOOP_BEGIN expr
{
if (!IS_RELOC ($2))
}
/* LOOP_END. */
+ | LOOP_END NUMBER
+ {
+ Expr_Node_Value val;
+ val.i_value = $2;
+ Expr_Node *tmp = Expr_Node_Create (Expr_Node_Constant, val, NULL, NULL);
+ bfin_loop_attempt_create_label (tmp, 1);
+ if (!IS_RELOC (tmp))
+ return yyerror ("Invalid expression in LOOP_END statement");
+ bfin_loop_beginend (tmp, 0);
+ $$ = 0;
+ }
| LOOP_END expr
{
if (!IS_RELOC ($2))
/* pseudoDEBUG. */
+ | ABORT
+ {
+ notethat ("psedoDEBUG: ABORT\n");
+ $$ = bfin_gen_pseudodbg (3, 3, 0);
+ }
+
| DBG
{
notethat ("pseudoDEBUG: DBG\n");
| DBG REG
{
notethat ("pseudoDEBUG: DBG allregs\n");
- $$ = bfin_gen_pseudodbg (0, $2.regno & CODE_MASK, $2.regno & CLASS_MASK);
+ $$ = bfin_gen_pseudodbg (0, $2.regno & CODE_MASK, ($2.regno & CLASS_MASK) >> 4);
}
| DBGCMPLX LPAREN REG RPAREN
if (!IS_DREG ($3))
return yyerror ("Dregs expected");
notethat ("pseudoDEBUG: DBGCMPLX (dregs )\n");
- $$ = bfin_gen_pseudodbg (3, 6, $3.regno & CODE_MASK);
+ $$ = bfin_gen_pseudodbg (3, 6, ($3.regno & CODE_MASK) >> 4);
}
| DBGHALT
$$ = bfin_gen_pseudodbg_assert (2, &$3, uimm16 ($5));
}
+ | OUTC expr
+ {
+ if (!IS_UIMM ($2, 8))
+ return yyerror ("Constant out of range");
+ notethat ("psedodbg_assert: OUTC uimm8\n");
+ $$ = bfin_gen_pseudochr (uimm8 ($2));
+ }
+
+ | OUTC REG
+ {
+ if (!IS_DREG ($2))
+ return yyerror ("Dregs expected");
+ notethat ("psedodbg_assert: OUTC dreg\n");
+ $$ = bfin_gen_pseudodbg (2, $2.regno & CODE_MASK, 0);
+ }
;
EXPR_T
mkexpr (int x, SYMBOL_T s)
{
- EXPR_T e = (EXPR_T) ALLOCATE (sizeof (struct expression_cell));
+ EXPR_T e = XNEW (struct expression_cell);
e->value = x;
EXPR_SYMBOL(e) = s;
return e;
value_match (Expr_Node *exp, int sz, int sign, int mul, int issigned)
{
int umax = (1 << sz) - 1;
- int min = -1 << (sz - 1);
+ int min = -(1 << (sz - 1));
int max = (1 << (sz - 1)) - 1;
int v = (EXPR_VALUE (exp)) & 0xffffffff;
int debug_codeselection = 0;
static void
-notethat (char *format, ...)
+notethat (const char *format, ...)
{
va_list ap;
va_start (ap, format);