* Fix for PR 18665, from sky branch.
[deliverable/binutils-gdb.git] / opcodes / fr30-asm.c
index 22f452cf0438243806adb0432f3b33acb46e52ab..8094201310a10cba525a1f2a8f6145cc430f7cb1 100644 (file)
@@ -42,9 +42,12 @@ along with this program; if not, write to the Free Software Foundation, Inc.,
 #define INLINE
 #endif
 
+/* Used by the ifield rtx function.  */
+#define FLD(f) (fields->f)
+
 static const char * insert_normal
-     PARAMS ((CGEN_OPCODE_DESC, long, unsigned int, int, int, int,
-             CGEN_INSN_BYTES_PTR));
+     PARAMS ((CGEN_OPCODE_DESC, long, unsigned int, unsigned int, unsigned int,
+             unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR));
 static const char * parse_insn_normal
      PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *,
              const char **, CGEN_FIELDS *));
@@ -53,6 +56,116 @@ static const char * insert_insn_normal
              CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma));
 \f
 /* -- assembler routines inserted here */
+/* -- asm.c */
+/* Handle register lists for LDMx and STMx  */
+
+static int
+parse_register_number (strp)
+     const char **strp;
+{
+  int regno;
+  if (**strp < '0' || **strp > '9')
+    return -1; /* error */
+  regno = **strp - '0';
+  ++*strp;
+
+  if (**strp >= '0' && **strp <= '9')
+    {
+      regno = regno * 10 + (**strp - '0');
+      ++*strp;
+    }
+
+  return regno;
+}
+
+static const char *
+parse_register_list (od, strp, opindex, valuep, high_low, load_store)
+     CGEN_OPCODE_DESC od;
+     const char **strp;
+     int opindex;
+     unsigned long *valuep;
+     int high_low;   /* 0 == high, 1 == low */
+     int load_store; /* 0 == load, 1 == store */
+{
+  int regno;
+  *valuep = 0;
+  while (**strp && **strp != ')')
+    {
+      if (**strp != 'R' && **strp != 'r')
+       break;
+      ++*strp;
+
+      regno = parse_register_number (strp);
+      if (regno == -1)
+       return "Register number is not valid";
+      if (regno > 7 && !high_low)
+       return "Register must be between r0 and r7";
+      if (regno < 8 && high_low)
+       return "Register must be between r8 and r15";
+
+      if (high_low)
+       regno -= 8;
+
+      if (load_store) /* mask is reversed for store */
+       *valuep |= 0x80 >> regno;
+      else
+       *valuep |= 1 << regno;
+
+      if (**strp == ',')
+       {
+         if (*(*strp + 1) == ')')
+           break;
+         ++*strp;
+       }
+    }
+
+  if (!*strp || **strp != ')')
+    return "Register list is not valid";
+
+  return NULL;
+}
+
+static const char *
+parse_low_register_list_ld (od, strp, opindex, valuep)
+     CGEN_OPCODE_DESC od;
+     const char **strp;
+     int opindex;
+     unsigned long *valuep;
+{
+  return parse_register_list (od, strp, opindex, valuep, 0/*low*/, 0/*load*/);
+}
+
+static const char *
+parse_hi_register_list_ld (od, strp, opindex, valuep)
+     CGEN_OPCODE_DESC od;
+     const char **strp;
+     int opindex;
+     unsigned long *valuep;
+{
+  return parse_register_list (od, strp, opindex, valuep, 1/*high*/, 0/*load*/);
+}
+
+static const char *
+parse_low_register_list_st (od, strp, opindex, valuep)
+     CGEN_OPCODE_DESC od;
+     const char **strp;
+     int opindex;
+     unsigned long *valuep;
+{
+  return parse_register_list (od, strp, opindex, valuep, 0/*low*/, 1/*store*/);
+}
+
+static const char *
+parse_hi_register_list_st (od, strp, opindex, valuep)
+     CGEN_OPCODE_DESC od;
+     const char **strp;
+     int opindex;
+     unsigned long *valuep;
+{
+  return parse_register_list (od, strp, opindex, valuep, 1/*high*/, 1/*store*/);
+}
+
+/* -- */
 
 /* Main entry point for operand parsing.
 
@@ -85,26 +198,59 @@ fr30_cgen_parse_operand (od, opindex, strp, fields)
     case FR30_OPERAND_RJ :
       errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_gr, & fields->f_Rj);
       break;
+    case FR30_OPERAND_RIC :
+      errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_gr, & fields->f_Ric);
+      break;
+    case FR30_OPERAND_RJC :
+      errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_gr, & fields->f_Rjc);
+      break;
+    case FR30_OPERAND_CRI :
+      errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_cr, & fields->f_CRi);
+      break;
+    case FR30_OPERAND_CRJ :
+      errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_cr, & fields->f_CRj);
+      break;
     case FR30_OPERAND_RS1 :
       errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_dr, & fields->f_Rs1);
       break;
     case FR30_OPERAND_RS2 :
       errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_dr, & fields->f_Rs2);
       break;
+    case FR30_OPERAND_R13 :
+      errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_r13, & fields->f_nil);
+      break;
+    case FR30_OPERAND_R14 :
+      errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_r14, & fields->f_nil);
+      break;
+    case FR30_OPERAND_R15 :
+      errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_r15, & fields->f_nil);
+      break;
+    case FR30_OPERAND_PS :
+      errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_ps, & fields->f_nil);
+      break;
     case FR30_OPERAND_U4 :
       errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_U4, &fields->f_u4);
       break;
-    case FR30_OPERAND_M4 :
-      errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_M4, &fields->f_m4);
+    case FR30_OPERAND_U4C :
+      errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_U4C, &fields->f_u4c);
+      break;
+    case FR30_OPERAND_U8 :
+      errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_U8, &fields->f_u8);
       break;
     case FR30_OPERAND_I8 :
       errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_I8, &fields->f_i8);
       break;
-    case FR30_OPERAND_U8 :
-      errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_U8, &fields->f_u8);
+    case FR30_OPERAND_UDISP6 :
+      errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_UDISP6, &fields->f_udisp6);
+      break;
+    case FR30_OPERAND_DISP8 :
+      errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_DISP8, &fields->f_disp8);
       break;
-    case FR30_OPERAND_O8 :
-      errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_O8, &fields->f_o8);
+    case FR30_OPERAND_DISP9 :
+      errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_DISP9, &fields->f_disp9);
+      break;
+    case FR30_OPERAND_DISP10 :
+      errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_DISP10, &fields->f_disp10);
       break;
     case FR30_OPERAND_S10 :
       errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_S10, &fields->f_s10);
@@ -112,6 +258,15 @@ fr30_cgen_parse_operand (od, opindex, strp, fields)
     case FR30_OPERAND_U10 :
       errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_U10, &fields->f_u10);
       break;
+    case FR30_OPERAND_I32 :
+      errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_I32, &fields->f_i32);
+      break;
+    case FR30_OPERAND_M4 :
+      errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_M4, &fields->f_m4);
+      break;
+    case FR30_OPERAND_I20 :
+      errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_I20, &fields->f_i20);
+      break;
     case FR30_OPERAND_DIR8 :
       errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_DIR8, &fields->f_dir8);
       break;
@@ -122,14 +277,37 @@ fr30_cgen_parse_operand (od, opindex, strp, fields)
       errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_DIR10, &fields->f_dir10);
       break;
     case FR30_OPERAND_LABEL9 :
-      errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_LABEL9, &fields->f_rel8);
+      {
+        bfd_vma value;
+        errmsg = cgen_parse_address (od, strp, FR30_OPERAND_LABEL9, 0, NULL,  & value);
+        fields->f_rel9 = value;
+      }
       break;
     case FR30_OPERAND_LABEL12 :
-      errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_LABEL12, &fields->f_rel11);
+      {
+        bfd_vma value;
+        errmsg = cgen_parse_address (od, strp, FR30_OPERAND_LABEL12, 0, NULL,  & value);
+        fields->f_rel12 = value;
+      }
+      break;
+    case FR30_OPERAND_REGLIST_LOW_LD :
+      errmsg = parse_low_register_list_ld (od, strp, FR30_OPERAND_REGLIST_LOW_LD, &fields->f_reglist_low_ld);
+      break;
+    case FR30_OPERAND_REGLIST_HI_LD :
+      errmsg = parse_hi_register_list_ld (od, strp, FR30_OPERAND_REGLIST_HI_LD, &fields->f_reglist_hi_ld);
+      break;
+    case FR30_OPERAND_REGLIST_LOW_ST :
+      errmsg = parse_low_register_list_st (od, strp, FR30_OPERAND_REGLIST_LOW_ST, &fields->f_reglist_low_st);
+      break;
+    case FR30_OPERAND_REGLIST_HI_ST :
+      errmsg = parse_hi_register_list_st (od, strp, FR30_OPERAND_REGLIST_HI_ST, &fields->f_reglist_hi_st);
       break;
     case FR30_OPERAND_CC :
       errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_CC, &fields->f_cc);
       break;
+    case FR30_OPERAND_CCC :
+      errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_CCC, &fields->f_ccc);
+      break;
 
     default :
       /* xgettext:c-format */
@@ -164,87 +342,168 @@ fr30_cgen_insert_operand (od, opindex, fields, buffer, pc)
      bfd_vma pc;
 {
   const char * errmsg;
+  unsigned int total_length = CGEN_FIELDS_BITSIZE (fields);
 
   switch (opindex)
     {
     case FR30_OPERAND_RI :
-      errmsg = insert_normal (od, fields->f_Ri, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, CGEN_FIELDS_BITSIZE (fields), buffer);
+      errmsg = insert_normal (od, fields->f_Ri, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 12, 4, 16, total_length, buffer);
       break;
     case FR30_OPERAND_RJ :
-      errmsg = insert_normal (od, fields->f_Rj, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 4, CGEN_FIELDS_BITSIZE (fields), buffer);
+      errmsg = insert_normal (od, fields->f_Rj, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 4, 16, total_length, buffer);
+      break;
+    case FR30_OPERAND_RIC :
+      errmsg = insert_normal (od, fields->f_Ric, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 12, 4, 16, total_length, buffer);
+      break;
+    case FR30_OPERAND_RJC :
+      errmsg = insert_normal (od, fields->f_Rjc, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 8, 4, 16, total_length, buffer);
+      break;
+    case FR30_OPERAND_CRI :
+      errmsg = insert_normal (od, fields->f_CRi, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 12, 4, 16, total_length, buffer);
+      break;
+    case FR30_OPERAND_CRJ :
+      errmsg = insert_normal (od, fields->f_CRj, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 8, 4, 16, total_length, buffer);
       break;
     case FR30_OPERAND_RS1 :
-      errmsg = insert_normal (od, fields->f_Rs1, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 4, CGEN_FIELDS_BITSIZE (fields), buffer);
+      errmsg = insert_normal (od, fields->f_Rs1, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 4, 16, total_length, buffer);
       break;
     case FR30_OPERAND_RS2 :
-      errmsg = insert_normal (od, fields->f_Rs2, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, CGEN_FIELDS_BITSIZE (fields), buffer);
+      errmsg = insert_normal (od, fields->f_Rs2, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 12, 4, 16, total_length, buffer);
+      break;
+    case FR30_OPERAND_R13 :
+      errmsg = insert_normal (od, fields->f_nil, 0, 0, 0, 0, 0, total_length, buffer);
+      break;
+    case FR30_OPERAND_R14 :
+      errmsg = insert_normal (od, fields->f_nil, 0, 0, 0, 0, 0, total_length, buffer);
+      break;
+    case FR30_OPERAND_R15 :
+      errmsg = insert_normal (od, fields->f_nil, 0, 0, 0, 0, 0, total_length, buffer);
+      break;
+    case FR30_OPERAND_PS :
+      errmsg = insert_normal (od, fields->f_nil, 0, 0, 0, 0, 0, total_length, buffer);
       break;
     case FR30_OPERAND_U4 :
-      errmsg = insert_normal (od, fields->f_u4, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 8, 4, CGEN_FIELDS_BITSIZE (fields), buffer);
+      errmsg = insert_normal (od, fields->f_u4, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 4, 16, total_length, buffer);
       break;
-    case FR30_OPERAND_M4 :
+    case FR30_OPERAND_U4C :
+      errmsg = insert_normal (od, fields->f_u4c, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 0, 12, 4, 16, total_length, buffer);
+      break;
+    case FR30_OPERAND_U8 :
+      errmsg = insert_normal (od, fields->f_u8, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
+      break;
+    case FR30_OPERAND_I8 :
+      errmsg = insert_normal (od, fields->f_i8, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 0, 4, 8, 16, total_length, buffer);
+      break;
+    case FR30_OPERAND_UDISP6 :
       {
-        long value = fields->f_m4;
-        value = ((value) & (15));
-        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 8, 4, CGEN_FIELDS_BITSIZE (fields), buffer);
+        long value = fields->f_udisp6;
+        value = ((unsigned int) (value) >> (2));
+        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 4, 16, total_length, buffer);
       }
       break;
-    case FR30_OPERAND_I8 :
-      errmsg = insert_normal (od, fields->f_i8, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 4, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+    case FR30_OPERAND_DISP8 :
+      errmsg = insert_normal (od, fields->f_disp8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), 0, 4, 8, 16, total_length, buffer);
       break;
-    case FR30_OPERAND_U8 :
-      errmsg = insert_normal (od, fields->f_u8, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+    case FR30_OPERAND_DISP9 :
+      {
+        long value = fields->f_disp9;
+        value = ((int) (value) >> (1));
+        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX), 0, 4, 8, 16, total_length, buffer);
+      }
       break;
-    case FR30_OPERAND_O8 :
-      errmsg = insert_normal (od, fields->f_o8, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 4, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+    case FR30_OPERAND_DISP10 :
+      {
+        long value = fields->f_disp10;
+        value = ((int) (value) >> (2));
+        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX), 0, 4, 8, 16, total_length, buffer);
+      }
       break;
     case FR30_OPERAND_S10 :
       {
         long value = fields->f_s10;
-        value = ((((unsigned int) (value) >> (2))) & (255));
-        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_SIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+        value = ((int) (value) >> (2));
+        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX), 0, 8, 8, 16, total_length, buffer);
       }
       break;
     case FR30_OPERAND_U10 :
       {
         long value = fields->f_u10;
-        value = ((((unsigned int) (value) >> (2))) & (255));
-        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+        value = ((unsigned int) (value) >> (2));
+        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
+      }
+      break;
+    case FR30_OPERAND_I32 :
+      errmsg = insert_normal (od, fields->f_i32, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_UNSIGNED), 16, 0, 32, 32, total_length, buffer);
+      break;
+    case FR30_OPERAND_M4 :
+      {
+        long value = fields->f_m4;
+        value = ((value) & (15));
+        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 4, 16, total_length, buffer);
+      }
+      break;
+    case FR30_OPERAND_I20 :
+      {
+do {
+  FLD (f_i20_4) = ((unsigned int) (FLD (f_i20)) >> (16));
+  FLD (f_i20_16) = ((FLD (f_i20)) & (65535));
+} while (0);
+        errmsg = insert_normal (od, fields->f_i20_4, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED)|(1<<CGEN_OPERAND_VIRTUAL), 0, 8, 4, 16, total_length, buffer);
+        if (errmsg)
+          break;
+        errmsg = insert_normal (od, fields->f_i20_16, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED)|(1<<CGEN_OPERAND_VIRTUAL), 16, 0, 16, 16, total_length, buffer);
+        if (errmsg)
+          break;
       }
       break;
     case FR30_OPERAND_DIR8 :
-      errmsg = insert_normal (od, fields->f_dir8, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+      errmsg = insert_normal (od, fields->f_dir8, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
       break;
     case FR30_OPERAND_DIR9 :
       {
         long value = fields->f_dir9;
-        value = ((((unsigned int) (value) >> (1))) & (255));
-        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+        value = ((unsigned int) (value) >> (1));
+        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
       }
       break;
     case FR30_OPERAND_DIR10 :
       {
         long value = fields->f_dir10;
-        value = ((((unsigned int) (value) >> (2))) & (255));
-        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+        value = ((unsigned int) (value) >> (2));
+        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
       }
       break;
     case FR30_OPERAND_LABEL9 :
       {
-        long value = fields->f_rel8;
-        value = ((((unsigned int) (value) >> (1))) & (255));
-        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_SIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+        long value = fields->f_rel9;
+        value = ((int) (((value) - (((pc) + (2))))) >> (1));
+        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_PCREL_ADDR), 0, 8, 8, 16, total_length, buffer);
       }
       break;
     case FR30_OPERAND_LABEL12 :
       {
-        long value = fields->f_rel11;
-        value = ((((unsigned int) (value) >> (1))) & (2047));
-        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_SIGNED), 5, 11, CGEN_FIELDS_BITSIZE (fields), buffer);
+        long value = fields->f_rel12;
+        value = ((int) (((value) - (((pc) + (2))))) >> (1));
+        errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_PCREL_ADDR), 0, 5, 11, 16, total_length, buffer);
       }
       break;
+    case FR30_OPERAND_REGLIST_LOW_LD :
+      errmsg = insert_normal (od, fields->f_reglist_low_ld, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
+      break;
+    case FR30_OPERAND_REGLIST_HI_LD :
+      errmsg = insert_normal (od, fields->f_reglist_hi_ld, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
+      break;
+    case FR30_OPERAND_REGLIST_LOW_ST :
+      errmsg = insert_normal (od, fields->f_reglist_low_st, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
+      break;
+    case FR30_OPERAND_REGLIST_HI_ST :
+      errmsg = insert_normal (od, fields->f_reglist_hi_st, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
+      break;
     case FR30_OPERAND_CC :
-      errmsg = insert_normal (od, fields->f_cc, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, CGEN_FIELDS_BITSIZE (fields), buffer);
+      errmsg = insert_normal (od, fields->f_cc, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 4, 4, 16, total_length, buffer);
+      break;
+    case FR30_OPERAND_CCC :
+      errmsg = insert_normal (od, fields->f_ccc, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 16, 0, 8, 16, total_length, buffer);
       break;
 
     default :
@@ -306,9 +565,9 @@ insert_1 (od, value, start, length, word_length, bufp)
       /* ??? This may need reworking as these cases don't necessarily
         want the first byte and the last two bytes handled like this.  */
       if (big_p)
-       x = (bfd_getb8 (bufp) << 16) | bfd_getb16 (bufp + 1);
+       x = (bufp[0] << 16) | bfd_getb16 (bufp + 1);
       else
-       x = bfd_getl16 (bufp) | (bfd_getb8 (bufp + 2) << 16);
+       x = bfd_getl16 (bufp) | (bufp[2] << 16);
       break;
     case 32:
       if (big_p)
@@ -323,7 +582,7 @@ insert_1 (od, value, start, length, word_length, bufp)
   /* Written this way to avoid undefined behaviour.  */
   mask = (((1L << (length - 1)) - 1) << 1) | 1;
   if (CGEN_INSN_LSB0_P)
-    shift = start;
+    shift = (start + 1) - length;
   else
     shift = (word_length - (start + length));
   x = (x & ~(mask << shift)) | ((value & mask) << shift);
@@ -344,13 +603,13 @@ insert_1 (od, value, start, length, word_length, bufp)
         want the first byte and the last two bytes handled like this.  */
       if (big_p)
        {
-         bfd_putb8 (x >> 16, bufp);
+         bufp[0] = x >> 16;
          bfd_putb16 (x, bufp + 1);
        }
       else
        {
          bfd_putl16 (x, bufp);
-         bfd_putb8 (x >> 16, bufp + 2);
+         bufp[2] = x >> 16;
        }
       break;
     case 32:
@@ -369,33 +628,26 @@ insert_1 (od, value, start, length, word_length, bufp)
 /* Default insertion routine.
 
    ATTRS is a mask of the boolean attributes.
-   START is the starting bit number, architecture origin.
+   WORD_OFFSET is the offset in bits from the start of the insn of the value.
+   WORD_LENGTH is the length of the word in bits in which the value resides.
+   START is the starting bit number in the word, architecture origin.
    LENGTH is the length of VALUE in bits.
-   TOTAL_LENGTH is the total length of the insn.
+   TOTAL_LENGTH is the total length of the insn in bits.
 
    The result is an error message or NULL if success.  */
 
-/* ??? May need to know word length in order to properly place values as
-   an insn may be made of multiple words and the current bit number handling
-   may be insufficient.  Word length is an architectural attribute and thus
-   methinks the way to go [if needed] is to fetch this value from OD or
-   define a macro in <arch>-opc.h rather than adding an extra argument -
-   after all that's how endianness is handled.  */
 /* ??? This duplicates functionality with bfd's howto table and
    bfd_install_relocation.  */
-/* ??? For architectures where insns can be representable as ints,
-   store insn in `field' struct and add registers, etc. while parsing?  */
 /* ??? This doesn't handle bfd_vma's.  Create another function when
    necessary.  */
 
 static const char *
-insert_normal (od, value, attrs, start, length, total_length, buffer)
+insert_normal (od, value, attrs, word_offset, start, length, word_length,
+              total_length, buffer)
      CGEN_OPCODE_DESC od;
      long value;
      unsigned int attrs;
-     int start;
-     int length;
-     int total_length;
+     unsigned int word_offset, start, length, word_length, total_length;
      CGEN_INSN_BYTES_PTR buffer;
 {
   static char errbuf[100];
@@ -406,8 +658,23 @@ insert_normal (od, value, attrs, start, length, total_length, buffer)
   if (length == 0)
     return NULL;
 
+  if (CGEN_INT_INSN_P
+      && word_offset != 0)
+    abort ();
+
+  if (word_length > 32)
+    abort ();
+
+  /* For architectures with insns smaller than the insn-base-bitsize,
+     word_length may be too big.  */
+#if CGEN_MIN_INSN_BITSIZE < CGEN_BASE_INSN_BITSIZE
+  if (word_offset == 0
+      && word_length > total_length)
+    word_length = total_length;
+#endif
+
   /* Ensure VALUE will fit.  */
-  if ((attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED)) != 0)
+  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
     {
       unsigned long maxval = mask;
       if ((unsigned long) value > maxval)
@@ -435,152 +702,23 @@ insert_normal (od, value, attrs, start, length, total_length, buffer)
 
 #if CGEN_INT_INSN_P
 
-  if (total_length > 32)
-    abort ();
   {
     int shift;
 
     if (CGEN_INSN_LSB0_P)
-      shift = start;
+      shift = (start + 1) - length;
     else
-      shift = total_length - (start + length);
+      shift = word_length - (start + length);
     *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
   }
 
-#else
-
-  /* FIXME: unfinished and untested */
-
-/* ??? To be defined in <arch>-opc.h as necessary.  */
-#ifndef CGEN_WORD_ENDIAN
-#define CGEN_WORD_ENDIAN(od) CGEN_OPCODE_ENDIAN (od)
-#endif
-#ifndef CGEN_INSN_WORD_ENDIAN
-#define CGEN_INSN_WORD_ENDIAN(od) CGEN_WORD_ENDIAN (od)
-#endif
-
-  /* The hard case is probably too slow for the normal cases.
-     It's certainly more difficult to understand than the normal case.
-     Thus this is split into two.  Keep it that way.  The hard case is defined
-     to be when a field straddles a (loosely defined) word boundary
-     (??? which may require target specific help to determine).  */
+#else /* ! CGEN_INT_INSN_P */
 
-#if 0 /*wip*/
-
-#define HARD_CASE_P 0 /* FIXME:wip */
-
-  if (HARD_CASE_P)
-    {
-      unsigned char *bufp = (unsigned char *) buffer;
-      int insn_length_left = total_length;
-
-      if (CGEN_INSN_LSB0_P)
-       {
-         int word_offset = (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG
-                            ? ...
-                            : start / CGEN_BASE_INSN_BITSIZE);
-         bufp += word_offset * (CGEN_BASE_INSN_BITSIZE / 8);
-         if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
-         else
-           start -= word_offset * CGEN_BASE_INSN_BITSIZE;
-       }
-      else
-       {
-         int word_offset = (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG
-                            ? start / CGEN_BASE_INSN_BITSIZE
-                            : ...);
-         bufp += word_offset * (CGEN_BASE_INSN_BITSIZE / 8);
-         if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
-           start -= word_offset * CGEN_BASE_INSN_BITSIZE;
-         else
-       }
-
-      /* Loop so we handle a field straddling an insn word boundary
-        (remember, "insn word boundary" is loosely defined here).  */
-
-      while (length > 0)
-       {
-         int this_pass_length = length;
-         int this_pass_start = start;
-         int this_pass_word_length = min (insn_length_left,
-                                          (CGEN_BASE_INSN_BITSIZE == 8
-                                           ? 32
-                                           : CGEN_BASE_INSN_BITSIZE));
-
-         insert_1 (od, value, attrs,
-                   this_pass_start, this_pass_length, this_pass_word_length,
-                   bufp);
-
-         length -= this_pass_length;
-         insn_length_left -= this_pass_word_length;
-         if (???)
-           {
-             value >>= ???;
-             start += ???;
-           }
-         else
-           {
-             value >>= ???;
-             start += ???;
-           }
-         bufp += this_pass_word_length / 8;
-       }
-    }
-  else
-#endif /* 0 */
-    {
-      unsigned char *bufp = (unsigned char *) buffer;
-
-      if (length > 32)
-       abort ();
-
-      /* Adjust start,total_length,bufp to point to the pseudo-word that holds
-        the value.  For example in a 48 bit insn where the value to insert
-        (say an immediate value) is the last 16 bits then word_length here
-        would be 16.  To handle a 24 bit insn with an 18 bit immediate,
-        insert_1 handles 24 bits (using a combination of bfd_get8,16).  */
-
-      if (total_length > 32)
-       {
-         int needed_width = start % 8 + length;
-         int fetch_length = (needed_width <= 8 ? 8
-                             : needed_width <= 16 ? 16
-                             : 32);
-
-         if (CGEN_INSN_LSB0_P)
-           {
-             if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
-               {
-                 abort (); /* wip */
-               }
-             else
-               {
-                 int offset = start & ~7;
-
-                 bufp += offset / 8;
-                 start -= offset;
-                 total_length -= offset;
-               }
-           }
-         else
-           {
-             if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
-               {
-                 int offset = start & ~7;
-
-                 bufp += offset / 8;
-                 start -= offset;
-                 total_length -= offset;
-               }
-             else
-               {
-                 abort (); /* wip */
-               }
-           }
-       }
+  {
+    unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
 
-      insert_1 (od, value, start, length, total_length, bufp);
-    }
+    insert_1 (od, value, start, length, word_length, bufp);
+  }
 
 #endif /* ! CGEN_INT_INSN_P */
 
@@ -719,7 +857,7 @@ insert_insn_normal (od, insn, fields, buffer, pc)
   const unsigned char * syn;
 
   CGEN_INIT_INSERT (od);
-  value = CGEN_INSN_VALUE (insn);
+  value = CGEN_INSN_BASE_VALUE (insn);
 
   /* If we're recording insns as numbers (rather than a string of bytes),
      target byte order handling is deferred until later.  */
@@ -730,14 +868,16 @@ insert_insn_normal (od, insn, fields, buffer, pc)
 
 #else
 
-  cgen_insn_put_value (od, buffer, min (CGEN_BASE_INSN_BITSIZE,
+  cgen_put_insn_value (od, buffer, min (CGEN_BASE_INSN_BITSIZE,
                                        CGEN_FIELDS_BITSIZE (fields)),
                       value);
 
 #endif /* ! CGEN_INT_INSN_P */
 
-  /* ??? Rather than scanning the syntax string again, we could store
-     in `fields' a null terminated list of the fields that are present.  */
+  /* ??? It would be better to scan the format's fields.
+     Still need to be able to insert a value based on the operand though;
+     e.g. storing a branch displacement that got resolved later.
+     Needs more thought first.  */
 
   for (syn = CGEN_SYNTAX_STRING (syntax); * syn != '\0'; ++ syn)
     {
@@ -810,9 +950,7 @@ fr30_cgen_assemble_insn (od, str, fields, buf, errmsg)
 
       str = start;
 
-      /* Record a default length for the insn.  This will get set to the
-        correct value while parsing.  */
-      /* FIXME: wip */
+      /* Allow parse/insert handlers to obtain length of insn.  */
       CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
 
       if (! CGEN_PARSE_FN (insn) (od, insn, & str, fields))
This page took 0.031482 seconds and 4 git commands to generate.