Convert more variables to a constant form.
[external/binutils.git] / gas / config / bfin-parse.y
index b3416aa..be53280 100644 (file)
@@ -1,12 +1,11 @@
 /* bfin-parse.y  ADI Blackfin parser
-   Copyright 2005, 2006
-   Free Software Foundation, Inc.
+   Copyright (C) 2005-2016 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
@@ -21,9 +20,8 @@
 %{
 
 #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"
        (value_match (expr, 24, 0, 2, 1))
 
 
-static int value_match (Expr_Node *expr, int sz, int sign, int mul, int issigned);
+static int value_match (Expr_Node *, int, int, int, int);
 
 extern FILE *errorf;
 extern INSTR_T insn;
@@ -160,26 +158,29 @@ extern INSTR_T insn;
 static Expr_Node *binary (Expr_Op_Type, Expr_Node *, Expr_Node *);
 static Expr_Node *unary  (Expr_Op_Type, Expr_Node *);
 
-static void notethat (char *format, ...);
+static void notethat (const char *, ...);
 
 char *current_inputline;
 extern char *yytext;
-int yyerror (char *msg);
+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;
-    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
-yyerror (char *msg)
+yyerror (const char *msg)
 {
   if (msg[0] == '\0')
     error ("%s", msg);
@@ -193,10 +194,10 @@ yyerror (char *msg)
 }
 
 static int
-in_range_p (Expr_Node *expr, int from, int to, unsigned int mask)
+in_range_p (Expr_Node *exp, int from, int to, unsigned int mask)
 {
-  int val = EXPR_VALUE (expr);
-  if (expr->type != Expr_Node_Constant)
+  int val = EXPR_VALUE (exp);
+  if (exp->type != Expr_Node_Constant)
     return 0;
   if (val < from || val > to)
     return 0;
@@ -212,6 +213,7 @@ extern int yylex (void);
 #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)
@@ -222,12 +224,6 @@ extern int yylex (void);
 
 /* Auxiliary functions.  */
 
-static void
-neg_value (Expr_Node *expr)
-{
-  expr->value.i_value = -expr->value.i_value;
-}
-
 static int
 valid_dreg_pair (Register *reg1, Expr_Node *reg2)
 {
@@ -264,6 +260,29 @@ check_multiply_halfregs (Macfunc *aa, Macfunc *ab)
 }
 
 
+/* 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
@@ -274,8 +293,13 @@ check_macfuncs (Macfunc *aa, Opt_mode *opa,
   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)
     {
       /*  (M) is not allowed here.  */
@@ -291,16 +315,14 @@ check_macfuncs (Macfunc *aa, Opt_mode *opa,
     {
       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;
@@ -315,27 +337,29 @@ check_macfuncs (Macfunc *aa, Opt_mode *opa,
       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");
     }
-  /* 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;
 }
 
 
@@ -361,6 +385,62 @@ is_group2 (INSTR_T x)
   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)
+{
+  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 != NULL && dsp16_grp1 != NULL
+      && (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");
+
+  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);
+}
+
 %}
 
 %union {
@@ -380,7 +460,7 @@ is_group2 (INSTR_T x)
 
 /* Vector Specific.  */
 %token BYTEOP16P BYTEOP16M
-%token BYTEOP1P BYTEOP2P BYTEOP2M BYTEOP3P
+%token BYTEOP1P BYTEOP2P BYTEOP3P
 %token BYTEUNPACK BYTEPACK
 %token PACK
 %token SAA
@@ -437,7 +517,7 @@ is_group2 (INSTR_T x)
 %token SHIFT LSHIFT ASHIFT BXORSHIFT
 %token _GREATER_GREATER_GREATER_THAN_ASSIGN
 %token ROT
-%token LESS_LESS GREATER_GREATER  
+%token LESS_LESS GREATER_GREATER
 %token _GREATER_GREATER_GREATER
 %token _LESS_LESS_ASSIGN _GREATER_GREATER_ASSIGN
 %token DIVS DIVQ
@@ -504,8 +584,8 @@ is_group2 (INSTR_T x)
 %type <reg> a_plusassign
 %type <reg> a_minusassign
 %type <macfunc> multiply_halfregs
-%type <macfunc> assign_macfunc 
-%type <macfunc> a_macfunc 
+%type <macfunc> assign_macfunc
+%type <macfunc> a_macfunc
 %type <expr> expr_1
 %type <instr> asm_1
 %type <r0> vmod
@@ -525,11 +605,11 @@ is_group2 (INSTR_T x)
 %type <reg> REG_A_DOUBLE_ZERO
 %type <reg> REG_A_DOUBLE_ONE
 %type <reg> REG_A
-%type <reg> STATUS_REG 
+%type <reg> STATUS_REG
 %type <expr> expr
 %type <r0> xpmod
 %type <r0> xpmod1
-%type <modcodes> smod 
+%type <modcodes> smod
 %type <modcodes> b3_op
 %type <modcodes> rnd_op
 %type <modcodes> post_op
@@ -564,7 +644,7 @@ is_group2 (INSTR_T x)
 %right TILDA BANG
 %start statement
 %%
-statement: 
+statement:
        | asm
        {
          insn = $1;
@@ -584,27 +664,27 @@ asm: asm_1 SEMICOLON
          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");
            }
@@ -617,25 +697,25 @@ asm: asm_1 SEMICOLON
          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");
        }
@@ -649,7 +729,7 @@ asm: asm_1 SEMICOLON
 
 /* DSPMAC.  */
 
-asm_1:   
+asm_1:
        MNOP
        {
          $$ = DSP32MAC (3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
@@ -660,9 +740,12 @@ asm_1:
          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) 
+             if ($2.MM)
                return yyerror ("(m) not allowed with a0 unit");
              op1 = 3;
              op0 = $1.op;
@@ -693,7 +776,7 @@ asm_1:
        {
          Register *dst;
 
-         if (check_macfuncs (&$1, &$2, &$4, &$5) < 0) 
+         if (check_macfuncs (&$1, &$2, &$4, &$5) < 0)
            return -1;
          notethat ("assign_macfunc (.), assign_macfunc (.)\n");
 
@@ -719,17 +802,17 @@ asm_1:
          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, &reg7, &reg7, 0, 0, 0);
            }
-         else 
+         else
            return yyerror ("Register mismatch");
-       }       
+       }
        | HALF_REG ASSIGN LPAREN a_plusassign REG_A RPAREN
        {
          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, &reg7, &reg7, 0, 0, 1);
            }
          else
            return yyerror ("Register mismatch");
@@ -749,22 +832,26 @@ asm_1:
        {
          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);
            }
        }
 
        | LPAREN REG COMMA REG RPAREN ASSIGN BYTEOP16M LPAREN REG COLON expr COMMA
-         REG COLON expr RPAREN aligndir 
+         REG COLON expr RPAREN aligndir
        {
-         if (!IS_DREG ($2) || !IS_DREG($4))
+         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))
@@ -780,6 +867,8 @@ asm_1:
        {
          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
@@ -790,6 +879,9 @@ asm_1:
        }
        | 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");
@@ -801,30 +893,36 @@ asm_1:
        | 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, &reg7, &reg7, 0, 0, 1);
            }
          else
            return yyerror ("Register mismatch");
        }
 
 
-       | REG ASSIGN REG_A PLUS REG_A COMMA REG ASSIGN REG_A MINUS REG_A amod1 
+       | 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, &reg7, &reg7, $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, &reg7, &reg7, $12.s0, $12.x0, 1);
            }
          else
            return yyerror ("Register mismatch");
@@ -832,7 +930,7 @@ asm_1:
 
        | REG ASSIGN REG plus_minus REG COMMA REG ASSIGN REG plus_minus REG amod1
        {
-         if ($4.r0 == $10.r0) 
+         if ($4.r0 == $10.r0)
            return yyerror ("Operators must differ");
 
          if (IS_DREG ($1) && IS_DREG ($3) && IS_DREG ($5)
@@ -848,15 +946,17 @@ asm_1:
 
 /*  Bar Operations.  */
 
-       | REG ASSIGN REG op_bar_op REG COMMA REG ASSIGN REG op_bar_op REG amod2 
+       | REG ASSIGN REG op_bar_op REG COMMA REG ASSIGN REG op_bar_op REG amod2
        {
          if (!REG_SAME ($3, $9) || !REG_SAME ($5, $11))
            return yyerror ("Differing source registers");
 
-         if (!IS_DREG ($1) || !IS_DREG ($3) || !IS_DREG ($5) || !IS_DREG ($7)) 
+         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)
            {
              notethat ("dsp32alu:  dregs = dregs .|. dregs , dregs = dregs .|. dregs (amod2)\n");
@@ -896,7 +996,7 @@ asm_1:
        | 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, &reg7, &reg7, 0, 0, IS_A1 ($3));
        }
        | A_ZERO_DOT_L ASSIGN HALF_REG
        {
@@ -975,22 +1075,6 @@ asm_1:
            }
        }
 
-       | 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
        {
@@ -1019,7 +1103,7 @@ asm_1:
        }
 
        | HALF_REG ASSIGN HALF_REG ASSIGN SIGN LPAREN HALF_REG RPAREN STAR
-         HALF_REG PLUS SIGN LPAREN HALF_REG RPAREN STAR HALF_REG 
+         HALF_REG PLUS SIGN LPAREN HALF_REG RPAREN STAR HALF_REG
        {
          if (IS_HCOMPL ($1, $3) && IS_HCOMPL ($7, $14) && IS_HCOMPL ($10, $17))
            {
@@ -1032,7 +1116,7 @@ asm_1:
          else
            return yyerror ("Dregs expected");
        }
-       | REG ASSIGN REG plus_minus REG amod1 
+       | REG ASSIGN REG plus_minus REG amod1
        {
          if (IS_DREG ($1) && IS_DREG ($3) && IS_DREG ($5))
            {
@@ -1079,7 +1163,7 @@ asm_1:
        | 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, &reg7, &reg7, 0, 0, IS_A1 ($3));
        }
        | HALF_REG ASSIGN HALF_REG plus_minus HALF_REG amod1
        {
@@ -1092,7 +1176,7 @@ asm_1:
          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, &reg7, &reg7, 0, 0, 2);
            }
          else
            return yyerror ("Bad value, 0 expected");
@@ -1104,7 +1188,7 @@ asm_1:
          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, &reg7, &reg7, 1, 0, IS_A1 ($1));
            }
          else
            return yyerror ("Registers must be equal");
@@ -1143,12 +1227,12 @@ asm_1:
            return yyerror ("Dregs expected");
        }
 
-       | a_assign REG_A 
+       | a_assign REG_A
        {
          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, &reg7, &reg7, IS_A1 ($1), 0, 3);
            }
          else
            return yyerror ("Accu reg arguments must differ");
@@ -1244,7 +1328,7 @@ asm_1:
                  notethat ("LDIMMhalf: regs = luimm16 (x)\n");
                  /* reg, H, S, Z.   */
                  $$ = LDIMMHALF_R5 (&$1, 0, 1, 0, $3);
-               } 
+               }
            }
          else
            {
@@ -1268,18 +1352,18 @@ asm_1:
          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, &reg7, &reg7, 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, &reg7, &reg7, 0, 0, 1);
            }
          else
            return yyerror ("Register mismatch");
        }
 
-       | REG ASSIGN REG op_bar_op REG amod0 
+       | REG ASSIGN REG op_bar_op REG amod0
        {
          if (IS_DREG ($1) && IS_DREG ($3) && IS_DREG ($5))
            {
@@ -1306,7 +1390,7 @@ asm_1:
          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, &reg7, &reg7, 0, 0, 3);
            }
          else
            return yyerror ("Register mismatch");
@@ -1317,7 +1401,7 @@ asm_1:
          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, &reg7, &reg7, 0, 0, 3);
            }
          else
            return yyerror ("Register mismatch");
@@ -1328,7 +1412,7 @@ asm_1:
          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, &reg7, &reg7, $3.r0, 0, 3);
            }
          else
            return yyerror ("Register mismatch");
@@ -1388,7 +1472,7 @@ asm_1:
          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, &reg7, &reg7, $4.r0, 0, 2);
            }
          else
            return yyerror ("Register mismatch");
@@ -1432,6 +1516,8 @@ asm_1:
              notethat ("COMPI2opD: dregs += imm7\n");
              $$ = COMPI2OPD (&$1, imm7 ($3), 1);
            }
+         else if ((IS_DREG ($1) || IS_PREG ($1)) && IS_CONST ($3))
+           return yyerror ("Immediate value out of range");
          else
            return yyerror ("Register mismatch");
        }
@@ -1465,7 +1551,7 @@ asm_1:
          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, &reg7, &reg7, 1, 0, 2);
            }
          else
            return yyerror ("Register mismatch");
@@ -1508,7 +1594,7 @@ asm_1:
          else
            return yyerror ("Register mismatch");
        }
-                       
+
 /*  COMP3 CCFLAG.  */
        | REG ASSIGN REG BAR REG
        {
@@ -1552,36 +1638,40 @@ asm_1:
        }
        | 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
        {
-         if (REG_CLASS($3) == REG_CLASS($5))
+         if ((IS_DREG ($3) && IS_DREG ($5))
+             || (IS_PREG ($3) && IS_PREG ($5)))
            {
              notethat ("CCflag: CC = dpregs < dpregs\n");
              $$ = CCFLAG (&$3, $5.regno & CODE_MASK, $6.r0, 0, IS_PREG ($3) ? 1 : 0);
            }
          else
-           return yyerror ("Compare only of same register class");
+           return yyerror ("Bad register in comparison");
        }
        | CCREG ASSIGN REG LESS_THAN expr iu_or_nothing
        {
+         if (!IS_DREG ($3) && !IS_PREG ($3))
+           return yyerror ("Bad register in comparison");
+
          if (($6.r0 == 1 && IS_IMM ($5, 3))
              || ($6.r0 == 3 && IS_UIMM ($5, 3)))
            {
@@ -1593,14 +1683,20 @@ asm_1:
        }
        | CCREG ASSIGN REG _ASSIGN_ASSIGN REG
        {
-         if (REG_CLASS($3) == REG_CLASS($5))
+         if ((IS_DREG ($3) && IS_DREG ($5))
+             || (IS_PREG ($3) && IS_PREG ($5)))
            {
              notethat ("CCflag: CC = dpregs == dpregs\n");
              $$ = CCFLAG (&$3, $5.regno & CODE_MASK, 0, 0, IS_PREG ($3) ? 1 : 0);
-           } 
+           }
+         else
+           return yyerror ("Bad register in comparison");
        }
        | CCREG ASSIGN REG _ASSIGN_ASSIGN expr
        {
+         if (!IS_DREG ($3) && !IS_PREG ($3))
+           return yyerror ("Bad register in comparison");
+
          if (IS_IMM ($5, 3))
            {
              notethat ("CCflag: CC = dpregs == imm3\n");
@@ -1611,44 +1707,36 @@ asm_1:
        }
        | 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 (REG_CLASS($3) == REG_CLASS($5))
+         if ((IS_DREG ($3) && IS_DREG ($5))
+             || (IS_PREG ($3) && IS_PREG ($5)))
            {
-             notethat ("CCflag: CC = pregs <= pregs (..)\n");
+             notethat ("CCflag: CC = dpregs <= dpregs (..)\n");
              $$ = CCFLAG (&$3, $5.regno & CODE_MASK,
                           1 + $6.r0, 0, IS_PREG ($3) ? 1 : 0);
            }
          else
-           return yyerror ("Compare only of same register class");
+           return yyerror ("Bad register in comparison");
        }
        | CCREG ASSIGN REG _LESS_THAN_ASSIGN expr iu_or_nothing
        {
+         if (!IS_DREG ($3) && !IS_PREG ($3))
+           return yyerror ("Bad register in comparison");
+
          if (($6.r0 == 1 && IS_IMM ($5, 3))
              || ($6.r0 == 3 && IS_UIMM ($5, 3)))
            {
-             if (IS_DREG ($3))
-               {
-                 notethat ("CCflag: CC = dregs <= (u)imm3\n");
-                 /*    x       y     opc     I     G   */
-                 $$ = CCFLAG (&$3, imm3 ($5), 1 + $6.r0, 1, 0);
-               }
-             else if (IS_PREG ($3))
-               {
-                 notethat ("CCflag: CC = pregs <= (u)imm3\n");
-                 /*    x       y     opc     I     G   */
-                 $$ = CCFLAG (&$3, imm3 ($5), 1 + $6.r0, 1, 1);
-               }
-             else
-               return yyerror ("Dreg or Preg expected");
+             notethat ("CCflag: CC = dpregs <= (u)imm3\n");
+             $$ = CCFLAG (&$3, imm3 ($5), 1 + $6.r0, 1, IS_PREG ($3) ? 1 : 0);
            }
          else
            return yyerror ("Bad constant value");
@@ -1673,13 +1761,24 @@ asm_1:
 
        | REG ASSIGN REG
        {
-         if (IS_ALLREG ($1) && IS_ALLREG ($3))
+         if ((IS_GENREG ($1) && IS_GENREG ($3))
+             || (IS_GENREG ($1) && IS_DAGREG ($3))
+             || (IS_DAGREG ($1) && IS_GENREG ($3))
+             || (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_GENREG ($3))
+             || (IS_ALLREG ($1) && IS_EMUDAT ($3))
+             || (IS_EMUDAT ($1) && IS_ALLREG ($3))
+             || (IS_SYSREG ($1) && $3.regno == REG_USP))
            {
-             notethat ("REGMV: allregs = allregs\n");
              $$ = bfin_gen_regmv (&$3, &$1);
            }
          else
-           return yyerror ("Register mismatch");
+           return yyerror ("Unsupported register move");
        }
 
        | CCREG ASSIGN REG
@@ -1690,7 +1789,7 @@ asm_1:
              $$ = bfin_gen_cc2dreg (1, &$3);
            }
          else
-           return yyerror ("Register mismatch");
+           return yyerror ("Only 'CC = Dreg' supported");
        }
 
        | REG ASSIGN CCREG
@@ -1701,7 +1800,7 @@ asm_1:
              $$ = bfin_gen_cc2dreg (0, &$1);
            }
          else
-           return yyerror ("Register mismatch");
+           return yyerror ("Only 'Dreg = CC' supported");
        }
 
        | CCREG _ASSIGN_BANG CCREG
@@ -1709,7 +1808,7 @@ asm_1:
          notethat ("CC2dreg: CC =! CC\n");
          $$ = bfin_gen_cc2dreg (3, 0);
        }
-                       
+
 /* DSPMULT.  */
 
        | HALF_REG ASSIGN multiply_halfregs opt_mode
@@ -1719,6 +1818,11 @@ asm_1:
          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,
@@ -1728,12 +1832,12 @@ asm_1:
          else
            {
              $$ = DSP32MULT (0, 0, $4.mod, 0, 0,
-                             0, 0, IS_H ($3.s0), IS_H ($3.s1), 
+                             0, 0, IS_H ($3.s0), IS_H ($3.s1),
                              &$1, 0, &$3.s0, &$3.s1, 1);
            }
        }
 
-       | REG ASSIGN multiply_halfregs opt_mode 
+       | REG ASSIGN multiply_halfregs opt_mode
        {
          /* Odd registers can use (M).  */
          if (!IS_DREG ($1))
@@ -1742,6 +1846,10 @@ asm_1:
          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");
@@ -1754,7 +1862,7 @@ asm_1:
            {
              notethat ("dsp32mult: dregs = multiply_halfregs opt_mode\n");
              $$ = DSP32MULT (0, 0, $4.mod, 0, 1,
-                             0, 0, IS_H ($3.s0), IS_H ($3.s1), 
+                             0, 0, IS_H ($3.s0), IS_H ($3.s1),
                              &$1,  0, &$3.s0, &$3.s1, 1);
            }
        }
@@ -1762,7 +1870,7 @@ asm_1:
        | HALF_REG ASSIGN multiply_halfregs opt_mode COMMA
           HALF_REG ASSIGN multiply_halfregs opt_mode
        {
-         if (!IS_DREG ($1) || !IS_DREG ($6)) 
+         if (!IS_DREG ($1) || !IS_DREG ($6))
            return yyerror ("Dregs expected");
 
          if (!IS_HCOMPL($1, $6))
@@ -1790,7 +1898,7 @@ asm_1:
 
        | REG ASSIGN multiply_halfregs opt_mode COMMA REG ASSIGN multiply_halfregs opt_mode
        {
-         if (!IS_DREG ($1) || !IS_DREG ($6)) 
+         if (!IS_DREG ($1) || !IS_DREG ($6))
            return yyerror ("Dregs expected");
 
          if ((IS_EVEN ($1) && $6.regno - $1.regno != 1)
@@ -1892,22 +2000,20 @@ asm_1:
          else
            return yyerror ("Bad shift value or register");
        }
-       | HALF_REG ASSIGN HALF_REG LESS_LESS expr
+       | 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, 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");
@@ -1926,7 +2032,7 @@ asm_1:
                }
              else
                {
-                 
+
                  op = 2;
                  notethat ("dsp32shift: dregs = ASHIFT dregs BY dregs_lo (.)\n");
                }
@@ -1989,7 +2095,7 @@ asm_1:
            return yyerror ("Register mismatch");
        }
 
-       | REG ASSIGN EXTRACT LPAREN REG COMMA HALF_REG RPAREN xpmod 
+       | REG ASSIGN EXTRACT LPAREN REG COMMA HALF_REG RPAREN xpmod
        {
          if (IS_DREG ($1) && IS_DREG ($5) && IS_DREG_L ($7))
            {
@@ -2166,7 +2272,7 @@ asm_1:
            return yyerror ("Register mismatch");
        }
 
-       | HALF_REG ASSIGN CCREG ASSIGN BXORSHIFT LPAREN REG_A COMMA REG RPAREN 
+       | HALF_REG ASSIGN CCREG ASSIGN BXORSHIFT LPAREN REG_A COMMA REG RPAREN
        {
          if (IS_DREG ($1)
              && $7.regno == REG_A0
@@ -2225,7 +2331,7 @@ asm_1:
            return yyerror ("Register mismatch");
        }
 
-       | a_assign ROT REG_A BY expr 
+       | a_assign ROT REG_A BY expr
        {
          if (IS_IMM ($5, 6))
            {
@@ -2236,7 +2342,7 @@ asm_1:
            return yyerror ("Register mismatch");
        }
 
-       | REG ASSIGN ROT REG BY expr 
+       | REG ASSIGN ROT REG BY expr
        {
          if (IS_DREG ($1) && IS_DREG ($4) && IS_IMM ($6, 6))
            {
@@ -2278,9 +2384,9 @@ asm_1:
          else
            return yyerror ("Register mismatch");
        }
-       
+
        /* The ASR bit is just inverted here. */
-       | HALF_REG ASSIGN VIT_MAX LPAREN REG RPAREN asr_asl 
+       | HALF_REG ASSIGN VIT_MAX LPAREN REG RPAREN asr_asl
        {
          if (IS_DREG_L ($1) && IS_DREG ($5))
            {
@@ -2291,7 +2397,7 @@ asm_1:
            return yyerror ("Register mismatch");
        }
 
-       | REG ASSIGN VIT_MAX LPAREN REG COMMA REG RPAREN asr_asl 
+       | REG ASSIGN VIT_MAX LPAREN REG COMMA REG RPAREN asr_asl
        {
          if (IS_DREG ($1) && IS_DREG ($5) && IS_DREG ($7))
            {
@@ -2304,6 +2410,9 @@ asm_1:
 
        | 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");
@@ -2597,6 +2706,9 @@ asm_1:
        {
          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);
            }
@@ -2883,76 +2995,105 @@ asm_1:
 
        | B LBRACK REG post_op RBRACK ASSIGN REG
        {
-         if (IS_PREG ($3) && IS_DREG ($7))
-           {
-             notethat ("LDST: B [ pregs <post_op> ] = dregs\n");
-             $$ = LDST (&$3, &$7, $4.x0, 2, 0, 1);
-           }
-         else
-           return yyerror ("Register mismatch");
+         if (!IS_DREG ($7))
+           return yyerror ("Dreg expected for source operand");
+         if (!IS_PREG ($3))
+           return yyerror ("Preg expected in address");
+
+         notethat ("LDST: B [ pregs <post_op> ] = dregs\n");
+         $$ = LDST (&$3, &$7, $4.x0, 2, 0, 1);
        }
 
 /* LDSTidxI:   B [ pregs + imm16 ] = dregs.  */
        | B LBRACK REG plus_minus expr RBRACK ASSIGN REG
        {
-         if (IS_PREG ($3) && IS_RANGE(16, $5, $4.r0, 1) && IS_DREG ($8))
+         Expr_Node *tmp = $5;
+
+         if (!IS_DREG ($8))
+           return yyerror ("Dreg expected for source operand");
+         if (!IS_PREG ($3))
+           return yyerror ("Preg expected in address");
+
+         if (IS_RELOC ($5))
+           return yyerror ("Plain symbol used as offset");
+
+         if ($4.r0)
+           tmp = unary (Expr_Op_Type_NEG, tmp);
+
+         if (in_range_p (tmp, -32768, 32767, 0))
            {
              notethat ("LDST: B [ pregs + imm16 ] = dregs\n");
-             if ($4.r0)
-               neg_value ($5);
              $$ = LDSTIDXI (&$3, &$8, 1, 2, 0, $5);
            }
          else
-           return yyerror ("Register mismatch or const size wrong");
+           return yyerror ("Displacement out of range");
        }
 
 
 /* LDSTii:     W [ pregs + uimm4s2 ] = dregs.  */
        | W LBRACK REG plus_minus expr RBRACK ASSIGN REG
        {
-         if (IS_PREG ($3) && IS_URANGE (4, $5, $4.r0, 2) && IS_DREG ($8))
+         Expr_Node *tmp = $5;
+
+         if (!IS_DREG ($8))
+           return yyerror ("Dreg expected for source operand");
+         if (!IS_PREG ($3))
+           return yyerror ("Preg expected in address");
+
+         if ($4.r0)
+           tmp = unary (Expr_Op_Type_NEG, tmp);
+
+         if (IS_RELOC ($5))
+           return yyerror ("Plain symbol used as offset");
+
+         if (in_range_p (tmp, 0, 30, 1))
            {
              notethat ("LDSTii: W [ pregs +- uimm5m2 ] = dregs\n");
-             $$ = LDSTII (&$3, &$8, $5, 1, 1);
+             $$ = LDSTII (&$3, &$8, tmp, 1, 1);
            }
-         else if (IS_PREG ($3) && IS_RANGE(16, $5, $4.r0, 2) && IS_DREG ($8))
+         else if (in_range_p (tmp, -65536, 65535, 1))
            {
              notethat ("LDSTidxI: W [ pregs + imm17m2 ] = dregs\n");
-             if ($4.r0)
-               neg_value ($5);
-             $$ = LDSTIDXI (&$3, &$8, 1, 1, 0, $5);
+             $$ = LDSTIDXI (&$3, &$8, 1, 1, 0, tmp);
            }
          else
-           return yyerror ("Bad register(s) or wrong constant size");
+           return yyerror ("Displacement out of range");
        }
 
 /* LDST:       W [ pregs <post_op> ] = dregs.  */
        | W LBRACK REG post_op RBRACK ASSIGN REG
        {
-         if (IS_PREG ($3) && IS_DREG ($7))
-           {
-             notethat ("LDST: W [ pregs <post_op> ] = dregs\n");
-             $$ = LDST (&$3, &$7, $4.x0, 1, 0, 1);
-           }
-         else
-           return yyerror ("Bad register(s) for STORE");
+         if (!IS_DREG ($7))
+           return yyerror ("Dreg expected for source operand");
+         if (!IS_PREG ($3))
+           return yyerror ("Preg expected in address");
+
+         notethat ("LDST: W [ pregs <post_op> ] = dregs\n");
+         $$ = LDST (&$3, &$7, $4.x0, 1, 0, 1);
        }
 
        | W LBRACK REG post_op RBRACK ASSIGN HALF_REG
        {
+         if (!IS_DREG ($7))
+           return yyerror ("Dreg expected for source operand");
+         if ($4.x0 == 2)
+           {
+             if (!IS_IREG ($3) && !IS_PREG ($3))
+               return yyerror ("Ireg or Preg expected in address");
+           }
+         else if (!IS_IREG ($3))
+           return yyerror ("Ireg expected in address");
+
          if (IS_IREG ($3))
            {
              notethat ("dspLDST: W [ iregs <post_op> ] = dregs_half\n");
              $$ = DSPLDST (&$3, 1 + IS_H ($7), &$7, $4.x0, 1);
            }
-         else if ($4.x0 == 2 && IS_PREG ($3) && IS_DREG ($7))
+         else
            {
-             notethat ("LDSTpmod: W [ pregs <post_op>] = dregs_half\n");
+             notethat ("LDSTpmod: W [ pregs ] = dregs_half\n");
              $$ = LDSTPMOD (&$3, &$7, &$3, 1 + IS_H ($7), 1);
-             
            }
-         else
-           return yyerror ("Bad register(s) for STORE");
        }
 
 /* LDSTiiFP:   [ FP - const ] = dpregs.  */
@@ -2962,14 +3103,17 @@ asm_1:
          int ispreg = IS_PREG ($7);
 
          if (!IS_PREG ($2))
-           return yyerror ("Preg expected for indirect");
+           return yyerror ("Preg expected in address");
 
          if (!IS_DREG ($7) && !ispreg)
-           return yyerror ("Bad source register for STORE");
+           return yyerror ("Preg expected for source operand");
 
          if ($3.r0)
            tmp = unary (Expr_Op_Type_NEG, tmp);
 
+         if (IS_RELOC ($4))
+           return yyerror ("Plain symbol used as offset");
+
          if (in_range_p (tmp, 0, 63, 3))
            {
              notethat ("LDSTii: dpregs = [ pregs + uimm6m4 ]\n");
@@ -2984,105 +3128,128 @@ asm_1:
          else if (in_range_p (tmp, -131072, 131071, 3))
            {
              notethat ("LDSTidxI: [ pregs + imm18m4 ] = dpregs\n");
-             $$ = LDSTIDXI (&$2, &$7, 1, 0, ispreg ? 1: 0, tmp);
+             $$ = LDSTIDXI (&$2, &$7, 1, 0, ispreg ? 1 : 0, tmp);
            }
          else
-           return yyerror ("Displacement out of range for store");
+           return yyerror ("Displacement out of range");
        }
 
        | REG ASSIGN W LBRACK REG plus_minus expr RBRACK xpmod
        {
-         if (IS_DREG ($1) && IS_PREG ($5) && IS_URANGE (4, $7, $6.r0, 2))
+         Expr_Node *tmp = $7;
+         if (!IS_DREG ($1))
+           return yyerror ("Dreg expected for destination operand");
+         if (!IS_PREG ($5))
+           return yyerror ("Preg expected in address");
+
+         if ($6.r0)
+           tmp = unary (Expr_Op_Type_NEG, tmp);
+
+         if (IS_RELOC ($7))
+           return yyerror ("Plain symbol used as offset");
+
+         if (in_range_p (tmp, 0, 30, 1))
            {
-             notethat ("LDSTii: dregs = W [ pregs + uimm4s2 ] (.)\n");
-             $$ = LDSTII (&$5, &$1, $7, 0, 1 << $9.r0);
+             notethat ("LDSTii: dregs = W [ pregs + uimm5m2 ] (.)\n");
+             $$ = LDSTII (&$5, &$1, tmp, 0, 1 << $9.r0);
            }
-         else if (IS_DREG ($1) && IS_PREG ($5) && IS_RANGE(16, $7, $6.r0, 2))
+         else if (in_range_p (tmp, -65536, 65535, 1))
            {
              notethat ("LDSTidxI: dregs = W [ pregs + imm17m2 ] (.)\n");
-             if ($6.r0)
-               neg_value ($7);
-             $$ = LDSTIDXI (&$5, &$1, 0, 1, $9.r0, $7);
+             $$ = LDSTIDXI (&$5, &$1, 0, 1, $9.r0, tmp);
            }
          else
-           return yyerror ("Bad register or constant for LOAD");
-       }       
+           return yyerror ("Displacement out of range");
+       }
 
        | HALF_REG ASSIGN W LBRACK REG post_op RBRACK
        {
+         if (!IS_DREG ($1))
+           return yyerror ("Dreg expected for source operand");
+         if ($6.x0 == 2)
+           {
+             if (!IS_IREG ($5) && !IS_PREG ($5))
+               return yyerror ("Ireg or Preg expected in address");
+           }
+         else if (!IS_IREG ($5))
+           return yyerror ("Ireg expected in address");
+
          if (IS_IREG ($5))
            {
-             notethat ("dspLDST: dregs_half = W [ iregs ]\n");
+             notethat ("dspLDST: dregs_half = W [ iregs <post_op> ]\n");
              $$ = DSPLDST(&$5, 1 + IS_H ($1), &$1, $6.x0, 0);
            }
-         else if ($6.x0 == 2 && IS_DREG ($1) && IS_PREG ($5))
+         else
            {
-             notethat ("LDSTpmod: dregs_half = W [ pregs ]\n");
+             notethat ("LDSTpmod: dregs_half = W [ pregs <post_op> ]\n");
              $$ = LDSTPMOD (&$5, &$1, &$5, 1 + IS_H ($1), 0);
            }
-         else
-           return yyerror ("Bad register or post_op for LOAD");
        }
 
 
        | REG ASSIGN W LBRACK REG post_op RBRACK xpmod
        {
-         if (IS_DREG ($1) && IS_PREG ($5))
-           {
-             notethat ("LDST: dregs = W [ pregs <post_op> ] (.)\n");
-             $$ = LDST (&$5, &$1, $6.x0, 1, $8.r0, 0);
-           }
-         else
-           return yyerror ("Bad register for LOAD");
+         if (!IS_DREG ($1))
+           return yyerror ("Dreg expected for destination operand");
+         if (!IS_PREG ($5))
+           return yyerror ("Preg expected in address");
+
+         notethat ("LDST: dregs = W [ pregs <post_op> ] (.)\n");
+         $$ = LDST (&$5, &$1, $6.x0, 1, $8.r0, 0);
        }
 
        | REG ASSIGN W LBRACK REG _PLUS_PLUS REG RBRACK xpmod
        {
-         if (IS_DREG ($1) && IS_PREG ($5) && IS_PREG ($7))
-           {
-             notethat ("LDSTpmod: dregs = W [ pregs ++ pregs ] (.)\n");
-             $$ = LDSTPMOD (&$5, &$1, &$7, 3, $9.r0);
-           }
-         else
-           return yyerror ("Bad register for LOAD");
+         if (!IS_DREG ($1))
+           return yyerror ("Dreg expected for destination operand");
+         if (!IS_PREG ($5) || !IS_PREG ($7))
+           return yyerror ("Preg expected in address");
+
+         notethat ("LDSTpmod: dregs = W [ pregs ++ pregs ] (.)\n");
+         $$ = LDSTPMOD (&$5, &$1, &$7, 3, $9.r0);
        }
 
        | HALF_REG ASSIGN W LBRACK REG _PLUS_PLUS REG RBRACK
        {
-         if (IS_DREG ($1) && IS_PREG ($5) && IS_PREG ($7))
-           {
-             notethat ("LDSTpmod: dregs_half = W [ pregs ++ pregs ]\n");
-             $$ = LDSTPMOD (&$5, &$1, &$7, 1 + IS_H ($1), 0);
-           }
-         else
-           return yyerror ("Bad register for LOAD");
+         if (!IS_DREG ($1))
+           return yyerror ("Dreg expected for destination operand");
+         if (!IS_PREG ($5) || !IS_PREG ($7))
+           return yyerror ("Preg expected in address");
+
+         notethat ("LDSTpmod: dregs_half = W [ pregs ++ pregs ]\n");
+         $$ = LDSTPMOD (&$5, &$1, &$7, 1 + IS_H ($1), 0);
        }
 
        | LBRACK REG post_op RBRACK ASSIGN REG
        {
-         if (IS_IREG ($2) && IS_DREG ($6))
+         if (!IS_IREG ($2) && !IS_PREG ($2))
+           return yyerror ("Ireg or Preg expected in address");
+         else if (IS_IREG ($2) && !IS_DREG ($6))
+           return yyerror ("Dreg expected for source operand");
+         else if (IS_PREG ($2) && !IS_DREG ($6) && !IS_PREG ($6))
+           return yyerror ("Dreg or Preg expected for source operand");
+
+         if (IS_IREG ($2))
            {
              notethat ("dspLDST: [ iregs <post_op> ] = dregs\n");
              $$ = DSPLDST(&$2, 0, &$6, $3.x0, 1);
            }
-         else if (IS_PREG ($2) && IS_DREG ($6))
+         else if (IS_DREG ($6))
            {
              notethat ("LDST: [ pregs <post_op> ] = dregs\n");
              $$ = LDST (&$2, &$6, $3.x0, 0, 0, 1);
            }
-         else if (IS_PREG ($2) && IS_PREG ($6))
+         else
            {
              notethat ("LDST: [ pregs <post_op> ] = pregs\n");
              $$ = LDST (&$2, &$6, $3.x0, 0, 1, 1);
            }
-         else
-           return yyerror ("Bad register for STORE");
        }
 
        | LBRACK REG _PLUS_PLUS REG RBRACK ASSIGN REG
        {
-         if (! IS_DREG ($7))
-           return yyerror ("Expected Dreg for last argument");
+         if (!IS_DREG ($7))
+           return yyerror ("Dreg expected for source operand");
 
          if (IS_IREG ($2) && IS_MREG ($4))
            {
@@ -3095,62 +3262,76 @@ asm_1:
              $$ = LDSTPMOD (&$2, &$7, &$4, 0, 1);
            }
          else
-           return yyerror ("Bad register for STORE");
+           return yyerror ("Preg ++ Preg or Ireg ++ Mreg expected in address");
        }
-                       
+
        | W LBRACK REG _PLUS_PLUS REG RBRACK ASSIGN HALF_REG
        {
          if (!IS_DREG ($8))
-           return yyerror ("Expect Dreg as last argument");
+           return yyerror ("Dreg expected for source operand");
+
          if (IS_PREG ($3) && IS_PREG ($5))
            {
              notethat ("LDSTpmod: W [ pregs ++ pregs ] = dregs_half\n");
              $$ = LDSTPMOD (&$3, &$8, &$5, 1 + IS_H ($8), 1);
            }
          else
-           return yyerror ("Bad register for STORE");
+           return yyerror ("Preg ++ Preg expected in address");
        }
 
        | REG ASSIGN B LBRACK REG plus_minus expr RBRACK xpmod
        {
-         if (IS_DREG ($1) && IS_PREG ($5) && IS_RANGE(16, $7, $6.r0, 1))
+         Expr_Node *tmp = $7;
+         if (!IS_DREG ($1))
+           return yyerror ("Dreg expected for destination operand");
+         if (!IS_PREG ($5))
+           return yyerror ("Preg expected in address");
+
+         if ($6.r0)
+           tmp = unary (Expr_Op_Type_NEG, tmp);
+
+         if (IS_RELOC ($7))
+           return yyerror ("Plain symbol used as offset");
+
+         if (in_range_p (tmp, -32768, 32767, 0))
            {
              notethat ("LDSTidxI: dregs = B [ pregs + imm16 ] (%c)\n",
                       $9.r0 ? 'X' : 'Z');
-             if ($6.r0)
-               neg_value ($7);
-             $$ = LDSTIDXI (&$5, &$1, 0, 2, $9.r0, $7);
+             $$ = LDSTIDXI (&$5, &$1, 0, 2, $9.r0, tmp);
            }
          else
-           return yyerror ("Bad register or value for LOAD");
+           return yyerror ("Displacement out of range");
        }
 
        | REG ASSIGN B LBRACK REG post_op RBRACK xpmod
        {
-         if (IS_DREG ($1) && IS_PREG ($5))
-           {
-             notethat ("LDST: dregs = B [ pregs <post_op> ] (%c)\n",
-                      $8.r0 ? 'X' : 'Z');
-             $$ = LDST (&$5, &$1, $6.x0, 2, $8.r0, 0);
-           }
-         else
-           return yyerror ("Bad register for LOAD");
+         if (!IS_DREG ($1))
+           return yyerror ("Dreg expected for destination operand");
+         if (!IS_PREG ($5))
+           return yyerror ("Preg expected in address");
+
+         notethat ("LDST: dregs = B [ pregs <post_op> ] (%c)\n",
+                   $8.r0 ? 'X' : 'Z');
+         $$ = LDST (&$5, &$1, $6.x0, 2, $8.r0, 0);
        }
-                       
+
        | REG ASSIGN LBRACK REG _PLUS_PLUS REG RBRACK
        {
-         if (IS_DREG ($1) && IS_IREG ($4) && IS_MREG ($6))
+         if (!IS_DREG ($1))
+           return yyerror ("Dreg expected for destination operand");
+
+         if (IS_IREG ($4) && IS_MREG ($6))
            {
              notethat ("dspLDST: dregs = [ iregs ++ mregs ]\n");
              $$ = DSPLDST(&$4, $6.regno & CODE_MASK, &$1, 3, 0);
            }
-         else if (IS_DREG ($1) && IS_PREG ($4) && IS_PREG ($6))
+         else if (IS_PREG ($4) && IS_PREG ($6))
            {
              notethat ("LDSTpmod: dregs = [ pregs ++ pregs ]\n");
              $$ = LDSTPMOD (&$4, &$1, &$6, 0, 0);
            }
          else
-           return yyerror ("Bad register for LOAD");
+           return yyerror ("Preg ++ Preg or Ireg ++ Mreg expected in address");
        }
 
        | REG ASSIGN LBRACK REG plus_minus got_or_expr RBRACK
@@ -3160,18 +3341,24 @@ asm_1:
          int isgot = IS_RELOC($6);
 
          if (!IS_PREG ($4))
-           return yyerror ("Preg expected for indirect");
+           return yyerror ("Preg expected in address");
 
          if (!IS_DREG ($1) && !ispreg)
-           return yyerror ("Bad destination register for LOAD");
+           return yyerror ("Dreg or Preg expected for destination operand");
+
+         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);
 
-         if(isgot){
+         if (isgot)
+           {
              notethat ("LDSTidxI: dpregs = [ pregs + sym@got ]\n");
-             $$ = LDSTIDXI (&$4, &$1, 0, 0, ispreg ? 1: 0, tmp);
-         }
+             $$ = LDSTIDXI (&$4, &$1, 0, 0, ispreg ? 1 : 0, tmp);
+           }
          else if (in_range_p (tmp, 0, 63, 3))
            {
              notethat ("LDSTii: dpregs = [ pregs + uimm7m4 ]\n");
@@ -3186,26 +3373,34 @@ asm_1:
          else if (in_range_p (tmp, -131072, 131071, 3))
            {
              notethat ("LDSTidxI: dpregs = [ pregs + imm18m4 ]\n");
-             $$ = LDSTIDXI (&$4, &$1, 0, 0, ispreg ? 1: 0, tmp);
-             
+             $$ = LDSTIDXI (&$4, &$1, 0, 0, ispreg ? 1 : 0, tmp);
+
            }
          else
-           return yyerror ("Displacement out of range for load");
+           return yyerror ("Displacement out of range");
        }
 
        | REG ASSIGN LBRACK REG post_op RBRACK
        {
-         if (IS_DREG ($1) && IS_IREG ($4))
+         if (!IS_IREG ($4) && !IS_PREG ($4))
+           return yyerror ("Ireg or Preg expected in address");
+         else if (IS_IREG ($4) && !IS_DREG ($1))
+           return yyerror ("Dreg expected in destination operand");
+         else if (IS_PREG ($4) && !IS_DREG ($1) && !IS_PREG ($1)
+                  && ($4.regno != REG_SP || !IS_ALLREG ($1) || $5.x0 != 0))
+           return yyerror ("Dreg or Preg expected in destination operand");
+
+         if (IS_IREG ($4))
            {
              notethat ("dspLDST: dregs = [ iregs <post_op> ]\n");
              $$ = DSPLDST (&$4, 0, &$1, $5.x0, 0);
            }
-         else if (IS_DREG ($1) && IS_PREG ($4))
+         else if (IS_DREG ($1))
            {
              notethat ("LDST: dregs = [ pregs <post_op> ]\n");
              $$ = LDST (&$4, &$1, $5.x0, 0, 0, 0);
            }
-         else if (IS_PREG ($1) && IS_PREG ($4))
+         else if (IS_PREG ($1))
            {
              if (REG_SAME ($1, $4) && $5.x0 != 2)
                return yyerror ("Pregs can't be same");
@@ -3213,13 +3408,11 @@ asm_1:
              notethat ("LDST: pregs = [ pregs <post_op> ]\n");
              $$ = LDST (&$4, &$1, $5.x0, 0, 1, 0);
            }
-         else if ($4.regno == REG_SP && IS_ALLREG ($1) && $5.x0 == 0)
+         else
            {
              notethat ("PushPopReg: allregs = [ SP ++ ]\n");
              $$ = PUSHPOPREG (&$1, 0);
            }
-         else
-           return yyerror ("Bad register or value");
        }
 
 
@@ -3315,7 +3508,7 @@ asm_1:
          else
            return yyerror ("Bad constant for LINK");
        }
-               
+
        | UNLINK
        {
                notethat ("linkage: UNLINK\n");
@@ -3334,7 +3527,7 @@ asm_1:
            }
          else
            return yyerror ("Bad register or values for LSETUP");
-         
+
        }
        | LSETUP LPAREN expr COMMA expr RPAREN REG ASSIGN REG
        {
@@ -3351,7 +3544,7 @@ asm_1:
        | LSETUP LPAREN expr COMMA expr RPAREN REG ASSIGN REG GREATER_GREATER expr
        {
          if (IS_PCREL4 ($3) && IS_LPPCREL10 ($5)
-             && IS_PREG ($9) && IS_CREG ($7) 
+             && IS_PREG ($9) && IS_CREG ($7)
              && EXPR_VALUE ($11) == 1)
            {
              notethat ("LoopSetup: LSETUP (pcrel4 , lppcrel10 ) counters = pregs >> 1\n");
@@ -3390,8 +3583,57 @@ asm_1:
          else
            return yyerror ("Bad register or values for LOOP");
        }
+
+/* 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))
+           return yyerror ("Invalid expression in LOOP_BEGIN statement");
+
+         bfin_loop_beginend ($2, 1);
+         $$ = 0;
+       }
+
+/* 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))
+           return yyerror ("Invalid expression in LOOP_END statement");
+
+         bfin_loop_beginend ($2, 0);
+         $$ = 0;
+       }
+
 /* pseudoDEBUG.  */
 
+       | ABORT
+       {
+         notethat ("psedoDEBUG: ABORT\n");
+         $$ = bfin_gen_pseudodbg (3, 3, 0);
+       }
+
        | DBG
        {
          notethat ("pseudoDEBUG: DBG\n");
@@ -3405,7 +3647,7 @@ asm_1:
        | 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
@@ -3413,33 +3655,54 @@ asm_1:
          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
        {
          notethat ("psedoDEBUG: DBGHALT\n");
          $$ = bfin_gen_pseudodbg (3, 5, 0);
        }
 
+       | HLT
+       {
+         notethat ("psedoDEBUG: HLT\n");
+         $$ = bfin_gen_pseudodbg (3, 4, 0);
+       }
+
        | DBGA LPAREN HALF_REG COMMA expr RPAREN
        {
-         notethat ("pseudodbg_assert: DBGA (dregs_lo , uimm16 )\n");
+         notethat ("pseudodbg_assert: DBGA (regs_lo/hi , uimm16 )\n");
          $$ = bfin_gen_pseudodbg_assert (IS_H ($3), &$3, uimm16 ($5));
        }
-               
+
        | DBGAH LPAREN REG COMMA expr RPAREN
        {
-         notethat ("pseudodbg_assert: DBGAH (dregs , uimm16 )\n");
+         notethat ("pseudodbg_assert: DBGAH (regs , uimm16 )\n");
          $$ = bfin_gen_pseudodbg_assert (3, &$3, uimm16 ($5));
        }
 
        | DBGAL LPAREN REG COMMA expr RPAREN
        {
-         notethat ("psedodbg_assert: DBGAL (dregs , uimm16 )\n");
+         notethat ("psedodbg_assert: DBGAL (regs , uimm16 )\n");
          $$ = 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);
+       }
 
 ;
 
@@ -3513,7 +3776,7 @@ sco:
        $$.x0 = 1;
        }
        | SCO
-       {       
+       {
        $$.s0 = 1;
        $$.x0 = 1;
        }
@@ -3803,7 +4066,7 @@ min_max:
        $$.r0 = 0;
        }
        ;
+
 op_bar_op:
        _PLUS_BAR_PLUS
        {
@@ -3924,8 +4187,8 @@ b3_op:
 post_op:
        {
        $$.x0 = 2;
-       } 
-       | _PLUS_PLUS 
+       }
+       | _PLUS_PLUS
        {
        $$.x0 = 0;
        }
@@ -3961,6 +4224,11 @@ a_plusassign:
 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);
@@ -3968,11 +4236,6 @@ assign_macfunc:
           $$.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
        {
@@ -3982,6 +4245,11 @@ assign_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;
@@ -3990,6 +4258,11 @@ assign_macfunc:
 
        | 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;
@@ -3998,6 +4271,11 @@ assign_macfunc:
 
        | 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);
@@ -4005,11 +4283,6 @@ assign_macfunc:
           $$.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");
        }
        ;
 
@@ -4072,27 +4345,27 @@ cc_op:
 ccstat:
        CCREG cc_op STATUS_REG
        {
-       $$.r0 = $3.regno;
-       $$.x0 = $2.r0;
-       $$.s0 = 0;
+         $$.r0 = $3.regno;
+         $$.x0 = $2.r0;
+         $$.s0 = 0;
        }
        | CCREG cc_op V
        {
-       $$.r0 = 0x18;
-       $$.x0 = $2.r0;
-       $$.s0 = 0;
+         $$.r0 = 0x18;
+         $$.x0 = $2.r0;
+         $$.s0 = 0;
        }
        | STATUS_REG cc_op CCREG
        {
-       $$.r0 = $1.regno;
-       $$.x0 = $2.r0;
-       $$.s0 = 1;
+         $$.r0 = $1.regno;
+         $$.x0 = $2.r0;
+         $$.s0 = 1;
        }
        | V cc_op CCREG
        {
-       $$.r0 = 0x18;
-       $$.x0 = $2.r0;
-       $$.s0 = 1;
+         $$.r0 = 0x18;
+         $$.x0 = $2.r0;
+         $$.s0 = 1;
        }
        ;
 
@@ -4192,7 +4465,7 @@ expr_1: expr_1 STAR expr_1
        }
        | expr_1 LESS_LESS expr_1
        {
-       $$ = binary (Expr_Op_Type_Lshift, $1, $3);      
+       $$ = binary (Expr_Op_Type_Lshift, $1, $3);
        }
        | expr_1 GREATER_GREATER expr_1
        {
@@ -4210,7 +4483,7 @@ expr_1: expr_1 STAR expr_1
        {
        $$ = binary (Expr_Op_Type_BOR, $1, $3);
        }
-       | eterm 
+       | eterm
        {
        $$ = $1;
        }
@@ -4229,17 +4502,17 @@ mkexpr (int x, SYMBOL_T s)
 }
 
 static int
-value_match (Expr_Node *expr, int sz, int sign, int mul, int issigned)
+value_match (Expr_Node *exp, int sz, int sign, int mul, int issigned)
 {
-  long umax = (1L << sz) - 1;
-  long min = -1L << (sz - 1);
-  long max = (1L << (sz - 1)) - 1;
-       
-  long v = EXPR_VALUE (expr);
+  int umax = (1 << sz) - 1;
+  int min = -(1 << (sz - 1));
+  int max = (1 << (sz - 1)) - 1;
+
+  int v = (EXPR_VALUE (exp)) & 0xffffffff;
 
   if ((v % mul) != 0)
     {
-      error ("%s:%d: Value Error -- Must align to %d\n", __FILE__, __LINE__, mul); 
+      error ("%s:%d: Value Error -- Must align to %d\n", __FILE__, __LINE__, mul);
       return 0;
     }
 
@@ -4257,7 +4530,7 @@ value_match (Expr_Node *expr, int sz, int sign, int mul, int issigned)
 #endif
       return 0;
     }
-  if (v <= umax && v >= 0) 
+  if (v <= umax && v >= 0)
     return 1;
 #ifdef DEBUG
   fprintf(stderr, "unsigned value %lx out of range\n", v * mul);
@@ -4276,48 +4549,48 @@ binary (Expr_Op_Type op, Expr_Node *x, Expr_Node *y)
     {
       switch (op)
        {
-        case Expr_Op_Type_Add: 
+        case Expr_Op_Type_Add:
          x->value.i_value += y->value.i_value;
          break;
-        case Expr_Op_Type_Sub: 
+        case Expr_Op_Type_Sub:
          x->value.i_value -= y->value.i_value;
          break;
-        case Expr_Op_Type_Mult: 
+        case Expr_Op_Type_Mult:
          x->value.i_value *= y->value.i_value;
          break;
-        case Expr_Op_Type_Div: 
+        case Expr_Op_Type_Div:
          if (y->value.i_value == 0)
            error ("Illegal Expression:  Division by zero.");
          else
            x->value.i_value /= y->value.i_value;
          break;
-        case Expr_Op_Type_Mod: 
+        case Expr_Op_Type_Mod:
          x->value.i_value %= y->value.i_value;
          break;
-        case Expr_Op_Type_Lshift: 
+        case Expr_Op_Type_Lshift:
          x->value.i_value <<= y->value.i_value;
          break;
-        case Expr_Op_Type_Rshift: 
+        case Expr_Op_Type_Rshift:
          x->value.i_value >>= y->value.i_value;
          break;
-        case Expr_Op_Type_BAND: 
+        case Expr_Op_Type_BAND:
          x->value.i_value &= y->value.i_value;
          break;
-        case Expr_Op_Type_BOR: 
+        case Expr_Op_Type_BOR:
          x->value.i_value |= y->value.i_value;
          break;
-        case Expr_Op_Type_BXOR: 
+        case Expr_Op_Type_BXOR:
          x->value.i_value ^= y->value.i_value;
          break;
-        case Expr_Op_Type_LAND: 
+        case Expr_Op_Type_LAND:
          x->value.i_value = x->value.i_value && y->value.i_value;
          break;
-        case Expr_Op_Type_LOR: 
+        case Expr_Op_Type_LOR:
          x->value.i_value = x->value.i_value || y->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;
     }
@@ -4350,20 +4623,20 @@ binary (Expr_Op_Type op, Expr_Node *x, Expr_Node *y)
 }
 
 static Expr_Node *
-unary (Expr_Op_Type op, Expr_Node *x) 
+unary (Expr_Op_Type op, Expr_Node *x)
 {
   if (x->type == Expr_Node_Constant)
     {
       switch (op)
        {
-       case Expr_Op_Type_NEG: 
+       case Expr_Op_Type_NEG:
          x->value.i_value = -x->value.i_value;
          break;
        case Expr_Op_Type_COMP:
          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;
     }
@@ -4378,7 +4651,7 @@ unary (Expr_Op_Type op, Expr_Node *x)
 
 int debug_codeselection = 0;
 static void
-notethat (char *format, ...)
+notethat (const char *format, ...)
 {
   va_list ap;
   va_start (ap, format);