[PATCH 1/3] opcodes: support insn endianness in cgen_cpu_open

Jose E. Marchesi jose.marchesi@oracle.com
Fri May 29 17:08:18 GMT 2020


This patch adds support for a new CGEN_OPEN_INSN_ENDIAN argument
for @arch@_cgen_cpu_open.  This is useful for architectures in
which the endianness of the instruction words is not the same
than the endianness used for data.

An accompanying patch has been sent to the CGEN mailing list that
adds support for this argument on the CGEN side [1].  Its been
already pre-approved [2], and will be applied simultaneously with
this binutils series.

[1] https://sourceware.org/pipermail/cgen/2020q2/002733.html
[2] https://sourceware.org/pipermail/cgen/2020q2/002737.html

include/ChangeLog:

2020-05-29  Jose E. Marchesi  <jemarch@gnu.org>

	* opcode/cgen.h (enum cgen_cpu_open_arg): New value
	CGEN_CPU_OPEN_INSN_ENDIAN.

opcodes/ChangeLog:

2020-05-29  Jose E. Marchesi  <jemarch@gnu.org>

	* cgen-dis.in (cpu_desc_list): New field `insn_endian'.
	(print_insn_): Handle instruction endian.
	* bpf-dis.c: Regenerate.
	* bpf-desc.c: Regenerate.
	* epiphany-dis.c: Likewise.
	* epiphany-desc.c: Likewise.
	* fr30-dis.c: Likewise.
	* fr30-desc.c: Likewise.
	* frv-dis.c: Likewise.
	* frv-desc.c: Likewise.
	* ip2k-dis.c: Likewise.
	* ip2k-desc.c: Likewise.
	* iq2000-dis.c: Likewise.
	* iq2000-desc.c: Likewise.
	* lm32-dis.c: Likewise.
	* lm32-desc.c: Likewise.
	* m32c-dis.c: Likewise.
	* m32c-desc.c: Likewise.
	* m32r-dis.c: Likewise.
	* m32r-desc.c: Likewise.
	* mep-dis.c: Likewise.
	* mep-desc.c: Likewise.
	* mt-dis.c: Likewise.
	* mt-desc.c: Likewise.
	* or1k-dis.c: Likewise.
	* or1k-desc.c: Likewise.
	* xc16x-dis.c: Likewise.
	* xc16x-desc.c: Likewise.
	* xstormy16-dis.c: Likewise.
	* xstormy16-desc.c: Likewise.

binutils/ChangeLog:

2020-05-29  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* objdump.c (disassemble_data): Set disasm_info.endian_code to
	disasm_info.endian after the later is initialized to the
	endianness reported by BFD.
---
 binutils/ChangeLog       |  6 ++++++
 binutils/objdump.c       |  2 ++
 include/ChangeLog        |  5 +++++
 include/opcode/cgen.h    |  9 ++++++++-
 opcodes/ChangeLog        | 33 +++++++++++++++++++++++++++++++++
 opcodes/bpf-desc.c       | 12 +++++++-----
 opcodes/bpf-dis.c        |  7 +++++++
 opcodes/cgen-dis.in      |  7 +++++++
 opcodes/epiphany-desc.c  | 28 +++++++++++++++++++---------
 opcodes/epiphany-dis.c   |  7 +++++++
 opcodes/fr30-desc.c      | 28 +++++++++++++++++++---------
 opcodes/fr30-dis.c       |  7 +++++++
 opcodes/frv-desc.c       | 28 +++++++++++++++++++---------
 opcodes/frv-dis.c        |  7 +++++++
 opcodes/ip2k-desc.c      | 28 +++++++++++++++++++---------
 opcodes/ip2k-dis.c       |  7 +++++++
 opcodes/iq2000-desc.c    | 28 +++++++++++++++++++---------
 opcodes/iq2000-dis.c     |  7 +++++++
 opcodes/lm32-desc.c      | 28 +++++++++++++++++++---------
 opcodes/lm32-dis.c       |  7 +++++++
 opcodes/m32c-desc.c      | 28 +++++++++++++++++++---------
 opcodes/m32c-dis.c       |  7 +++++++
 opcodes/m32r-desc.c      | 28 +++++++++++++++++++---------
 opcodes/m32r-dis.c       |  7 +++++++
 opcodes/mep-desc.c       | 28 +++++++++++++++++++---------
 opcodes/mep-dis.c        |  7 +++++++
 opcodes/mt-desc.c        | 28 +++++++++++++++++++---------
 opcodes/mt-dis.c         |  7 +++++++
 opcodes/or1k-desc.c      | 28 +++++++++++++++++++---------
 opcodes/or1k-dis.c       |  7 +++++++
 opcodes/xc16x-desc.c     | 28 +++++++++++++++++++---------
 opcodes/xc16x-dis.c      |  7 +++++++
 opcodes/xstormy16-desc.c | 28 +++++++++++++++++++---------
 opcodes/xstormy16-dis.c  |  7 +++++++
 34 files changed, 413 insertions(+), 123 deletions(-)

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 101255de21..eb3eb6102d 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,9 @@
+2020-05-29  Jose E. Marchesi  <jose.marchesi@oracle.com>
+
+	* objdump.c (disassemble_data): Set disasm_info.endian_code to
+	disasm_info.endian after the later is initialized to the
+	endianness reported by BFD.
+
 2020-05-28  Max Filippov  <jcmvbkbc@gmail.com>
 
 	* MAINTAINERS (Xtensa): Add myself as maintainer.
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 99e6df6eb1..9b3d5b7acb 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -3479,6 +3479,8 @@ disassemble_data (bfd *abfd)
        instead.  */
     disasm_info.endian = BFD_ENDIAN_UNKNOWN;
 
+  disasm_info.endian_code = disasm_info.endian;
+
   /* Allow the target to customize the info structure.  */
   disassemble_init_for_target (& disasm_info);
 
diff --git a/include/ChangeLog b/include/ChangeLog
index 08eadb6cbd..adadc49fef 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,8 @@
+2020-05-29  Jose E. Marchesi  <jemarch@gnu.org>
+
+	* opcode/cgen.h (enum cgen_cpu_open_arg): New value
+	CGEN_CPU_OPEN_INSN_ENDIAN.
+
 2020-05-28  Alan Modra  <amodra@gmail.com>
 
 	PR 26044
diff --git a/include/opcode/cgen.h b/include/opcode/cgen.h
index 95bbdf43e3..3f325447b9 100644
--- a/include/opcode/cgen.h
+++ b/include/opcode/cgen.h
@@ -1392,7 +1392,9 @@ enum cgen_cpu_open_arg {
      Multiple machines can be specified by repeated use.  */
   CGEN_CPU_OPEN_BFDMACH,
   /* Select endian, arg is CGEN_ENDIAN_*.  */
-  CGEN_CPU_OPEN_ENDIAN
+  CGEN_CPU_OPEN_ENDIAN,
+  /* Select instruction endian, arg is CGEN_ENDIAN_*.  */
+  CGEN_CPU_OPEN_INSN_ENDIAN,
 };
 
 /* Open a cpu descriptor table for use.
@@ -1465,6 +1467,11 @@ extern CGEN_INSN_INT cgen_get_insn_value
 extern void cgen_put_insn_value
   (CGEN_CPU_DESC, unsigned char *, int, CGEN_INSN_INT);
 
+extern CGEN_INSN_INT cgen_get_base_insn_value
+  (CGEN_CPU_DESC, unsigned char *, int);
+extern void cgen_put_base_insn_value
+  (CGEN_CPU_DESC, unsigned char *, int, CGEN_INSN_INT);
+
 /* Read in a cpu description file.
    ??? For future concerns, including adding instructions to the assembler/
    disassembler at run-time.  */
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 15405a5215..bb639637aa 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,3 +1,36 @@
+2020-05-29  Jose E. Marchesi  <jemarch@gnu.org>
+
+	* cgen-dis.in (cpu_desc_list): New field `insn_endian'.
+	(print_insn_): Handle instruction endian.
+	* bpf-dis.c: Regenerate.
+	* bpf-desc.c: Regenerate.
+	* epiphany-dis.c: Likewise.
+	* epiphany-desc.c: Likewise.
+	* fr30-dis.c: Likewise.
+	* fr30-desc.c: Likewise.
+	* frv-dis.c: Likewise.
+	* frv-desc.c: Likewise.
+	* ip2k-dis.c: Likewise.
+	* ip2k-desc.c: Likewise.
+	* iq2000-dis.c: Likewise.
+	* iq2000-desc.c: Likewise.
+	* lm32-dis.c: Likewise.
+	* lm32-desc.c: Likewise.
+	* m32c-dis.c: Likewise.
+	* m32c-desc.c: Likewise.
+	* m32r-dis.c: Likewise.
+	* m32r-desc.c: Likewise.
+	* mep-dis.c: Likewise.
+	* mep-desc.c: Likewise.
+	* mt-dis.c: Likewise.
+	* mt-desc.c: Likewise.
+	* or1k-dis.c: Likewise.
+	* or1k-desc.c: Likewise.
+	* xc16x-dis.c: Likewise.
+	* xc16x-desc.c: Likewise.
+	* xstormy16-dis.c: Likewise.
+	* xstormy16-desc.c: Likewise.
+
 2020-05-28  Jose E. Marchesi  <jose.marchesi@oracle.com>
 	    David Faust <david.faust@oracle.com>
 
diff --git a/opcodes/bpf-desc.c b/opcodes/bpf-desc.c
index ddd55b9fb6..986810254c 100644
--- a/opcodes/bpf-desc.c
+++ b/opcodes/bpf-desc.c
@@ -1701,6 +1701,7 @@ bpf_cgen_rebuild_tables (CGEN_CPU_TABLE *cd)
    CGEN_CPU_OPEN_MACHS:   bitmap of values in enum mach_attr
    CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
    CGEN_CPU_OPEN_ENDIAN:  specify endian choice
+   CGEN_CPU_OPEN_INSN_ENDIAN: specify instruction endian choice
    CGEN_CPU_OPEN_END:     terminates arguments
 
    ??? Simultaneous multiple isas might not make sense, but it's not (yet)
@@ -1714,6 +1715,7 @@ bpf_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   CGEN_BITSET *isas = 0;  /* 0 = "unspecified" */
   unsigned int machs = 0; /* 0 = "unspecified" */
   enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+  enum cgen_endian insn_endian = CGEN_ENDIAN_UNKNOWN;
   va_list ap;
 
   if (! init_p)
@@ -1748,6 +1750,9 @@ bpf_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
 	case CGEN_CPU_OPEN_ENDIAN :
 	  endian = va_arg (ap, enum cgen_endian);
 	  break;
+	case CGEN_CPU_OPEN_INSN_ENDIAN :
+	  insn_endian = va_arg (ap, enum cgen_endian);
+	  break;
 	default :
 	  opcodes_error_handler
 	    (/* xgettext:c-format */
@@ -1777,11 +1782,8 @@ bpf_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   cd->isas = cgen_bitset_copy (isas);
   cd->machs = machs;
   cd->endian = endian;
-  /* FIXME: for the sparc case we can determine insn-endianness statically.
-     The worry here is where both data and insn endian can be independently
-     chosen, in which case this function will need another argument.
-     Actually, will want to allow for more arguments in the future anyway.  */
-  cd->insn_endian = endian;
+  if (insn_endian == CGEN_ENDIAN_UNKNOWN)
+    cd->insn_endian = endian;
 
   /* Table (re)builder.  */
   cd->rebuild_tables = bpf_cgen_rebuild_tables;
diff --git a/opcodes/bpf-dis.c b/opcodes/bpf-dis.c
index 60e0d960c8..21d9308be0 100644
--- a/opcodes/bpf-dis.c
+++ b/opcodes/bpf-dis.c
@@ -507,6 +507,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -519,12 +520,16 @@ print_insn_bpf (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -590,9 +595,11 @@ print_insn_bpf (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = bpf_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
diff --git a/opcodes/cgen-dis.in b/opcodes/cgen-dis.in
index 5f448fbd3f..378b984551 100644
--- a/opcodes/cgen-dis.in
+++ b/opcodes/cgen-dis.in
@@ -341,6 +341,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -353,12 +354,16 @@ print_insn_@arch@ (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -424,9 +429,11 @@ print_insn_@arch@ (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = @arch@_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
diff --git a/opcodes/epiphany-desc.c b/opcodes/epiphany-desc.c
index 3776ebba5b..5c0695fed9 100644
--- a/opcodes/epiphany-desc.c
+++ b/opcodes/epiphany-desc.c
@@ -2139,6 +2139,7 @@ epiphany_cgen_rebuild_tables (CGEN_CPU_TABLE *cd)
    CGEN_CPU_OPEN_MACHS:   bitmap of values in enum mach_attr
    CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
    CGEN_CPU_OPEN_ENDIAN:  specify endian choice
+   CGEN_CPU_OPEN_INSN_ENDIAN: specify instruction endian choice
    CGEN_CPU_OPEN_END:     terminates arguments
 
    ??? Simultaneous multiple isas might not make sense, but it's not (yet)
@@ -2152,6 +2153,7 @@ epiphany_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   CGEN_BITSET *isas = 0;  /* 0 = "unspecified" */
   unsigned int machs = 0; /* 0 = "unspecified" */
   enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+  enum cgen_endian insn_endian = CGEN_ENDIAN_UNKNOWN;
   va_list ap;
 
   if (! init_p)
@@ -2186,6 +2188,9 @@ epiphany_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
 	case CGEN_CPU_OPEN_ENDIAN :
 	  endian = va_arg (ap, enum cgen_endian);
 	  break;
+	case CGEN_CPU_OPEN_INSN_ENDIAN :
+	  insn_endian = va_arg (ap, enum cgen_endian);
+	  break;
 	default :
 	  opcodes_error_handler
 	    (/* xgettext:c-format */
@@ -2215,11 +2220,8 @@ epiphany_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   cd->isas = cgen_bitset_copy (isas);
   cd->machs = machs;
   cd->endian = endian;
-  /* FIXME: for the sparc case we can determine insn-endianness statically.
-     The worry here is where both data and insn endian can be independently
-     chosen, in which case this function will need another argument.
-     Actually, will want to allow for more arguments in the future anyway.  */
-  cd->insn_endian = endian;
+  if (insn_endian == CGEN_ENDIAN_UNKNOWN)
+    cd->insn_endian = endian;
 
   /* Table (re)builder.  */
   cd->rebuild_tables = epiphany_cgen_rebuild_tables;
@@ -2269,10 +2271,18 @@ epiphany_cgen_cpu_close (CGEN_CPU_DESC cd)
 	  regfree (CGEN_INSN_RX (insns));
     }
 
-  free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
-  free ((CGEN_INSN *) cd->insn_table.init_entries);
-  free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
-  free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+  if (cd->macro_insn_table.init_entries)
+    free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
+
+  if (cd->insn_table.init_entries)
+    free ((CGEN_INSN *) cd->insn_table.init_entries);
+
+  if (cd->hw_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
+
+  if (cd->operand_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+
   free (cd);
 }
 
diff --git a/opcodes/epiphany-dis.c b/opcodes/epiphany-dis.c
index 1621d08e3e..966b39fe09 100644
--- a/opcodes/epiphany-dis.c
+++ b/opcodes/epiphany-dis.c
@@ -582,6 +582,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -594,12 +595,16 @@ print_insn_epiphany (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -665,9 +670,11 @@ print_insn_epiphany (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = epiphany_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
diff --git a/opcodes/fr30-desc.c b/opcodes/fr30-desc.c
index 5fe16b781a..7b8b495cb4 100644
--- a/opcodes/fr30-desc.c
+++ b/opcodes/fr30-desc.c
@@ -1616,6 +1616,7 @@ fr30_cgen_rebuild_tables (CGEN_CPU_TABLE *cd)
    CGEN_CPU_OPEN_MACHS:   bitmap of values in enum mach_attr
    CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
    CGEN_CPU_OPEN_ENDIAN:  specify endian choice
+   CGEN_CPU_OPEN_INSN_ENDIAN: specify instruction endian choice
    CGEN_CPU_OPEN_END:     terminates arguments
 
    ??? Simultaneous multiple isas might not make sense, but it's not (yet)
@@ -1629,6 +1630,7 @@ fr30_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   CGEN_BITSET *isas = 0;  /* 0 = "unspecified" */
   unsigned int machs = 0; /* 0 = "unspecified" */
   enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+  enum cgen_endian insn_endian = CGEN_ENDIAN_UNKNOWN;
   va_list ap;
 
   if (! init_p)
@@ -1663,6 +1665,9 @@ fr30_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
 	case CGEN_CPU_OPEN_ENDIAN :
 	  endian = va_arg (ap, enum cgen_endian);
 	  break;
+	case CGEN_CPU_OPEN_INSN_ENDIAN :
+	  insn_endian = va_arg (ap, enum cgen_endian);
+	  break;
 	default :
 	  opcodes_error_handler
 	    (/* xgettext:c-format */
@@ -1692,11 +1697,8 @@ fr30_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   cd->isas = cgen_bitset_copy (isas);
   cd->machs = machs;
   cd->endian = endian;
-  /* FIXME: for the sparc case we can determine insn-endianness statically.
-     The worry here is where both data and insn endian can be independently
-     chosen, in which case this function will need another argument.
-     Actually, will want to allow for more arguments in the future anyway.  */
-  cd->insn_endian = endian;
+  if (insn_endian == CGEN_ENDIAN_UNKNOWN)
+    cd->insn_endian = endian;
 
   /* Table (re)builder.  */
   cd->rebuild_tables = fr30_cgen_rebuild_tables;
@@ -1746,10 +1748,18 @@ fr30_cgen_cpu_close (CGEN_CPU_DESC cd)
 	  regfree (CGEN_INSN_RX (insns));
     }
 
-  free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
-  free ((CGEN_INSN *) cd->insn_table.init_entries);
-  free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
-  free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+  if (cd->macro_insn_table.init_entries)
+    free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
+
+  if (cd->insn_table.init_entries)
+    free ((CGEN_INSN *) cd->insn_table.init_entries);
+
+  if (cd->hw_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
+
+  if (cd->operand_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+
   free (cd);
 }
 
diff --git a/opcodes/fr30-dis.c b/opcodes/fr30-dis.c
index 331b5fb06e..b98ea94a1a 100644
--- a/opcodes/fr30-dis.c
+++ b/opcodes/fr30-dis.c
@@ -603,6 +603,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -615,12 +616,16 @@ print_insn_fr30 (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -686,9 +691,11 @@ print_insn_fr30 (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = fr30_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
diff --git a/opcodes/frv-desc.c b/opcodes/frv-desc.c
index 869237e674..e210c3b06f 100644
--- a/opcodes/frv-desc.c
+++ b/opcodes/frv-desc.c
@@ -6356,6 +6356,7 @@ frv_cgen_rebuild_tables (CGEN_CPU_TABLE *cd)
    CGEN_CPU_OPEN_MACHS:   bitmap of values in enum mach_attr
    CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
    CGEN_CPU_OPEN_ENDIAN:  specify endian choice
+   CGEN_CPU_OPEN_INSN_ENDIAN: specify instruction endian choice
    CGEN_CPU_OPEN_END:     terminates arguments
 
    ??? Simultaneous multiple isas might not make sense, but it's not (yet)
@@ -6369,6 +6370,7 @@ frv_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   CGEN_BITSET *isas = 0;  /* 0 = "unspecified" */
   unsigned int machs = 0; /* 0 = "unspecified" */
   enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+  enum cgen_endian insn_endian = CGEN_ENDIAN_UNKNOWN;
   va_list ap;
 
   if (! init_p)
@@ -6403,6 +6405,9 @@ frv_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
 	case CGEN_CPU_OPEN_ENDIAN :
 	  endian = va_arg (ap, enum cgen_endian);
 	  break;
+	case CGEN_CPU_OPEN_INSN_ENDIAN :
+	  insn_endian = va_arg (ap, enum cgen_endian);
+	  break;
 	default :
 	  opcodes_error_handler
 	    (/* xgettext:c-format */
@@ -6432,11 +6437,8 @@ frv_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   cd->isas = cgen_bitset_copy (isas);
   cd->machs = machs;
   cd->endian = endian;
-  /* FIXME: for the sparc case we can determine insn-endianness statically.
-     The worry here is where both data and insn endian can be independently
-     chosen, in which case this function will need another argument.
-     Actually, will want to allow for more arguments in the future anyway.  */
-  cd->insn_endian = endian;
+  if (insn_endian == CGEN_ENDIAN_UNKNOWN)
+    cd->insn_endian = endian;
 
   /* Table (re)builder.  */
   cd->rebuild_tables = frv_cgen_rebuild_tables;
@@ -6486,10 +6488,18 @@ frv_cgen_cpu_close (CGEN_CPU_DESC cd)
 	  regfree (CGEN_INSN_RX (insns));
     }
 
-  free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
-  free ((CGEN_INSN *) cd->insn_table.init_entries);
-  free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
-  free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+  if (cd->macro_insn_table.init_entries)
+    free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
+
+  if (cd->insn_table.init_entries)
+    free ((CGEN_INSN *) cd->insn_table.init_entries);
+
+  if (cd->hw_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
+
+  if (cd->operand_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+
   free (cd);
 }
 
diff --git a/opcodes/frv-dis.c b/opcodes/frv-dis.c
index 6f3d6cc6fd..60f1a6141e 100644
--- a/opcodes/frv-dis.c
+++ b/opcodes/frv-dis.c
@@ -700,6 +700,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -712,12 +713,16 @@ print_insn_frv (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -783,9 +788,11 @@ print_insn_frv (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = frv_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
diff --git a/opcodes/ip2k-desc.c b/opcodes/ip2k-desc.c
index 9e5cf6ce23..744431f988 100644
--- a/opcodes/ip2k-desc.c
+++ b/opcodes/ip2k-desc.c
@@ -1045,6 +1045,7 @@ ip2k_cgen_rebuild_tables (CGEN_CPU_TABLE *cd)
    CGEN_CPU_OPEN_MACHS:   bitmap of values in enum mach_attr
    CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
    CGEN_CPU_OPEN_ENDIAN:  specify endian choice
+   CGEN_CPU_OPEN_INSN_ENDIAN: specify instruction endian choice
    CGEN_CPU_OPEN_END:     terminates arguments
 
    ??? Simultaneous multiple isas might not make sense, but it's not (yet)
@@ -1058,6 +1059,7 @@ ip2k_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   CGEN_BITSET *isas = 0;  /* 0 = "unspecified" */
   unsigned int machs = 0; /* 0 = "unspecified" */
   enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+  enum cgen_endian insn_endian = CGEN_ENDIAN_UNKNOWN;
   va_list ap;
 
   if (! init_p)
@@ -1092,6 +1094,9 @@ ip2k_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
 	case CGEN_CPU_OPEN_ENDIAN :
 	  endian = va_arg (ap, enum cgen_endian);
 	  break;
+	case CGEN_CPU_OPEN_INSN_ENDIAN :
+	  insn_endian = va_arg (ap, enum cgen_endian);
+	  break;
 	default :
 	  opcodes_error_handler
 	    (/* xgettext:c-format */
@@ -1121,11 +1126,8 @@ ip2k_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   cd->isas = cgen_bitset_copy (isas);
   cd->machs = machs;
   cd->endian = endian;
-  /* FIXME: for the sparc case we can determine insn-endianness statically.
-     The worry here is where both data and insn endian can be independently
-     chosen, in which case this function will need another argument.
-     Actually, will want to allow for more arguments in the future anyway.  */
-  cd->insn_endian = endian;
+  if (insn_endian == CGEN_ENDIAN_UNKNOWN)
+    cd->insn_endian = endian;
 
   /* Table (re)builder.  */
   cd->rebuild_tables = ip2k_cgen_rebuild_tables;
@@ -1175,10 +1177,18 @@ ip2k_cgen_cpu_close (CGEN_CPU_DESC cd)
 	  regfree (CGEN_INSN_RX (insns));
     }
 
-  free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
-  free ((CGEN_INSN *) cd->insn_table.init_entries);
-  free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
-  free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+  if (cd->macro_insn_table.init_entries)
+    free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
+
+  if (cd->insn_table.init_entries)
+    free ((CGEN_INSN *) cd->insn_table.init_entries);
+
+  if (cd->hw_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
+
+  if (cd->operand_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+
   free (cd);
 }
 
diff --git a/opcodes/ip2k-dis.c b/opcodes/ip2k-dis.c
index 5f79b804fe..4a53a7c246 100644
--- a/opcodes/ip2k-dis.c
+++ b/opcodes/ip2k-dis.c
@@ -592,6 +592,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -604,12 +605,16 @@ print_insn_ip2k (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -675,9 +680,11 @@ print_insn_ip2k (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = ip2k_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
diff --git a/opcodes/iq2000-desc.c b/opcodes/iq2000-desc.c
index b14842767e..bba3a4b055 100644
--- a/opcodes/iq2000-desc.c
+++ b/opcodes/iq2000-desc.c
@@ -2050,6 +2050,7 @@ iq2000_cgen_rebuild_tables (CGEN_CPU_TABLE *cd)
    CGEN_CPU_OPEN_MACHS:   bitmap of values in enum mach_attr
    CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
    CGEN_CPU_OPEN_ENDIAN:  specify endian choice
+   CGEN_CPU_OPEN_INSN_ENDIAN: specify instruction endian choice
    CGEN_CPU_OPEN_END:     terminates arguments
 
    ??? Simultaneous multiple isas might not make sense, but it's not (yet)
@@ -2063,6 +2064,7 @@ iq2000_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   CGEN_BITSET *isas = 0;  /* 0 = "unspecified" */
   unsigned int machs = 0; /* 0 = "unspecified" */
   enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+  enum cgen_endian insn_endian = CGEN_ENDIAN_UNKNOWN;
   va_list ap;
 
   if (! init_p)
@@ -2097,6 +2099,9 @@ iq2000_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
 	case CGEN_CPU_OPEN_ENDIAN :
 	  endian = va_arg (ap, enum cgen_endian);
 	  break;
+	case CGEN_CPU_OPEN_INSN_ENDIAN :
+	  insn_endian = va_arg (ap, enum cgen_endian);
+	  break;
 	default :
 	  opcodes_error_handler
 	    (/* xgettext:c-format */
@@ -2126,11 +2131,8 @@ iq2000_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   cd->isas = cgen_bitset_copy (isas);
   cd->machs = machs;
   cd->endian = endian;
-  /* FIXME: for the sparc case we can determine insn-endianness statically.
-     The worry here is where both data and insn endian can be independently
-     chosen, in which case this function will need another argument.
-     Actually, will want to allow for more arguments in the future anyway.  */
-  cd->insn_endian = endian;
+  if (insn_endian == CGEN_ENDIAN_UNKNOWN)
+    cd->insn_endian = endian;
 
   /* Table (re)builder.  */
   cd->rebuild_tables = iq2000_cgen_rebuild_tables;
@@ -2180,10 +2182,18 @@ iq2000_cgen_cpu_close (CGEN_CPU_DESC cd)
 	  regfree (CGEN_INSN_RX (insns));
     }
 
-  free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
-  free ((CGEN_INSN *) cd->insn_table.init_entries);
-  free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
-  free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+  if (cd->macro_insn_table.init_entries)
+    free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
+
+  if (cd->insn_table.init_entries)
+    free ((CGEN_INSN *) cd->insn_table.init_entries);
+
+  if (cd->hw_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
+
+  if (cd->operand_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+
   free (cd);
 }
 
diff --git a/opcodes/iq2000-dis.c b/opcodes/iq2000-dis.c
index 64f18aea2c..3aab139c51 100644
--- a/opcodes/iq2000-dis.c
+++ b/opcodes/iq2000-dis.c
@@ -493,6 +493,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -505,12 +506,16 @@ print_insn_iq2000 (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -576,9 +581,11 @@ print_insn_iq2000 (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = iq2000_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
diff --git a/opcodes/lm32-desc.c b/opcodes/lm32-desc.c
index 7470c3f9f1..9ea02502c9 100644
--- a/opcodes/lm32-desc.c
+++ b/opcodes/lm32-desc.c
@@ -1032,6 +1032,7 @@ lm32_cgen_rebuild_tables (CGEN_CPU_TABLE *cd)
    CGEN_CPU_OPEN_MACHS:   bitmap of values in enum mach_attr
    CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
    CGEN_CPU_OPEN_ENDIAN:  specify endian choice
+   CGEN_CPU_OPEN_INSN_ENDIAN: specify instruction endian choice
    CGEN_CPU_OPEN_END:     terminates arguments
 
    ??? Simultaneous multiple isas might not make sense, but it's not (yet)
@@ -1045,6 +1046,7 @@ lm32_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   CGEN_BITSET *isas = 0;  /* 0 = "unspecified" */
   unsigned int machs = 0; /* 0 = "unspecified" */
   enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+  enum cgen_endian insn_endian = CGEN_ENDIAN_UNKNOWN;
   va_list ap;
 
   if (! init_p)
@@ -1079,6 +1081,9 @@ lm32_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
 	case CGEN_CPU_OPEN_ENDIAN :
 	  endian = va_arg (ap, enum cgen_endian);
 	  break;
+	case CGEN_CPU_OPEN_INSN_ENDIAN :
+	  insn_endian = va_arg (ap, enum cgen_endian);
+	  break;
 	default :
 	  opcodes_error_handler
 	    (/* xgettext:c-format */
@@ -1108,11 +1113,8 @@ lm32_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   cd->isas = cgen_bitset_copy (isas);
   cd->machs = machs;
   cd->endian = endian;
-  /* FIXME: for the sparc case we can determine insn-endianness statically.
-     The worry here is where both data and insn endian can be independently
-     chosen, in which case this function will need another argument.
-     Actually, will want to allow for more arguments in the future anyway.  */
-  cd->insn_endian = endian;
+  if (insn_endian == CGEN_ENDIAN_UNKNOWN)
+    cd->insn_endian = endian;
 
   /* Table (re)builder.  */
   cd->rebuild_tables = lm32_cgen_rebuild_tables;
@@ -1162,10 +1164,18 @@ lm32_cgen_cpu_close (CGEN_CPU_DESC cd)
 	  regfree (CGEN_INSN_RX (insns));
     }
 
-  free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
-  free ((CGEN_INSN *) cd->insn_table.init_entries);
-  free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
-  free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+  if (cd->macro_insn_table.init_entries)
+    free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
+
+  if (cd->insn_table.init_entries)
+    free ((CGEN_INSN *) cd->insn_table.init_entries);
+
+  if (cd->hw_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
+
+  if (cd->operand_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+
   free (cd);
 }
 
diff --git a/opcodes/lm32-dis.c b/opcodes/lm32-dis.c
index 7c53c400b6..7ba84b3a66 100644
--- a/opcodes/lm32-dis.c
+++ b/opcodes/lm32-dis.c
@@ -451,6 +451,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -463,12 +464,16 @@ print_insn_lm32 (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -534,9 +539,11 @@ print_insn_lm32 (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = lm32_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
diff --git a/opcodes/m32c-desc.c b/opcodes/m32c-desc.c
index d79d2f49df..ac158e44c2 100644
--- a/opcodes/m32c-desc.c
+++ b/opcodes/m32c-desc.c
@@ -63063,6 +63063,7 @@ m32c_cgen_rebuild_tables (CGEN_CPU_TABLE *cd)
    CGEN_CPU_OPEN_MACHS:   bitmap of values in enum mach_attr
    CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
    CGEN_CPU_OPEN_ENDIAN:  specify endian choice
+   CGEN_CPU_OPEN_INSN_ENDIAN: specify instruction endian choice
    CGEN_CPU_OPEN_END:     terminates arguments
 
    ??? Simultaneous multiple isas might not make sense, but it's not (yet)
@@ -63076,6 +63077,7 @@ m32c_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   CGEN_BITSET *isas = 0;  /* 0 = "unspecified" */
   unsigned int machs = 0; /* 0 = "unspecified" */
   enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+  enum cgen_endian insn_endian = CGEN_ENDIAN_UNKNOWN;
   va_list ap;
 
   if (! init_p)
@@ -63110,6 +63112,9 @@ m32c_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
 	case CGEN_CPU_OPEN_ENDIAN :
 	  endian = va_arg (ap, enum cgen_endian);
 	  break;
+	case CGEN_CPU_OPEN_INSN_ENDIAN :
+	  insn_endian = va_arg (ap, enum cgen_endian);
+	  break;
 	default :
 	  opcodes_error_handler
 	    (/* xgettext:c-format */
@@ -63139,11 +63144,8 @@ m32c_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   cd->isas = cgen_bitset_copy (isas);
   cd->machs = machs;
   cd->endian = endian;
-  /* FIXME: for the sparc case we can determine insn-endianness statically.
-     The worry here is where both data and insn endian can be independently
-     chosen, in which case this function will need another argument.
-     Actually, will want to allow for more arguments in the future anyway.  */
-  cd->insn_endian = endian;
+  if (insn_endian == CGEN_ENDIAN_UNKNOWN)
+    cd->insn_endian = endian;
 
   /* Table (re)builder.  */
   cd->rebuild_tables = m32c_cgen_rebuild_tables;
@@ -63193,10 +63195,18 @@ m32c_cgen_cpu_close (CGEN_CPU_DESC cd)
 	  regfree (CGEN_INSN_RX (insns));
     }
 
-  free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
-  free ((CGEN_INSN *) cd->insn_table.init_entries);
-  free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
-  free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+  if (cd->macro_insn_table.init_entries)
+    free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
+
+  if (cd->insn_table.init_entries)
+    free ((CGEN_INSN *) cd->insn_table.init_entries);
+
+  if (cd->hw_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
+
+  if (cd->operand_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+
   free (cd);
 }
 
diff --git a/opcodes/m32c-dis.c b/opcodes/m32c-dis.c
index 9df688e943..41afca3cc0 100644
--- a/opcodes/m32c-dis.c
+++ b/opcodes/m32c-dis.c
@@ -1195,6 +1195,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -1207,12 +1208,16 @@ print_insn_m32c (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -1278,9 +1283,11 @@ print_insn_m32c (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = m32c_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
diff --git a/opcodes/m32r-desc.c b/opcodes/m32r-desc.c
index 142cea3408..d1ee2e8bdf 100644
--- a/opcodes/m32r-desc.c
+++ b/opcodes/m32r-desc.c
@@ -1395,6 +1395,7 @@ m32r_cgen_rebuild_tables (CGEN_CPU_TABLE *cd)
    CGEN_CPU_OPEN_MACHS:   bitmap of values in enum mach_attr
    CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
    CGEN_CPU_OPEN_ENDIAN:  specify endian choice
+   CGEN_CPU_OPEN_INSN_ENDIAN: specify instruction endian choice
    CGEN_CPU_OPEN_END:     terminates arguments
 
    ??? Simultaneous multiple isas might not make sense, but it's not (yet)
@@ -1408,6 +1409,7 @@ m32r_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   CGEN_BITSET *isas = 0;  /* 0 = "unspecified" */
   unsigned int machs = 0; /* 0 = "unspecified" */
   enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+  enum cgen_endian insn_endian = CGEN_ENDIAN_UNKNOWN;
   va_list ap;
 
   if (! init_p)
@@ -1442,6 +1444,9 @@ m32r_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
 	case CGEN_CPU_OPEN_ENDIAN :
 	  endian = va_arg (ap, enum cgen_endian);
 	  break;
+	case CGEN_CPU_OPEN_INSN_ENDIAN :
+	  insn_endian = va_arg (ap, enum cgen_endian);
+	  break;
 	default :
 	  opcodes_error_handler
 	    (/* xgettext:c-format */
@@ -1471,11 +1476,8 @@ m32r_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   cd->isas = cgen_bitset_copy (isas);
   cd->machs = machs;
   cd->endian = endian;
-  /* FIXME: for the sparc case we can determine insn-endianness statically.
-     The worry here is where both data and insn endian can be independently
-     chosen, in which case this function will need another argument.
-     Actually, will want to allow for more arguments in the future anyway.  */
-  cd->insn_endian = endian;
+  if (insn_endian == CGEN_ENDIAN_UNKNOWN)
+    cd->insn_endian = endian;
 
   /* Table (re)builder.  */
   cd->rebuild_tables = m32r_cgen_rebuild_tables;
@@ -1525,10 +1527,18 @@ m32r_cgen_cpu_close (CGEN_CPU_DESC cd)
 	  regfree (CGEN_INSN_RX (insns));
     }
 
-  free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
-  free ((CGEN_INSN *) cd->insn_table.init_entries);
-  free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
-  free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+  if (cd->macro_insn_table.init_entries)
+    free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
+
+  if (cd->insn_table.init_entries)
+    free ((CGEN_INSN *) cd->insn_table.init_entries);
+
+  if (cd->hw_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
+
+  if (cd->operand_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+
   free (cd);
 }
 
diff --git a/opcodes/m32r-dis.c b/opcodes/m32r-dis.c
index 59402220f9..e666739801 100644
--- a/opcodes/m32r-dis.c
+++ b/opcodes/m32r-dis.c
@@ -583,6 +583,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -595,12 +596,16 @@ print_insn_m32r (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -666,9 +671,11 @@ print_insn_m32r (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = m32r_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
diff --git a/opcodes/mep-desc.c b/opcodes/mep-desc.c
index 305f744707..e2e62b7be7 100644
--- a/opcodes/mep-desc.c
+++ b/opcodes/mep-desc.c
@@ -6256,6 +6256,7 @@ mep_cgen_rebuild_tables (CGEN_CPU_TABLE *cd)
    CGEN_CPU_OPEN_MACHS:   bitmap of values in enum mach_attr
    CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
    CGEN_CPU_OPEN_ENDIAN:  specify endian choice
+   CGEN_CPU_OPEN_INSN_ENDIAN: specify instruction endian choice
    CGEN_CPU_OPEN_END:     terminates arguments
 
    ??? Simultaneous multiple isas might not make sense, but it's not (yet)
@@ -6269,6 +6270,7 @@ mep_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   CGEN_BITSET *isas = 0;  /* 0 = "unspecified" */
   unsigned int machs = 0; /* 0 = "unspecified" */
   enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+  enum cgen_endian insn_endian = CGEN_ENDIAN_UNKNOWN;
   va_list ap;
 
   if (! init_p)
@@ -6303,6 +6305,9 @@ mep_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
 	case CGEN_CPU_OPEN_ENDIAN :
 	  endian = va_arg (ap, enum cgen_endian);
 	  break;
+	case CGEN_CPU_OPEN_INSN_ENDIAN :
+	  insn_endian = va_arg (ap, enum cgen_endian);
+	  break;
 	default :
 	  opcodes_error_handler
 	    (/* xgettext:c-format */
@@ -6332,11 +6337,8 @@ mep_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   cd->isas = cgen_bitset_copy (isas);
   cd->machs = machs;
   cd->endian = endian;
-  /* FIXME: for the sparc case we can determine insn-endianness statically.
-     The worry here is where both data and insn endian can be independently
-     chosen, in which case this function will need another argument.
-     Actually, will want to allow for more arguments in the future anyway.  */
-  cd->insn_endian = endian;
+  if (insn_endian == CGEN_ENDIAN_UNKNOWN)
+    cd->insn_endian = endian;
 
   /* Table (re)builder.  */
   cd->rebuild_tables = mep_cgen_rebuild_tables;
@@ -6386,10 +6388,18 @@ mep_cgen_cpu_close (CGEN_CPU_DESC cd)
 	  regfree (CGEN_INSN_RX (insns));
     }
 
-  free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
-  free ((CGEN_INSN *) cd->insn_table.init_entries);
-  free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
-  free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+  if (cd->macro_insn_table.init_entries)
+    free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
+
+  if (cd->insn_table.init_entries)
+    free ((CGEN_INSN *) cd->insn_table.init_entries);
+
+  if (cd->hw_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
+
+  if (cd->operand_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+
   free (cd);
 }
 
diff --git a/opcodes/mep-dis.c b/opcodes/mep-dis.c
index 71da5a73ab..d2df588303 100644
--- a/opcodes/mep-dis.c
+++ b/opcodes/mep-dis.c
@@ -1491,6 +1491,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -1503,12 +1504,16 @@ print_insn_mep (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -1574,9 +1579,11 @@ print_insn_mep (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = mep_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
diff --git a/opcodes/mt-desc.c b/opcodes/mt-desc.c
index ca1f50c4af..44d1f81acc 100644
--- a/opcodes/mt-desc.c
+++ b/opcodes/mt-desc.c
@@ -1176,6 +1176,7 @@ mt_cgen_rebuild_tables (CGEN_CPU_TABLE *cd)
    CGEN_CPU_OPEN_MACHS:   bitmap of values in enum mach_attr
    CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
    CGEN_CPU_OPEN_ENDIAN:  specify endian choice
+   CGEN_CPU_OPEN_INSN_ENDIAN: specify instruction endian choice
    CGEN_CPU_OPEN_END:     terminates arguments
 
    ??? Simultaneous multiple isas might not make sense, but it's not (yet)
@@ -1189,6 +1190,7 @@ mt_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   CGEN_BITSET *isas = 0;  /* 0 = "unspecified" */
   unsigned int machs = 0; /* 0 = "unspecified" */
   enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+  enum cgen_endian insn_endian = CGEN_ENDIAN_UNKNOWN;
   va_list ap;
 
   if (! init_p)
@@ -1223,6 +1225,9 @@ mt_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
 	case CGEN_CPU_OPEN_ENDIAN :
 	  endian = va_arg (ap, enum cgen_endian);
 	  break;
+	case CGEN_CPU_OPEN_INSN_ENDIAN :
+	  insn_endian = va_arg (ap, enum cgen_endian);
+	  break;
 	default :
 	  opcodes_error_handler
 	    (/* xgettext:c-format */
@@ -1252,11 +1257,8 @@ mt_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   cd->isas = cgen_bitset_copy (isas);
   cd->machs = machs;
   cd->endian = endian;
-  /* FIXME: for the sparc case we can determine insn-endianness statically.
-     The worry here is where both data and insn endian can be independently
-     chosen, in which case this function will need another argument.
-     Actually, will want to allow for more arguments in the future anyway.  */
-  cd->insn_endian = endian;
+  if (insn_endian == CGEN_ENDIAN_UNKNOWN)
+    cd->insn_endian = endian;
 
   /* Table (re)builder.  */
   cd->rebuild_tables = mt_cgen_rebuild_tables;
@@ -1306,10 +1308,18 @@ mt_cgen_cpu_close (CGEN_CPU_DESC cd)
 	  regfree (CGEN_INSN_RX (insns));
     }
 
-  free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
-  free ((CGEN_INSN *) cd->insn_table.init_entries);
-  free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
-  free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+  if (cd->macro_insn_table.init_entries)
+    free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
+
+  if (cd->insn_table.init_entries)
+    free ((CGEN_INSN *) cd->insn_table.init_entries);
+
+  if (cd->hw_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
+
+  if (cd->operand_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+
   free (cd);
 }
 
diff --git a/opcodes/mt-dis.c b/opcodes/mt-dis.c
index 2cbca8cbf7..3d552e8acb 100644
--- a/opcodes/mt-dis.c
+++ b/opcodes/mt-dis.c
@@ -594,6 +594,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -606,12 +607,16 @@ print_insn_mt (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -677,9 +682,11 @@ print_insn_mt (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = mt_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
diff --git a/opcodes/or1k-desc.c b/opcodes/or1k-desc.c
index 8bf986d9e0..dcbe4c0884 100644
--- a/opcodes/or1k-desc.c
+++ b/opcodes/or1k-desc.c
@@ -2070,6 +2070,7 @@ or1k_cgen_rebuild_tables (CGEN_CPU_TABLE *cd)
    CGEN_CPU_OPEN_MACHS:   bitmap of values in enum mach_attr
    CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
    CGEN_CPU_OPEN_ENDIAN:  specify endian choice
+   CGEN_CPU_OPEN_INSN_ENDIAN: specify instruction endian choice
    CGEN_CPU_OPEN_END:     terminates arguments
 
    ??? Simultaneous multiple isas might not make sense, but it's not (yet)
@@ -2083,6 +2084,7 @@ or1k_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   CGEN_BITSET *isas = 0;  /* 0 = "unspecified" */
   unsigned int machs = 0; /* 0 = "unspecified" */
   enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+  enum cgen_endian insn_endian = CGEN_ENDIAN_UNKNOWN;
   va_list ap;
 
   if (! init_p)
@@ -2117,6 +2119,9 @@ or1k_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
 	case CGEN_CPU_OPEN_ENDIAN :
 	  endian = va_arg (ap, enum cgen_endian);
 	  break;
+	case CGEN_CPU_OPEN_INSN_ENDIAN :
+	  insn_endian = va_arg (ap, enum cgen_endian);
+	  break;
 	default :
 	  opcodes_error_handler
 	    (/* xgettext:c-format */
@@ -2146,11 +2151,8 @@ or1k_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   cd->isas = cgen_bitset_copy (isas);
   cd->machs = machs;
   cd->endian = endian;
-  /* FIXME: for the sparc case we can determine insn-endianness statically.
-     The worry here is where both data and insn endian can be independently
-     chosen, in which case this function will need another argument.
-     Actually, will want to allow for more arguments in the future anyway.  */
-  cd->insn_endian = endian;
+  if (insn_endian == CGEN_ENDIAN_UNKNOWN)
+    cd->insn_endian = endian;
 
   /* Table (re)builder.  */
   cd->rebuild_tables = or1k_cgen_rebuild_tables;
@@ -2200,10 +2202,18 @@ or1k_cgen_cpu_close (CGEN_CPU_DESC cd)
 	  regfree (CGEN_INSN_RX (insns));
     }
 
-  free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
-  free ((CGEN_INSN *) cd->insn_table.init_entries);
-  free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
-  free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+  if (cd->macro_insn_table.init_entries)
+    free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
+
+  if (cd->insn_table.init_entries)
+    free ((CGEN_INSN *) cd->insn_table.init_entries);
+
+  if (cd->hw_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
+
+  if (cd->operand_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+
   free (cd);
 }
 
diff --git a/opcodes/or1k-dis.c b/opcodes/or1k-dis.c
index dcb02c08ca..d350d2bbae 100644
--- a/opcodes/or1k-dis.c
+++ b/opcodes/or1k-dis.c
@@ -478,6 +478,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -490,12 +491,16 @@ print_insn_or1k (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -561,9 +566,11 @@ print_insn_or1k (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = or1k_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
diff --git a/opcodes/xc16x-desc.c b/opcodes/xc16x-desc.c
index 621f2eb738..7495d16bd3 100644
--- a/opcodes/xc16x-desc.c
+++ b/opcodes/xc16x-desc.c
@@ -3379,6 +3379,7 @@ xc16x_cgen_rebuild_tables (CGEN_CPU_TABLE *cd)
    CGEN_CPU_OPEN_MACHS:   bitmap of values in enum mach_attr
    CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
    CGEN_CPU_OPEN_ENDIAN:  specify endian choice
+   CGEN_CPU_OPEN_INSN_ENDIAN: specify instruction endian choice
    CGEN_CPU_OPEN_END:     terminates arguments
 
    ??? Simultaneous multiple isas might not make sense, but it's not (yet)
@@ -3392,6 +3393,7 @@ xc16x_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   CGEN_BITSET *isas = 0;  /* 0 = "unspecified" */
   unsigned int machs = 0; /* 0 = "unspecified" */
   enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+  enum cgen_endian insn_endian = CGEN_ENDIAN_UNKNOWN;
   va_list ap;
 
   if (! init_p)
@@ -3426,6 +3428,9 @@ xc16x_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
 	case CGEN_CPU_OPEN_ENDIAN :
 	  endian = va_arg (ap, enum cgen_endian);
 	  break;
+	case CGEN_CPU_OPEN_INSN_ENDIAN :
+	  insn_endian = va_arg (ap, enum cgen_endian);
+	  break;
 	default :
 	  opcodes_error_handler
 	    (/* xgettext:c-format */
@@ -3455,11 +3460,8 @@ xc16x_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   cd->isas = cgen_bitset_copy (isas);
   cd->machs = machs;
   cd->endian = endian;
-  /* FIXME: for the sparc case we can determine insn-endianness statically.
-     The worry here is where both data and insn endian can be independently
-     chosen, in which case this function will need another argument.
-     Actually, will want to allow for more arguments in the future anyway.  */
-  cd->insn_endian = endian;
+  if (insn_endian == CGEN_ENDIAN_UNKNOWN)
+    cd->insn_endian = endian;
 
   /* Table (re)builder.  */
   cd->rebuild_tables = xc16x_cgen_rebuild_tables;
@@ -3509,10 +3511,18 @@ xc16x_cgen_cpu_close (CGEN_CPU_DESC cd)
 	  regfree (CGEN_INSN_RX (insns));
     }
 
-  free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
-  free ((CGEN_INSN *) cd->insn_table.init_entries);
-  free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
-  free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+  if (cd->macro_insn_table.init_entries)
+    free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
+
+  if (cd->insn_table.init_entries)
+    free ((CGEN_INSN *) cd->insn_table.init_entries);
+
+  if (cd->hw_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
+
+  if (cd->operand_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+
   free (cd);
 }
 
diff --git a/opcodes/xc16x-dis.c b/opcodes/xc16x-dis.c
index 84bc1e02ee..2cf926b68f 100644
--- a/opcodes/xc16x-dis.c
+++ b/opcodes/xc16x-dis.c
@@ -724,6 +724,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -736,12 +737,16 @@ print_insn_xc16x (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -807,9 +812,11 @@ print_insn_xc16x (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = xc16x_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
diff --git a/opcodes/xstormy16-desc.c b/opcodes/xstormy16-desc.c
index c1669c06e6..feecd8e282 100644
--- a/opcodes/xstormy16-desc.c
+++ b/opcodes/xstormy16-desc.c
@@ -1347,6 +1347,7 @@ xstormy16_cgen_rebuild_tables (CGEN_CPU_TABLE *cd)
    CGEN_CPU_OPEN_MACHS:   bitmap of values in enum mach_attr
    CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
    CGEN_CPU_OPEN_ENDIAN:  specify endian choice
+   CGEN_CPU_OPEN_INSN_ENDIAN: specify instruction endian choice
    CGEN_CPU_OPEN_END:     terminates arguments
 
    ??? Simultaneous multiple isas might not make sense, but it's not (yet)
@@ -1360,6 +1361,7 @@ xstormy16_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   CGEN_BITSET *isas = 0;  /* 0 = "unspecified" */
   unsigned int machs = 0; /* 0 = "unspecified" */
   enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+  enum cgen_endian insn_endian = CGEN_ENDIAN_UNKNOWN;
   va_list ap;
 
   if (! init_p)
@@ -1394,6 +1396,9 @@ xstormy16_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
 	case CGEN_CPU_OPEN_ENDIAN :
 	  endian = va_arg (ap, enum cgen_endian);
 	  break;
+	case CGEN_CPU_OPEN_INSN_ENDIAN :
+	  insn_endian = va_arg (ap, enum cgen_endian);
+	  break;
 	default :
 	  opcodes_error_handler
 	    (/* xgettext:c-format */
@@ -1423,11 +1428,8 @@ xstormy16_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
   cd->isas = cgen_bitset_copy (isas);
   cd->machs = machs;
   cd->endian = endian;
-  /* FIXME: for the sparc case we can determine insn-endianness statically.
-     The worry here is where both data and insn endian can be independently
-     chosen, in which case this function will need another argument.
-     Actually, will want to allow for more arguments in the future anyway.  */
-  cd->insn_endian = endian;
+  if (insn_endian == CGEN_ENDIAN_UNKNOWN)
+    cd->insn_endian = endian;
 
   /* Table (re)builder.  */
   cd->rebuild_tables = xstormy16_cgen_rebuild_tables;
@@ -1477,10 +1479,18 @@ xstormy16_cgen_cpu_close (CGEN_CPU_DESC cd)
 	  regfree (CGEN_INSN_RX (insns));
     }
 
-  free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
-  free ((CGEN_INSN *) cd->insn_table.init_entries);
-  free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
-  free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+  if (cd->macro_insn_table.init_entries)
+    free ((CGEN_INSN *) cd->macro_insn_table.init_entries);
+
+  if (cd->insn_table.init_entries)
+    free ((CGEN_INSN *) cd->insn_table.init_entries);
+
+  if (cd->hw_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
+
+  if (cd->operand_table.entries)
+    free ((CGEN_HW_ENTRY *) cd->operand_table.entries);
+
   free (cd);
 }
 
diff --git a/opcodes/xstormy16-dis.c b/opcodes/xstormy16-dis.c
index 07e025fd3b..8382c3da85 100644
--- a/opcodes/xstormy16-dis.c
+++ b/opcodes/xstormy16-dis.c
@@ -472,6 +472,7 @@ typedef struct cpu_desc_list
   CGEN_BITSET *isa;
   int mach;
   int endian;
+  int insn_endian;
   CGEN_CPU_DESC cd;
 } cpu_desc_list;
 
@@ -484,12 +485,16 @@ print_insn_xstormy16 (bfd_vma pc, disassemble_info *info)
   static CGEN_BITSET *prev_isa;
   static int prev_mach;
   static int prev_endian;
+  static int prev_insn_endian;
   int length;
   CGEN_BITSET *isa;
   int mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
 		: CGEN_ENDIAN_LITTLE);
+  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
+                     ? CGEN_ENDIAN_BIG
+                     : CGEN_ENDIAN_LITTLE);
   enum bfd_architecture arch;
 
   /* ??? gdb will set mach but leave the architecture as "unknown" */
@@ -555,9 +560,11 @@ print_insn_xstormy16 (bfd_vma pc, disassemble_info *info)
       prev_isa = cgen_bitset_copy (isa);
       prev_mach = mach;
       prev_endian = endian;
+      prev_insn_endian = insn_endian;
       cd = xstormy16_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
+                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
 				 CGEN_CPU_OPEN_END);
       if (!cd)
 	abort ();
-- 
2.25.0.2.g232378479e



More information about the Binutils mailing list