]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-microblaze.c
opcodes: microblaze: Add new bit-field instructions
[thirdparty/binutils-gdb.git] / gas / config / tc-microblaze.c
index d900a9e1d0520a60802e6ebdebffb0b5af88c3a3..554c1d77e668ec951fdabb219cfe769e85cceb8a 100644 (file)
@@ -915,7 +915,7 @@ md_assemble (char * str)
   unsigned reg2;
   unsigned reg3;
   unsigned isize;
-  unsigned int immed = 0, temp;
+  unsigned int immed = 0, immed2 = 0, temp;
   expressionS exp;
   char name[20];
 
@@ -1177,6 +1177,77 @@ md_assemble (char * str)
       inst |= (immed << IMM_LOW) & IMM5_MASK;
       break;
 
+    case INST_TYPE_RD_R1_IMM5_IMM5:
+      if (strcmp (op_end, ""))
+       op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
+      else
+       {
+         as_fatal (_("Error in statement syntax"));
+         reg1 = 0;
+       }
+      if (strcmp (op_end, ""))
+       op_end = parse_reg (op_end + 1, &reg2);  /* Get r1.  */
+      else
+       {
+         as_fatal (_("Error in statement syntax"));
+         reg2 = 0;
+       }
+
+      /* Check for spl registers.  */
+      if (check_spl_reg (&reg1))
+       as_fatal (_("Cannot use special register with this instruction"));
+      if (check_spl_reg (&reg2))
+       as_fatal (_("Cannot use special register with this instruction"));
+
+      /* Width immediate value.  */
+      if (strcmp (op_end, ""))
+       op_end = parse_imm (op_end + 1, &exp, MIN_IMM_WIDTH, MAX_IMM_WIDTH);
+      else
+       as_fatal (_("Error in statement syntax"));
+      if (exp.X_op != O_constant)
+       {
+         as_warn (_("Symbol used as immediate width value for bit field instruction"));
+         immed = 1;
+       }
+      else
+       immed = exp.X_add_number;
+      if (opcode->instr == bsefi && immed > 31)
+       as_fatal (_("Width value must be less than 32"));
+
+      /* Shift immediate value.  */
+      if (strcmp (op_end, ""))
+       op_end = parse_imm (op_end + 1, &exp, MIN_IMM, MAX_IMM);
+      else
+       as_fatal (_("Error in statement syntax"));
+      if (exp.X_op != O_constant)
+           {
+         as_warn (_("Symbol used as immediate shift value for bit field instruction"));
+         immed2 = 0;
+       }
+      else
+           {
+         output = frag_more (isize);
+         immed2 = exp.X_add_number;
+           }
+      if (immed2 != (immed2 % 32))
+           {
+         as_warn (_("Shift value greater than 32. using <value %% 32>"));
+         immed2 = immed2 % 32;
+       }
+
+      /* Check combined value.  */
+      if (immed + immed2 > 32)
+       as_fatal (_("Width value + shift value must not be greater than 32"));
+
+      inst |= (reg1 << RD_LOW) & RD_MASK;
+      inst |= (reg2 << RA_LOW) & RA_MASK;
+      if (opcode->instr == bsefi)
+       inst |= (immed & IMM5_MASK) << IMM_WIDTH_LOW; /* bsefi */
+      else
+       inst |= ((immed + immed2 - 1) & IMM5_MASK) << IMM_WIDTH_LOW; /* bsifi */
+      inst |= (immed2 << IMM_LOW) & IMM5_MASK;
+      break;
+
     case INST_TYPE_R1_R2:
       if (strcmp (op_end, ""))
         op_end = parse_reg (op_end + 1, &reg1);  /* Get r1.  */
@@ -2209,9 +2280,12 @@ md_apply_fix (fixS *   fixP,
         moves code around due to relaxing.  */
       if (fixP->fx_r_type == BFD_RELOC_64_PCREL)
        fixP->fx_r_type = BFD_RELOC_MICROBLAZE_64_NONE;
+      else if (fixP->fx_r_type == BFD_RELOC_32)
+       fixP->fx_r_type = BFD_RELOC_MICROBLAZE_32_NONE;
       else
        fixP->fx_r_type = BFD_RELOC_NONE;
       fixP->fx_addsy = section_symbol (absolute_section);
+      fixP->fx_done = 0;
     }
   return;
 }
@@ -2432,6 +2506,7 @@ tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
   switch (fixp->fx_r_type)
     {
     case BFD_RELOC_NONE:
+    case BFD_RELOC_MICROBLAZE_32_NONE:
     case BFD_RELOC_MICROBLAZE_64_NONE:
     case BFD_RELOC_32:
     case BFD_RELOC_MICROBLAZE_32_LO: