[v2] RISC-V: Add .insn support

Message ID CA+yXCZB4bt31qyEHaY+3C8mcas77eo841QPaseoxLPHaQHxLjw@mail.gmail.com
State New
Headers show
Series
  • [v2] RISC-V: Add .insn support
Related show

Commit Message

Kito Cheng March 9, 2018, 9:15 a.m.
This is v2 patch to support new directive, .insn for RISC-V assembler, it
able to write instruction with another form just like s/390's .insn
directive.

Main purpose of this directive is to make people easier to add new
instruction for experimentation without modify binutils, and it's much
usable than just use .word to encode instruction.

Changes since V1:
- Fix several typos.
-- Fix typo in document.
-- JAR -> JAL.
- Fix wrong value for NMADD and NMSUB.
- Allow 4 register operands for type R instruction.
- Allow to use FPR in all instruction format except base register operand.
- Remove "O2,CF3,d,Cj" for ci format.
- Fix wrong implementation for ciw and add update test case for that.

Comments

Jim Wilson March 14, 2018, 11:07 p.m. | #1
On 03/09/2018 01:15 AM, Kito Cheng wrote:
> This is v2 patch to support new directive, .insn for RISC-V assembler, it

> able to write instruction with another form just like s/390's .insn

> directive.


OK.  I committed it.

Jim

Patch

From b3861176e4febce0185ea6e6aff3a270ed9bb777 Mon Sep 17 00:00:00 2001
From: Kito Cheng <kito.cheng@gmail.com>
Date: Tue, 13 Feb 2018 16:44:13 +0800
Subject: [PATCH] RISC-V: Add .insn support

gas/ChangeLog
2018-03-07  Kito Cheng  <kito.cheng@gmail.com>

	* config/tc-riscv.c (opcode_name_list): New.
	(opcode_names_hash): Likewise.
	(init_opcode_names_hash): Likewise.
	(opcode_name_lookup): Likewise.
	(validate_riscv_insn): New argument length, and add new format
	which used in .insn directive.
	(md_begin): Refine hash table initialization logic into
	init_opcode_hash.
	(init_opcode_hash): New.
	(my_getOpcodeExpression): Parse opcode name for .insn.
	(riscv_ip): New argument hash, able to handle .insn directive.
	(s_riscv_insn): Handler for .insn directive.
	(riscv_pseudo_table): New entry for .insn.
	* doc/c-riscv.texi: Add documentation for .insn directive.
	* testsuite/gas/riscv/insn.d: Add testcase for .insn directive.
	* testsuite/gas/riscv/insn.s: Likewise.

include/ChangeLog
2018-03-07  Kito Cheng  <kito.cheng@gmail.com>

	* opcode/riscv.h (OP_MASK_FUNCT3): New.
	(OP_SH_FUNCT3): Likewise.
	(OP_MASK_FUNCT7): Likewise.
	(OP_SH_FUNCT7): Likewise.
	(OP_MASK_OP2): Likewise.
	(OP_SH_OP2): Likewise.
	(OP_MASK_CFUNCT4): Likewise.
	(OP_SH_CFUNCT4): Likewise.
	(OP_MASK_CFUNCT3): Likewise.
	(OP_SH_CFUNCT3): Likewise.
	(riscv_insn_types): Likewise.

opcodes/ChangeLog
2018-03-07  Kito Cheng  <kito.cheng@gmail.com>

	* riscv-opc.c (riscv_insn_types): New.
---
 gas/config/tc-riscv.c          | 440 ++++++++++++++++++++++++++++++++++++++---
 gas/doc/c-riscv.texi           | 241 ++++++++++++++++++++++
 gas/testsuite/gas/riscv/insn.d |  51 +++++
 gas/testsuite/gas/riscv/insn.s |  39 ++++
 include/opcode/riscv.h         |  21 ++
 opcodes/riscv-opc.c            |  74 +++++++
 6 files changed, 839 insertions(+), 27 deletions(-)
 create mode 100644 gas/testsuite/gas/riscv/insn.d
 create mode 100644 gas/testsuite/gas/riscv/insn.s

diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index f1bc7f9..454f283 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -221,6 +221,9 @@  riscv_set_arch (const char *s)
 /* Handle of the OPCODE hash table.  */
 static struct hash_control *op_hash = NULL;
 
+/* Handle of the type of .insn hash table.  */
+static struct hash_control *insn_type_hash = NULL;
+
 /* This array holds the chars that always start a comment.  If the
     pre-processor is disabled, these aren't very useful */
 const char comment_chars[] = "#";
@@ -391,6 +394,111 @@  relaxed_branch_length (fragS *fragp, asection *sec, int update)
   return length;
 }
 
+/* Information about an opcode name, mnemonics and its value.  */
+struct opcode_name_t
+{
+  const char *name;
+  unsigned int val;
+};
+
+/* List for all supported opcode name.  */
+static const struct opcode_name_t opcode_name_list[] =
+{
+  {"C0",        0x0},
+  {"C1",        0x1},
+  {"C2",        0x2},
+
+  {"LOAD",      0x03},
+  {"LOAD_FP",   0x07},
+  {"CUSTOM_0",  0x0b},
+  {"MISC_MEM",  0x0f},
+  {"OP_IMM",    0x13},
+  {"AUIPC",     0x17},
+  {"OP_IMM_32", 0x1b},
+  /* 48b        0x1f.  */
+
+  {"STORE",     0x23},
+  {"STORE_FP",  0x27},
+  {"CUSTOM_1",  0x2b},
+  {"AMO",       0x2f},
+  {"OP",        0x33},
+  {"LUI",       0x37},
+  {"OP_32",     0x3b},
+  /* 64b        0x3f.  */
+
+  {"MADD",      0x43},
+  {"MSUB",      0x47},
+  {"NMADD",     0x4f},
+  {"NMSUB",     0x4b},
+  {"OP_FP",     0x53},
+  /*reserved    0x57.  */
+  {"CUSTOM_2",  0x5b},
+  /* 48b        0x5f.  */
+
+  {"BRANCH",    0x63},
+  {"JALR",      0x67},
+  /*reserved    0x5b.  */
+  {"JAL",       0x6f},
+  {"SYSTEM",    0x73},
+  /*reserved    0x77.  */
+  {"CUSTOM_3",  0x7b},
+  /* >80b       0x7f.  */
+
+  {NULL, 0}
+};
+
+/* Hash table for lookup opcode name.  */
+static struct hash_control *opcode_names_hash = NULL;
+
+/* Initialization for hash table of opcode name.  */
+static void
+init_opcode_names_hash (void)
+{
+  const char *retval;
+  const struct opcode_name_t *opcode;
+
+  for (opcode = &opcode_name_list[0]; opcode->name != NULL; ++opcode)
+    {
+      retval = hash_insert (opcode_names_hash, opcode->name, (void *)opcode);
+
+      if (retval != NULL)
+	as_fatal (_("internal error: can't hash `%s': %s"),
+		  opcode->name, retval);
+    }
+}
+
+/* Find `s` is a valid opcode name or not,
+   return the opcode name info if found.  */
+static const struct opcode_name_t *
+opcode_name_lookup (char **s)
+{
+  char *e;
+  char save_c;
+  struct opcode_name_t *o;
+
+  /* Find end of name.  */
+  e = *s;
+  if (is_name_beginner (*e))
+    ++e;
+  while (is_part_of_name (*e))
+    ++e;
+
+  /* Terminate name.  */
+  save_c = *e;
+  *e = '\0';
+
+  o = (struct opcode_name_t *) hash_find (opcode_names_hash, *s);
+
+  /* Advance to next token if one was recognized.  */
+  if (o)
+    *s = e;
+
+  *e = save_c;
+  expr_end = e;
+
+  return o;
+}
+
 struct regname
 {
   const char *name;
@@ -488,15 +596,24 @@  arg_lookup (char **s, const char *const *array, size_t size, unsigned *regnop)
 
 /* For consistency checking, verify that all bits are specified either
    by the match/mask part of the instruction definition, or by the
-   operand list.  */
+   operand list.
+
+   `length` could be 0, 4 or 8, 0 for auto detection.  */
 static bfd_boolean
-validate_riscv_insn (const struct riscv_opcode *opc)
+validate_riscv_insn (const struct riscv_opcode *opc, int length)
 {
   const char *p = opc->args;
   char c;
   insn_t used_bits = opc->mask;
-  int insn_width = 8 * riscv_insn_length (opc->match);
-  insn_t required_bits = ~0ULL >> (64 - insn_width);
+  int insn_width;
+  insn_t required_bits;
+
+  if (length == 0)
+    insn_width = 8 * riscv_insn_length (opc->match);
+  else
+    insn_width = 8 * length;
+
+  required_bits = ~0ULL >> (64 - insn_width);
 
   if ((used_bits & opc->match) != (opc->match & required_bits))
     {
@@ -536,8 +653,22 @@  validate_riscv_insn (const struct riscv_opcode *opc)
 	  case 'V': USE_BITS (OP_MASK_CRS2, OP_SH_CRS2); break;
 	  case '<': used_bits |= ENCODE_RVC_IMM (-1U); break;
 	  case '>': used_bits |= ENCODE_RVC_IMM (-1U); break;
+	  case '8': used_bits |= ENCODE_RVC_UIMM8 (-1U); break;
+	  case 'S': USE_BITS (OP_MASK_CRS1S, OP_SH_CRS1S); break;
 	  case 'T': USE_BITS (OP_MASK_CRS2, OP_SH_CRS2); break;
 	  case 'D': USE_BITS (OP_MASK_CRS2S, OP_SH_CRS2S); break;
+	  case 'F': /* funct */
+	    switch (c = *p++)
+	      {
+		case '4': USE_BITS (OP_MASK_CFUNCT4, OP_SH_CFUNCT4); break;
+		case '3': USE_BITS (OP_MASK_CFUNCT3, OP_SH_CFUNCT3); break;
+		default:
+		  as_bad (_("internal: bad RISC-V opcode"
+			    " (unknown operand type `CF%c'): %s %s"),
+			  c, opc->name, opc->args);
+		  return FALSE;
+	      }
+	    break;
 	  default:
 	    as_bad (_("internal: bad RISC-V opcode (unknown operand type `C%c'): %s %s"),
 		    c, opc->name, opc->args);
@@ -562,6 +693,7 @@  validate_riscv_insn (const struct riscv_opcode *opc)
       case 'm':	USE_BITS (OP_MASK_RM,		OP_SH_RM);	break;
       case 's':	USE_BITS (OP_MASK_RS1,		OP_SH_RS1);	break;
       case 't':	USE_BITS (OP_MASK_RS2,		OP_SH_RS2);	break;
+      case 'r':	USE_BITS (OP_MASK_RS3,          OP_SH_RS3);     break;
       case 'P':	USE_BITS (OP_MASK_PRED,		OP_SH_PRED); break;
       case 'Q':	USE_BITS (OP_MASK_SUCC,		OP_SH_SUCC); break;
       case 'o':
@@ -574,6 +706,31 @@  validate_riscv_insn (const struct riscv_opcode *opc)
       case '[': break;
       case ']': break;
       case '0': break;
+      case 'F': /* funct */
+	switch (c = *p++)
+	  {
+	    case '7': USE_BITS (OP_MASK_FUNCT7, OP_SH_FUNCT7); break;
+	    case '3': USE_BITS (OP_MASK_FUNCT3, OP_SH_FUNCT3); break;
+	    case '2': USE_BITS (OP_MASK_FUNCT2, OP_SH_FUNCT2); break;
+	    default:
+	      as_bad (_("internal: bad RISC-V opcode"
+			" (unknown operand type `F%c'): %s %s"),
+		      c, opc->name, opc->args);
+	    return FALSE;
+	  }
+	break;
+      case 'O': /* opcode */
+	switch (c = *p++)
+	  {
+	    case '4': USE_BITS (OP_MASK_OP, OP_SH_OP); break;
+	    case '2': USE_BITS (OP_MASK_OP2, OP_SH_OP2); break;
+	    default:
+	      as_bad (_("internal: bad RISC-V opcode"
+			" (unknown operand type `F%c'): %s %s"),
+		      c, opc->name, opc->args);
+	     return FALSE;
+	  }
+	break;
       default:
 	as_bad (_("internal: bad RISC-V opcode "
 		  "(unknown operand type `%c'): %s %s"),
@@ -597,52 +754,73 @@  struct percent_op_match
   bfd_reloc_code_real_type reloc;
 };
 
-/* This function is called once, at assembler startup time.  It should set up
-   all the tables, etc. that the MD part of the assembler will need.  */
-
-void
-md_begin (void)
+/* Common hash table initialization function for
+   instruction and .insn directive.  */
+static struct hash_control *
+init_opcode_hash (const struct riscv_opcode *opcodes,
+		  bfd_boolean insn_directive_p)
 {
   int i = 0;
-  unsigned long mach = xlen == 64 ? bfd_mach_riscv64 : bfd_mach_riscv32;
-
-  if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, mach))
-    as_warn (_("Could not set architecture and machine"));
-
-  op_hash = hash_new ();
-
-  while (riscv_opcodes[i].name)
+  int length;
+  struct hash_control *hash = hash_new ();
+  while (opcodes[i].name)
     {
-      const char *name = riscv_opcodes[i].name;
+      const char *name = opcodes[i].name;
       const char *hash_error =
-	hash_insert (op_hash, name, (void *) &riscv_opcodes[i]);
+	hash_insert (hash, name, (void *) &opcodes[i]);
 
       if (hash_error)
 	{
 	  fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
-		   riscv_opcodes[i].name, hash_error);
+		   opcodes[i].name, hash_error);
 	  /* Probably a memory allocation problem?  Give up now.  */
 	  as_fatal (_("Broken assembler.  No assembly attempted."));
 	}
 
       do
 	{
-	  if (riscv_opcodes[i].pinfo != INSN_MACRO)
+	  if (opcodes[i].pinfo != INSN_MACRO)
 	    {
-	      if (!validate_riscv_insn (&riscv_opcodes[i]))
+	      if (insn_directive_p)
+		length = ((name[0] == 'c') ? 2 : 4);
+	      else
+		length = 0; /* Let assembler determine the length. */
+	      if (!validate_riscv_insn (&opcodes[i], length))
 		as_fatal (_("Broken assembler.  No assembly attempted."));
 	    }
+	  else
+	    gas_assert (!insn_directive_p);
 	  ++i;
 	}
-      while (riscv_opcodes[i].name && !strcmp (riscv_opcodes[i].name, name));
+      while (opcodes[i].name && !strcmp (opcodes[i].name, name));
     }
 
+  return hash;
+}
+
+/* This function is called once, at assembler startup time.  It should set up
+   all the tables, etc. that the MD part of the assembler will need.  */
+
+void
+md_begin (void)
+{
+  unsigned long mach = xlen == 64 ? bfd_mach_riscv64 : bfd_mach_riscv32;
+
+  if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, mach))
+    as_warn (_("Could not set architecture and machine"));
+
+  op_hash = init_opcode_hash (riscv_opcodes, FALSE);
+  insn_type_hash = init_opcode_hash (riscv_insn_types, TRUE);
+
   reg_names_hash = hash_new ();
   hash_reg_names (RCLASS_GPR, riscv_gpr_names_numeric, NGPR);
   hash_reg_names (RCLASS_GPR, riscv_gpr_names_abi, NGPR);
   hash_reg_names (RCLASS_FPR, riscv_fpr_names_numeric, NFPR);
   hash_reg_names (RCLASS_FPR, riscv_fpr_names_abi, NFPR);
 
+  opcode_names_hash = hash_new ();
+  init_opcode_names_hash ();
+
 #define DECLARE_CSR(name, num) hash_reg_name (RCLASS_CSR, #name, num);
 #define DECLARE_CSR_ALIAS(name, num) DECLARE_CSR(name, num);
 #include "opcode/riscv-opc.h"
@@ -1186,6 +1364,23 @@  my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
   return reloc_index;
 }
 
+/* Parse opcode name, could be an mnemonics or number.  */
+static size_t
+my_getOpcodeExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
+			char *str, const struct percent_op_match *percent_op)
+{
+  const struct opcode_name_t *o = opcode_name_lookup (&str);
+
+  if (o != NULL)
+    {
+      ep->X_op = O_constant;
+      ep->X_add_number = o->val;
+      return 0;
+    }
+
+  return my_getSmallExpression (ep, reloc, str, percent_op);
+}
+
 /* Detect and handle implicitly zero load-store offsets.  For example,
    "lw t0, (t1)" is shorthand for "lw t0, 0(t1)".  Return TRUE iff such
    an implicit offset was detected.  */
@@ -1211,7 +1406,7 @@  riscv_handle_implicit_zero_offset (expressionS *ep, const char *s)
 
 static const char *
 riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
-	  bfd_reloc_code_real_type *imm_reloc)
+	  bfd_reloc_code_real_type *imm_reloc, struct hash_control *hash)
 {
   char *s;
   const char *args;
@@ -1234,7 +1429,7 @@  riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
 	break;
       }
 
-  insn = (struct riscv_opcode *) hash_find (op_hash, str);
+  insn = (struct riscv_opcode *) hash_find (hash, str);
 
   argsStart = s;
   for ( ; insn && insn->name && strcmp (insn->name, str) == 0; insn++)
@@ -1259,7 +1454,12 @@  riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
 		{
 		  if (!insn->match_func (insn, ip->insn_opcode))
 		    break;
-		  if (riscv_insn_length (insn->match) == 2 && !riscv_opts.rvc)
+
+		  /* For .insn, insn->match and insn->mask are 0.  */
+		  if (riscv_insn_length ((insn->match == 0 && insn->mask == 0)
+					 ? ip->insn_opcode
+					 : insn->match) == 2
+		      && !riscv_opts.rvc)
 		    break;
 		}
 	      if (*s != '\0')
@@ -1328,6 +1528,15 @@  rvc_imm_done:
 		    break;
 		  ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number);
 		  goto rvc_imm_done;
+		case '8':
+		  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
+		      || imm_expr->X_op != O_constant
+		      || !VALID_RVC_UIMM8 (imm_expr->X_add_number)
+		      || imm_expr->X_add_number < 0
+		      || imm_expr->X_add_number >= 256)
+		    break;
+		  ip->insn_opcode |= ENCODE_RVC_UIMM8 (imm_expr->X_add_number);
+		  goto rvc_imm_done;
 		case 'i':
 		  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
 		      || imm_expr->X_op != O_constant
@@ -1457,6 +1666,12 @@  rvc_lui:
 		  goto branch;
 		case 'a':
 		  goto jump;
+		case 'S': /* Floating-point RS1 x8-x15.  */
+		  if (!reg_lookup (&s, RCLASS_FPR, &regno)
+		      || !(regno >= 8 && regno <= 15))
+		    break;
+		  INSERT_OPERAND (CRS1S, *ip, regno % 8);
+		  continue;
 		case 'D': /* Floating-point RS2 x8-x15.  */
 		  if (!reg_lookup (&s, RCLASS_FPR, &regno)
 		      || !(regno >= 8 && regno <= 15))
@@ -1468,6 +1683,45 @@  rvc_lui:
 		    break;
 		  INSERT_OPERAND (CRS2, *ip, regno);
 		  continue;
+		case 'F':
+		  switch (*++args)
+		    {
+		      case '4':
+		        if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
+			    || imm_expr->X_op != O_constant
+			    || imm_expr->X_add_number < 0
+			    || imm_expr->X_add_number >= 16)
+			  {
+			    as_bad (_("bad value for funct4 field, "
+				      "value must be 0...15"));
+			    break;
+			  }
+
+			INSERT_OPERAND (CFUNCT4, *ip, imm_expr->X_add_number);
+			imm_expr->X_op = O_absent;
+			s = expr_end;
+			continue;
+		      case '3':
+			if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
+			    || imm_expr->X_op != O_constant
+			    || imm_expr->X_add_number < 0
+			    || imm_expr->X_add_number >= 8)
+			  {
+			    as_bad (_("bad value for funct3 field, "
+				      "value must be 0...7"));
+			    break;
+			  }
+			INSERT_OPERAND (CFUNCT3, *ip, imm_expr->X_add_number);
+			imm_expr->X_op = O_absent;
+			s = expr_end;
+			continue;
+		      default:
+			as_bad (_("bad compressed FUNCT field"
+				  " specifier 'CF%c'\n"),
+				*args);
+		    }
+		  break;
+
 		default:
 		  as_bad (_("bad RVC field specifier 'C%c'\n"), *args);
 		}
@@ -1561,6 +1815,7 @@  rvc_lui:
 	    case 'd':		/* Destination register.  */
 	    case 's':		/* Source register.  */
 	    case 't':		/* Target register.  */
+	    case 'r':		/* rs3.  */
 	      if (reg_lookup (&s, RCLASS_GPR, &regno))
 		{
 		  c = *args;
@@ -1580,6 +1835,9 @@  rvc_lui:
 		    case 't':
 		      INSERT_OPERAND (RS2, *ip, regno);
 		      break;
+		    case 'r':
+		      INSERT_OPERAND (RS3, *ip, regno);
+		      break;
 		    }
 		  continue;
 		}
@@ -1712,6 +1970,99 @@  jump:
 	      else
 		*imm_reloc = BFD_RELOC_RISCV_CALL;
 	      continue;
+	    case 'O':
+	      switch (*++args)
+		{
+		case '4':
+		  if (my_getOpcodeExpression (imm_expr, imm_reloc, s, p)
+		      || imm_expr->X_op != O_constant
+		      || imm_expr->X_add_number < 0
+		      || imm_expr->X_add_number >= 128
+		      || (imm_expr->X_add_number & 0x3) != 3)
+		    {
+		      as_bad (_("bad value for opcode field, "
+				"value must be 0...127 and "
+				"lower 2 bits must be 0x3"));
+		      break;
+		    }
+
+		  INSERT_OPERAND (OP, *ip, imm_expr->X_add_number);
+		  imm_expr->X_op = O_absent;
+		  s = expr_end;
+		  continue;
+		case '2':
+		  if (my_getOpcodeExpression (imm_expr, imm_reloc, s, p)
+		      || imm_expr->X_op != O_constant
+		      || imm_expr->X_add_number < 0
+		      || imm_expr->X_add_number >= 3)
+		    {
+		      as_bad (_("bad value for opcode field, "
+				"value must be 0...2"));
+		      break;
+		    }
+
+		  INSERT_OPERAND (OP2, *ip, imm_expr->X_add_number);
+		  imm_expr->X_op = O_absent;
+		  s = expr_end;
+		  continue;
+		default:
+		  as_bad (_("bad Opcode field specifier 'O%c'\n"), *args);
+		}
+	      break;
+
+	    case 'F':
+	      switch (*++args)
+		{
+		case '7':
+		  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
+		      || imm_expr->X_op != O_constant
+		      || imm_expr->X_add_number < 0
+		      || imm_expr->X_add_number >= 128)
+		    {
+		      as_bad (_("bad value for funct7 field, "
+				"value must be 0...127"));
+		      break;
+		    }
+
+		  INSERT_OPERAND (FUNCT7, *ip, imm_expr->X_add_number);
+		  imm_expr->X_op = O_absent;
+		  s = expr_end;
+		  continue;
+		case '3':
+		  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
+		      || imm_expr->X_op != O_constant
+		      || imm_expr->X_add_number < 0
+		      || imm_expr->X_add_number >= 8)
+		    {
+		      as_bad (_("bad value for funct3 field, "
+			        "value must be 0...7"));
+		      break;
+		    }
+
+		  INSERT_OPERAND (FUNCT3, *ip, imm_expr->X_add_number);
+		  imm_expr->X_op = O_absent;
+		  s = expr_end;
+		  continue;
+		case '2':
+		  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
+		      || imm_expr->X_op != O_constant
+		      || imm_expr->X_add_number < 0
+		      || imm_expr->X_add_number >= 4)
+		    {
+		      as_bad (_("bad value for funct2 field, "
+			        "value must be 0...3"));
+		      break;
+		    }
+
+		  INSERT_OPERAND (FUNCT2, *ip, imm_expr->X_add_number);
+		  imm_expr->X_op = O_absent;
+		  s = expr_end;
+		  continue;
+
+		default:
+		  as_bad (_("bad FUNCT field specifier 'F%c'\n"), *args);
+		}
+	      break;
 
 	    case 'z':
 	      if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
@@ -1746,7 +2097,7 @@  md_assemble (char *str)
   expressionS imm_expr;
   bfd_reloc_code_real_type imm_reloc = BFD_RELOC_UNUSED;
 
-  const char *error = riscv_ip (str, &insn, &imm_expr, &imm_reloc);
+  const char *error = riscv_ip (str, &insn, &imm_expr, &imm_reloc, op_hash);
 
   if (error)
     {
@@ -2614,6 +2965,40 @@  s_riscv_leb128 (int sign)
   return s_leb128 (sign);
 }
 
+/* Parse the .insn directive.  */
+
+static void
+s_riscv_insn (int x ATTRIBUTE_UNUSED)
+{
+  char *str = input_line_pointer;
+  struct riscv_cl_insn insn;
+  expressionS imm_expr;
+  bfd_reloc_code_real_type imm_reloc = BFD_RELOC_UNUSED;
+  char save_c;
+
+  while (!is_end_of_line[(unsigned char) *input_line_pointer])
+    ++input_line_pointer;
+
+  save_c = *input_line_pointer;
+  *input_line_pointer = '\0';
+
+  const char *error = riscv_ip (str, &insn, &imm_expr,
+				&imm_reloc, insn_type_hash);
+
+  if (error)
+    {
+      as_bad ("%s `%s'", error, str);
+    }
+  else
+    {
+      gas_assert (insn.insn_mo->pinfo != INSN_MACRO);
+      append_insn (&insn, &imm_expr, imm_reloc);
+    }
+
+  *input_line_pointer = save_c;
+  demand_empty_rest_of_line ();
+}
+
 /* Pseudo-op table.  */
 
 static const pseudo_typeS riscv_pseudo_table[] =
@@ -2628,6 +3013,7 @@  static const pseudo_typeS riscv_pseudo_table[] =
   {"bss", s_bss, 0},
   {"uleb128", s_riscv_leb128, 0},
   {"sleb128", s_riscv_leb128, 1},
+  {"insn", s_riscv_insn, 0},
 
   { NULL, NULL, 0 },
 };
diff --git a/gas/doc/c-riscv.texi b/gas/doc/c-riscv.texi
index 3f327d6..30e6125 100644
--- a/gas/doc/c-riscv.texi
+++ b/gas/doc/c-riscv.texi
@@ -17,6 +17,7 @@ 
 @menu
 * RISC-V-Options::        RISC-V Options
 * RISC-V-Directives::     RISC-V Directives
+* RISC-V-Formats::        RISC-V Instruction Formats
 @end menu
 
 @node RISC-V-Options
@@ -148,4 +149,244 @@  opportunistically relax some code sequences, but sometimes this behavior is not
 desirable.
 @end table
 
+@cindex INSN directives
+@item .insn @var{value}
+@itemx .insn @var{value}
+This directive permits the numeric representation of an instructions
+and makes the assembler insert the operands according to one of the
+instruction formats for @samp{.insn} (@ref{RISC-V-Formats}).
+For example, the instruction @samp{add a0, a1, a2} could be written as
+@samp{.insn r 0x33, 0, 0, a0, a1, a2}.
+
 @end table
+
+@node RISC-V-Formats
+@section Instruction Formats
+@cindex instruction formats, risc-v
+@cindex RISC-V instruction formats
+
+The RISC-V Instruction Set Manual Volume I: User-Level ISA lists 12
+instruction formats where some of the formats have multiple variants.
+For the @samp{.insn} pseudo directive the assembler recognizes some
+of the formats.
+Typically, the most general variant of the instruction format is used
+by the @samp{.insn} directive.
+
+The following table lists the abbreviations used in the table of
+instruction formats:
+
+@display
+@multitable @columnfractions .15 .40
+@item opcode @tab Unsigned immediate or opcode name for 7-bits opcode.
+@item opcode2 @tab Unsigned immediate or opcode name for 2-bits opcode.
+@item func7 @tab Unsigned immediate for 7-bits function code.
+@item func4 @tab Unsigned immediate for 4-bits function code.
+@item func3 @tab Unsigned immediate for 3-bits function code.
+@item func2 @tab Unsigned immediate for 2-bits function code.
+@item rd @tab Destination register number for operand x, can be GPR or FPR.
+@item rd' @tab Destination register number for operand x,
+only accept s0-s1, a0-a5, fs0-fs1 and fa0-fa5.
+@item rs1 @tab First source register number for operand x, can be GPR or FPR.
+@item rs1' @tab First source register number for operand x,
+only accept s0-s1, a0-a5, fs0-fs1 and fa0-fa5.
+@item rs2 @tab Second source register number for operand x, can be GPR or FPR.
+@item rs2' @tab Second source register number for operand x,
+only accept s0-s1, a0-a5, fs0-fs1 and fa0-fa5.
+@item simm12 @tab Sign-extended 12-bit immediate for operand x.
+@item simm20 @tab Sign-extended 20-bit immediate for operand x.
+@item simm6 @tab Sign-extended 6-bit immediate for operand x.
+@item uimm8 @tab Unsigned 8-bit immediate for operand x.
+@item symbol @tab Symbol or lable reference for operand x.
+@end multitable
+@end display
+
+The following table lists all available opcode name:
+
+@table @code
+@item C0
+@item C1
+@item C2
+Opcode space for compressed instructions.
+
+@item LOAD
+Opcode space for load instructions.
+
+@item LOAD_FP
+Opcode space for floating-point load instructions.
+
+@item STORE
+Opcode space for store instructions.
+
+@item STORE_FP
+Opcode space for floating-point store instructions.
+
+@item AUIPC
+Opcode space for auipc instruction.
+
+@item LUI
+Opcode space for lui instruction.
+
+@item BRANCH
+Opcode space for branch instructions.
+
+@item JAL
+Opcode space for jal instruction.
+
+@item JALR
+Opcode space for jalr instruction.
+
+@item OP
+Opcode space for ALU instructions.
+
+@item OP_32
+Opcode space for 32-bits ALU instructions.
+
+@item OP_IMM
+Opcode space for ALU with immediate instructions.
+
+@item OP_IMM_32
+Opcode space for 32-bits ALU with immediate instructions.
+
+@item OP_FP
+Opcode space for floating-point operation instructions.
+
+@item MADD
+Opcode space for madd instruction.
+
+@item MSUB
+Opcode space for msub instruction.
+
+@item NMADD
+Opcode space for nmadd instruction.
+
+@item NMSUB
+Opcode space for msub instruction.
+
+@item AMO
+Opcode space for atomic memory operation instructions.
+
+@item MISC_IMM
+Opcode space for misc instructions.
+
+@item SYSTEM
+Opcode space for system instructions.
+
+@item CUSTOM_0
+@item CUSTOM_1
+@item CUSTOM_2
+@item CUSTOM_3
+Opcode space for customize instructions.
+
+@end table
+
+An instruction is two or four bytes in length and must be aligned
+on a 2 byte boundary. The first two bits of the instruction specify the
+length of the instruction, 00, 01 and 10 indicates a two byte instruction,
+11 indicates a four byte instruction.
+
+The following table lists the RISC-V instruction formats that are available
+with the @samp{.insn} pseudo directive:
+
+@table @code
+@item R type: .insn r opcode, func3, func7, rd, rs1, rs2
+@verbatim
++-------+-----+-----+-------+----+-------------+
+| func7 | rs2 | rs1 | func3 | rd |      opcode |
++-------+-----+-----+-------+----+-------------+
+31      25    20    15      12   7             0
+@end verbatim
+
+@item R type with 4 register operands: .insn r opcode, func3, func2, rd, rs1, rs2, rs3
+@verbatim
++-----+-------+-----+-----+-------+----+-------------+
+| rs3 | func2 | rs2 | rs1 | func3 | rd |      opcode |
++-----+-------+-----+-----+-------+----+-------------+
+31    27      25    20    15      12   7             0
+@end verbatim
+
+@item I type: .insn i opcode, func3, rd, rs1, simm12
+@verbatim
++-------------+-----+-------+----+-------------+
+|      simm12 | rs1 | func3 | rd |      opcode |
++-------------+-----+-------+----+-------------+
+31            20    15      12   7             0
+@end verbatim
+
+@item S type: .insn s opcode, func3, rd, rs1, simm12
+@verbatim
++--------------+-----+-----+-------+-------------+-------------+
+| simm12[11:5] | rs2 | rs1 | func3 | simm12[4:0] |      opcode |
++--------------+-----+-----+-------+-------------+-------------+
+31             25    20    15      12            7             0
+@end verbatim
+
+@item SB type: .insn sb opcode, func3, rd, rs1, symbol
+@itemx SB type: .insn sb opcode, func3, rd, simm12(rs1)
+@verbatim
++--------------+-----+-----+-------+-------------+-------------+
+| simm21[11:5] | rs2 | rs1 | func3 | simm12[4:0] |      opcode |
++--------------+-----+-----+-------+-------------+-------------+
+31             25    20    15      12            7             0
+@end verbatim
+
+@item U type: .insn u opcode, rd, simm20
+@verbatim
++---------------------------+----+-------------+
+|                    simm20 | rd |      opcode |
++---------------------------+----+-------------+
+31                          12   7             0
+@end verbatim
+
+@item UJ type: .insn uj opcode, rd, symbol
+@verbatim
++------------+--------------+------------+---------------+----+-------------+
+| simm20[20] | simm20[10:1] | simm20[11] | simm20[19:12] | rd |      opcode |
++------------+--------------+------------+---------------+----+-------------+
+31           30             21           20              12   7             0
+@end verbatim
+
+@item CR type: .insn cr opcode2, func4, rd, rs1
+@verbatim
++---------+--------+-----+---------+
+|   func4 | rd/rs1 | rs2 | opcode2 |
++---------+--------+-----+---------+
+15        12       7     2        0
+@end verbatim
+
+@item CI type: .insn ci opcode2, func3, rd, simm6
+@verbatim
++---------+-----+--------+-----+---------+
+|   func3 | imm | rd/rs1 | imm | opcode2 |
++---------+-----+--------+-----+---------+
+15        13    12       7     2         0
+@end verbatim
+
+@item CIW type: .insn ciw opcode2, func3, rd, uimm8
+@verbatim
++---------+--------------+-----+---------+
+|   func3 |          imm | rd' | opcode2 |
++---------+--------------+-----+---------+
+15        13             7     2         0
+@end verbatim
+
+@item CB type: .insn cb opcode2, func3, rs1, symbol
+@verbatim
++---------+--------+------+--------+---------+
+|   func3 | offset | rs1' | offset | opcode2 |
++---------+--------+------+--------+---------+
+15        13       10     7        2         0
+@end verbatim
+
+@item CJ type: .insn cj opcode2, symbol
+@verbatim
++---------+--------------------+---------+
+|   func3 |        jump target | opcode2 |
++---------+--------------------+---------+
+15        13             7     2         0
+@end verbatim
+
+
+@end table
+
+For the complete list of all instruction format variants see
+The RISC-V Instruction Set Manual Volume I: User-Level ISA.
diff --git a/gas/testsuite/gas/riscv/insn.d b/gas/testsuite/gas/riscv/insn.d
new file mode 100644
index 0000000..3d1049b
--- /dev/null
+++ b/gas/testsuite/gas/riscv/insn.d
@@ -0,0 +1,51 @@ 
+#as: -march=rv32ic
+#objdump: -dr
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section .text:
+
+0+000 <target>:
+[ 	]+0:[ 	]+00c58533[ 	]+add[ 	]+a0,a1,a2
+[ 	]+4:[ 	]+00d58513[ 	]+addi[ 	]+a0,a1,13
+[ 	]+8:[ 	]+00a58567[ 	]+jalr[ 	]+a0,10\(a1\)
+[ 	]+c:[ 	]+00458503[ 	]+lb[ 	]+a0,4\(a1\)
+[ 	]+10:[ 	]+feb508e3[ 	]+beq[ 	]+a0,a1,0 \<target\>
+[	]+10: R_RISCV_BRANCH[	]+target
+[ 	]+14:[ 	]+00a58223[ 	]+sb[ 	]+a0,4\(a1\)
+[ 	]+18:[ 	]+00fff537[ 	]+lui[ 	]+a0,0xfff
+[ 	]+1c:[ 	]+fe5ff56f[ 	]+jal[ 	]+a0,0 \<target\>
+[	]+1c: R_RISCV_JAL[	]+target
+[ 	]+20:[ 	]+0511[ 	]+addi[ 	]+a0,a0,4
+[ 	]+22:[ 	]+852e[ 	]+mv[ 	]+a0,a1
+[ 	]+24:[ 	]+002c[ 	]+addi[ 	]+a1,sp,8
+[ 	]+26:[ 	]+dde9[ 	]+beqz[ 	]+a1,0 \<target\>
+[	]+26: R_RISCV_RVC_BRANCH[	]+target
+[ 	]+28:[ 	]+bfe1[ 	]+j[ 	]+0 \<target\>
+[	]+28: R_RISCV_RVC_JUMP[	]+target
+[ 	]+2a:[ 	]+00c58533[ 	]+add[ 	]+a0,a1,a2
+[ 	]+2e:[ 	]+00d58513[ 	]+addi[ 	]+a0,a1,13
+[ 	]+32:[ 	]+00a58567[ 	]+jalr[ 	]+a0,10\(a1\)
+[ 	]+36:[ 	]+00458503[ 	]+lb[ 	]+a0,4\(a1\)
+[ 	]+3a:[ 	]+fcb503e3[ 	]+beq[ 	]+a0,a1,0 \<target\>
+[	]+3a: R_RISCV_BRANCH[	]+target
+[ 	]+3e:[ 	]+00a58223[ 	]+sb[ 	]+a0,4\(a1\)
+[ 	]+42:[ 	]+00fff537[ 	]+lui[ 	]+a0,0xfff
+[ 	]+46:[ 	]+fbbff56f[ 	]+jal[ 	]+a0,0 \<target\>
+[	]+46: R_RISCV_JAL[	]+target
+[ 	]+4a:[ 	]+0511[ 	]+addi[ 	]+a0,a0,4
+[ 	]+4c:[ 	]+852e[ 	]+mv[ 	]+a0,a1
+[ 	]+4e:[ 	]+002c[ 	]+addi[ 	]+a1,sp,8
+[ 	]+50:[ 	]+d9c5[ 	]+beqz[ 	]+a1,0 \<target\>
+[	]+50: R_RISCV_RVC_BRANCH[	]+target
+[ 	]+52:[ 	]+b77d[ 	]+j[ 	]+0 \<target\>
+[	]+52: R_RISCV_RVC_JUMP[	]+target
+[ 	]+54:[ 	]+68c58543[ 	]+fmadd.s[ 	]+fa0,fa1,fa2,fa3,rne
+[ 	]+58:[ 	]+00c58533[ 	]+add[ 	]+a0,a1,a2
+[ 	]+5c:[ 	]+00c58533[ 	]+add[ 	]+a0,a1,a2
+[ 	]+60:[ 	]+00c58533[ 	]+add[ 	]+a0,a1,a2
+[ 	]+64:[ 	]+00c58533[ 	]+add[ 	]+a0,a1,a2
+[ 	]+68:[ 	]+00c58533[ 	]+add[ 	]+a0,a1,a2
+[ 	]+6c:[ 	]+00c58533[ 	]+add[ 	]+a0,a1,a2
+[ 	]+70:[ 	]+00c58533[ 	]+add[ 	]+a0,a1,a2
diff --git a/gas/testsuite/gas/riscv/insn.s b/gas/testsuite/gas/riscv/insn.s
new file mode 100644
index 0000000..7ad1753
--- /dev/null
+++ b/gas/testsuite/gas/riscv/insn.s
@@ -0,0 +1,39 @@ 
+target:
+	.insn r  0x33,  0,  0, a0, a1, a2
+	.insn i  0x13,  0, a0, a1, 13
+	.insn i  0x67,  0, a0, 10(a1)
+	.insn s   0x3,  0, a0, 4(a1)
+	.insn sb 0x63,  0, a0, a1, target
+	.insn sb 0x23,  0, a0, 4(a1)
+	.insn u  0x37, a0, 0xfff
+	.insn uj 0x6f, a0, target
+
+	.insn ci 0x1, 0x0, a0, 4
+	.insn cr 0x2, 0x8, a0, a1
+	.insn ciw 0x0, 0x0, a1, 1
+	.insn cb 0x1, 0x6, a1, target
+	.insn cj 0x1, 0x5, target
+
+	.insn r  OP,  0,  0, a0, a1, a2
+	.insn i  OP_IMM,  0, a0, a1, 13
+	.insn i  JALR,  0, a0, 10(a1)
+	.insn s  LOAD,  0, a0, 4(a1)
+	.insn sb BRANCH,  0, a0, a1, target
+	.insn sb STORE,  0, a0, 4(a1)
+	.insn u  LUI, a0, 0xfff
+	.insn uj JAL, a0, target
+
+	.insn ci C1, 0x0, a0, 4
+	.insn cr C2, 0x8, a0, a1
+	.insn ciw C0, 0x0, a1, 1
+	.insn cb C1, 0x6, a1, target
+	.insn cj C1, 0x5, target
+
+	.insn r MADD, 0, 0, a0, a1, a2, a3
+	.insn r  0x33,  0,  0, fa0, a1, a2
+	.insn r  0x33,  0,  0, a0, fa1, a2
+	.insn r  0x33,  0,  0, fa0, fa1, a2
+	.insn r  0x33,  0,  0, a0, a1, fa2
+	.insn r  0x33,  0,  0, fa0, a1, fa2
+	.insn r  0x33,  0,  0, a0, fa1, fa2
+	.insn r  0x33,  0,  0, fa0, fa1, fa2
diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
index b87c719..ac6f773 100644
--- a/include/opcode/riscv.h
+++ b/include/opcode/riscv.h
@@ -77,6 +77,8 @@  static const char * const riscv_pred_succ[16] =
   (EXTRACT_RVC_IMM (x) << RISCV_IMM_BITS)
 #define EXTRACT_RVC_SIMM3(x) \
   (RV_X(x, 10, 2) | (-RV_X(x, 12, 1) << 2))
+#define EXTRACT_RVC_UIMM8(x) \
+  (RV_X(x, 5, 8))
 #define EXTRACT_RVC_ADDI4SPN_IMM(x) \
   ((RV_X(x, 6, 1) << 2) | (RV_X(x, 5, 1) << 3) | (RV_X(x, 11, 2) << 4) | (RV_X(x, 7, 4) << 6))
 #define EXTRACT_RVC_ADDI16SP_IMM(x) \
@@ -114,6 +116,8 @@  static const char * const riscv_pred_succ[16] =
   ENCODE_RVC_IMM ((x) >> RISCV_IMM_BITS)
 #define ENCODE_RVC_SIMM3(x) \
   (RV_X(x, 0, 3) << 10)
+#define ENCODE_RVC_UIMM8(x) \
+  (RV_X(x, 0, 8) << 5)
 #define ENCODE_RVC_ADDI4SPN_IMM(x) \
   ((RV_X(x, 2, 1) << 6) | (RV_X(x, 3, 1) << 5) | (RV_X(x, 4, 2) << 11) | (RV_X(x, 6, 4) << 7))
 #define ENCODE_RVC_ADDI16SP_IMM(x) \
@@ -143,6 +147,7 @@  static const char * const riscv_pred_succ[16] =
 #define VALID_RVC_IMM(x) (EXTRACT_RVC_IMM(ENCODE_RVC_IMM(x)) == (x))
 #define VALID_RVC_LUI_IMM(x) (ENCODE_RVC_LUI_IMM(x) != 0 && EXTRACT_RVC_LUI_IMM(ENCODE_RVC_LUI_IMM(x)) == (x))
 #define VALID_RVC_SIMM3(x) (EXTRACT_RVC_SIMM3(ENCODE_RVC_SIMM3(x)) == (x))
+#define VALID_RVC_UIMM8(x) (EXTRACT_RVC_UIMM8(ENCODE_RVC_UIMM8(x)) == (x))
 #define VALID_RVC_ADDI4SPN_IMM(x) (EXTRACT_RVC_ADDI4SPN_IMM(ENCODE_RVC_ADDI4SPN_IMM(x)) == (x))
 #define VALID_RVC_ADDI16SP_IMM(x) (EXTRACT_RVC_ADDI16SP_IMM(ENCODE_RVC_ADDI16SP_IMM(x)) == (x))
 #define VALID_RVC_LW_IMM(x) (EXTRACT_RVC_LW_IMM(ENCODE_RVC_LW_IMM(x)) == (x))
@@ -223,8 +228,18 @@  static const char * const riscv_pred_succ[16] =
 #define OP_MASK_CSR		0xfff
 #define OP_SH_CSR		20
 
+#define OP_MASK_FUNCT3         0x7
+#define OP_SH_FUNCT3           12
+#define OP_MASK_FUNCT7         0x7f
+#define OP_SH_FUNCT7           25
+#define OP_MASK_FUNCT2         0x3
+#define OP_SH_FUNCT2           25
+
 /* RVC fields.  */
 
+#define OP_MASK_OP2            0x3
+#define OP_SH_OP2              0
+
 #define OP_MASK_CRS2 0x1f
 #define OP_SH_CRS2 2
 #define OP_MASK_CRS1S 0x7
@@ -232,6 +247,11 @@  static const char * const riscv_pred_succ[16] =
 #define OP_MASK_CRS2S 0x7
 #define OP_SH_CRS2S 2
 
+#define OP_MASK_CFUNCT4                0xf
+#define OP_SH_CFUNCT4          12
+#define OP_MASK_CFUNCT3                0x7
+#define OP_SH_CFUNCT3          13
+
 /* ABI names for selected x-registers.  */
 
 #define X_RA 1
@@ -340,5 +360,6 @@  extern const char * const riscv_fpr_names_numeric[NFPR];
 extern const char * const riscv_fpr_names_abi[NFPR];
 
 extern const struct riscv_opcode riscv_opcodes[];
+extern const struct riscv_opcode riscv_insn_types[];
 
 #endif /* _RISCV_H_ */
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
index 4aeb55a..a285b14 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -741,3 +741,77 @@  const struct riscv_opcode riscv_opcodes[] =
 /* Terminate the list.  */
 {0, 0, 0, 0, 0, 0, 0}
 };
+
+/* Instruction format for .insn directive.  */
+const struct riscv_opcode riscv_insn_types[] =
+{
+/* name,  isa,          operands, match, mask,    match_func, pinfo.  */
+{"r",     "I",  "O4,F3,F7,d,s,t",     0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F7,D,s,t",     0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F7,d,S,t",     0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F7,D,S,t",     0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F7,d,s,T",     0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F7,D,s,T",     0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F7,d,S,T",     0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F7,D,S,T",     0,    0,  match_opcode, 0 },
+
+{"r",     "I",  "O4,F3,F2,d,s,t,r",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,D,s,t,r",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,d,S,t,r",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,D,S,t,r",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,d,s,T,r",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,D,s,T,r",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,d,S,T,r",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,D,S,T,r",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,d,s,t,R",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,D,s,t,R",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,d,S,t,R",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,D,S,t,R",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,d,s,T,R",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,D,s,T,R",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,d,S,T,R",   0,    0,  match_opcode, 0 },
+{"r",     "I",  "O4,F3,F2,D,S,T,R",   0,    0,  match_opcode, 0 },
+
+{"i",     "I",  "O4,F3,d,s,j",        0,    0,  match_opcode, 0 },
+{"i",     "I",  "O4,F3,D,s,j",        0,    0,  match_opcode, 0 },
+{"i",     "I",  "O4,F3,d,S,j",        0,    0,  match_opcode, 0 },
+{"i",     "I",  "O4,F3,D,S,j",        0,    0,  match_opcode, 0 },
+
+{"i",     "I",  "O4,F3,d,o(s)",       0,    0,  match_opcode, 0 },
+{"i",     "I",  "O4,F3,D,o(s)",       0,    0,  match_opcode, 0 },
+
+{"s",     "I",  "O4,F3,d,o(s)",       0,    0,  match_opcode, 0 },
+{"s",     "I",  "O4,F3,D,o(s)",       0,    0,  match_opcode, 0 },
+
+{"sb",    "I",  "O4,F3,s,t,p",        0,    0,  match_opcode, 0 },
+{"sb",    "I",  "O4,F3,S,t,p",        0,    0,  match_opcode, 0 },
+{"sb",    "I",  "O4,F3,s,T,p",        0,    0,  match_opcode, 0 },
+{"sb",    "I",  "O4,F3,S,T,p",        0,    0,  match_opcode, 0 },
+
+{"sb",    "I",  "O4,F3,t,q(s)",       0,    0,  match_opcode, 0 },
+{"sb",    "I",  "O4,F3,T,q(s)",       0,    0,  match_opcode, 0 },
+
+{"u",     "I",  "O4,d,u",             0,    0,  match_opcode, 0 },
+{"u",     "I",  "O4,D,u",             0,    0,  match_opcode, 0 },
+
+{"uj",    "I",  "O4,d,a",             0,    0,  match_opcode, 0 },
+{"uj",    "I",  "O4,D,a",             0,    0,  match_opcode, 0 },
+
+{"cr",    "C",  "O2,CF4,d,CV",        0,    0,  match_opcode, 0 },
+{"cr",    "C",  "O2,CF4,D,CV",        0,    0,  match_opcode, 0 },
+{"cr",    "C",  "O2,CF4,d,CT",        0,    0,  match_opcode, 0 },
+{"cr",    "C",  "O2,CF4,D,CT",        0,    0,  match_opcode, 0 },
+
+{"ci",    "C",  "O2,CF3,d,Co",        0,    0,  match_opcode, 0 },
+{"ci",    "C",  "O2,CF3,D,Co",        0,    0,  match_opcode, 0 },
+
+{"ciw",   "C",  "O2,CF3,Ct,C8",        0,    0,  match_opcode, 0 },
+{"ciw",   "C",  "O2,CF3,CD,C8",        0,    0,  match_opcode, 0 },
+
+{"cb",    "C",  "O2,CF3,Cs,Cp",       0,    0,  match_opcode, 0 },
+{"cb",    "C",  "O2,CF3,CS,Cp",       0,    0,  match_opcode, 0 },
+
+{"cj",    "C",  "O2,CF3,Ca",          0,    0,  match_opcode, 0 },
+/* Terminate the list.  */
+{0, 0, 0, 0, 0, 0, 0}
+};
-- 
2.7.4