This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] CR16 Target specific - bug fixes


Hi,

I have fixed a few issues with CR16 binutils tools.
Could you please review the patch attached with this mail.

Source base is: binutils-2.18 release sources (binutils-2.18.src.tar).

Thanks,
Swami
Index: gas/ChangeLog
===================================================================
--- gas/ChangeLog	(revision 494)
+++ gas/ChangeLog	(working copy)
@@ -1,3 +1,8 @@
+2007-10-01  M R Swami Reddy <MR.Swami.Reddy@nsc.com>
+
+	* config/tc-cr16.c: Replaced 'tabs' with white spaces and
+	added R_CR16_DISP8 as default reloc type for b<cc> instructions.
+
 2007-08-28  Robert Sebastian Gerus  <arachnist@gmail.com>
 
 	* configure.tgt: Add support for i[3-7]86-*-dragonfly*.
Index: gas/config/tc-cr16.c
===================================================================
--- gas/config/tc-cr16.c	(revision 494)
+++ gas/config/tc-cr16.c	(working copy)
@@ -141,92 +141,92 @@
       expression (&exp);
 
       if (*input_line_pointer == ':')
-	{
-	  /* Bitfields.  */
-	  long value = 0;
+        {
+          /* Bitfields.  */
+          long value = 0;
 
-	  for (;;)
-	    {
-	      unsigned long width;
+          for (;;)
+            {
+              unsigned long width;
 
-	      if (*input_line_pointer != ':')
-		{
-		  input_line_pointer = hold;
-		  break;
-		}
-	      if (exp.X_op == O_absent)
-		{
-		  as_warn (_("using a bit field width of zero"));
-		  exp.X_add_number = 0;
-		  exp.X_op = O_constant;
-		}
+              if (*input_line_pointer != ':')
+                {
+                  input_line_pointer = hold;
+                  break;
+                }
+              if (exp.X_op == O_absent)
+                {
+                  as_warn (_("using a bit field width of zero"));
+                  exp.X_add_number = 0;
+                  exp.X_op = O_constant;
+                }
 
-	      if (exp.X_op != O_constant)
-		{
-		  *input_line_pointer = '\0';
-		  as_bad (_("field width \"%s\" too complex for a bitfield"), hold);
-		  *input_line_pointer = ':';
-		  demand_empty_rest_of_line ();
-		  return;
-		}
+              if (exp.X_op != O_constant)
+                {
+                  *input_line_pointer = '\0';
+                  as_bad (_("field width \"%s\" too complex for a bitfield"), hold);
+                  *input_line_pointer = ':';
+                  demand_empty_rest_of_line ();
+                  return;
+                }
 
-	      if ((width = exp.X_add_number) >
-		  (unsigned int)(BITS_PER_CHAR * nbytes))
-		{
-		  as_warn (_("field width %lu too big to fit in %d bytes: truncated to %d bits"), width, nbytes, (BITS_PER_CHAR * nbytes));
-		  width = BITS_PER_CHAR * nbytes;
-		}                   /* Too big.  */
+              if ((width = exp.X_add_number) >
+                  (unsigned int)(BITS_PER_CHAR * nbytes))
+                {
+                  as_warn (_("field width %lu too big to fit in %d bytes: truncated to %d bits"), width, nbytes, (BITS_PER_CHAR * nbytes));
+                  width = BITS_PER_CHAR * nbytes;
+                }                   /* Too big.  */
 
 
-	      if (width > bits_available)
-		{
-		  /* FIXME-SOMEDAY: backing up and reparsing is wasteful.  */
-		  input_line_pointer = hold;
-		  exp.X_add_number = value;
-		  break;
-		}
+              if (width > bits_available)
+                {
+                  /* FIXME-SOMEDAY: backing up and reparsing is wasteful.  */
+                  input_line_pointer = hold;
+                  exp.X_add_number = value;
+                  break;
+                }
 
-	      /* Skip ':'.  */
-	      hold = ++input_line_pointer;
+              /* Skip ':'.  */
+              hold = ++input_line_pointer;
 
-	      expression (&exp);
-	      if (exp.X_op != O_constant)
-		{
-		  char cache = *input_line_pointer;
+              expression (&exp);
+              if (exp.X_op != O_constant)
+                {
+                  char cache = *input_line_pointer;
 
-		  *input_line_pointer = '\0';
-		  as_bad (_("field value \"%s\" too complex for a bitfield"), hold);
-		  *input_line_pointer = cache;
-		  demand_empty_rest_of_line ();
-		  return;
-		}
+                  *input_line_pointer = '\0';
+                  as_bad (_("field value \"%s\" too complex for a bitfield"), hold);
+                  *input_line_pointer = cache;
+                  demand_empty_rest_of_line ();
+                  return;
+                }
 
-	      value |= ((~(-1 << width) & exp.X_add_number)
-			<< ((BITS_PER_CHAR * nbytes) - bits_available));
+              value |= ((~(-1 << width) & exp.X_add_number)
+                        << ((BITS_PER_CHAR * nbytes) - bits_available));
 
-	      if ((bits_available -= width) == 0
-		  || is_it_end_of_statement ()
-		  || *input_line_pointer != ',')
-		break;
+              if ((bits_available -= width) == 0
+                  || is_it_end_of_statement ()
+                  || *input_line_pointer != ',')
+                break;
 
-	      hold = ++input_line_pointer;
-	      expression (&exp);
-	    }
+              hold = ++input_line_pointer;
+              expression (&exp);
+            }
 
-	  exp.X_add_number = value;
-	  exp.X_op = O_constant;
-	  exp.X_unsigned = 1;
-	}
+          exp.X_add_number = value;
+          exp.X_op = O_constant;
+          exp.X_unsigned = 1;
+        }
 
       if ((*(input_line_pointer) == '@') && (*(input_line_pointer +1) == 'c'))
-	code_label = 1;
+        code_label = 1;
       emit_expr (&exp, (unsigned int) nbytes);
       ++c;
       if ((*(input_line_pointer) == '@') && (*(input_line_pointer +1) == 'c'))
-	{
-	  input_line_pointer +=3;
-	  break;
-	}
+        {
+          input_line_pointer +=3;
+          break;
+        }
     }
   while ((*input_line_pointer++ == ','));
 
@@ -373,8 +373,8 @@
   if (reg != NULL)
     {
       if ((reg->value.reg_val != 1) || (reg->value.reg_val != 7)
-	  || (reg->value.reg_val != 9) || (reg->value.reg_val > 10))
-	return reg->value.reg_val;
+          || (reg->value.reg_val != 9) || (reg->value.reg_val > 10))
+        return reg->value.reg_val;
 
       as_bad (_("Unknown register pair - index relative mode: `%d'"), reg->value.reg_val);
     }
@@ -478,9 +478,7 @@
 int
 cr16_force_relocation (fixS *fix)
 {
-  /* REVISIT: Check if the "SWITCH_TABLE (fix)" should be added
-     if (generic_force_reloc (fix) || SWITCH_TABLE (fix))  */
-  if (generic_force_reloc (fix))
+  if (generic_force_reloc (fix) || SWITCH_TABLE (fix))
     return 1;
 
   return 0;
@@ -499,12 +497,12 @@
     case 2: rtype = BFD_RELOC_CR16_NUM16; break;
     case 4:
       if (code_label)
-	{
-	  rtype = BFD_RELOC_CR16_NUM32a;
-	  code_label = 0;
-	}
+        {
+          rtype = BFD_RELOC_CR16_NUM32a;
+          code_label = 0;
+        }
       else
-	rtype = BFD_RELOC_CR16_NUM32;
+        rtype = BFD_RELOC_CR16_NUM32;
       break;
     }
 
@@ -534,21 +532,21 @@
 
           switch (fixP->fx_r_type)
             {
-	    case BFD_RELOC_CR16_NUM8:
-	      fixP->fx_r_type = BFD_RELOC_CR16_NUM8;
-	      break;
-	    case BFD_RELOC_CR16_NUM16:
-	      fixP->fx_r_type = BFD_RELOC_CR16_NUM16;
-	      break;
-	    case BFD_RELOC_CR16_NUM32:
-	      fixP->fx_r_type = BFD_RELOC_CR16_NUM32;
-	      break;
-	    case BFD_RELOC_CR16_NUM32a:
-	      fixP->fx_r_type = BFD_RELOC_CR16_NUM32a;
-	      break;
-	    default:
-	      abort ();
-	      break;
+            case BFD_RELOC_CR16_NUM8:
+              fixP->fx_r_type = BFD_RELOC_CR16_SWITCH8;
+              break;
+            case BFD_RELOC_CR16_NUM16:
+              fixP->fx_r_type = BFD_RELOC_CR16_SWITCH16;
+              break;
+            case BFD_RELOC_CR16_NUM32:
+              fixP->fx_r_type = BFD_RELOC_CR16_SWITCH32;
+              break;
+            case BFD_RELOC_CR16_NUM32a:
+              fixP->fx_r_type = BFD_RELOC_CR16_NUM32a;
+              break;
+            default:
+              abort ();
+              break;
             }
         }
       else
@@ -613,10 +611,41 @@
 {
   /* 'opcode' points to the start of the instruction, whether
      we need to change the instruction's fixed encoding.  */
-  bfd_reloc_code_real_type reloc = BFD_RELOC_NONE;
+  char *opcode = fragP->fr_literal + fragP->fr_fix;
+  bfd_reloc_code_real_type reloc;
 
   subseg_change (sec, 0);
 
+  switch (fragP->fr_subtype)
+    {
+    case 0:
+      reloc = BFD_RELOC_CR16_DISP8;
+      break;
+    case 1:
+      /* If the subtype is not changed due to :m operand qualifier,
+         then no need to update the opcode value.  */
+      if ((int)opcode[1] != 0x18)
+        {
+          opcode[0] = (opcode[0] & 0xf0);
+          opcode[1] = 0x18;
+        }
+      reloc = BFD_RELOC_CR16_DISP16;
+      break;
+    case 2:
+      /* If the subtype is not changed due to :l operand qualifier,
+         then no need to update the opcode value.  */
+      if ((int)opcode[1] != 0)
+        {
+          opcode[2] = opcode[0];
+          opcode[0] = opcode[1];
+          opcode[1] = 0x0;
+        }
+      reloc = BFD_RELOC_CR16_DISP24;
+      break;
+    default:
+      abort();
+    }
+
   fix_new (fragP, fragP->fr_fix,
            bfd_get_reloc_size (bfd_reloc_type_lookup (stdoutput, reloc)),
            fragP->fr_symbol, fragP->fr_offset, 1, reloc);
@@ -752,8 +781,8 @@
 
 static void
 initialise_reg_hash_table (struct hash_control ** hash_table,
-			   const reg_entry * register_table,
-			   const unsigned int num_entries)
+                           const reg_entry * register_table,
+                           const unsigned int num_entries)
 {
   const reg_entry * reg;
   const char *hashret;
@@ -767,8 +796,8 @@
     {
       hashret = hash_insert (* hash_table, reg->name, (char *) reg);
       if (hashret)
-	as_fatal (_("Internal Error:  Can't hash %s: %s"),
-		  reg->name, hashret);
+        as_fatal (_("Internal Error:  Can't hash %s: %s"),
+                  reg->name, hashret);
     }
 }
 
@@ -790,7 +819,7 @@
       const char *mnemonic = cr16_instruction[i].mnemonic;
 
       hashret = hash_insert (cr16_inst_hash, mnemonic,
-			     (char *)(cr16_instruction + i));
+                             (char *)(cr16_instruction + i));
 
       if (hashret != NULL && *hashret != '\0')
         as_fatal (_("Can't hash `%s': %s\n"), cr16_instruction[i].mnemonic,
@@ -845,7 +874,7 @@
     case O_absent:
       /* Missing or bad expr becomes absolute 0.  */
       as_bad (_("missing or invalid displacement expression `%s' taken as 0"),
-	      str);
+              str);
       cr16_ins->exp.X_op = O_constant;
       cr16_ins->exp.X_add_number = 0;
       cr16_ins->exp.X_add_symbol = NULL;
@@ -865,105 +894,105 @@
       relocatable = 1;
 
       if (strneq (input_line_pointer, "@c", 2))
-	symbol_with_at = 1;
+        symbol_with_at = 1;
 
       if (strneq (input_line_pointer, "@l", 2)
-	  || strneq (input_line_pointer, ":l", 2))
-	symbol_with_l = 1;
+          || strneq (input_line_pointer, ":l", 2))
+        symbol_with_l = 1;
 
       if (strneq (input_line_pointer, "@m", 2)
-	  || strneq (input_line_pointer, ":m", 2))
-	symbol_with_m = 1;
+          || strneq (input_line_pointer, ":m", 2))
+        symbol_with_m = 1;
 
       if (strneq (input_line_pointer, "@s", 2)
-	  || strneq (input_line_pointer, ":s", 2))
-	symbol_with_s = 1;
+          || strneq (input_line_pointer, ":s", 2))
+        symbol_with_s = 1;
 
       switch (cur_arg->type)
         {
-	case arg_cr:
-	  if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
-	    {
-	      if (cur_arg->size == 20)
-		cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
-	      else
-		cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a;
-	    }
-	  break;
+        case arg_cr:
+          if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
+            {
+              if (cur_arg->size == 20)
+                cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
+              else
+                cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a;
+            }
+          break;
 
-	case arg_crp:
-	  if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
-	    switch (instruction->size)
-	      {
-	      case 1:
-		switch (cur_arg->size)
-		  {
-		  case 0:
-		    cr16_ins->rtype = BFD_RELOC_CR16_REGREL0;
-		    break;
-		  case 4:
-		    if (IS_INSN_MNEMONIC ("loadb") || IS_INSN_MNEMONIC ("storb"))
-		      cr16_ins->rtype = BFD_RELOC_CR16_REGREL4;
-		    else
-		      cr16_ins->rtype = BFD_RELOC_CR16_REGREL4a;
-		    break;
-		  default: break;
-		  }
-		break;
-	      case 2:
-		cr16_ins->rtype = BFD_RELOC_CR16_REGREL16;
-		break;
-	      case 3:
-		if (cur_arg->size == 20)
-		  cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
-		else
-		  cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a;
-		break;
-	      default:
-		break;
-	      }
-	  break;
+        case arg_crp:
+          if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
+            switch (instruction->size)
+              {
+              case 1:
+                switch (cur_arg->size)
+                  {
+                  case 0:
+                    cr16_ins->rtype = BFD_RELOC_CR16_REGREL0;
+                    break;
+                  case 4:
+                    if (IS_INSN_MNEMONIC ("loadb") || IS_INSN_MNEMONIC ("storb"))
+                      cr16_ins->rtype = BFD_RELOC_CR16_REGREL4;
+                    else
+                      cr16_ins->rtype = BFD_RELOC_CR16_REGREL4a;
+                    break;
+                  default: break;
+                  }
+                break;
+              case 2:
+                cr16_ins->rtype = BFD_RELOC_CR16_REGREL16;
+                break;
+              case 3:
+                if (cur_arg->size == 20)
+                  cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
+                else
+                  cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a;
+                break;
+              default:
+                break;
+              }
+          break;
 
-	case arg_idxr:
-	  if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
-	    cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
-	  break;
+        case arg_idxr:
+          if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
+            cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
+          break;
 
-	case arg_idxrp:
-	  if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
-	    switch (instruction->size)
-	      {
-	      case 1: cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; break;
-	      case 2: cr16_ins->rtype = BFD_RELOC_CR16_REGREL14; break;
-	      case 3: cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; break;
-	      default: break;
-	      }
-	  break;
+        case arg_idxrp:
+          if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
+            switch (instruction->size)
+              {
+              case 1: cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; break;
+              case 2: cr16_ins->rtype = BFD_RELOC_CR16_REGREL14; break;
+              case 3: cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; break;
+              default: break;
+              }
+          break;
 
-	case arg_c:
-	  if (IS_INSN_MNEMONIC ("bal"))
-	    cr16_ins->rtype = BFD_RELOC_CR16_DISP24;
-	  else if (IS_INSN_TYPE (BRANCH_INS))
-	    {
-	      if (symbol_with_s)
-		cr16_ins->rtype = BFD_RELOC_CR16_DISP8;
-	      else if (symbol_with_m)
-		cr16_ins->rtype = BFD_RELOC_CR16_DISP16;
-	      else
-		cr16_ins->rtype = BFD_RELOC_CR16_DISP24;
-	    }
-	  else if (IS_INSN_TYPE (STOR_IMM_INS) || IS_INSN_TYPE (LD_STOR_INS)
-		   || IS_INSN_TYPE (CSTBIT_INS))
-	    {
-	      if (symbol_with_s)
-		as_bad (_("operand %d: illegal use expression: `%s`"), cur_arg_num + 1, str);
-	      if (symbol_with_m)
-		cr16_ins->rtype = BFD_RELOC_CR16_ABS20;
-	      else /* Default to (symbol_with_l) */
-		cr16_ins->rtype = BFD_RELOC_CR16_ABS24;
-	    }
-	  else if (IS_INSN_TYPE (BRANCH_NEQ_INS))
-	    cr16_ins->rtype = BFD_RELOC_CR16_DISP4;
+        case arg_c:
+          if (IS_INSN_MNEMONIC ("bal"))
+            cr16_ins->rtype = BFD_RELOC_CR16_DISP24;
+          else if (IS_INSN_TYPE (BRANCH_INS))
+            {
+              if (symbol_with_l)
+                cr16_ins->rtype = BFD_RELOC_CR16_DISP24;
+              else if (symbol_with_m)
+                cr16_ins->rtype = BFD_RELOC_CR16_DISP16;
+              else
+                cr16_ins->rtype = BFD_RELOC_CR16_DISP8;
+            }
+          else if (IS_INSN_TYPE (STOR_IMM_INS) || IS_INSN_TYPE (LD_STOR_INS)
+                   || IS_INSN_TYPE (CSTBIT_INS))
+            {
+              if (symbol_with_s)
+                as_bad (_("operand %d: illegal use expression: `%s`"), cur_arg_num + 1, str);
+              if (symbol_with_m)
+                cr16_ins->rtype = BFD_RELOC_CR16_ABS20;
+              else /* Default to (symbol_with_l) */
+                cr16_ins->rtype = BFD_RELOC_CR16_ABS24;
+            }
+          else if (IS_INSN_TYPE (BRANCH_NEQ_INS))
+            cr16_ins->rtype = BFD_RELOC_CR16_DISP4;
           break;
 
         case arg_ic:
@@ -979,13 +1008,13 @@
                 cr16_ins->rtype = BFD_RELOC_CR16_IMM32;
             }
           else if (IS_INSN_TYPE (ARITH_BYTE_INS))
-	    {
-	      cr16_ins->rtype = BFD_RELOC_CR16_IMM16;
-	    }
+            {
+              cr16_ins->rtype = BFD_RELOC_CR16_IMM16;
+            }
           break;
         default:
           break;
-	}
+        }
       break;
 
     default:
@@ -1029,9 +1058,9 @@
     {
     case CR16_R_REGTYPE:
       if (! is_procreg)
-	return reg->image;
+        return reg->image;
       else
-	IMAGE_ERR;
+        IMAGE_ERR;
 
     case CR16_P_REGTYPE:
       return reg->image;
@@ -1097,10 +1126,10 @@
 
       /* set the arg->rp, if reg is "r12" or "r13" or "14" or "15" */
       if ((cur_arg->type != arg_rbase)
-	  && ((getreg_image (cur_arg->r) == 12)
-	      || (getreg_image (cur_arg->r) == 13)
-	      || (getreg_image (cur_arg->r) == 14)
-	      || (getreg_image (cur_arg->r) == 15)))
+          && ((getreg_image (cur_arg->r) == 12)
+              || (getreg_image (cur_arg->r) == 13)
+              || (getreg_image (cur_arg->r) == 14)
+              || (getreg_image (cur_arg->r) == 15)))
          {
            cur_arg->type = arg_crp;
            cur_arg->rp = cur_arg->r;
@@ -1137,7 +1166,7 @@
          cur_arg->type = arg_idxrp;
         }
       else
-	cur_arg->rp = -1;
+        cur_arg->rp = -1;
 
        operandE = operandS;
       /* Set displacement constant.  */
@@ -1245,9 +1274,9 @@
     {
     case '$':
       if (strchr (operand, '(') != NULL)
-	cur_arg->type = arg_icr;
+        cur_arg->type = arg_icr;
       else
-	cur_arg->type = arg_ic;
+        cur_arg->type = arg_ic;
       goto set_params;
       break;
 
@@ -1439,7 +1468,7 @@
 is_bcc_insn (char * op)
 {
   if (!(streq (op, "bal") || streq (op, "beq0b") || streq (op, "bnq0b")
-	|| streq (op, "beq0w") || streq (op, "bnq0w")))
+        || streq (op, "beq0w") || streq (op, "bnq0w")))
     if ((op[0] == 'b') && (get_b_cc (op) != NULL))
       return 1;
   return 0;
@@ -1540,18 +1569,18 @@
   if (reg->type == CR16_RP_REGTYPE)
     {
       switch (reg->image)
-	{
-	case 0:  return 0; break;
-	case 2:  return 1; break;
-	case 4:  return 2; break;
-	case 6:  return 3; break;
-	case 8:  return 4; break;
-	case 10: return 5; break;
-	case 3:  return 6; break;
-	case 5:  return 7; break;
-	default:
-	  break;
-	}
+        {
+        case 0:  return 0; break;
+        case 2:  return 1; break;
+        case 4:  return 2; break;
+        case 6:  return 3; break;
+        case 8:  return 4; break;
+        case 10: return 5; break;
+        case 3:  return 6; break;
+        case 5:  return 7; break;
+        default:
+          break;
+        }
     }
 
   IDX_RPAIR_IMAGE_ERR;
@@ -1612,17 +1641,17 @@
       r = r - MAX_REG;
       switch (r)
         {
-	case 4: pregptab_disp = 1;  break;
-	case 6: pregptab_disp = 2;  break;
-	case 8:
-	case 9:
-	case 10:
-	  pregptab_disp = 3;  break;
-	case 12:
-	  pregptab_disp = 4;  break;
-	case 14:
-	  pregptab_disp = 5;  break;
-	default: break;
+        case 4: pregptab_disp = 1;  break;
+        case 6: pregptab_disp = 2;  break;
+        case 8:
+        case 9:
+        case 10:
+          pregptab_disp = 3;  break;
+        case 12:
+          pregptab_disp = 4;  break;
+        case 14:
+          pregptab_disp = 5;  break;
+        default: break;
         }
       reg = &cr16_pregptab[r - pregptab_disp];
     }
@@ -1679,16 +1708,16 @@
     case 32:
     case 28:
       /* mask the upper part of the constant, that is, the bits
-	 going to the lowest byte of output_opcode[0].
-	 The upper part of output_opcode[1] is always filled,
-	 therefore it is always masked with 0xFFFF.  */
+         going to the lowest byte of output_opcode[0].
+         The upper part of output_opcode[1] is always filled,
+         therefore it is always masked with 0xFFFF.  */
       mask = (1 << (nbits - 16)) - 1;
       /* Divide the constant between two consecutive words :
-	 0        1         2         3
-	 +---------+---------+---------+---------+
-	 |         | X X X X | x X x X |         |
-	 +---------+---------+---------+---------+
-	 output_opcode[0]    output_opcode[1]     */
+         0        1         2         3
+         +---------+---------+---------+---------+
+         |         | X X X X | x X x X |         |
+         +---------+---------+---------+---------+
+         output_opcode[0]    output_opcode[1]     */
 
       CR16_PRINT (0, (constant >> WORD_SHIFT) & mask, 0);
       CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
@@ -1700,65 +1729,65 @@
     case 22:
     case 20:
       /* mask the upper part of the constant, that is, the bits
-	 going to the lowest byte of output_opcode[0].
-	 The upper part of output_opcode[1] is always filled,
-	 therefore it is always masked with 0xFFFF.  */
+         going to the lowest byte of output_opcode[0].
+         The upper part of output_opcode[1] is always filled,
+         therefore it is always masked with 0xFFFF.  */
       mask = (1 << (nbits - 16)) - 1;
       /* Divide the constant between two consecutive words :
-	 0        1         2          3
-	 +---------+---------+---------+---------+
-	 |         | X X X X | - X - X |         |
-	 +---------+---------+---------+---------+
-	 output_opcode[0]    output_opcode[1]     */
+         0        1         2          3
+         +---------+---------+---------+---------+
+         |         | X X X X | - X - X |         |
+         +---------+---------+---------+---------+
+         output_opcode[0]    output_opcode[1]     */
 
       if ((instruction->size > 2) && (shift == WORD_SHIFT))
-	{
-	  if (arg->type == arg_idxrp)
-	    {
-	      CR16_PRINT (0, ((constant >> WORD_SHIFT) & mask) << 8, 0);
-	      CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
-	    }
-	  else
-	    {
-	      CR16_PRINT (0, (((((constant >> WORD_SHIFT) & mask) << 8) & 0x0f00) | ((((constant >> WORD_SHIFT) & mask) >> 4) & 0xf)),0);
-	      CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
-	    }
-	}
+        {
+          if (arg->type == arg_idxrp)
+            {
+              CR16_PRINT (0, ((constant >> WORD_SHIFT) & mask) << 8, 0);
+              CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
+            }
+          else
+            {
+              CR16_PRINT (0, (((((constant >> WORD_SHIFT) & mask) << 8) & 0x0f00) | ((((constant >> WORD_SHIFT) & mask) >> 4) & 0xf)),0);
+              CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
+            }
+        }
       else
-	CR16_PRINT (0, constant, shift);
+        CR16_PRINT (0, constant, shift);
       break;
 
     case 14:
       if (arg->type == arg_idxrp)
-	{
-	  if (instruction->size == 2)
-	    {
-	      CR16_PRINT (0, ((constant)&0xf), shift);         // 0-3 bits
-	      CR16_PRINT (0, ((constant>>4)&0x3), (shift+20)); // 4-5 bits
-	      CR16_PRINT (0, ((constant>>6)&0x3), (shift+14)); // 6-7 bits
-	      CR16_PRINT (0, ((constant>>8)&0x3f), (shift+8)); // 8-13 bits
-	    }
-	  else
-	    CR16_PRINT (0, constant, shift);
-	}
+        {
+          if (instruction->size == 2)
+            {
+              CR16_PRINT (0, ((constant)&0xf), shift);         // 0-3 bits
+              CR16_PRINT (0, ((constant>>4)&0x3), (shift+20)); // 4-5 bits
+              CR16_PRINT (0, ((constant>>6)&0x3), (shift+14)); // 6-7 bits
+              CR16_PRINT (0, ((constant>>8)&0x3f), (shift+8)); // 8-13 bits
+            }
+          else
+            CR16_PRINT (0, constant, shift);
+        }
       break;
 
     case 16:
     case 12:
       /* When instruction size is 3 and 'shift' is 16, a 16-bit constant is
-	 always filling the upper part of output_opcode[1]. If we mistakenly
-	 write it to output_opcode[0], the constant prefix (that is, 'match')
-	 will be overriden.
-	 0        1         2         3
-	 +---------+---------+---------+---------+
-	 | 'match' |         | X X X X |         |
-	 +---------+---------+---------+---------+
-	 output_opcode[0]    output_opcode[1]     */
+         always filling the upper part of output_opcode[1]. If we mistakenly
+         write it to output_opcode[0], the constant prefix (that is, 'match')
+         will be overriden.
+         0        1         2         3
+         +---------+---------+---------+---------+
+         | 'match' |         | X X X X |         |
+         +---------+---------+---------+---------+
+         output_opcode[0]    output_opcode[1]     */
 
       if ((instruction->size > 2) && (shift == WORD_SHIFT))
-	CR16_PRINT (1, constant, WORD_SHIFT);
+        CR16_PRINT (1, constant, WORD_SHIFT);
       else
-	CR16_PRINT (0, constant, shift);
+        CR16_PRINT (0, constant, shift);
       break;
 
     case 8:
@@ -1810,35 +1839,35 @@
             +-----------------------------+          */
 
       if (instruction->size == 3)
-	{
-	  CR16_PRINT (0, getidxregp_image (arg->rp), 0);
-	  if (getreg_image (arg->i_r) == 12)
-	    CR16_PRINT (0, 0, 3);
-	  else
-	    CR16_PRINT (0, 1, 3);
-	}
+        {
+          CR16_PRINT (0, getidxregp_image (arg->rp), 0);
+          if (getreg_image (arg->i_r) == 12)
+            CR16_PRINT (0, 0, 3);
+          else
+            CR16_PRINT (0, 1, 3);
+        }
       else
-	{
-	  CR16_PRINT (0, getidxregp_image (arg->rp), 16);
-	  if (getreg_image (arg->i_r) == 12)
-	    CR16_PRINT (0, 0, 19);
-	  else
-	    CR16_PRINT (0, 1, 19);
-	}
+        {
+          CR16_PRINT (0, getidxregp_image (arg->rp), 16);
+          if (getreg_image (arg->i_r) == 12)
+            CR16_PRINT (0, 0, 19);
+          else
+            CR16_PRINT (0, 1, 19);
+        }
       print_constant (nbits, shift, arg);
       break;
 
     case arg_idxr:
       if (getreg_image (arg->i_r) == 12)
-	if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb")
-	    || IS_INSN_MNEMONIC ("tbitb"))
-	  CR16_PRINT (0, 0, 23);
-	else CR16_PRINT (0, 0, 24);
+        if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb")
+            || IS_INSN_MNEMONIC ("tbitb"))
+          CR16_PRINT (0, 0, 23);
+        else CR16_PRINT (0, 0, 24);
       else
-	if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb")
-	    || IS_INSN_MNEMONIC ("tbitb"))
-	  CR16_PRINT (0, 1, 23);
-	else CR16_PRINT (0, 1, 24);
+        if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb")
+            || IS_INSN_MNEMONIC ("tbitb"))
+          CR16_PRINT (0, 1, 23);
+        else CR16_PRINT (0, 1, 24);
 
       print_constant (nbits, shift, arg);
       break;
@@ -1861,16 +1890,16 @@
     case arg_crp:
       print_constant (nbits, shift , arg);
       if (instruction->size > 1)
-	CR16_PRINT (0, getregp_image (arg->rp), (shift + 16));
+        CR16_PRINT (0, getregp_image (arg->rp), (shift + 16));
       else if (IS_INSN_TYPE (LD_STOR_INS) || (IS_INSN_TYPE (CSTBIT_INS)))
-	{
-	  if (instruction->size == 2)
-	    CR16_PRINT (0, getregp_image (arg->rp), (shift - 8));
-	  else if (instruction->size == 1)
-	    CR16_PRINT (0, getregp_image (arg->rp), 16);
-	}
+        {
+          if (instruction->size == 2)
+            CR16_PRINT (0, getregp_image (arg->rp), (shift - 8));
+          else if (instruction->size == 1)
+            CR16_PRINT (0, getregp_image (arg->rp), 16);
+        }
       else
-	CR16_PRINT (0, getregp_image (arg->rp), shift);
+        CR16_PRINT (0, getregp_image (arg->rp), shift);
       break;
 
     default:
@@ -1949,11 +1978,11 @@
       if (value == 0xB || value == 0x9)
         return OP_OUT_OF_RANGE;
       else if (value == -1)
-	{
-	  if (update)
-	    *num = 9;
-	  return retval;
-	}
+        {
+          if (update)
+            *num = 9;
+          return retval;
+        }
     }
 
   if (flags & OP_ESC1)
@@ -2011,17 +2040,17 @@
       unsigned int count = insn->arg[0].constant, reg_val;
 
       /* Check if count operand caused to save/retrive the RA twice
-	 to generate warning message.  */
+         to generate warning message.  */
      if (insn->nargs > 2)
        {
          reg_val = getreg_image (insn->arg[1].r);
 
          if (   ((reg_val == 9) &&  (count > 7))
-	     || ((reg_val == 10) && (count > 6))
-	     || ((reg_val == 11) && (count > 5))
-	     || ((reg_val == 12) && (count > 4))
-	     || ((reg_val == 13) && (count > 2))
-	     || ((reg_val == 14) && (count > 0)))
+             || ((reg_val == 10) && (count > 6))
+             || ((reg_val == 11) && (count > 5))
+             || ((reg_val == 12) && (count > 4))
+             || ((reg_val == 13) && (count > 2))
+             || ((reg_val == 14) && (count > 0)))
            as_warn (_("RA register is saved twice."));
 
          /* Check if the third operand is "RA" or "ra" */
@@ -2036,10 +2065,10 @@
          /* If register is a register pair ie r12/r13/r14 in operand1, then
             the count constant should be validated.  */
          if (((reg_val == 11) && (count > 7))
-	     || ((reg_val == 12) && (count > 6))
-	     || ((reg_val == 13) && (count > 4))
-	     || ((reg_val == 14) && (count > 2))
-	     || ((reg_val == 15) && (count > 0)))
+             || ((reg_val == 12) && (count > 6))
+             || ((reg_val == 13) && (count > 4))
+             || ((reg_val == 14) && (count > 2))
+             || ((reg_val == 15) && (count > 0)))
            as_bad (_("`%s' Illegal count-register combination."), ins_parse);
        }
      else
@@ -2187,14 +2216,14 @@
           /* If 'bal' instruction size is '2' and reg operand is not 'ra'
              then goto next instruction.  */
           if (IS_INSN_MNEMONIC ("bal") && (i == 0)
-	      && (instruction->size == 2) && (insn->arg[i].rp != 14))
+              && (instruction->size == 2) && (insn->arg[i].rp != 14))
             goto next_insn;
 
           /* If 'storb' instruction with 'sp' reg and 16-bit disp of
            * reg-pair, leads to undifined trap, so this should use
            * 20-bit disp of reg-pair.  */
           if (IS_INSN_MNEMONIC ("storb") && (instruction->size == 2)
-	      && (insn->arg[i].r == 15) && (insn->arg[i + 1].type == arg_crp))
+              && (insn->arg[i].r == 15) && (insn->arg[i + 1].type == arg_crp))
             goto next_insn;
 
           /* Only check range - don't update the constant's value, since the
@@ -2216,7 +2245,7 @@
              determined) is sufficient.  */
           else if ((insn->arg[i].X_op == O_symbol)
                    && ((bfd_reloc_type_lookup (stdoutput, insn->rtype))->bitsize
-		       > cur_size[i]))
+                       > cur_size[i]))
                   goto next_insn;
         }
       found_const_within_range = 1;
@@ -2241,15 +2270,15 @@
         {
           switch (const_err)
             {
-	    case OP_OUT_OF_RANGE:
-	      as_bad (_("Operand out of range (arg %d)"), invalid_const);
-	      break;
-	    case OP_NOT_EVEN:
-	      as_bad (_("Operand has odd displacement (arg %d)"), invalid_const);
-	      break;
-	    default:
-	      as_bad (_("Illegal operand (arg %d)"), invalid_const);
-	      break;
+            case OP_OUT_OF_RANGE:
+              as_bad (_("Operand out of range (arg %d)"), invalid_const);
+              break;
+            case OP_NOT_EVEN:
+              as_bad (_("Operand has odd displacement (arg %d)"), invalid_const);
+              break;
+            default:
+              as_bad (_("Illegal operand (arg %d)"), invalid_const);
+              break;
             }
         }
 
@@ -2321,28 +2350,61 @@
       words[j++] = output_opcode[i] & 0xFFFF;
     }
 
-    insn_size = instruction->size;
-    this_frag = frag_more (insn_size * 2);
-
     /* Handle relocation.  */
-    if ((relocatable) && (insn->rtype != BFD_RELOC_NONE))
+    if ((instruction->flags & RELAXABLE) && relocatable)
       {
-         reloc_howto_type *reloc_howto;
-         int size;
+        int relax_subtype;
+        /* Write the maximal instruction size supported.  */
+        insn_size = INSN_MAX_SIZE;
 
-         reloc_howto = bfd_reloc_type_lookup (stdoutput, insn->rtype);
+        if (IS_INSN_TYPE (BRANCH_INS))
+          {
+            switch (insn->rtype)
+              {
+              case BFD_RELOC_CR16_DISP24:
+                relax_subtype = 2;
+                break;
+              case BFD_RELOC_CR16_DISP16:
+                relax_subtype = 1;
+                break;
+              default:
+                relax_subtype = 0;
+                break;
+              }
+          }
+        else
+          abort ();
 
-         if (!reloc_howto)
-           abort ();
+        this_frag = frag_var (rs_machine_dependent, insn_size *2,
+                              4, relax_subtype,
+                              insn->exp.X_add_symbol,
+                              insn->exp.X_add_number,
+                              0);
+      }
+    else
+      {
+        insn_size = instruction->size;
+        this_frag = frag_more (insn_size * 2);
 
-         size = bfd_get_reloc_size (reloc_howto);
+        if ((relocatable) && (insn->rtype != BFD_RELOC_NONE))
+          {
+             reloc_howto_type *reloc_howto;
+             int size;
 
-         if (size < 1 || size > 4)
-           abort ();
+             reloc_howto = bfd_reloc_type_lookup (stdoutput, insn->rtype);
+  
+             if (!reloc_howto)
+               abort ();
 
-         fix_new_exp (frag_now, this_frag - frag_now->fr_literal,
-                      size, &insn->exp, reloc_howto->pc_relative,
-                      insn->rtype);
+             size = bfd_get_reloc_size (reloc_howto);
+
+             if (size < 1 || size > 4)
+               abort ();
+
+             fix_new_exp (frag_now, this_frag - frag_now->fr_literal,
+                          size, &insn->exp, reloc_howto->pc_relative,
+                          insn->rtype);
+          }
       }
 
   /* Verify a 2-byte code alignment.  */
@@ -2410,14 +2472,14 @@
       instruction = (const inst *) hash_find (cr16_inst_hash, op);
        parse_operands (&cr16_ins, param1);
       if (((&cr16_ins)->arg[0].type == arg_ic)
-	  && ((&cr16_ins)->arg[0].constant >= 0))
+          && ((&cr16_ins)->arg[0].constant >= 0))
         {
            if (streq ("lshb", op))
-	     op = "ashub";
+             op = "ashub";
            else if (streq ("lshd", op))
-	     op = "ashud";
-	   else
-	     op = "ashuw";
+             op = "ashud";
+           else
+             op = "ashuw";
         }
     }
 
Index: include/elf/cr16.h
===================================================================
--- include/elf/cr16.h	(revision 494)
+++ include/elf/cr16.h	(working copy)
@@ -51,6 +51,9 @@
   RELOC_NUMBER (R_CR16_DISP16,         23)
   RELOC_NUMBER (R_CR16_DISP24,         24)
   RELOC_NUMBER (R_CR16_DISP24a,        25)
+  RELOC_NUMBER (R_CR16_SWITCH8,        26)
+  RELOC_NUMBER (R_CR16_SWITCH16,       27)
+  RELOC_NUMBER (R_CR16_SWITCH32,       28)
 END_RELOC_NUMBERS(R_CR16_MAX)
         
 #endif /* _ELF_CR16_H */
Index: include/elf/ChangeLog
===================================================================
--- include/elf/ChangeLog	(revision 494)
+++ include/elf/ChangeLog	(working copy)
@@ -1,3 +1,7 @@
+2007-10-01  M R Swami Reddy <MR.Swami.Reddy@nsc.com>
+
+	* cr16.h: Updated with new relocaction macros.
+
 2007-08-25  Ulrich Weigand  <uweigand@de.ibm.com>
 
 	* common.h (NT_SPU): Define.
Index: bfd/ChangeLog
===================================================================
--- bfd/ChangeLog	(revision 494)
+++ bfd/ChangeLog	(working copy)
@@ -1,3 +1,11 @@
+2007-08-28  M R Swami Reddy <MR.Swami.Reddy@nsc.com>
+
+	* elf32-cr16.c: Fixed DISP8, DISP20 and IMM20 relocations at
+	final relocation phase. Added the below relaxations:
+	IMM32 -> IMM20/IM16 -> IMM4. Added 3 new relocations. 
+	1. R_CR16_SWITCH8  2. R_CR16_SWITCH16 and 3. R_CR16_SWITCH32.
+
+
 2007-08-28  Daniel Jacobowitz  <dan@codesourcery.com>
 
 	* configure.in (VERSION): Update.
Index: bfd/elf32-cr16.c
===================================================================
--- bfd/elf32-cr16.c	(revision 494)
+++ bfd/elf32-cr16.c	(working copy)
@@ -61,7 +61,10 @@
   {BFD_RELOC_CR16_DISP8,     R_CR16_DISP8},
   {BFD_RELOC_CR16_DISP16,    R_CR16_DISP16},
   {BFD_RELOC_CR16_DISP24,    R_CR16_DISP24},
-  {BFD_RELOC_CR16_DISP24a,   R_CR16_DISP24a}
+  {BFD_RELOC_CR16_DISP24a,   R_CR16_DISP24a},
+  {BFD_RELOC_CR16_SWITCH8,   R_CR16_SWITCH8},
+  {BFD_RELOC_CR16_SWITCH16,  R_CR16_SWITCH16},
+  {BFD_RELOC_CR16_SWITCH32,  R_CR16_SWITCH32}
 };
 
 static reloc_howto_type cr16_elf_howto_table[] =
@@ -429,7 +432,58 @@
          FALSE,                    /* partial_inplace */
          0xffffff,                 /* src_mask */
          0xffffff,                 /* dst_mask */
-         FALSE)                    /* pcrel_offset */
+         FALSE),                   /* pcrel_offset */
+
+  /* An 8 bit switch table entry.  This is generated for an expression
+     such as ``.byte L1 - L2''.  The offset holds the difference
+     between the reloc address and L2.  */
+  HOWTO (R_CR16_SWITCH8,           /* type */
+         0,                        /* rightshift */
+         0,                        /* size (0 = byte, 1 = short, 2 = long) */
+         8,                        /* bitsize */
+         FALSE,                    /* pc_relative */
+         0,                        /* bitpos */
+         complain_overflow_unsigned, /* complain_on_overflow */
+         bfd_elf_generic_reloc,    /* special_function */
+         "R_CR16_SWITCH8",         /* name */
+         FALSE,                    /* partial_inplace */
+         0xff,                     /* src_mask */
+         0xff,                     /* dst_mask */
+         TRUE),                    /* pcrel_offset */
+
+  /* A 16 bit switch table entry.  This is generated for an expression
+     such as ``.word L1 - L2''.  The offset holds the difference
+     between the reloc address and L2.  */
+  HOWTO (R_CR16_SWITCH16,          /* type */
+         0,                        /* rightshift */
+         1,                        /* size (0 = byte, 1 = short, 2 = long) */
+         16,                       /* bitsize */
+         FALSE,                    /* pc_relative */
+         0,                        /* bitpos */
+         complain_overflow_unsigned, /* complain_on_overflow */
+         bfd_elf_generic_reloc,    /* special_function */
+         "R_CR16_SWITCH16",        /* name */
+         FALSE,                    /* partial_inplace */
+         0xffff,                   /* src_mask */
+         0xffff,                   /* dst_mask */
+         TRUE),                    /* pcrel_offset */
+
+  /* A 32 bit switch table entry.  This is generated for an expression
+     such as ``.long L1 - L2''.  The offset holds the difference
+     between the reloc address and L2.  */
+  HOWTO (R_CR16_SWITCH32,          /* type */
+         0,                        /* rightshift */
+         2,                        /* size (0 = byte, 1 = short, 2 = long) */
+         32,                       /* bitsize */
+         FALSE,                    /* pc_relative */
+         0,                        /* bitpos */
+         complain_overflow_unsigned, /* complain_on_overflow */
+         bfd_elf_generic_reloc,    /* special_function */
+         "R_CR16_SWITCH32",        /* name */
+         FALSE,                    /* partial_inplace */
+         0xffffffff,               /* src_mask */
+         0xffffffff,               /* dst_mask */
+         TRUE)                     /* pcrel_offset */
 };
 
 /* Retrieve a howto ptr using a BFD reloc_code.  */
@@ -478,13 +532,13 @@
 
 static bfd_reloc_status_type
 cr16_elf_final_link_relocate (reloc_howto_type *howto,
-			      bfd *input_bfd,
+                              bfd *input_bfd,
                               bfd *output_bfd ATTRIBUTE_UNUSED,
                               asection *input_section,
-			      bfd_byte *contents,
+                              bfd_byte *contents,
                               bfd_vma offset,
-			      bfd_vma Rvalue,
-			      bfd_vma addend,
+                              bfd_vma Rvalue,
+                              bfd_vma addend,
                               struct bfd_link_info *info ATTRIBUTE_UNUSED,
                               asection *sec ATTRIBUTE_UNUSED,
                               int is_local ATTRIBUTE_UNUSED)
@@ -496,9 +550,12 @@
   switch (r_type)
     {
      case R_CR16_IMM4:
+     case R_CR16_IMM20:
+     case R_CR16_ABS20:
+       break;
+
      case R_CR16_IMM8:
      case R_CR16_IMM16:
-     case R_CR16_IMM20:
      case R_CR16_IMM32:
      case R_CR16_IMM32a:
      case R_CR16_REGREL4:
@@ -507,7 +564,6 @@
      case R_CR16_REGREL14a:
      case R_CR16_REGREL16:
      case R_CR16_REGREL20:
-     case R_CR16_ABS20:
      case R_CR16_ABS24:
      case R_CR16_DISP16:
      case R_CR16_DISP24:
@@ -521,11 +577,20 @@
        break;
 
      case R_CR16_DISP4:
+       if (is_local) Rvalue += -1;
+       break;
+
      case R_CR16_DISP8:
      case R_CR16_DISP24a:
+       if (is_local) Rvalue -= -1;
+       break;
+
+     case R_CR16_SWITCH8:
+     case R_CR16_SWITCH16:
+     case R_CR16_SWITCH32:
        /* We only care about the addend, where the difference between
           expressions is kept.  */
-       if (is_local) Rvalue -= -1;
+       Rvalue = 0;
 
      default:
        break;
@@ -582,15 +647,30 @@
   switch (howto->size)
     {
       case 0:
-        if ((r_type == R_CR16_IMM4)
-	    || (r_type == R_CR16_DISP4)
-	    || (r_type == R_CR16_DISP8))
+        if (r_type == R_CR16_DISP8)
           {
              Rvalue1 = bfd_get_16 (input_bfd, hit_data);
-             Rvalue = ((Rvalue1 & 0xf000) | ((Rvalue << 4) & 0xf00)
-		       | (Rvalue1 & 0x00f0) | (Rvalue & 0xf));
-             bfd_put_16 (input_bfd,  Rvalue, hit_data);
+             Rvalue = ((Rvalue1&0xf000) | ((Rvalue<<4)&0xf00)
+                       | (Rvalue1&0x00f0) | (Rvalue&0xf));
+             bfd_put_16 (input_bfd, Rvalue, hit_data);
           }
+        else if (r_type == R_CR16_IMM4)
+          {
+             Rvalue1 = bfd_get_16 (input_bfd, hit_data);
+             Rvalue = (((Rvalue1 & 0xff) << 8) | ((Rvalue << 4) & 0xf0)
+                       | ((Rvalue1 & 0x0f00) >> 8));
+             bfd_put_16 (input_bfd, Rvalue, hit_data);
+          }
+        else if (r_type == R_CR16_DISP4)
+          {
+             Rvalue1 = bfd_get_16 (input_bfd, hit_data);
+             Rvalue = (Rvalue1 | ((Rvalue & 0xf) << 4));
+             bfd_put_16 (input_bfd, Rvalue, hit_data);
+          }
+        else 
+          {
+             bfd_put_8 (input_bfd, (unsigned char) Rvalue, hit_data);
+          }
         break;
 
       case 1:
@@ -598,66 +678,50 @@
           {
             Rvalue |= (bfd_get_16 (input_bfd, hit_data));
             Rvalue = ((Rvalue & 0xfffe) | ((Rvalue >> 16) & 0x1));
+          }
 
-            bfd_put_16 (input_bfd, Rvalue, hit_data);
-          }
+          bfd_put_16 (input_bfd, Rvalue, hit_data);
         break;
 
       case 2:
-        if (r_type == R_CR16_ABS20)
+        if ((r_type == R_CR16_ABS20) || (r_type == R_CR16_IMM20))
           {
-            Rvalue |= (((bfd_get_16 (input_bfd, hit_data) << 16)
-			| (bfd_get_16 (input_bfd, hit_data + 2)))
-		       & ~howto->dst_mask);
-            Rvalue |= (bfd_get_16 (input_bfd, hit_data + 2) << 16);
-
-            /* Relocation on INSTRUCTIONS is different : Instructions are
-               word-addressable, that is, each word itself is arranged according
-               to little-endian convention, whereas the words are arranged with
-               respect to one another in BIG ENDIAN fashion.
-               When there is an immediate value that spans a word boundary,
-               it is split in a big-endian way with respect to the words.  */
-            bfd_put_16 (input_bfd, (Rvalue) & 0xffff, hit_data);
-            bfd_put_16 (input_bfd, (Rvalue >> 16)& 0xffff, hit_data + 2);
+             bfd_put_16 (input_bfd, (bfd_get_16 (input_bfd, hit_data)) |
+                         ((Rvalue >> 16)& 0xf), hit_data);
+             bfd_put_16 (input_bfd, (Rvalue) & 0xffff, hit_data+2);
           }
-        else if (r_type == R_CR16_ABS24)
+        else   
           {
-            Rvalue = ((((Rvalue >> 20)& 0xf)
-		       | (((Rvalue >> 16) & 0xf) << 8)
-		       | (bfd_get_16 (input_bfd, hit_data)))
-		      | ((Rvalue & 0xffff) << 16));
+            if (r_type == R_CR16_ABS24)
+              {
+                Rvalue = ((((Rvalue >> 20)& 0xf) | (((Rvalue >>16) & 0xf)<<8)
+                          | (bfd_get_16 (input_bfd, hit_data))) 
+                          | ((Rvalue & 0xffff) << 16));
+              }
+            if (r_type == R_CR16_DISP24)
+              {
+                Rvalue = ((((Rvalue >> 20)& 0xf) | (((Rvalue >>16) & 0xf)<<8)
+                          | (bfd_get_16 (input_bfd, hit_data))) 
+                          | (((Rvalue & 0xfffe)
+                              | ((Rvalue >> 24) & 0x1)) << 16));
+              }
+            else if ((r_type == R_CR16_IMM32) ||(r_type == R_CR16_IMM32a))
+              {
+                Rvalue = (((Rvalue >> 16)& 0xffff)
+                          | (bfd_get_16 (input_bfd, hit_data))) 
+                          | ((Rvalue & 0xffff) << 16);
+              }
+            else if (r_type == R_CR16_DISP24a)
+              {
+                Rvalue = (((Rvalue & 0xfffffe) | (Rvalue >> 23)));
+                Rvalue = ((Rvalue >> 16) & 0xff) | ((Rvalue & 0xffff) << 16)
+                          | (bfd_get_32 (input_bfd, hit_data));
+              }
 
             bfd_put_32 (input_bfd, Rvalue, hit_data);
           }
-        else if (r_type == R_CR16_DISP24)
-          {
-            Rvalue = ((((Rvalue >> 20)& 0xf) | (((Rvalue >> 16) & 0xf)<<8)
-		       | (bfd_get_16 (input_bfd, hit_data)))
-		      | (((Rvalue & 0xfffE) | ((Rvalue >> 24) & 0x1)) << 16));
+        break;
 
-            bfd_put_32 (input_bfd, Rvalue, hit_data);
-          }
-        else if ((r_type == R_CR16_IMM32) || (r_type == R_CR16_IMM32a))
-          {
-            Rvalue = (((Rvalue >> 16)& 0xffff)
-		      | (bfd_get_16 (input_bfd, hit_data)))
-	      | ((Rvalue & 0xffff) << 16);
-            bfd_put_32 (input_bfd, Rvalue, hit_data);
-          }
-        else if (r_type == R_CR16_DISP24a)
-          {
-            Rvalue = (((Rvalue & 0xfffffe) | (Rvalue >> 23)));
-            Rvalue = ((Rvalue >> 16) & 0xff) | ((Rvalue & 0xffff) << 16)
-	      | (bfd_get_32 (input_bfd, hit_data));
-
-            bfd_put_32 (input_bfd, Rvalue, hit_data);
-          }
-        else if ((r_type == R_CR16_NUM32) || (r_type == R_CR16_NUM32a))
-          {
-            bfd_put_32 (input_bfd, Rvalue, hit_data);
-          }
-      break;
-
       default:
         return bfd_reloc_notsupported;
     }
@@ -705,7 +769,7 @@
   for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
     /* Get the new reloc address.  */
     if ((irel->r_offset > addr && irel->r_offset < toaddr))
-	irel->r_offset -= count;
+        irel->r_offset -= count;
 
   /* Adjust the local symbols defined in this section.  */
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
@@ -724,6 +788,12 @@
               Elf_Internal_Sym *rsym;
               bfd_vma addsym, subsym;
 
+              /* Skip if not a SWITCH relocation.  */
+              if (ELF32_R_TYPE (irel->r_info) != (int) R_CR16_SWITCH8
+                   && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_SWITCH16
+                   && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_SWITCH32)
+                continue;
+
               r_symndx = ELF32_R_SYM (irel->r_info);
               rsym = (Elf_Internal_Sym *) symtab_hdr->contents + r_symndx;
 
@@ -769,10 +839,10 @@
           /* Loop only over the symbols whom been already checked.  */
           for (cur_sym_hashes = start_hashes; cur_sym_hashes < sym_hashes;
                cur_sym_hashes++)
-	    /* If the current symbol is identical to 'sym_hash', that means
-	       the symbol was already adjusted (or at least checked).  */
-	    if (*cur_sym_hashes == sym_hash)
-	      break;
+            /* If the current symbol is identical to 'sym_hash', that means
+               the symbol was already adjusted (or at least checked).  */
+            if (*cur_sym_hashes == sym_hash)
+              break;
 
           /* Don't adjust the symbol again.  */
           if (cur_sym_hashes < sym_hashes)
@@ -953,7 +1023,7 @@
       bfd_size_type amt;
 
       internal_relocs = _bfd_elf_link_read_relocs (input_bfd, input_section,
-						   NULL, NULL, FALSE);
+                                                   NULL, NULL, FALSE);
       if (internal_relocs == NULL)
         goto error_return;
 
@@ -1024,8 +1094,9 @@
    There's quite a few relaxing opportunites available on the CR16:
 
         * bcond:24 -> bcond:16                                2 bytes
-        * bcond:16 -> bcond:8                                2 bytes
-        * arithmetic imm32 -> arithmetic imm16                2 bytes
+        * bcond:16 -> bcond:8                                 2 bytes
+        * arithmetic imm32 -> arithmetic imm20/imm16          2 bytes
+        * arithmetic imm20/imm16 -> arithmetic imm4           2 bytes
 
    Symbol- and reloc-reading infrastructure copied from elf-m10200.c.  */
 
@@ -1055,7 +1126,7 @@
 
   /* Get a copy of the native relocations.  */
   internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
-					       link_info->keep_memory);
+                                               link_info->keep_memory);
   if (internal_relocs == NULL)
     goto error_return;
 
@@ -1068,7 +1139,10 @@
       /* If this isn't something that can be relaxed, then ignore
          this reloc.  */
       if (ELF32_R_TYPE (irel->r_info) != (int) R_CR16_DISP16
-          && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_DISP24)
+          && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_DISP24
+          && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_IMM32
+          && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_IMM20
+          && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_IMM16)
         continue;
 
       /* Get the section contents if we haven't done so already.  */
@@ -1244,73 +1318,156 @@
             }
         }
 
-#if 0 // REVISIT: To support IMM relaxation in CR16 target
       /* Try to turn a 32bit immediate address into
-         a 20bit immediate address.  */
+         a 20/16bit immediate address.  */
       if (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM32)
         {
           bfd_vma value = symval;
+          unsigned short is_add_mov = 0;
 
           /* See if the value will fit in 20 bits.  */
-          if ((long) value < 0x7ffff && (long) value > -0x80000)
+          if ((long) value < 0xfffff && (long) value > 0)
             {
               unsigned short code;
 
               /* Get the opcode.  */
               code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset);
 
-              /* Verify it's a 'arithmetic double'.  */
-              if ((code & 0xfff0) != 0x0070)
-                continue;
+              /* Verify it's a arithmetic ADDD or MOVD instruction.
+                 For ADDD and MOVD only, convert to IMM32 -> IMM20.  */
+              if (((code & 0xfff0) != 0x0070) || ((code & 0xfff0) != 0x0020))
+                is_add_mov = 1;
 
+              if (is_add_mov)
+                {
+                  /* Note that we've changed the relocs, section contents, 
+                     etc.  */
+                  elf_section_data (sec)->relocs = internal_relocs;
+                  elf_section_data (sec)->this_hdr.contents = contents;
+                  symtab_hdr->contents = (unsigned char *) isymbuf;
+
+                  /* Fix the opcode.  */
+                  if ((code & 0xfff0) == 0x0070) /* For movd.  */
+                    bfd_put_8 (abfd, 0x05, contents + irel->r_offset + 1);
+                  else                          /* code == 0x0020 for addd.  */
+                    bfd_put_8 (abfd, 0x04, contents + irel->r_offset + 1);
+ 
+                  bfd_put_8 (abfd, (code & 0xf) << 4, contents + irel->r_offset);
+
+
+                  /* Fix the relocation's type.  */
+                  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                              R_CR16_IMM20);
+                  /* Delete two bytes of data.  */
+                  if (!elf32_cr16_relax_delete_bytes (link_info, abfd, sec,
+                                                       irel->r_offset + 2, 2))
+                    goto error_return;
+
+                  /* That will change things, so, we should relax again.
+                     Note that this is not required, and it may be slow.  */
+                  *again = TRUE;
+                }
+            }
+         /* See if the value will fit in 16 bits.  */
+          if ((!is_add_mov) && ((long)value < 0x7fff && (long)value > 0))
+            {
+              unsigned short code;
+
+              /* Get the opcode.  */
+              code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset);
+
               /* Note that we've changed the relocs, section contents, etc.  */
               elf_section_data (sec)->relocs = internal_relocs;
               elf_section_data (sec)->this_hdr.contents = contents;
               symtab_hdr->contents = (unsigned char *) isymbuf;
 
               /* Fix the opcode.  */
-              bfd_put_8 (abfd, (code & 0xff) - 0x10, contents + irel->r_offset);
+              if ((code & 0xf0) == 0x70)          /* For movd.  */
+                bfd_put_8 (abfd, 0x54, contents + irel->r_offset + 1);
+              else if ((code & 0xf0) == 0x20)     /* For addd.  */
+                bfd_put_8 (abfd, 0x60, contents + irel->r_offset + 1);
+              else if ((code & 0xf0) == 0x90)     /* For cmpd.  */
+                bfd_put_8 (abfd, 0x56, contents + irel->r_offset + 1);
+              else
+                continue;
 
+              bfd_put_8 (abfd, 0xb0|(code & 0xf), contents + irel->r_offset);
+
               /* Fix the relocation's type.  */
               irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
-                                           R_CR16_IMM20);
+                                           R_CR16_IMM16);
 
               /* Delete two bytes of data.  */
               if (!elf32_cr16_relax_delete_bytes (link_info, abfd, sec,
-                                                   irel->r_offset + 2, 2))
-                goto error_return;
+                                                  irel->r_offset + 2, 2))
+                 goto error_return;
 
               /* That will change things, so, we should relax again.
                  Note that this is not required, and it may be slow.  */
-              *again = TRUE;
+                 *again = TRUE;
             }
         }
-      /* Try to turn a 20bit/16bit immediate address into
+
+      /* Try to turn a 20/16bit immediate address into
          a 4bit immediate address.  */
       if ((ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM20)
-	  || (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM16))
+          || (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM16))
         {
           bfd_vma value = symval;
 
           /* See if the value will fit in 4 bits.  */
-          if ((long) value < 0x7 && (long) value > -0x8)
+          if ((long) value < 0xf && (long) value > 0)
             {
               unsigned short code;
 
               /* Get the opcode.  */
-              code = (unsigned short) bfd_get_8 (abfd, contents + irel->r_offset);
+              code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset);
 
-              /* Verify it's a 'arithmetic double'.  */
-              if (((code & 0xff) != 0x50) || ((code & 0xff) != 0x45))
-                continue;
-
               /* Note that we've changed the relocs, section contents, etc.  */
               elf_section_data (sec)->relocs = internal_relocs;
               elf_section_data (sec)->this_hdr.contents = contents;
               symtab_hdr->contents = (unsigned char *) isymbuf;
 
               /* Fix the opcode.  */
-              bfd_put_8 (abfd, (code & 0xff) - 0x10, contents + irel->r_offset);
+              if (((code & 0x0f00) == 0x0400) || ((code & 0x0f00) == 0x0500))
+                {
+                  if ((code & 0x0f00) == 0x0400)      /* For movd imm20.  */
+                    bfd_put_8 (abfd, 0x60, contents + irel->r_offset);
+                  else                                /* For addd imm20.  */
+                    bfd_put_8 (abfd, 0x54, contents + irel->r_offset);
+                  bfd_put_8 (abfd, (code & 0xf0)>>4, contents + irel->r_offset+1);
+                }
+              else
+                {
+                  if ((code & 0xfff0) == 0x56b0)       /*  For cmpd imm16.  */
+                    bfd_put_8 (abfd, 0x56, contents + irel->r_offset);
+                  else if ((code & 0xfff0) == 0x54b0)  /*  For movd imm16.  */
+                    bfd_put_8 (abfd, 0x54, contents + irel->r_offset);
+                  else if ((code & 0xfff0) == 0x58b0)  /*  For movb imm16.  */
+                    bfd_put_8 (abfd, 0x58, contents + irel->r_offset);
+                  else if ((code & 0xfff0) == 0x5Ab0)  /*  For movw imm16.  */
+                    bfd_put_8 (abfd, 0x5A, contents + irel->r_offset);
+                  else if ((code & 0xfff0) == 0x60b0)  /*  For addd imm16.  */
+                    bfd_put_8 (abfd, 0x60, contents + irel->r_offset);
+                  else if ((code & 0xfff0) == 0x30b0)  /*  For addb imm16.  */
+                    bfd_put_8 (abfd, 0x30, contents + irel->r_offset);
+                  else if ((code & 0xfff0) == 0x2Cb0)  /*  For addub imm16.  */
+                    bfd_put_8 (abfd, 0x2C, contents + irel->r_offset);
+                  else if ((code & 0xfff0) == 0x32b0)  /*  For adduw imm16.  */
+                    bfd_put_8 (abfd, 0x32, contents + irel->r_offset);
+                  else if ((code & 0xfff0) == 0x38b0)  /*  For subb imm16.  */
+                    bfd_put_8 (abfd, 0x38, contents + irel->r_offset);
+                  else if ((code & 0xfff0) == 0x3Ab0)  /*  For subw imm16.  */
+                    bfd_put_8 (abfd, 0x3A, contents + irel->r_offset);
+                  else if ((code & 0xfff0) == 0x50b0)  /*  For cmpb imm16.  */
+                    bfd_put_8 (abfd, 0x50, contents + irel->r_offset);
+                  else if ((code & 0xfff0) == 0x52b0)  /*  For cmpw imm16.  */
+                    bfd_put_8 (abfd, 0x52, contents + irel->r_offset);
+                  else
+                    continue;
+              
+                  bfd_put_8 (abfd, (code & 0xf), contents + irel->r_offset + 1);
+                }
 
               /* Fix the relocation's type.  */
               irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
@@ -1326,7 +1483,6 @@
               *again = TRUE;
             }
         }
-#endif
     }
 
   if (isymbuf != NULL
Index: bfd/bfd-in2.h
===================================================================
--- bfd/bfd-in2.h	(revision 494)
+++ bfd/bfd-in2.h	(working copy)
@@ -4141,6 +4141,9 @@
   BFD_RELOC_CR16_DISP20,
   BFD_RELOC_CR16_DISP24,
   BFD_RELOC_CR16_DISP24a,
+  BFD_RELOC_CR16_SWITCH8,
+  BFD_RELOC_CR16_SWITCH16,
+  BFD_RELOC_CR16_SWITCH32,
 
 /* NS CRX Relocations.  */
   BFD_RELOC_CRX_REL4,
Index: bfd/reloc.c
===================================================================
--- bfd/reloc.c	(revision 494)
+++ bfd/reloc.c	(working copy)
@@ -4570,6 +4570,12 @@
   BFD_RELOC_CR16_DISP24
 ENUMX
   BFD_RELOC_CR16_DISP24a
+ENUMX
+  BFD_RELOC_CR16_SWITCH8
+ENUMX
+  BFD_RELOC_CR16_SWITCH16
+ENUMX
+  BFD_RELOC_CR16_SWITCH32
 ENUMDOC
   NS CR16 Relocations.
 
Index: opcodes/cr16-opc.c
===================================================================
--- opcodes/cr16-opc.c	(revision 494)
+++ opcodes/cr16-opc.c	(working copy)
@@ -160,11 +160,11 @@
 /* Create a conditional branch instruction.  */
 #define  BRANCH_INST(NAME, OPC)                                       \
   /* opc4 c4 dispe9 */                                                \
-  {NAME,  1, OPC, 28, BRANCH_INS, {{cc,20}, {dispe9,16}}},            \
+  {NAME,  1, OPC, 28, BRANCH_INS | RELAXABLE, {{cc,20}, {dispe9,16}}},\
   /* opc4 c4 disps17 */                                               \
-  {NAME,  2, ((OPC<<4)+0x8), 24, BRANCH_INS, {{cc,20}, {disps17,0}}}, \
+  {NAME,  2, ((OPC<<4)+0x8), 24, BRANCH_INS | RELAXABLE, {{cc,20}, {disps17,0}}},\
   /* opc4 c4 disps25 */                                               \
-  {NAME,  3, (OPC<<4), 16 , BRANCH_INS, {{cc,4}, {disps25,16}}}
+  {NAME,  3, (OPC<<4), 16 , BRANCH_INS | RELAXABLE, {{cc,4}, {disps25,16}}}
 
   BRANCH_INST ("b", 0x1),
 
Index: opcodes/ChangeLog
===================================================================
--- opcodes/ChangeLog	(revision 494)
+++ opcodes/ChangeLog	(working copy)
@@ -1,3 +1,8 @@
+2007-10-01  M R Swami Reddy <MR.Swami.Reddy@nsc.com>
+
+	* cr16-opc.c: Updated the branch on condition instructions with
+		      RELAXABLE flag.
+
 2007-08-28  Daniel Jacobowitz  <dan@codesourcery.com>
 
 	* po/nl.po: Updated translation.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]