bfd_boolean dsp_work_bloop (void);
 bfd_boolean float_work_fpuv3_fmovi (void);
 bfd_boolean float_work_fpuv3_fstore (void);
+bfd_boolean v2_work_addc (void);
 
 /* csky-opc.h must be included after workers are declared.  */
 #include "opcodes/csky-opc.h"
 parse_type_ctrlreg (char** oper)
 {
   int i = -1;
-  int len = 0;
+  int group = 0;
+  int crx;
+  int sel;
+  char *s = *oper;
+  expressionS e;
 
   if (TOLOWER (*(*oper + 0)) == 'c'
       && TOLOWER (*(*oper + 1)) == 'r'
       && ISDIGIT (*(*oper + 2)))
     {
       /* The control registers are named crxx.  */
-      i = *(*oper + 2) - 0x30;
-      i = ISDIGIT (*(*oper + 3)) ? (*(*oper + 3) - 0x30) + 10 * i : i;
-      len = ISDIGIT (*(*oper + 3)) ? 4 : 3;
-      *oper += len;
-    }
-  else if (!(TOLOWER (*(*oper + 0)) == 'c'
-            && TOLOWER (*(*oper + 1)) == 'r'))
-    {
-      /* The control registers are aliased.  */
-      struct csky_reg *reg = &csky_ctrl_regs[0];
-      while (reg->name)
-       {
-         if (memcmp (*oper, reg->name, strlen (reg->name)) == 0
-             && (!reg->flag || (isa_flag & reg->flag)))
-           {
-             i = reg->index;
-             len = strlen (reg->name);
-             *oper += len;
-             break;
-           }
-         reg++;
+      s = *oper+2;
+      s = parse_exp (s, &e);
+      if (e.X_op == O_constant)
+        {
+         i = e.X_add_number;
+         *oper = s;
        }
     }
 
   if (IS_CSKY_V2 (mach_flag))
     {
-      char *s = *oper;
-      int crx;
-      int sel;
+
+      s = *oper;
       if (i != -1)
        {
          crx = i;
-         sel = 0;
+         sel = group;
        }
-      else
+      else if (TOLOWER (*(*oper + 0)) == 'c'
+              && TOLOWER (*(*oper + 1)) == 'r')
        {
-         if (s[0] == 'c' && s[1] == 'r')
+         s += 2;
+         if (*s != '<')
            {
-             s += 2;
-             if (*s == '<')
-               {
-                 s++;
-                 if (s[0] == '3' && s[1] >= '0' && s[1] <= '1')
-                   {
-                     crx = 30 + s[1] - '0';
-                     s += 2;
-                   }
-                 else if (s[0] == '2' && s[1] >= '0' && s[1] <= '9')
-                   {
-                     crx = 20 + s[1] - '0';
-                     s += 2;
-                   }
-                 else if (s[0] == '1' && s[1] >= '0' && s[1] <= '9')
-                   {
-                     crx = 10 + s[1] - '0';
-                     s += 2;
-                   }
-                 else if (s[0] >= '0' && s[0] <= '9')
-                   {
-                     crx = s[0] - '0';
-                     s += 1;
-                   }
-                 else
-                   {
-                     SET_ERROR_STRING (ERROR_REG_OVER_RANGE, "control");
-                     return FALSE;
-                   }
-                 if (*s == ',')
-                   s++;
-                 else
-                   {
-                     SET_ERROR_STRING (ERROR_CREG_ILLEGAL, NULL);
-                     return FALSE;
-                   }
-                 char *pS = s;
-                 while (*pS != '>' && !is_end_of_line[(unsigned char) *pS])
-                   pS++;
-                 if (*pS == '>')
-                     *pS = '\0';
-                 else
-                   {
-                     /* Error. Missing '>'.  */
-                     SET_ERROR_STRING (ERROR_MISSING_RANGLE_BRACKETS, NULL);
-                     return FALSE;
-                   }
-                 expressionS e;
-                 s = parse_exp (s, &e);
-                 if (e.X_op == O_constant
-                     && e.X_add_number >= 0
-                     && e.X_add_number <= 31)
-                   {
-                     *oper = s;
-                     sel = e.X_add_number;
-                   }
-                 else
-                   return FALSE;
-               }
-             else
-               {
-                 /* Error. Missing '<'.  */
-                 SET_ERROR_STRING (ERROR_MISSING_LANGLE_BRACKETS, NULL);
-                 return FALSE;
-               }
+             SET_ERROR_STRING (ERROR_CREG_ILLEGAL, s);
+             return FALSE;
            }
-         else
+         s++;
+         crx = strtol(s, &s, 10);
+         if (crx < 0 || crx > 31 || *s != ',')
+           {
+             SET_ERROR_STRING (ERROR_CREG_ILLEGAL, s);
+             return FALSE;
+           }
+         s++;
+         sel = strtol(s, &s, 10);
+         if (sel < 0 || sel > 31 || *s != '>')
            {
-             SET_ERROR_STRING (ERROR_CREG_ILLEGAL, NULL);
+             SET_ERROR_STRING (ERROR_CREG_ILLEGAL, s);
+             return FALSE;
+           }
+         s++;
+       }
+      else
+       {
+         crx = csky_get_control_regno (mach_flag & CSKY_ARCH_MASK,
+                         s, &s, &sel);
+         if (crx < 0)
+           {
+             SET_ERROR_STRING (ERROR_CREG_ILLEGAL, s);
              return FALSE;
            }
        }
        i = (sel << 5) | crx;
     }
+  else if (i == -1)
+    {
+      i = csky_get_control_regno (mach_flag & CSKY_ARCH_MASK,
+                                 s, &s, &sel);
+      if (i < 0)
+       {
+         SET_ERROR_STRING (ERROR_CREG_ILLEGAL, s);
+         return FALSE;
+       }
+    }
+  *oper = s;
   csky_insn.val[csky_insn.idx++] = i;
   return TRUE;
 }
 
+static int
+csky_get_reg_val (char *str, int *len)
+{
+  int regno = 0;
+  char *s = str;
+  regno = csky_get_general_regno (mach_flag & CSKY_ARCH_MASK, str, &s);
+  *len = (s - str);
+  return regno;
+}
+
 static bfd_boolean
 is_reg_sp_with_bracket (char **oper)
 {
-  const char **regs;
+  int reg;
   int sp_idx;
   int len;
 
   if (**oper != '(')
       return FALSE;
   *oper += 1;
-  regs = csky_general_reg;
-  len = strlen (regs[sp_idx]);
-  if (memcmp (*oper, regs[sp_idx], len) == 0)
+  reg = csky_get_reg_val (*oper, &len);
+  *oper += len;
+  if (reg == sp_idx)
     {
-      *oper += len;
       if (**oper != ')')
-       return FALSE;
+        {
+          SET_ERROR_STRING (ERROR_UNDEFINE,
+                           "Operand format is error. '(sp)' expected");
+          return FALSE;
+        }
       *oper += 1;
       csky_insn.val[csky_insn.idx++] = sp_idx;
       return TRUE;
     }
-  else
-    {
-      if (IS_CSKY_V1 (mach_flag))
-       regs = cskyv1_general_alias_reg;
-      else
-       regs = cskyv2_general_alias_reg;
-      len = strlen (regs[sp_idx]);
-      if (memcmp (*oper, regs[sp_idx], len) == 0)
-       {
-         *oper += len;
-         if (**oper != ')')
-           return FALSE;
-         *oper += 1;
-         return TRUE;
-       }
-    }
+
+  SET_ERROR_STRING (ERROR_UNDEFINE,
+                   "Operand format is error. '(sp)' expected");
   return FALSE;
 }
 
 static bfd_boolean
 is_reg_sp (char **oper)
 {
-  const char **regs;
+  char sp_name[16];
   int sp_idx;
   int len;
   if (IS_CSKY_V1 (mach_flag))
   else
     sp_idx = 14;
 
-  regs = csky_general_reg;
-  len = strlen (regs[sp_idx]);
-  if (memcmp (*oper, regs[sp_idx], len) == 0)
+  /* ABI names: "sp". */
+  if (memcmp (*oper, "sp", 2) == 0)
     {
-      *oper += len;
+      *oper += 2;
       csky_insn.val[csky_insn.idx++] = sp_idx;
       return TRUE;
     }
-  else
-    {
-      if (IS_CSKY_V1 (mach_flag))
-       regs = cskyv1_general_alias_reg;
-      else
-       regs = cskyv2_general_alias_reg;
-      len = strlen (regs[sp_idx]);
-      if (memcmp (*oper, regs[sp_idx], len) == 0)
-       {
-         *oper += len;
-         csky_insn.val[csky_insn.idx++] = sp_idx;
-         return TRUE;
-       }
-    }
-  return FALSE;
-}
-
-static int
-csky_get_reg_val (char *str, int *len)
-{
-  long reg = 0;
-  if (TOLOWER (str[0]) == 'r' && ISDIGIT (str[1]))
-    {
-      if (ISDIGIT (str[1]) && ISDIGIT (str[2]))
-       {
-         reg = (str[1] - '0') * 10 + str[2] - '0';
-         *len = 3;
-       }
-      else if (ISDIGIT (str[1]))
-       {
-         reg = str[1] - '0';
-         *len = 2;
-       }
-      else
-       return -1;
-    }
-  else if (TOLOWER (str[0]) == 's' && TOLOWER (str[1]) == 'p'
-          && !ISDIGIT (str[2]))
-    {
-      /* sp.  */
-      if (IS_CSKY_V1 (mach_flag))
-       reg = 0;
-      else
-       reg = 14;
-      *len = 2;
-    }
-  else if (TOLOWER (str[0]) == 'g' && TOLOWER (str[1]) == 'b'
-          && !ISDIGIT (str[2]))
-    {
-      /* gb.  */
-      if (IS_CSKY_V1 (mach_flag))
-       reg = 14;
-      else
-       reg = 28;
-      *len = 2;
-    }
-  else if (TOLOWER (str[0]) == 'l' && TOLOWER (str[1]) == 'r'
-          && !ISDIGIT (str[2]))
-    {
-      /* lr.  */
-      reg = 15;
-      *len = 2;
-    }
-  else if (TOLOWER (str[0]) == 't' && TOLOWER (str[1]) == 'l'
-          && TOLOWER (str[2]) == 's' && !ISDIGIT (str[3]))
-    {
-      /* tls.  */
-      if (IS_CSKY_V2 (mach_flag))
-       reg = 31;
-      else
-       return -1;
-      *len = 3;
-    }
-  else if (TOLOWER (str[0]) == 's' && TOLOWER (str[1]) == 'v'
-          && TOLOWER (str[2]) == 'b' && TOLOWER (str[3]) == 'r')
-    {
-      if (IS_CSKY_V2 (mach_flag))
-       reg = 30;
-      else
-       return -1;
-      *len = 4;
-    }
-  else if (TOLOWER (str[0]) == 'a')
-    {
-      if (ISDIGIT (str[1]) && !ISDIGIT (str[2]))
-       {
-         if (IS_CSKY_V1 (mach_flag) && (str[1] - '0') <= 5)
-           /* a0 - a5.  */
-           reg = 2 + str[1] - '0';
-         else if (IS_CSKY_V2 (mach_flag) && (str[1] - '0') <= 3)
-           /* a0 - a3.  */
-           reg = str[1] - '0';
-         else
-           return -1;
-         *len = 2;
-       }
-    }
-  else if (TOLOWER (str[0]) == 't')
-    {
-      if (IS_CSKY_V2 (mach_flag))
-       {
-         reg = atoi (str + 1);
-         if (reg > 9)
-           return -1;
-
-         if (reg > 1)
-           /* t2 - t9.  */
-           reg = reg + 16;
-         else
-           /* t0 - t1.  */
-           reg = reg + 12;
-         *len = 2;
-       }
-    }
-  else if (TOLOWER (str[0]) == 'l')
-    {
-      if (str[1] < '0' || str[1] > '9')
-       return -1;
-      if (IS_CSKY_V2 (mach_flag))
-       {
-         reg = atoi (str + 1);
-         if (reg > 9)
-           return -1;
-         if (reg > 7)
-           /* l8 - l9.  */
-           reg = reg + 8;
-         else
-           /* l0 - l7.  */
-           reg = reg + 4;
-       }
-      else
-       {
-         reg = atoi (str + 1);
-         if (reg > 5)
-           return -1;
-         /* l0 - l6 -> r8 - r13.  */
-         reg = reg + 8;
-       }
-      *len = 2;
-    }
-  else
-    return -1;
 
-  /* Is register available?  */
-  if (IS_CSKY_ARCH_801 (mach_flag))
-    {
-      /* CK801 register range is r0-r8 & r13-r15.  */
-      if ((reg > 8 && reg < 13) || reg > 15)
-       {
-         SET_ERROR_STRING (ERROR_REG_OVER_RANGE, reg);
-         return -1;
-       }
-    }
-  else if (IS_CSKY_ARCH_802 (mach_flag))
-    {
-      /* CK802 register range is r0-r15 & r23-r25 & r30.  */
-      if ((reg > 15 && reg < 23) || (reg > 25 && reg != 30))
-       {
-         SET_ERROR_STRING (ERROR_REG_OVER_RANGE, reg);
-         return -1;
-       }
-    }
-  else if (reg > 31 || reg < 0)
+  len = sprintf (sp_name, "r%d", sp_idx);
+  if (memcmp (*oper, sp_name, len) == 0)
     {
-      SET_ERROR_STRING (ERROR_REG_OVER_RANGE, reg);
-      return -1;
+      *oper += len;
+      csky_insn.val[csky_insn.idx++] = sp_idx;
+      return TRUE;
     }
 
-  return reg;
+  return FALSE;
 }
 
 static int
        e.X_add_number |= 0x80000000;
       csky_insn.val[csky_insn.idx++] = e.X_add_number;
     }
-
   else
     SET_ERROR_STRING(ERROR_IMM_ILLEGAL, NULL);
 
        }
       csky_insn.val[csky_insn.idx++] = e.X_add_number - 1;
     }
+  else
+    SET_ERROR_STRING (ERROR_IMM_ILLEGAL, NULL);
 
   return ret;
 }
 static bfd_boolean
 parse_type_cpreg (char** oper)
 {
-  const char **regs = csky_cp_reg;
-  int i;
-  int len;
+  expressionS e;
 
-  for (i = 0; i < (int)(sizeof (csky_cp_reg) / sizeof (char *)); i++)
+  if (strncasecmp (*oper, "cpr", 3) != 0)
     {
-      len = strlen (regs[i]);
-      if (memcmp (*oper, regs[i], len) == 0 && !ISDIGIT (*(*oper + len)))
-       {
-         *oper += len;
-         csky_insn.val[csky_insn.idx++] = i;
-         return TRUE;
-       }
+      SET_ERROR_STRING(ERROR_CPREG_ILLEGAL, *oper);
+      return FALSE;
     }
-  SET_ERROR_STRING (ERROR_CPREG_ILLEGAL, *oper);
-  return FALSE;
+
+  *oper += 3;
+
+  *oper = parse_exp (*oper, &e);
+  if (e.X_op != O_constant)
+    {
+      SET_ERROR_STRING(ERROR_CPREG_ILLEGAL, *oper);
+      return FALSE;
+    }
+
+  csky_insn.val[csky_insn.idx++] = e.X_add_number;
+
+  return TRUE;
 }
 
 static bfd_boolean
 parse_type_cpcreg (char** oper)
 {
-  const char **regs;
-  int i;
-  int len;
-  regs = csky_cp_creg;
-  for (i = 0; i < (int)(sizeof (csky_cp_creg) / sizeof (char *)); i++)
+  expressionS e;
+
+  if (strncasecmp (*oper, "cpcr", 4) != 0)
     {
-      len = strlen (regs[i]);
-      if (memcmp (*oper, regs[i], len) == 0 && !ISDIGIT (*(*oper + len)))
-       {
-         *oper += len;
-         csky_insn.val[csky_insn.idx++] = i;
-         return TRUE;
-       }
+      SET_ERROR_STRING(ERROR_CPREG_ILLEGAL, *oper);
+      return FALSE;
     }
-  SET_ERROR_STRING (ERROR_CPREG_ILLEGAL, *oper);
-  return FALSE;
+
+  *oper += 4;
+
+  *oper = parse_exp (*oper, &e);
+  if (e.X_op != O_constant)
+    {
+      SET_ERROR_STRING(ERROR_CPREG_ILLEGAL, *oper);
+      return FALSE;
+    }
+
+  csky_insn.val[csky_insn.idx++] = e.X_add_number;
+
+  return TRUE;
 }
 
 static bfd_boolean
        else
          return FALSE;
 
+    case OPRND_TYPE_IMM5b_LS:
+      return is_imm_within_range (oper,
+                                 0,
+                                 csky_insn.val[csky_insn.idx - 1]);
     case OPRND_TYPE_IMM5b_RORI:
       {
        unsigned max_shift = IS_CSKY_V1 (mach_flag) ? 31 : 32;
                       (void *)error_state.arg1, (void *)error_state.arg1);
       return;
     }
+  error_state.err_num = ERROR_NONE;
 
   /* if this insn has work in opcode table, then do it.  */
   if (csky_insn.opcode->work != NULL)
   int reg1;
   int reg2;
   int reg3;
+  char reg1_name[16] = {0};
+  char reg3_name[16] = {0};
 
   if (!get_macro_reg_vals (®1, ®2, ®3))
     return;
-  csky_macro_md_assemble ("cmplt",
-                         csky_general_reg[reg1],
-                         csky_general_reg[reg1],
-                         NULL);
-  csky_macro_md_assemble ("addc",
-                         csky_general_reg[reg1 + (target_big_endian ? 1 : 0)],
-                         csky_general_reg[reg3 + (target_big_endian ? 1 : 0)],
-                         NULL);
-  csky_macro_md_assemble ("addc",
-                         csky_general_reg[reg1 + (target_big_endian ? 0 : 1)],
-                         csky_general_reg[reg3 + (target_big_endian ? 0 : 1)],
-                         NULL);
+
+  sprintf (reg1_name, "r%d", reg1);
+  csky_macro_md_assemble ("cmplt", reg1_name, reg1_name, NULL);
+  if (error_state.err_num != ERROR_NONE)
+    return;
+
+  sprintf (reg1_name, "r%d", reg1 + (target_big_endian ? 1 : 0));
+  sprintf (reg3_name, "r%d", reg3 + (target_big_endian ? 1 : 0));
+  csky_macro_md_assemble ("addc", reg1_name, reg3_name, NULL);
+  if (error_state.err_num != ERROR_NONE)
+    return;
+
+  sprintf (reg1_name, "r%d", reg1 + (target_big_endian ? 0 : 1));
+  sprintf (reg3_name, "r%d", reg3 + (target_big_endian ? 0 : 1));
+  csky_macro_md_assemble ("addc", reg1_name, reg3_name, NULL);
   return;
 }
 
   int reg1;
   int reg2;
   int reg3;
+  char reg1_name[16] = {0};
+  char reg3_name[16] = {0};
 
   if (!get_macro_reg_vals (®1, ®2, ®3))
     return;
-  csky_macro_md_assemble ("cmphs",
-                         csky_general_reg[reg1],
-                         csky_general_reg[reg1],
-                         NULL);
-  csky_macro_md_assemble ("subc",
-                         csky_general_reg[reg1 + (target_big_endian ? 1 : 0)],
-                         csky_general_reg[reg3 + (target_big_endian ? 1 : 0)],
-                         NULL);
-  csky_macro_md_assemble ("subc",
-                         csky_general_reg[reg1 + (target_big_endian ? 0 : 1)],
-                         csky_general_reg[reg3 + (target_big_endian ? 0 : 1)],
-                         NULL);
+
+  sprintf (reg1_name, "r%d", reg1);
+  csky_macro_md_assemble ("cmphs", reg1_name, reg1_name, NULL);
+  if (error_state.err_num != ERROR_NONE)
+    return;
+
+  sprintf (reg1_name, "r%d", reg1 + (target_big_endian ? 1 : 0));
+  sprintf (reg3_name, "r%d", reg3 + (target_big_endian ? 1 : 0));
+  csky_macro_md_assemble ("subc", reg1_name, reg3_name, NULL);
+  if (error_state.err_num != ERROR_NONE)
+    return;
+
+  sprintf (reg1_name, "r%d", reg1 + (target_big_endian ? 0 : 1));
+  sprintf (reg3_name, "r%d", reg3 + (target_big_endian ? 0 : 1));
+  csky_macro_md_assemble ("subc", reg1_name, reg3_name, NULL);
   return;
 }
 
   int reg1;
   int reg2;
   int reg3;
+  char reg1_name[16] = {0};
+  char reg3_name[16] = {0};
 
   if (!get_macro_reg_vals (®1, ®2, ®3))
     return;
-  csky_macro_md_assemble ("or",
-                         csky_general_reg[reg1 + (target_big_endian ? 1 : 0)],
-                         csky_general_reg[reg3 + (target_big_endian ? 1 : 0)],
-                         NULL);
-  csky_macro_md_assemble ("or",
-                         csky_general_reg[reg1 + (target_big_endian ? 0 : 1)],
-                         csky_general_reg[reg3 + (target_big_endian ? 0 : 1)],
-                         NULL);
+  sprintf (reg1_name, "r%d", reg1 + (target_big_endian ? 1 : 0));
+  sprintf (reg3_name, "r%d", reg3 + (target_big_endian ? 1 : 0));
+  csky_macro_md_assemble ("or", reg1_name, reg3_name, NULL);
+
+  if (error_state.err_num != ERROR_NONE)
+    return;
+  sprintf (reg1_name, "r%d", reg1 + (target_big_endian ? 0 : 1));
+  sprintf (reg3_name, "r%d", reg3 + (target_big_endian ? 0 : 1));
+  csky_macro_md_assemble ("or", reg1_name, reg3_name, NULL);
   return;
 }
 
   int reg1;
   int reg2;
   int reg3;
+  char reg1_name[16] = {0};
+  char reg3_name[16] = {0};
 
   if (!get_macro_reg_vals (®1, ®2, ®3))
     return;
-  csky_macro_md_assemble ("xor",
-                         csky_general_reg[reg1 + (target_big_endian ? 1 : 0)],
-                         csky_general_reg[reg3 + (target_big_endian ? 1 : 0)],
-                         NULL);
-  csky_macro_md_assemble ("xor",
-                         csky_general_reg[reg1 + (target_big_endian ? 0 : 1)],
-                         csky_general_reg[reg3 + (target_big_endian ? 0 : 1)],
-                         NULL);
+
+  sprintf (reg1_name, "r%d", reg1 + (target_big_endian ? 1 : 0));
+  sprintf (reg3_name, "r%d", reg3 + (target_big_endian ? 1 : 0));
+  csky_macro_md_assemble ("xor", reg1_name, reg3_name, NULL);
+  if (error_state.err_num != ERROR_NONE)
+    return;
+
+  sprintf (reg1_name, "r%d", reg1 + (target_big_endian ? 0 : 1));
+  sprintf (reg3_name, "r%d", reg3 + (target_big_endian ? 0 : 1));
+  csky_macro_md_assemble ("xor", reg1_name, reg3_name, NULL);
   return;
 }
 
   inst = csky_insn.inst;
 
   /* Now get greg and inst, we can write instruction to floating unit.  */
-  sprintf (buff, "lrw %s,0x%x", csky_general_reg[greg], inst);
+  sprintf (buff, "lrw r%d,0x%x", greg, inst);
   md_assemble (buff);
-  sprintf (buff, "cpwir %s", csky_general_reg[greg]);
+  sprintf (buff, "cpwir r%d", greg);
   md_assemble (buff);
-
   return FALSE;
 }
 
   inst = csky_insn.inst;
 
   /* Now get greg and inst, we can write instruction to floating unit.  */
-  sprintf (buff, "lrw %s,0x%x", csky_general_reg[greg], inst);
+  sprintf (buff, "lrw r%d,0x%x", greg, inst);
   md_assemble (buff);
-  sprintf (buff, "cpwir %s", csky_general_reg[greg]);
+  sprintf (buff, "cpwir r%d", greg);
   md_assemble (buff);
   sprintf (buff, "cprc");
   md_assemble (buff);
   freg = csky_insn.val[1];
 
   /* Now get greg and freg, we can write instruction to floating unit.  */
-  sprintf (buff, "cpwgr %s,%s", csky_general_reg[greg], csky_cp_reg[freg]);
+  sprintf (buff, "cpwgr r%d,cpr%d", greg, freg);
   md_assemble (buff);
 
   return FALSE;
   greg = csky_insn.val[0];
   freg = csky_insn.val[1];
   /* Now get greg and freg, we can write instruction to floating unit.  */
-  sprintf (buff, "cprgr %s,%s", csky_general_reg[greg], csky_cp_reg[freg]);
+  sprintf (buff, "cprgr r%d,cpr%d", greg, freg);
   md_assemble (buff);
 
   return FALSE;
     }
   /* Now get greg and freg, we can write instruction to floating unit.  */
   if (target_big_endian)
-    sprintf (buff, "cpwgr %s,%s",
-            csky_general_reg[greg + 1], csky_cp_reg[freg]);
+    sprintf (buff, "cpwgr r%d,cpr%d", greg + 1, freg);
   else
-    sprintf (buff, "cpwgr %s,%s",
-            csky_general_reg[greg], csky_cp_reg[freg]);
+    sprintf (buff, "cpwgr r%d,cpr%d", greg, freg);
   md_assemble (buff);
   if (target_big_endian)
-    sprintf (buff, "cpwgr %s,%s",
-            csky_general_reg[greg], csky_cp_reg[freg + 1]);
+    sprintf (buff, "cpwgr r%d,cpr%d", greg, freg + 1);
   else
-    sprintf (buff, "cpwgr %s,%s",
-            csky_general_reg[greg + 1], csky_cp_reg[freg + 1]);
+    sprintf (buff, "cpwgr r%d,cpr%d", greg+1, freg + 1);
   md_assemble (buff);
-
   return FALSE;
 }
 
     }
   /* Now get greg and freg, we can write instruction to floating unit.  */
   if (target_big_endian)
-    sprintf (buff, "cprgr %s,%s",
-            csky_general_reg[greg + 1], csky_cp_reg[freg]);
+    sprintf (buff, "cprgr r%d,cpr%d", greg+1, freg);
   else
-    sprintf (buff, "cprgr %s,%s",
-            csky_general_reg[greg], csky_cp_reg[freg]);
+    sprintf (buff, "cprgr r%d,cpr%d", greg, freg);
   md_assemble (buff);
   if (target_big_endian)
-    sprintf (buff, "cprgr %s,%s",
-            csky_general_reg[greg], csky_cp_reg[freg + 1]);
+    sprintf (buff, "cprgr r%d,cpr%d", greg, freg + 1);
   else
-    sprintf (buff, "cprgr %s,%s",
-            csky_general_reg[greg + 1], csky_cp_reg[freg + 1]);
+    sprintf (buff, "cprgr r%d,cpr%d", greg+1, freg + 1);
   md_assemble (buff);
 
   return FALSE;
   return TRUE;
 }
 
+bfd_boolean
+v2_work_addc (void)
+{
+  int reg1;
+  int reg2;
+  int reg3 = 0;
+  int is_16_bit = 0;
+
+  reg1 = csky_insn.val[0];
+  reg2 = csky_insn.val[1];
+  if (csky_insn.number == 2)
+    {
+      if (reg1 > 15 || reg2 > 15)
+       {
+         is_16_bit = 0;
+         reg3 = reg1;
+       }
+      else
+       is_16_bit = 1;
+    }
+  else
+    {
+      reg3 = csky_insn.val[2];
+      if (reg1 > 15 || reg2 > 15 || reg3 > 15)
+       is_16_bit = 0;
+      else if (reg1 == reg2 || reg1 == reg3)
+       {
+         is_16_bit = 1;
+         reg2 = (reg1 == reg2) ? reg3 : reg2;
+       }
+      else
+       is_16_bit = 0;
+    }
+
+  if (is_16_bit
+      && csky_insn.flag_force != INSN_OPCODE32F)
+    {
+      csky_insn.isize = 2;
+      csky_insn.inst = csky_insn.opcode->op16[0].opcode
+       | (reg1 << 6) | (reg2 << 2);
+    }
+  else if (csky_insn.flag_force != INSN_OPCODE16F)
+    {
+      csky_insn.isize = 4;
+      csky_insn.inst = csky_insn.opcode->op32[0].opcode
+       | (reg1 << 0) | (reg2 << 16) | (reg3 << 21);
+    }
+  else
+    {
+      SET_ERROR_INTEGER (ERROR_REG_OVER_RANGE, reg1 > 15 ? reg1 : reg2);
+      csky_show_error (ERROR_REG_OVER_RANGE, 0, 0, NULL);
+    }
+
+  /* Generate relax or reloc if necessary.  */
+  csky_generate_frags ();
+  /* Write inst to frag.  */
+  csky_write_insn (csky_insn.output,
+                  csky_insn.inst,
+                  csky_insn.isize);
+
+  return TRUE;
+}
+
 /* The following are for assembler directive handling.  */
 
 /* Helper function to adjust constant pool counts when we emit a
 
    02110-1301, USA.  */
 
 #include "opcode/csky.h"
+#include "safe-ctype.h"
 
 #define OP_TABLE_NUM    2
 #define MAX_OPRND_NUM   5
   /* OPRND_TYPE_IMM5b_a_b means: Immediate in (a, b).  */
   OPRND_TYPE_IMM5b_1_31,
   OPRND_TYPE_IMM5b_7_31,
+  /* OPRND_TYPE_IMM5b_LS means: Imm <= prev Imm.  */
+  OPRND_TYPE_IMM5b_LS,
   /* Operand type for rori and rotri.  */
   OPRND_TYPE_IMM5b_RORI,
   OPRND_TYPE_IMM5b_POWER,
 #define V1_REG_SP              0
 #define V1_REG_LR             15
 
-struct csky_reg
+struct psrbit
 {
+  int value;
+  int isa;
   const char *name;
-  int  index;
-  int  flag;
 };
 
-const char *csky_general_reg[] =
+const struct psrbit cskyv1_psr_bits[] =
 {
-  "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
-  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
-  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
-  "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
-  NULL,
+  {1,    0, "ie"},
+  {2,    0, "fe"},
+  {4,    0, "ee"},
+  {8,    0, "af"},
+  {0, 0, NULL},
 };
 
-/* TODO: optimize.  */
-const char *cskyv2_general_alias_reg[] =
+const struct psrbit cskyv2_psr_bits[] =
 {
-  "a0", "a1", "a2", "a3", "l0", "l1", "l2", "l3",
-  "l4", "l5", "l6", "l7", "t0", "t1", "sp", "lr",
-  "l8", "l9", "t2", "t3", "t4", "t5", "t6", "t7",
-  "t8", "t9", "r26", "r27", "rdb", "gb", "r30", "r31",
-  NULL,
+  {8, 0, "ee"},
+  {4, 0, "ie"},
+  {2, 0, "fe"},
+  {1, 0, "af"},
+  {0x10, CSKY_ISA_TRUST, "sie"},
+  {0, 0, NULL},
 };
 
-/* TODO: optimize.  */
-const char *cskyv1_general_alias_reg[] =
+#define GENARAL_REG_BANK      0x80000000
+#define REG_SUPPORT_ALL 0xffffffff
+
+/* CSKY register description.  */
+struct csky_reg_def
 {
-  "sp", "r1", "a0", "a1", "a2", "a3", "a4", "a5",
-  "fp", "l0", "l1", "l2", "l3", "l4", "gb", "lr",
-  NULL,
+  /* The group number for control registers,
+     and set the bank of genaral registers to a special number.  */
+  int bank;
+  int regno;
+  /* The name displayed by serial number.  */
+  const char *name;
+  /* The name displayed by ABI infomation,
+     used when objdump add option -Mabi-names.  */
+  const char *abi_name;
+  /* The flags indicate which arches support the register.  */
+  int arch_flag;
+  /* Some registers depend on special features.  */
+  char *features;
 };
 
-/* TODO: optimize.  */
-const char *csky_fpu_reg[] =
+/* Arch flag.  */
+#define ASH(a) (1 << CSKY_ARCH_##a)
+
+/* All arches exclued 801.  */
+#define REG_SUPPORT_A   (REG_SUPPORT_ALL & ~ASH(801))
+
+/* All arches exclued 801 and 802.  */
+#define REG_SUPPORT_B   (REG_SUPPORT_ALL & ~(ASH(801) | ASH(802)))
+
+/* All arches exclued 801, 802, 803, 805.*/
+#define REG_SUPPORT_C   (REG_SUPPORT_ALL & ~(ASH(801)                  \
+                       | ASH(802) | ASH(803) | ASH(805)))
+
+/* All arches exclued 801, 802, 803, 805, 807, 810.  */
+#define REG_SUPPORT_D   (REG_SUPPORT_C & ~(ASH(807) | ASH(810)))
+
+/* All arches exclued 807, 810, 860.  */
+#define REG_SUPPORT_E   (REG_SUPPORT_ALL & ~(ASH(807) | ASH(810) |     \
+                       ASH(860)))
+
+/* C-SKY V1 general registers table.  */
+static struct csky_reg_def csky_abiv1_general_regs[] = 
 {
-  "fr0",  "fr1",  "fr2",  "fr3",  "fr4",  "fr5",  "fr6",  "fr7",
-  "fr8",  "fr9",  "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
-  "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23",
-  "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31",
-  NULL,
+#define DECLARE_REG(regno, abi_name, support)          \
+  {GENARAL_REG_BANK, regno, "r"#regno, abi_name, support, NULL}
+
+  DECLARE_REG (0, "sp", REG_SUPPORT_ALL),
+  DECLARE_REG (1, NULL, REG_SUPPORT_ALL),
+  DECLARE_REG (2, "a0", REG_SUPPORT_ALL),
+  DECLARE_REG (3, "a1", REG_SUPPORT_ALL),
+  DECLARE_REG (4, "a2", REG_SUPPORT_ALL),
+  DECLARE_REG (5, "a3", REG_SUPPORT_ALL),
+  DECLARE_REG (6, "a4", REG_SUPPORT_ALL),
+  DECLARE_REG (7, "a5", REG_SUPPORT_ALL),
+  DECLARE_REG (8, "fp", REG_SUPPORT_ALL),
+  DECLARE_REG (8, "l0", REG_SUPPORT_ALL),
+  DECLARE_REG (9, "l1", REG_SUPPORT_ALL),
+  DECLARE_REG (10, "l2", REG_SUPPORT_ALL),
+  DECLARE_REG (11, "l3", REG_SUPPORT_ALL),
+  DECLARE_REG (12, "l4", REG_SUPPORT_ALL),
+  DECLARE_REG (13, "l5", REG_SUPPORT_ALL),
+  DECLARE_REG (14, "gb", REG_SUPPORT_ALL),
+  DECLARE_REG (15, "lr", REG_SUPPORT_ALL),
+#undef DECLARE_REG
+  {-1, -1, NULL, NULL, 0, NULL},
 };
 
-/* Control Registers.  */
-struct csky_reg csky_ctrl_regs[] =
+/* C-SKY V1 control registers table.  */
+static struct csky_reg_def csky_abiv1_control_regs[] = 
 {
-  {"psr", 0, 0},  {"vbr", 1, 0},    {"epsr", 2, 0},  {"fpsr", 3, 0},
-  {"epc", 4, 0},  {"fpc", 5, 0},    {"ss0", 6, 0},   {"ss1", 7, 0},
-  {"ss2", 8, 0},  {"ss3", 9, 0},    {"ss4", 10, 0},  {"gcr", 11, 0},
-  {"gsr", 12, 0}, {"cpuidr", 13, 0}, {"dcsr", 14, 0}, {"cwr", 15, 0},
-  {"cfr", 16, 0}, {"ccr", 17, 0},   {"capr", 19, 0}, {"pacr", 20, 0},
-  {"rid", 21, 0}, {"sedcr", 8, CSKY_ISA_TRUST}, {"sepcr", 9, CSKY_ISA_TRUST},
-  {NULL, 0, 0}
+#define DECLARE_REG(regno, abi_name, support)          \
+  {0, regno, "cr"#regno, abi_name, support, NULL}
+
+  DECLARE_REG (0, "psr", REG_SUPPORT_ALL),
+  DECLARE_REG (1, "vbr", REG_SUPPORT_ALL),
+  DECLARE_REG (2, "epsr", REG_SUPPORT_ALL),
+  DECLARE_REG (3, "fpsr", REG_SUPPORT_ALL),
+  DECLARE_REG (4, "epc", REG_SUPPORT_ALL),
+  DECLARE_REG (5, "fpc", REG_SUPPORT_ALL),
+  DECLARE_REG (6, "ss0", REG_SUPPORT_ALL),
+  DECLARE_REG (7, "ss1", REG_SUPPORT_ALL),
+  DECLARE_REG (8, "ss2", REG_SUPPORT_ALL),
+  DECLARE_REG (9, "ss3", REG_SUPPORT_ALL),
+  DECLARE_REG (10, "ss4", REG_SUPPORT_ALL),
+  DECLARE_REG (11, "gcr", REG_SUPPORT_ALL),
+  DECLARE_REG (12, "gsr", REG_SUPPORT_ALL),
+  DECLARE_REG (13, "cpid", REG_SUPPORT_ALL),
+  DECLARE_REG (14, "dcsr", REG_SUPPORT_ALL),
+  DECLARE_REG (15, "cwr", REG_SUPPORT_ALL),
+  DECLARE_REG (16, NULL, REG_SUPPORT_ALL),
+  DECLARE_REG (17, "cfr", REG_SUPPORT_ALL),
+  DECLARE_REG (18, "ccr", REG_SUPPORT_ALL),
+  DECLARE_REG (19, "capr", REG_SUPPORT_ALL),
+  DECLARE_REG (20, "pacr", REG_SUPPORT_ALL),
+  DECLARE_REG (21, "prsr", REG_SUPPORT_ALL),
+  DECLARE_REG (22, "mir", REG_SUPPORT_ALL),
+  DECLARE_REG (23, "mrr", REG_SUPPORT_ALL),
+  DECLARE_REG (24, "mel0", REG_SUPPORT_ALL),
+  DECLARE_REG (25, "mel1", REG_SUPPORT_ALL),
+  DECLARE_REG (26, "meh", REG_SUPPORT_ALL),
+  DECLARE_REG (27, "mcr", REG_SUPPORT_ALL),
+  DECLARE_REG (28, "mpr", REG_SUPPORT_ALL),
+  DECLARE_REG (29, "mwr", REG_SUPPORT_ALL),
+  DECLARE_REG (30, "mcir", REG_SUPPORT_ALL),
+#undef DECLARE_REG
+  {-1, -1, NULL, NULL, 0, NULL},
 };
 
-const char *csky_cp_idx[] =
+/* C-SKY V2 general registers table.  */
+static struct csky_reg_def csky_abiv2_general_regs[] = 
 {
-  "cp0", "cp1", "cp2", "cp3", "cp4", "cp5", "cp6", "cp7",
-  "cp8", "cp9", "cp10", "cp11", "cp12", "cp13", "cp14", "cp15",
-  "cp16", "cp17", "cp18", "cp19", "cp20",
-  NULL,
+#ifdef DECLARE_REG
+#undef DECLARE_REG
+#endif
+#define DECLARE_REG(regno, abi_name, support)          \
+  {GENARAL_REG_BANK, regno, "r"#regno, abi_name, support, NULL}
+
+  DECLARE_REG (0, "a0", REG_SUPPORT_ALL),
+  DECLARE_REG (1, "a1", REG_SUPPORT_ALL),
+  DECLARE_REG (2, "a2", REG_SUPPORT_ALL),
+  DECLARE_REG (3, "a3", REG_SUPPORT_ALL),
+  DECLARE_REG (4, "l0", REG_SUPPORT_ALL),
+  DECLARE_REG (5, "l1", REG_SUPPORT_ALL),
+  DECLARE_REG (6, "l2", REG_SUPPORT_ALL),
+  DECLARE_REG (7, "l3", REG_SUPPORT_ALL),
+  DECLARE_REG (8, "l4", REG_SUPPORT_ALL),
+  DECLARE_REG (9, "l5", REG_SUPPORT_A),
+  DECLARE_REG (10, "l6", REG_SUPPORT_A),
+  DECLARE_REG (11, "l7", REG_SUPPORT_A),
+  DECLARE_REG (12, "t0", REG_SUPPORT_A),
+  DECLARE_REG (13, "t1", REG_SUPPORT_ALL),
+  DECLARE_REG (14, "sp", REG_SUPPORT_ALL),
+  DECLARE_REG (15, "lr", REG_SUPPORT_ALL),
+  DECLARE_REG (16, "l8", REG_SUPPORT_B),
+  DECLARE_REG (17, "l9", REG_SUPPORT_B),
+  DECLARE_REG (18, "t2", REG_SUPPORT_B),
+  DECLARE_REG (19, "t3", REG_SUPPORT_B),
+  DECLARE_REG (20, "t4", REG_SUPPORT_B),
+  DECLARE_REG (21, "t5", REG_SUPPORT_B),
+  DECLARE_REG (22, "t6", REG_SUPPORT_B),
+  DECLARE_REG (23, "t7", REG_SUPPORT_B),
+  DECLARE_REG (24, "t8", REG_SUPPORT_B),
+  DECLARE_REG (25, "t9", REG_SUPPORT_B),
+  DECLARE_REG (26, NULL, REG_SUPPORT_B),
+  DECLARE_REG (27, NULL, REG_SUPPORT_B),
+  DECLARE_REG (28, "gb", REG_SUPPORT_B),
+  DECLARE_REG (28, "rgb", REG_SUPPORT_B),
+  DECLARE_REG (28, "rdb", REG_SUPPORT_B),
+  DECLARE_REG (29, "tb", REG_SUPPORT_B),
+  DECLARE_REG (29, "rtb", REG_SUPPORT_B),
+  DECLARE_REG (30, "svbr", REG_SUPPORT_A),
+  DECLARE_REG (31, "tls", REG_SUPPORT_B),
+
+  /* The followings JAVA/BCTM's features.  */
+  DECLARE_REG (23, "fp", REG_SUPPORT_ALL),
+  DECLARE_REG (24, "top", REG_SUPPORT_ALL),
+  DECLARE_REG (25, "bsp", REG_SUPPORT_ALL),
+
+  {-1, -1, NULL, NULL, 0, NULL},
 };
 
-const char *csky_cp_reg[] =
+/* C-SKY V2 control registers table.  */
+static struct csky_reg_def csky_abiv2_control_regs[] = 
 {
-  "cpr0",  "cpr1",  "cpr2",  "cpr3",  "cpr4",  "cpr5",  "cpr6",  "cpr7",
-  "cpr8",  "cpr9",  "cpr10", "cpr11", "cpr12", "cpr13", "cpr14", "cpr15",
-  "cpr16", "cpr17", "cpr18", "cpr19", "cpr20", "cpr21", "cpr22", "cpr23",
-  "cpr24", "cpr25", "cpr26", "cpr27", "cpr28", "cpr29", "cpr30", "cpr31",
-  "cpr32", "cpr33", "cpr34", "cpr35", "cpr36", "cpr37", "cpr38", "cpr39",
-  "cpr40", "cpr41", "cpr42", "cpr43", "cpr44", "cpr45", "cpr46", "cpr47",
-  "cpr48", "cpr49", "cpr50", "cpr51", "cpr52", "cpr53", "cpr54", "cpr55",
-  "cpr56", "cpr57", "cpr58", "cpr59", "cpr60", "cpr61", "cpr62", "cpr63",
-  NULL,
+
+#ifdef DECLARE_REG
+#undef DECLARE_REG
+#endif
+  /* Bank0.  */
+#define DECLARE_REG(regno, abi_name)           \
+  {0, regno, "cr<"#regno", 0>", abi_name, REG_SUPPORT_ALL, NULL}
+  DECLARE_REG (0, "psr"),
+  DECLARE_REG (1, "vbr"),
+  DECLARE_REG (2, "epsr"),
+  DECLARE_REG (3, "fpsr"),
+  DECLARE_REG (4, "epc"),
+  DECLARE_REG (5, "fpc"),
+  DECLARE_REG (6, "ss0"),
+  DECLARE_REG (7, "ss1"),
+  DECLARE_REG (8, "ss2"),
+  DECLARE_REG (9, "ss3"),
+  DECLARE_REG (10, "ss4"),
+  DECLARE_REG (11, "gcr"),
+  DECLARE_REG (12, "gsr"),
+  DECLARE_REG (13, "cpid"),
+  DECLARE_REG (14, "dcsr"),
+  DECLARE_REG (15, NULL),
+  DECLARE_REG (16, NULL),
+  DECLARE_REG (17, "cfr"),
+  DECLARE_REG (18, "ccr"),
+  DECLARE_REG (19, "capr"),
+  DECLARE_REG (20, "pacr"),
+  DECLARE_REG (21, "prsr"),
+  DECLARE_REG (22, "cir"),
+  DECLARE_REG (23, "ccr2"),
+  DECLARE_REG (24, NULL),
+  DECLARE_REG (25, "cer2"),
+  DECLARE_REG (26, NULL),
+  DECLARE_REG (27, NULL),
+  DECLARE_REG (28, "rvbr"),
+  DECLARE_REG (29, "rmr"),
+  DECLARE_REG (30, "mpid"),
+
+#undef DECLARE_REG
+#define DECLARE_REG(regno, abi_name, support)          \
+  {0, regno, "cr<"#regno", 0>", abi_name, support, NULL}
+  DECLARE_REG (31, "chr", REG_SUPPORT_E),
+  DECLARE_REG (31, "hint", REG_SUPPORT_C),
+
+  /* Bank1.  */
+#undef DECLARE_REG
+#define DECLARE_REG(regno, abi_name)           \
+  {1, regno, "cr<"#regno", 1>", abi_name, REG_SUPPORT_ALL, NULL}
+
+  DECLARE_REG (14, "usp"),
+  DECLARE_REG (26, "cindex"),
+  DECLARE_REG (27, "cdata0"),
+  DECLARE_REG (28, "cdata1"),
+  DECLARE_REG (29, "cdata2"),
+  DECLARE_REG (30, "cdata3"),
+  DECLARE_REG (31, "cins"),
+
+  /* Bank2.  */
+#undef DECLARE_REG
+#define DECLARE_REG(regno, abi_name)           \
+  {2, regno, "cr<"#regno", 2>", abi_name, REG_SUPPORT_ALL, NULL}
+
+  DECLARE_REG (0, "fid"),
+  DECLARE_REG (1, "fcr"),
+  DECLARE_REG (2, "fesr"),
+
+  /* Bank3.  */
+#undef DECLARE_REG
+#define DECLARE_REG(regno, abi_name)           \
+  {3, regno, "cr<"#regno", 3>", abi_name, REG_SUPPORT_ALL, NULL}
+  DECLARE_REG (8, "dcr"),
+  DECLARE_REG (8, "sedcr"),
+  DECLARE_REG (9, "pcr"),
+  DECLARE_REG (9, "sepcr"),
+
+  /* Bank15.  */
+#undef DECLARE_REG
+#define DECLARE_REG(regno, abi_name)           \
+  {15, regno, "cr<"#regno", 15>", abi_name, REG_SUPPORT_ALL, NULL}
+
+  DECLARE_REG (0, "mir"),
+  DECLARE_REG (2, "mel0"),
+  DECLARE_REG (3, "mel1"),
+  DECLARE_REG (4, "meh"),
+  DECLARE_REG (6, "mpr"),
+  DECLARE_REG (8, "mcir"),
+  DECLARE_REG (28, "mpgd0"),
+  DECLARE_REG (29, "mpgd"),
+  DECLARE_REG (29, "mpgd1"),
+  DECLARE_REG (30, "msa0"),
+  DECLARE_REG (31, "msa1"),
+#undef DECLARE_REG
+  {-1, -1, NULL, NULL, 0, NULL},
 };
 
-const char *csky_cp_creg[] =
+/* Get register name according to giving parameters,
+   IS_ABI controls whether is ABI name or not.  */
+static inline const char *
+get_register_name (struct csky_reg_def *reg_table,
+                  int arch, int bank, int regno, int is_abi)
 {
-  "cpcr0",  "cpcr1",  "cpcr2",  "cpcr3",
-  "cpcr4",  "cpcr5",  "cpcr6",  "cpcr7",
-  "cpcr8",  "cpcr9",  "cpcr10", "cpcr11",
-  "cpcr12", "cpcr13", "cpcr14", "cpcr15",
-  "cpcr16", "cpcr17", "cpcr18", "cpcr19",
-  "cpcr20", "cpcr21", "cpcr22", "cpcr23",
-  "cpcr24", "cpcr25", "cpcr26", "cpcr27",
-  "cpcr28", "cpcr29", "cpcr30", "cpcr31",
-  "cpcr32", "cpcr33", "cpcr34", "cpcr35",
-  "cpcr36", "cpcr37", "cpcr38", "cpcr39",
-  "cpcr40", "cpcr41", "cpcr42", "cpcr43",
-  "cpcr44", "cpcr45", "cpcr46", "cpcr47",
-  "cpcr48", "cpcr49", "cpcr50", "cpcr51",
-  "cpcr52", "cpcr53", "cpcr54", "cpcr55",
-  "cpcr56", "cpcr57", "cpcr58", "cpcr59",
-  "cpcr60", "cpcr61", "cpcr62", "cpcr63",
-  NULL,
-};
+  static char regname[64] = {0};
+  unsigned int i = 0;
+  while (reg_table[i].name != NULL)
+    {
+      if (reg_table[i].bank == bank
+         && reg_table[i].regno == regno
+         && (reg_table[i].arch_flag & (1 << arch)))
+       {
+         if (is_abi && reg_table[i].abi_name)
+           return reg_table[i].abi_name;
+         else
+           return reg_table[i].name;
+       }
+      i++;
+    }
 
-struct psrbit
+  if (bank & 0x80000000)
+    return "unkown register";
+
+  sprintf (regname, "cr<%d, %d>", regno, bank);
+
+  return regname;
+}
+
+/* Get register number according to giving parameters.
+   If not found, return -1.  */
+static inline int
+get_register_number (struct csky_reg_def *reg_table,
+                    int arch, char *s, char **end, int *bank)
 {
-  int value;
-  int isa;
-  const char *name;
-};
-const struct psrbit cskyv1_psr_bits[] =
+  unsigned int i = 0;
+  int len = 0;
+  while (reg_table[i].name != NULL)
+    {
+      len = strlen (reg_table[i].name);
+      if ((strncasecmp (reg_table[i].name, s, len) == 0)
+         && !(ISDIGIT (s[len]))
+         && (reg_table[i].arch_flag & (1 << arch)))
+       {
+         *end = s + len;
+         *bank = reg_table[i].bank;
+         return reg_table[i].regno;
+       }
+
+      if (reg_table[i].abi_name == NULL)
+       {
+         i++;
+         continue;
+       }
+
+      len = strlen (reg_table[i].abi_name);
+      if ((strncasecmp (reg_table[i].abi_name, s, len) == 0)
+         && !(ISALNUM (s[len]))
+         && (reg_table[i].arch_flag & (1 << arch)))
+       {
+         *end = s + len;
+         *bank = reg_table[i].bank;
+         return reg_table[i].regno;
+       }
+      i++;
+    }
+  return -1;
+}
+
+/* Return general register's name.  */
+static inline const char *
+csky_get_general_reg_name (int arch, int regno, int is_abi)
 {
-  {1,    0, "ie"},
-  {2,    0, "fe"},
-  {4,    0, "ee"},
-  {8,    0, "af"},
-  {0, 0, NULL},
-};
-const struct psrbit cskyv2_psr_bits[] =
+  struct csky_reg_def *reg_table;
+
+  if (IS_CSKY_ARCH_V1(arch))
+    reg_table = csky_abiv1_general_regs;
+  else
+    reg_table = csky_abiv2_general_regs;
+
+  return get_register_name (reg_table, arch,
+                           GENARAL_REG_BANK, regno, is_abi);
+}
+
+/* Return general register's number.  */
+static inline int
+csky_get_general_regno(int arch, char *s, char **end)
 {
-  {8, 0, "ee"},
-  {4, 0, "ie"},
-  {2, 0, "fe"},
-  {1, 0, "af"},
-  {0x10, CSKY_ISA_TRUST, "sie"},
-  {0, 0, NULL},
-};
+  struct csky_reg_def *reg_table;
+  int bank = 0;
 
+  if (IS_CSKY_ARCH_V1(arch))
+    reg_table = csky_abiv1_general_regs;
+  else
+    reg_table = csky_abiv2_general_regs;
+
+  return get_register_number (reg_table, arch, s, end, &bank);
+}
+
+/* Return control register's name.  */
+static inline const char *
+csky_get_control_reg_name (int arch, int bank, int regno, int is_abi)
+{
+  struct csky_reg_def *reg_table;
+
+  if (IS_CSKY_ARCH_V1(arch))
+    reg_table = csky_abiv1_control_regs;
+  else
+    reg_table = csky_abiv2_control_regs;
+
+  return get_register_name (reg_table, arch, bank,
+                           regno, is_abi);
+}
+
+/* Return control register's number.  */
+static inline int
+csky_get_control_regno(int arch, char *s, char **end, int *bank)
+{
+  struct csky_reg_def *reg_table;
+
+  if (IS_CSKY_ARCH_V1(arch))
+    reg_table = csky_abiv1_control_regs;
+  else
+    reg_table = csky_abiv2_control_regs;
+
+  return get_register_number (reg_table, arch, s, end, bank);
+}
 
 /* C-SKY V1 opcodes.  */
 const struct csky_opcode csky_v1_opcodes[] =
 #undef _TRANSFER
 #define _TRANSFER   0
     DOP16_DOP32 ("bclri",
-                OPCODE_INFO3 (0x3880,
+                OPCODE_INFO2 (0x3880,
                               (8_10, GREG0_7, OPRND_SHIFT_0_BIT),
-                              (NONE, DUMMY_REG, OPRND_SHIFT_0_BIT),
                               (0_4, IMM5b, OPRND_SHIFT_0_BIT)),
-                OPCODE_INFO2 (0x3880,
+                OPCODE_INFO3 (0x3880,
                               (8_10, GREG0_7, OPRND_SHIFT_0_BIT),
+                              (NONE, DUMMY_REG, OPRND_SHIFT_0_BIT),
                               (0_4, IMM5b, OPRND_SHIFT_0_BIT)),
                 CSKYV2_ISA_E1,
                 OPCODE_INFO3 (0xc4002820,
                               (21_25, IMM5b, OPRND_SHIFT_0_BIT)),
                 CSKYV2_ISA_1E2),
     DOP16_DOP32 ("bseti",
-                OPCODE_INFO3 (0x38a0,
+                OPCODE_INFO2 (0x38a0,
                               (8_10, GREG0_7, OPRND_SHIFT_0_BIT),
-                              (NONE, DUMMY_REG, OPRND_SHIFT_0_BIT),
                               (0_4, IMM5b, OPRND_SHIFT_0_BIT)),
-                OPCODE_INFO2 (0x38a0,
+                OPCODE_INFO3 (0x38a0,
                               (8_10, GREG0_7, OPRND_SHIFT_0_BIT),
+                              (NONE, DUMMY_REG, OPRND_SHIFT_0_BIT),
                               (0_4, IMM5b, OPRND_SHIFT_0_BIT)),
                 CSKYV2_ISA_E1,
                 OPCODE_INFO3 (0xc4002840,
                             (16_20, AREG, OPRND_SHIFT_0_BIT),
                             (21_25, IMM5b, OPRND_SHIFT_0_BIT)),
               CSKYV2_ISA_1E2),
-    DOP16_DOP32 ("addc",
-                OPCODE_INFO2 (0x6001,
-                              (6_9, GREG0_15, OPRND_SHIFT_0_BIT),
-                              (2_5, GREG0_15, OPRND_SHIFT_0_BIT)),
-                OPCODE_INFO3 (0x6001,
-                              (6_9, GREG0_15, OPRND_SHIFT_0_BIT),
-                              (2_5, 2IN1_DUMMY, OPRND_SHIFT_0_BIT),
-                              (2_5, 2IN1_DUMMY, OPRND_SHIFT_0_BIT)),
-                CSKYV2_ISA_E1,
-                OPCODE_INFO3 (0xc4000040,
-                              (0_4, AREG, OPRND_SHIFT_0_BIT),
-                              (16_20, AREG, OPRND_SHIFT_0_BIT),
-                              (21_25, AREG, OPRND_SHIFT_0_BIT)),
-                OPCODE_INFO2 (0xc4000040,
-                              (0_4or16_20, DUP_AREG, OPRND_SHIFT_0_BIT),
-                              (21_25, AREG, OPRND_SHIFT_0_BIT)),
-                CSKYV2_ISA_1E2),
+    DOP16_DOP32_WITH_WORK ("addc",
+                          OPCODE_INFO2 (0x6001,
+                                        (6_9, GREG0_15, OPRND_SHIFT_0_BIT),
+                                        (2_5, GREG0_15, OPRND_SHIFT_0_BIT)),
+                          OPCODE_INFO3 (0x6001,
+                                        (6_9, GREG0_15, OPRND_SHIFT_0_BIT),
+                                        (2_5, GREG0_15, OPRND_SHIFT_0_BIT),
+                                        (2_5, GREG0_15, OPRND_SHIFT_0_BIT)),
+                          CSKYV2_ISA_E1,
+                          OPCODE_INFO3 (0xc4000040,
+                                        (0_4, AREG, OPRND_SHIFT_0_BIT),
+                                        (16_20, AREG, OPRND_SHIFT_0_BIT),
+                                        (21_25, AREG, OPRND_SHIFT_0_BIT)),
+                          OPCODE_INFO2 (0xc4000040,
+                                        (0_4or16_20, AREG, OPRND_SHIFT_0_BIT),
+                                        (21_25, AREG, OPRND_SHIFT_0_BIT)),
+                          CSKYV2_ISA_1E2,
+                          v2_work_addc),
     DOP16_DOP32 ("subc",
                 OPCODE_INFO2 (0x6003,
                               (6_9, GREG0_15, OPRND_SHIFT_0_BIT),
                        (0_4, AREG, OPRND_SHIFT_0_BIT),
                        (16_20, AREG, OPRND_SHIFT_0_BIT),
                        (5_9, IMM5b, OPRND_SHIFT_0_BIT),
-                       (21_25, IMM5b, OPRND_SHIFT_0_BIT)),
+                       (21_25, IMM5b_LS, OPRND_SHIFT_0_BIT)),
          CSKYV2_ISA_2E3),
     OP32 ("sext",
          OPCODE_INFO4 (0xc4005800,
                        (0_4, AREG, OPRND_SHIFT_0_BIT),
                        (16_20, AREG, OPRND_SHIFT_0_BIT),
                        (5_9, IMM5b, OPRND_SHIFT_0_BIT),
-                       (21_25, IMM5b, OPRND_SHIFT_0_BIT)),
+                       (21_25, IMM5b_LS, OPRND_SHIFT_0_BIT)),
          CSKYV2_ISA_2E3),
 #undef _TRANSFER
 #define _TRANSFER   2