[v5] Add support for nanoMIPS architecture

Message ID 20230505092316.1046472-1-aleksandar.rikalo@syrmia.com
State Accepted
Headers
Series [v5] Add support for nanoMIPS architecture |

Checks

Context Check Description
snail/binutils-gdb-check success Github commit url

Commit Message

Aleksandar Rikalo May 5, 2023, 9:23 a.m. UTC
  Add a subset of the functionality required for GDB.

Co-Authored-By: Jaydeep Patil <jaydeep.patil@imgtec.com>
Co-Authored-By: Matthew Fortune <matthew.fortune@imgtec.com>
Co-Authored-By: Maciej W. Rozycki <macro@mips.com>
Co-Authored-By: Stefan Markovic <stefan.markovic@mips.com>
Co-Authored-By: Sara Graovac <sara.graovac@syrmia.com>
Co-Authored-By: Dragan Mladjenovic <dragan.mladjenovic@syrmia.com>
---
 bfd/Makefile.am            |   19 +
 bfd/Makefile.in            |   22 +
 bfd/archures.c             |    5 +
 bfd/bfd-in2.h              |   74 ++
 bfd/config.bfd             |    6 +
 bfd/configure              |    4 +
 bfd/configure.ac           |    4 +
 bfd/cpu-nanomips.c         |   61 ++
 bfd/elf-bfd.h              |    1 +
 bfd/elfnn-nanomips.c       | 1423 ++++++++++++++++++++++++++++++++++
 bfd/elfxx-mips.h           |    5 +
 bfd/elfxx-nanomips.c       |  794 +++++++++++++++++++
 bfd/elfxx-nanomips.h       |   54 ++
 bfd/libbfd.h               |   69 ++
 bfd/reloc.c                |  140 ++++
 bfd/targets.c              |   11 +
 binutils/readelf.c         |  502 +++++++++++-
 include/dis-asm.h          |   11 +
 include/elf/common.h       |    2 +-
 include/elf/mips-common.h  |   41 +
 include/elf/nanomips.h     |  260 +++++++
 include/opcode/nanomips.h  | 1453 +++++++++++++++++++++++++++++++++++
 opcodes/Makefile.am        |    2 +
 opcodes/Makefile.in        |   10 +
 opcodes/configure          |    1 +
 opcodes/configure.ac       |    1 +
 opcodes/dis-buf.c          |    9 +
 opcodes/dis-init.c         |    1 +
 opcodes/disassemble.c      |   13 +
 opcodes/nanomips-dis.c     | 1470 ++++++++++++++++++++++++++++++++++++
 opcodes/nanomips-formats.h |  265 +++++++
 opcodes/nanomips-opc.c     | 1073 ++++++++++++++++++++++++++
 32 files changed, 7804 insertions(+), 2 deletions(-)
 create mode 100644 bfd/cpu-nanomips.c
 create mode 100644 bfd/elfnn-nanomips.c
 create mode 100644 bfd/elfxx-nanomips.c
 create mode 100644 bfd/elfxx-nanomips.h
 create mode 100644 include/elf/mips-common.h
 create mode 100644 include/elf/nanomips.h
 create mode 100644 include/opcode/nanomips.h
 create mode 100644 opcodes/nanomips-dis.c
 create mode 100644 opcodes/nanomips-formats.h
 create mode 100644 opcodes/nanomips-opc.c
  

Comments

Tsing May 8, 2023, 9:42 a.m. UTC | #1
Hi.

Results of tests on the patch are all passed, 
but the size of the patch is too large. 
Is it possible to split the patch into smaller ones?

Thanks.
Tsing

> Add a subset of the functionality required for GDB.
  

Patch

diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 5c5fdefd3b8..8f452f856f7 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -142,6 +142,7 @@  ALL_MACHINES = \
 	cpu-moxie.lo \
 	cpu-msp430.lo \
 	cpu-mt.lo \
+	cpu-nanomips.lo \
 	cpu-nds32.lo \
 	cpu-nfp.lo \
 	cpu-nios2.lo \
@@ -547,6 +548,7 @@  BFD64_BACKENDS = \
 	coff64-rs6000.lo \
 	elf32-ia64.lo \
 	elf32-mips.lo \
+	elf32-nanomips.lo \
 	elf32-score.lo \
 	elf32-score7.lo \
 	elf64-alpha.lo \
@@ -564,6 +566,8 @@  BFD64_BACKENDS = \
 	elfxx-mips.lo \
 	elf64-mmix.lo \
 	elf64-nfp.lo \
+	elf64-nanomips.lo \
+	elfxx-nanomips.lo \
 	elf64-ppc.lo \
 	elf32-riscv.lo \
 	elf64-riscv.lo \
@@ -607,6 +611,7 @@  BFD64_BACKENDS_CFILES = \
 	elf64-mips.c \
 	elf64-mmix.c \
 	elf64-nfp.c \
+	elf64-nanomips.c \
 	elf64-ppc.c \
 	elf64-s390.c \
 	elf64-sparc.c \
@@ -620,6 +625,7 @@  BFD64_BACKENDS_CFILES = \
 	elfxx-ia64.c \
 	elfxx-loongarch.c \
 	elfxx-mips.c \
+	elfxx-nanomips.c \
 	elfxx-riscv.c \
 	mach-o-aarch64.c \
 	mach-o-x86-64.c \
@@ -684,6 +690,7 @@  BUILD_CFILES = \
 	elf32-ia64.c elf64-ia64.c \
 	elf32-loongarch.c elf64-loongarch.c \
 	elf32-riscv.c elf64-riscv.c \
+	elf32-nanomips.c elf64-nanomips.c \
 	peigen.c pepigen.c pex64igen.c pe-aarch64igen.c pe-loongarch64igen.c
 
 CFILES = $(SOURCE_CFILES) $(BUILD_CFILES)
@@ -886,6 +893,18 @@  pe-loongarch64igen.c: peXXigen.c
 	$(AM_V_at)echo "#line 1 \"peXXigen.c\"" > $@
 	$(AM_V_GEN)$(SED) -e s/XX/peLoongArch64/g < $< >> $@
 
+elf32-nanomips.c : elfnn-nanomips.c
+	rm -f elf32-nanomips.c
+	echo "#line 1 \"$(srcdir)/elfnn-nanomips.c\"" > elf32-nanomips.new
+	sed -e s/NN/32/g < $(srcdir)/elfnn-nanomips.c >> elf32-nanomips.new
+	mv -f elf32-nanomips.new elf32-nanomips.c
+
+elf64-nanomips.c : elfnn-nanomips.c
+	rm -f elf64-nanomips.c
+	echo "#line 1 \"$(srcdir)/elfnn-nanomips.c\"" > elf64-nanomips.new
+	sed -e s/NN/64/g < $(srcdir)/elfnn-nanomips.c >> elf64-nanomips.new
+	mv -f elf64-nanomips.new elf64-nanomips.c
+
 host-aout.lo: Makefile
 
 # The following program can be used to generate a simple config file
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index 4edfedee924..64ff01733fd 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -597,6 +597,7 @@  ALL_MACHINES = \
 	cpu-moxie.lo \
 	cpu-msp430.lo \
 	cpu-mt.lo \
+	cpu-nanomips.lo \
 	cpu-nds32.lo \
 	cpu-nfp.lo \
 	cpu-nios2.lo \
@@ -1004,6 +1005,7 @@  BFD64_BACKENDS = \
 	coff64-rs6000.lo \
 	elf32-ia64.lo \
 	elf32-mips.lo \
+	elf32-nanomips.lo \
 	elf32-score.lo \
 	elf32-score7.lo \
 	elf64-alpha.lo \
@@ -1021,6 +1023,8 @@  BFD64_BACKENDS = \
 	elfxx-mips.lo \
 	elf64-mmix.lo \
 	elf64-nfp.lo \
+	elf64-nanomips.lo \
+	elfxx-nanomips.lo \
 	elf64-ppc.lo \
 	elf32-riscv.lo \
 	elf64-riscv.lo \
@@ -1064,6 +1068,7 @@  BFD64_BACKENDS_CFILES = \
 	elf64-mips.c \
 	elf64-mmix.c \
 	elf64-nfp.c \
+	elf64-nanomips.c \
 	elf64-ppc.c \
 	elf64-s390.c \
 	elf64-sparc.c \
@@ -1077,6 +1082,7 @@  BFD64_BACKENDS_CFILES = \
 	elfxx-ia64.c \
 	elfxx-loongarch.c \
 	elfxx-mips.c \
+	elfxx-nanomips.c \
 	elfxx-riscv.c \
 	mach-o-aarch64.c \
 	mach-o-x86-64.c \
@@ -1140,6 +1146,7 @@  BUILD_CFILES = \
 	elf32-ia64.c elf64-ia64.c \
 	elf32-loongarch.c elf64-loongarch.c \
 	elf32-riscv.c elf64-riscv.c \
+	elf32-nanomips.c elf64-nanomips.c \
 	peigen.c pepigen.c pex64igen.c pe-aarch64igen.c pe-loongarch64igen.c
 
 CFILES = $(SOURCE_CFILES) $(BUILD_CFILES)
@@ -1593,6 +1600,7 @@  distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-moxie.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-msp430.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-nanomips.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-nds32.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-nios2.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-or1k.Plo@am__quote@
@@ -1633,6 +1641,7 @@  distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-mips.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-mmix.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-nfp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-nanomips.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-ppc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-riscv.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-s390.Plo@am__quote@
@@ -1646,6 +1655,7 @@  distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-ia64.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-loongarch.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-mips.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-nanomips.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-riscv.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-sparc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-tilegx.Plo@am__quote@
@@ -2384,6 +2394,18 @@  pe-loongarch64igen.c: peXXigen.c
 	$(AM_V_at)echo "#line 1 \"peXXigen.c\"" > $@
 	$(AM_V_GEN)$(SED) -e s/XX/peLoongArch64/g < $< >> $@
 
+elf32-nanomips.c : elfnn-nanomips.c
+	rm -f elf32-nanomips.c
+	echo "#line 1 \"$(srcdir)/elfnn-nanomips.c\"" > elf32-nanomips.new
+	sed -e s/NN/32/g < $(srcdir)/elfnn-nanomips.c >> elf32-nanomips.new
+	mv -f elf32-nanomips.new elf32-nanomips.c
+
+elf64-nanomips.c : elfnn-nanomips.c
+	rm -f elf64-nanomips.c
+	echo "#line 1 \"$(srcdir)/elfnn-nanomips.c\"" > elf64-nanomips.new
+	sed -e s/NN/64/g < $(srcdir)/elfnn-nanomips.c >> elf64-nanomips.new
+	mv -f elf64-nanomips.new elf64-nanomips.c
+
 host-aout.lo: Makefile
 
 # The following program can be used to generate a simple config file
diff --git a/bfd/archures.c b/bfd/archures.c
index 6fe8701b412..5e5fd28e71d 100644
--- a/bfd/archures.c
+++ b/bfd/archures.c
@@ -563,6 +563,9 @@  DESCRIPTION
 .#define bfd_mach_amdgcn_gfx1030 0x036
 .#define bfd_mach_amdgcn_gfx1031 0x037
 .#define bfd_mach_amdgcn_gfx1032 0x038
+.  bfd_arch_nanomips,      {* nanoMIPS.  *}
+.#define bfd_mach_nanomipsisa32r6       32
+.#define bfd_mach_nanomipsisa64r6       64
 .  bfd_arch_last
 .  };
 */
@@ -663,6 +666,7 @@  extern const bfd_arch_info_type bfd_moxie_arch;
 extern const bfd_arch_info_type bfd_ft32_arch;
 extern const bfd_arch_info_type bfd_msp430_arch;
 extern const bfd_arch_info_type bfd_mt_arch;
+extern const bfd_arch_info_type bfd_nanomips_arch;
 extern const bfd_arch_info_type bfd_nds32_arch;
 extern const bfd_arch_info_type bfd_nfp_arch;
 extern const bfd_arch_info_type bfd_nios2_arch;
@@ -751,6 +755,7 @@  static const bfd_arch_info_type * const bfd_archures_list[] =
     &bfd_ft32_arch,
     &bfd_msp430_arch,
     &bfd_mt_arch,
+    &bfd_nanomips_arch,
     &bfd_nds32_arch,
     &bfd_nfp_arch,
     &bfd_nios2_arch,
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 7be18db20a8..98fd0bf2d8f 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -1816,6 +1816,9 @@  enum bfd_architecture
 #define bfd_mach_amdgcn_gfx1030 0x036
 #define bfd_mach_amdgcn_gfx1031 0x037
 #define bfd_mach_amdgcn_gfx1032 0x038
+  bfd_arch_nanomips,      /* nanoMIPS.  */
+#define bfd_mach_nanomipsisa32r6       32
+#define bfd_mach_nanomipsisa64r6       64
   bfd_arch_last
   };
 
@@ -3663,6 +3666,77 @@  to compensate for the borrow when the low bits are added.  */
   BFD_RELOC_MIPS_JUMP_SLOT,
 
 
+/* nanoMIPS relocations  */
+  BFD_RELOC_NANOMIPS_HI20,
+  BFD_RELOC_NANOMIPS_LO12,
+  BFD_RELOC_NANOMIPS_LO4_S2,
+  BFD_RELOC_NANOMIPS_IMM16,
+  BFD_RELOC_NANOMIPS_NEG12,
+  BFD_RELOC_NANOMIPS_GPREL7_S2,
+  BFD_RELOC_NANOMIPS_GPREL18,
+  BFD_RELOC_NANOMIPS_GPREL19_S2,
+  BFD_RELOC_NANOMIPS_GPREL16_S2,
+  BFD_RELOC_NANOMIPS_GPREL18_S3,
+  BFD_RELOC_NANOMIPS_4_PCREL_S1,
+  BFD_RELOC_NANOMIPS_7_PCREL_S1,
+  BFD_RELOC_NANOMIPS_10_PCREL_S1,
+  BFD_RELOC_NANOMIPS_11_PCREL_S1,
+  BFD_RELOC_NANOMIPS_14_PCREL_S1,
+  BFD_RELOC_NANOMIPS_21_PCREL_S1,
+  BFD_RELOC_NANOMIPS_25_PCREL_S1,
+  BFD_RELOC_NANOMIPS_PCREL_HI20,
+  BFD_RELOC_NANOMIPS_GOT_CALL,
+  BFD_RELOC_NANOMIPS_GOTPC_HI20,
+  BFD_RELOC_NANOMIPS_GOTPC_I32,
+  BFD_RELOC_NANOMIPS_GOT_LO12,
+  BFD_RELOC_NANOMIPS_GOT_DISP,
+  BFD_RELOC_NANOMIPS_GOT_PAGE,
+  BFD_RELOC_NANOMIPS_GOT_OFST,
+  BFD_RELOC_NANOMIPS_I32,
+  BFD_RELOC_NANOMIPS_GPREL_HI20,
+  BFD_RELOC_NANOMIPS_GPREL_LO12,
+  BFD_RELOC_NANOMIPS_TLS_GD,
+  BFD_RELOC_NANOMIPS_TLS_GD_I32,
+  BFD_RELOC_NANOMIPS_TLS_LD,
+  BFD_RELOC_NANOMIPS_TLS_LD_I32,
+  BFD_RELOC_NANOMIPS_TLS_DTPREL12,
+  BFD_RELOC_NANOMIPS_TLS_DTPREL16,
+  BFD_RELOC_NANOMIPS_TLS_DTPREL_I32,
+  BFD_RELOC_NANOMIPS_TLS_GOTTPREL,
+  BFD_RELOC_NANOMIPS_TLS_GOTTPREL_PC_I32,
+  BFD_RELOC_NANOMIPS_TLS_TPREL12,
+  BFD_RELOC_NANOMIPS_TLS_TPREL16,
+  BFD_RELOC_NANOMIPS_TLS_TPREL_I32,
+  BFD_RELOC_NANOMIPS_TLS_DTPMOD,
+  BFD_RELOC_NANOMIPS_TLS_DTPREL,
+  BFD_RELOC_NANOMIPS_TLS_TPREL,
+  BFD_RELOC_NANOMIPS_PC_I32,
+  BFD_RELOC_NANOMIPS_GPREL_I32,
+  BFD_RELOC_NANOMIPS_GPREL17_S1,
+  BFD_RELOC_NANOMIPS_NEG,
+  BFD_RELOC_NANOMIPS_ASHIFTR_1,
+  BFD_RELOC_NANOMIPS_UNSIGNED_8,
+  BFD_RELOC_NANOMIPS_UNSIGNED_16,
+  BFD_RELOC_NANOMIPS_SIGNED_8,
+  BFD_RELOC_NANOMIPS_SIGNED_16,
+  BFD_RELOC_NANOMIPS_EH,
+  BFD_RELOC_NANOMIPS_JUMP_SLOT,
+  BFD_RELOC_NANOMIPS_ALIGN,
+  BFD_RELOC_NANOMIPS_FILL,
+  BFD_RELOC_NANOMIPS_MAX,
+  BFD_RELOC_NANOMIPS_INSN32,
+  BFD_RELOC_NANOMIPS_INSN16,
+  BFD_RELOC_NANOMIPS_FIXED,
+  BFD_RELOC_NANOMIPS_RELAX,
+  BFD_RELOC_NANOMIPS_NORELAX,
+  BFD_RELOC_NANOMIPS_SAVERESTORE,
+  BFD_RELOC_NANOMIPS_JALR16,
+  BFD_RELOC_NANOMIPS_JALR32,
+  BFD_RELOC_NANOMIPS_COPY,
+  BFD_RELOC_NANOMIPS_SIGNED_9,
+  BFD_RELOC_NANOMIPS_JUMPTABLE_LOAD,
+
+
 /* Moxie ELF relocations.  */
   BFD_RELOC_MOXIE_10_PCREL,
 
diff --git a/bfd/config.bfd b/bfd/config.bfd
index 954837033c8..6f9324f89a8 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -202,6 +202,7 @@  m6812*|m68hc12*) targ_archs="bfd_m68hc12_arch bfd_m68hc11_arch bfd_m9s12x_arch b
 m68*)		 targ_archs=bfd_m68k_arch ;;
 microblaze*)	 targ_archs=bfd_microblaze_arch ;;
 mips*)		 targ_archs=bfd_mips_arch ;;
+nanomips*)	 targ_archs=bfd_nanomips_arch ;;
 nds32*)		 targ_archs=bfd_nds32_arch ;;
 nios2*)          targ_archs=bfd_nios2_arch ;;
 or1k*|or1knd*)	 targ_archs=bfd_or1k_arch ;;
@@ -1020,6 +1021,11 @@  case "${targ}" in
     targ_selvecs=msp430_elf32_ti_vec
     ;;
 
+  nanomips*-*-elf*)
+    targ_defvec=nanomips_elf32_le_vec
+    targ_selvecs="nanomips_elf32_be_vec nanomips_elf64_be_vec nanomips_elf64_le_vec"
+    ;;
+
   nds32*le-*-linux*)
     targ_defvec=nds32_elf32_linux_le_vec
     targ_selvecs=nds32_elf32_linux_be_vec
diff --git a/bfd/configure b/bfd/configure
index 41d280ef461..81cb3cfec49 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -13988,6 +13988,10 @@  do
     msp430_elf32_vec)		 tb="$tb elf32-msp430.lo elf32.lo $elf" ;;
     msp430_elf32_ti_vec)	 tb="$tb elf32-msp430.lo elf32.lo $elf" ;;
     mt_elf32_vec)		 tb="$tb elf32-mt.lo elf32.lo $elf" ;;
+    nanomips_elf32_be_vec)	 tb="$tb elf32-nanomips.lo elfxx-nanomips.lo elf32.lo $elf ecofflink.lo" ;;
+    nanomips_elf32_le_vec)	 tb="$tb elf32-nanomips.lo elfxx-nanomips.lo elf32.lo $elf ecofflink.lo" ;;
+    nanomips_elf64_be_vec)	 tb="$tb elf64-nanomips.lo elf64.lo elfxx-nanomips.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
+    nanomips_elf64_le_vec)	 tb="$tb elf64-nanomips.lo elf64.lo elfxx-nanomips.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
     nds32_elf32_be_vec)		 tb="$tb elf32-nds32.lo elf32.lo $elf" ;;
     nds32_elf32_le_vec)		 tb="$tb elf32-nds32.lo elf32.lo $elf" ;;
     nds32_elf32_linux_be_vec)	 tb="$tb elf32-nds32.lo elf32.lo $elf" ;;
diff --git a/bfd/configure.ac b/bfd/configure.ac
index f044616f4d9..b2c54704d48 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -555,6 +555,10 @@  do
     msp430_elf32_vec)		 tb="$tb elf32-msp430.lo elf32.lo $elf" ;;
     msp430_elf32_ti_vec)	 tb="$tb elf32-msp430.lo elf32.lo $elf" ;;
     mt_elf32_vec)		 tb="$tb elf32-mt.lo elf32.lo $elf" ;;
+    nanomips_elf32_be_vec)	 tb="$tb elf32-nanomips.lo elfxx-nanomips.lo elf32.lo $elf ecofflink.lo" ;;
+    nanomips_elf32_le_vec)	 tb="$tb elf32-nanomips.lo elfxx-nanomips.lo elf32.lo $elf ecofflink.lo" ;;
+    nanomips_elf64_be_vec)	 tb="$tb elf64-nanomips.lo elf64.lo elfxx-nanomips.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
+    nanomips_elf64_le_vec)	 tb="$tb elf64-nanomips.lo elf64.lo elfxx-nanomips.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
     nds32_elf32_be_vec)		 tb="$tb elf32-nds32.lo elf32.lo $elf" ;;
     nds32_elf32_le_vec)		 tb="$tb elf32-nds32.lo elf32.lo $elf" ;;
     nds32_elf32_linux_be_vec)	 tb="$tb elf32-nds32.lo elf32.lo $elf" ;;
diff --git a/bfd/cpu-nanomips.c b/bfd/cpu-nanomips.c
new file mode 100644
index 00000000000..2cd66786cfe
--- /dev/null
+++ b/bfd/cpu-nanomips.c
@@ -0,0 +1,61 @@ 
+/* bfd back-end for nanomips support
+   Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+   Written by Faraz Shahbazker <faraz.shahbazker@mips.com>
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+
+#define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT)     \
+  {                                                               \
+    BITS_WORD, /*  bits in a word */                              \
+    BITS_ADDR, /* bits in an address */                           \
+    8,         /* 8 bits in a byte */                             \
+    bfd_arch_nanomips,                                            \
+    NUMBER,                                                       \
+    "nanomips",                                                   \
+    PRINT,                                                        \
+    3,                                                            \
+    DEFAULT,                                                      \
+    bfd_default_compatible,                                       \
+    bfd_default_scan,                                             \
+    bfd_arch_default_fill,                                        \
+    NEXT,                                                         \
+    0 /* Maximum offset of a reloc from the start of an insn.  */ \
+  }
+
+enum
+{
+  I_nanomipsisa32r6,
+  I_nanomipsisa64r6,
+};
+
+#define NN(index) (&arch_info_struct[(index) + 1])
+
+static const bfd_arch_info_type arch_info_struct[] = {
+  N (32, 32, bfd_mach_nanomipsisa32r6, "nanomips:isa32r6", false,
+     NN (I_nanomipsisa32r6)),
+  N (64, 64, bfd_mach_nanomipsisa64r6, "nanomips:isa64r6", false,
+     0),
+};
+
+const bfd_arch_info_type bfd_nanomips_arch =
+N (32, 32, 0, "nanomips", true, &arch_info_struct[0]);
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 2a64a1e6a03..cbdc0d61758 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -554,6 +554,7 @@  enum elf_target_id
   MICROBLAZE_ELF_DATA,
   MIPS_ELF_DATA,
   MN10300_ELF_DATA,
+  NANOMIPS_ELF_DATA,
   NDS32_ELF_DATA,
   NIOS2_ELF_DATA,
   OR1K_ELF_DATA,
diff --git a/bfd/elfnn-nanomips.c b/bfd/elfnn-nanomips.c
new file mode 100644
index 00000000000..e134a51c5ee
--- /dev/null
+++ b/bfd/elfnn-nanomips.c
@@ -0,0 +1,1423 @@ 
+/* nanoMIPS-specific support for 32-bit ELF
+   Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+   Written by Faraz Shahbazker <faraz.shahbazker@mips.com>
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+
+/* This file handles nanoMIPS ELF targets.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "elfxx-nanomips.h"
+#include "elf/nanomips.h"
+
+#define ARCH_SIZE	NN
+
+#if ARCH_SIZE == 32
+/* Nonzero if ABFD is using the P32 ABI.  */
+#define ABI_P32_P(abfd) \
+  ((elf_elfheader (abfd)->e_flags & EF_NANOMIPS_ABI) != E_NANOMIPS_ABI_P64)
+#else /* ARCH_SIZE != 32 */
+/* Nonzero if ABFD is using the P64 ABI.  */
+#define ABI_P64_P(abfd) \
+  ((elf_elfheader (abfd)->e_flags & EF_NANOMIPS_ABI) != E_NANOMIPS_ABI_P32)
+#endif /* ARCH_SIZE == 32 */
+
+/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
+   from smaller values.  Start with zero, widen, *then* decrement.  */
+#define MINUS_ONE	(((bfd_vma)0) - 1)
+
+/* The relocation table used for SHT_RELA sections.  */
+
+static reloc_howto_type elfNN_nanomips_howto_table_rela[] = {
+  /* No relocation.  */
+  HOWTO (R_NANOMIPS_NONE,	/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_NONE",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* 32 bit relocation.  */
+  HOWTO (R_NANOMIPS_32,		/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_32",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* 64 bit relocation.  */
+  HOWTO (R_NANOMIPS_64, 	/* type */
+	 0,			/* rightshift */
+	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 64,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_64",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 MINUS_ONE,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Symbol address negation, can be composed for label differences.  */
+  HOWTO (R_NANOMIPS_NEG,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 64,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_negative_reloc, /* special_function */
+	 "R_NANOMIPS_NEG",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* A 5 bit shift field.  */
+  HOWTO (R_NANOMIPS_ASHIFTR_1,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_ASHIFTR_1", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  HOWTO (R_NANOMIPS_UNSIGNED_8, /* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 8,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_UNSIGNED_8", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xff,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  HOWTO (R_NANOMIPS_SIGNED_8,	/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 8,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_SIGNED_8",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xff,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  HOWTO (R_NANOMIPS_UNSIGNED_16, /* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_UNSIGNED_16", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  HOWTO (R_NANOMIPS_SIGNED_16,	/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_SIGNED_16", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  EMPTY_HOWTO (R_NANOMIPS_RELATIVE),
+  EMPTY_HOWTO (R_NANOMIPS_GLOBAL),
+
+  /* Lazy resolver jump slot.  */
+  HOWTO (R_NANOMIPS_JUMP_SLOT,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_JUMP_SLOT", /* name */
+	 false,			/* partial_inplace */
+	 0x0,         		/* src_mask */
+	 0x0,		        /* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Reserved for IFUNC support.  */
+  EMPTY_HOWTO (R_NANOMIPS_IRELATIVE),
+
+  HOWTO (R_NANOMIPS_PC25_S1,	/* type */
+	 1,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 25,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_PC25_S1",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x01ffffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_NANOMIPS_PC21_S1,	/* type */
+	 1,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 21,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_PC21_S1",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x0001ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_NANOMIPS_PC14_S1,	/* type */
+	 1,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 14,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_PC14_S1",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x00003fff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_NANOMIPS_PC11_S1,	/* type */
+	 1,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 11,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_PC11_S1",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x000007ff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_NANOMIPS_PC10_S1,	/* type */
+	 1,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 10,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_PC10_S1",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x000003ff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  /* This is for nanoMIPS branches.  */
+  HOWTO (R_NANOMIPS_PC7_S1,	/* type */
+	 1,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 7,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_PC7_S1",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x0000007f,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_NANOMIPS_PC4_S1,	/* type */
+	 1,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 4,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_PC4_S1",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x0000000f,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  /* GP relative reference.  */
+  HOWTO (R_NANOMIPS_GPREL19_S2,	/* type */
+	 2,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 19,			/* bitsize */
+	 false,			/* pc_relative */
+	 2,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GPREL19_S2",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x001ffffc,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* GP relative reference.  */
+  HOWTO (R_NANOMIPS_GPREL18_S3,	/* type */
+	 3,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 18,			/* bitsize */
+	 false,			/* pc_relative */
+	 3,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GPREL18_S3",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x001ffff8,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* GP relative reference.  */
+  HOWTO (R_NANOMIPS_GPREL18,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 18,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GPREL18",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x0003ffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* GP relative reference.  */
+  HOWTO (R_NANOMIPS_GPREL17_S1,	/* type */
+	 1,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 17,			/* bitsize */
+	 false,			/* pc_relative */
+	 1,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GPREL17_S1",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x0001fffe,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* GP relative reference.  */
+  HOWTO (R_NANOMIPS_GPREL16_S2,	/* type */
+	 2,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 false,			/* pc_relative */
+	 2,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GPREL16_S2",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x0003fffc,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* GP- and PC-relative relocations.  */
+  HOWTO (R_NANOMIPS_GPREL7_S2,	/* type */
+	 2,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 7,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GPREL7_S2", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x0000007f,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* High 20 bits of GP relative reference.  */
+  HOWTO (R_NANOMIPS_GPREL_HI20,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 20,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GPREL_HI20", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x001ffffd,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  HOWTO (R_NANOMIPS_PCHI20,	/* type */
+	 12,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 20,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_PCHI20", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x001ffffd,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  /* High 20 bits of symbol value.  */
+  HOWTO (R_NANOMIPS_HI20,	/* type */
+	 12,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 20,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_HI20",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x001ffffd,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Low 12 bits of symbol value.  */
+  HOWTO (R_NANOMIPS_LO12,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 12,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_LO12",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x00000fff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* High 32 bits of 64-bit address.  */
+  HOWTO (R_NANOMIPS_GPREL_I32,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GPREL_I32", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* High 32 bits of 64-bit address.  */
+  HOWTO (R_NANOMIPS_PC_I32,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_PC_I32",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Refers to low 32-bits of 48-bit instruction. The 32-bit value
+     is encoded as nanoMIPS instruction stream - so it will be
+     half-word swapped on little endian targets.  */
+  HOWTO (R_NANOMIPS_I32,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_I32",	/* name */
+	 false,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Displacement in the global offset table.  */
+  HOWTO (R_NANOMIPS_GOT_DISP,	/* type */
+	 2,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 19,			/* bitsize */
+	 false,			/* pc_relative */
+	 2,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GOT_DISP", /* name */
+	 false,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0x001ffffc,		/* dst_mask */
+	 false),		/* pcrel_offset */
+  /* High 32 bits of 64-bit address.  */
+  HOWTO (R_NANOMIPS_GOTPC_I32,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GOTPC_I32", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* High 20 bits of PC-relative GOT offset.  */
+  HOWTO (R_NANOMIPS_GOTPC_HI20,	/* type */
+	 12,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 20,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GOTPC_HI20", /* name */
+	 false,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0x001ffffd,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  /* Low 12 bits of displacement in global offset table.  */
+  HOWTO (R_NANOMIPS_GOT_LO12,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 12,			/* bitsize */
+	 false,			/* pc_relative */
+	 2,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GOT_LO12", /* name */
+	 false,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0x00000fff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  /* 19 bit call through global offset table.  */
+  HOWTO (R_NANOMIPS_GOT_CALL,	/* type */
+	 2,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 19,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GOT_CALL",	/* name */
+	 false,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0x001ffffc,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Displacement to page pointer in the global offset table.  */
+  HOWTO (R_NANOMIPS_GOT_PAGE,	/* type */
+	 2,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 19,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GOT_PAGE", /* name */
+	 false,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0x001ffffc,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Offset from page pointer in the global offset table.  */
+  HOWTO (R_NANOMIPS_GOT_OFST,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 12,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GOT_OFST", /* name */
+	 false,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0x00000fff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Low 4 bits of symbol value.  */
+  HOWTO (R_NANOMIPS_LO4_S2,	/* type */
+	 2,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 4,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_LO4_S2",	/* name */
+	 false,			/* partial_inplace */
+	 0x0000000f,		/* src_mask */
+	 0x0000000f,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Reserved for 64-bit ABI, HI32 relocation.  */
+  EMPTY_HOWTO (R_NANOMIPS_RESERVED1),
+
+  /* Low 12 bits of GP-relative displacement.  */
+  HOWTO (R_NANOMIPS_GPREL_LO12,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 12,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_GPREL_LO12", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x00000fff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Section displacement.  */
+  HOWTO (R_NANOMIPS_SCN_DISP,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_SCN_DISP",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Copy relocation.  */
+  HOWTO (R_NANOMIPS_COPY,	/* type */
+	 0,			/* rightshift */
+	 0,			/* this one is variable size */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_COPY",	/* name */
+	 false,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0x0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  EMPTY_HOWTO (45),
+  EMPTY_HOWTO (46),
+  EMPTY_HOWTO (47),
+  EMPTY_HOWTO (48),
+  EMPTY_HOWTO (49),
+  EMPTY_HOWTO (50),
+  EMPTY_HOWTO (51),
+  EMPTY_HOWTO (52),
+  EMPTY_HOWTO (53),
+  EMPTY_HOWTO (54),
+  EMPTY_HOWTO (55),
+  EMPTY_HOWTO (56),
+  EMPTY_HOWTO (57),
+  EMPTY_HOWTO (58),
+  EMPTY_HOWTO (59),
+  EMPTY_HOWTO (60),
+  EMPTY_HOWTO (61),
+  EMPTY_HOWTO (62),
+  EMPTY_HOWTO (63),
+
+  /* Place-holder for code alignment.  */
+  HOWTO (R_NANOMIPS_ALIGN,	/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special handler.  */
+	 "R_NANOMIPS_ALIGN",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Fill value for code alignment.  */
+  HOWTO (R_NANOMIPS_FILL,	/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special handler.  */
+	 "R_NANOMIPS_FILL",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Maximum padding bytes for code alignment.  */
+  HOWTO (R_NANOMIPS_MAX,	/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special handler.  */
+	 "R_NANOMIPS_MAX",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Place-holder to enforce 32-bit instruction encoding.  */
+  HOWTO (R_NANOMIPS_INSN32,	/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special handler.  */
+	 "R_NANOMIPS_INSN32",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Place-holder to inhibit relaxation on one instruction.  */
+  HOWTO (R_NANOMIPS_FIXED,	/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special handler.  */
+	 "R_NANOMIPS_FIXED",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Marker to inhibit linker relaxation.  */
+  HOWTO (R_NANOMIPS_NORELAX,	/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false, 		/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special handler.  */
+	 "R_NANOMIPS_NORELAX",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Marker to enable linker relaxation.  */
+  HOWTO (R_NANOMIPS_RELAX,	/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special handler.  */
+	 "R_NANOMIPS_RELAX",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Place-holder for relaxation of save/restore instructions.  */
+  HOWTO (R_NANOMIPS_SAVERESTORE, /* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special handler.  */
+	 "R_NANOMIPS_SAVERESTORE", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Place-holder to enforce 16-bit instruction encoding.  */
+  HOWTO (R_NANOMIPS_INSN16,	/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special handler.  */
+	 "R_NANOMIPS_INSN16",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Place-holder to enforce 32-bit JALR encoding.  */
+  HOWTO (R_NANOMIPS_JALR32,	/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special handler.  */
+	 "R_NANOMIPS_JALR32",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Place-holder to enforce 16-bit JALR encoding.  */
+  HOWTO (R_NANOMIPS_JALR16,	/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special handler.  */
+	 "R_NANOMIPS_JALR16",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Place-holder for compressed jump-table load instructions.  */
+  HOWTO (R_NANOMIPS_JUMPTABLE_LOAD, /* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special handler */
+	 "R_NANOMIPS_JUMPTABLE_LOAD", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Place-holder for relaxing frame-register information.  */
+  HOWTO (R_NANOMIPS_FRAME_REG, /* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special handler */
+	 "R_NANOMIPS_FRAME_REG", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+
+  EMPTY_HOWTO (77),
+  EMPTY_HOWTO (78),
+  EMPTY_HOWTO (79),
+
+  /* TLS GD/LD dynamic relocations.  */
+  HOWTO (R_NANOMIPS_TLS_DTPMOD, /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_DTPMOD", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  HOWTO (R_NANOMIPS_TLS_DTPREL, /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_DTPREL", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* TLS IE dynamic relocations.  */
+  HOWTO (R_NANOMIPS_TLS_TPREL, /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_TPREL", /* name */
+	 false,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* TLS general dynamic variable reference.  */
+  HOWTO (R_NANOMIPS_TLS_GD,	/* type */
+	 2,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 19,			/* bitsize */
+	 false,			/* pc_relative */
+	 2,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_GD",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x001ffffc,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  HOWTO (R_NANOMIPS_TLS_GD_I32,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_GD_I32", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* TLS local dynamic variable reference.  */
+  HOWTO (R_NANOMIPS_TLS_LD,	/* type */
+	 2,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 19,			/* bitsize */
+	 false,			/* pc_relative */
+	 2,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_LD",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x001ffffc,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  HOWTO (R_NANOMIPS_TLS_LD_I32,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_LD_I32", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* TLS local dynamic 12-bit offset.  */
+  HOWTO (R_NANOMIPS_TLS_DTPREL12, /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 12,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_DTPREL12", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x00000fff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* TLS local dynamic 16-bit offset.  */
+  HOWTO (R_NANOMIPS_TLS_DTPREL16, /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_DTPREL16", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* TLS local dynamic 32-bit offset.  */
+  HOWTO (R_NANOMIPS_TLS_DTPREL_I32, /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_DTPREL_I32", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* TLS thread pointer 21-bit GOT offset.  */
+  HOWTO (R_NANOMIPS_TLS_GOTTPREL,	/* type */
+	 2,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 19,			/* bitsize */
+	 false,			/* pc_relative */
+	 2,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_GOTTPREL", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x001ffffc,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* TLS thread pointer 32-bit GOT offset.  */
+  HOWTO (R_NANOMIPS_TLS_GOTTPREL_PC_I32, /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_GOTTPREL_PC_I32", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 true), 		/* pcrel_offset */
+
+  /* TLS thread pointer 12-bit offset.  */
+  HOWTO (R_NANOMIPS_TLS_TPREL12, /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 12,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_TPREL12", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x00000fff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* TLS thread pointer 16-bit offset.  */
+  HOWTO (R_NANOMIPS_TLS_TPREL16, /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_unsigned, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_TPREL16", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* TLS thread pointer 32-bit offset.  */
+  HOWTO (R_NANOMIPS_TLS_TPREL_I32, /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_TLS_TPREL_I32", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+};
+
+/* GNU extension to record C++ vtable hierarchy */
+static reloc_howto_type elf_nanomips_gnu_vtinherit_howto =
+  HOWTO (R_NANOMIPS_GNU_VTINHERIT, /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false, 		/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 NULL,			/* special_function */
+	 "R_NANOMIPS_GNU_VTINHERIT", /* name */
+	 false, 		/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false);		/* pcrel_offset */
+
+/* GNU extension to record C++ vtable member usage */
+static reloc_howto_type elf_nanomips_gnu_vtentry_howto =
+  HOWTO (R_NANOMIPS_GNU_VTENTRY, /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
+	 "R_NANOMIPS_GNU_VTENTRY", /* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false);		/* pcrel_offset */
+
+/* 32 bit pc-relative.  */
+static reloc_howto_type elf_nanomips_gnu_pcrel32 =
+  HOWTO (R_NANOMIPS_PC32,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_PC32",	/* name */
+	 true,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 true);			/* pcrel_offset */
+
+/* Used in EH tables.  */
+static reloc_howto_type elf_nanomips_eh_howto =
+  HOWTO (R_NANOMIPS_EH, 	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_nanomips_elf_generic_reloc, /* special_function */
+	 "R_NANOMIPS_EH",	/* name */
+	 true,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,	        /* dst_mask */
+	 false);		/* pcrel_offset */
+
+/* A mapping from BFD reloc types to nanoMIPS ELF reloc types.  */
+
+struct elf_reloc_map
+{
+  bfd_reloc_code_real_type bfd_val;
+  enum elf_nanomips_reloc_type elf_val;
+};
+
+static const struct elf_reloc_map nanomips_reloc_map[] = {
+  { BFD_RELOC_NONE, R_NANOMIPS_NONE },
+  { BFD_RELOC_32, R_NANOMIPS_32 },
+  { BFD_RELOC_64, R_NANOMIPS_64 },
+  { BFD_RELOC_NANOMIPS_NEG, R_NANOMIPS_NEG },
+  { BFD_RELOC_NANOMIPS_ASHIFTR_1, R_NANOMIPS_ASHIFTR_1 },
+  { BFD_RELOC_NANOMIPS_UNSIGNED_8, R_NANOMIPS_UNSIGNED_8 },
+  { BFD_RELOC_NANOMIPS_SIGNED_8, R_NANOMIPS_SIGNED_8 },
+  { BFD_RELOC_NANOMIPS_UNSIGNED_16, R_NANOMIPS_UNSIGNED_16 },
+  { BFD_RELOC_16, R_NANOMIPS_UNSIGNED_16 },
+  { BFD_RELOC_NANOMIPS_SIGNED_16, R_NANOMIPS_SIGNED_16 },
+  { BFD_RELOC_NANOMIPS_HI20, R_NANOMIPS_HI20 },
+  { BFD_RELOC_NANOMIPS_LO12, R_NANOMIPS_LO12 },
+  { BFD_RELOC_NANOMIPS_IMM16, R_NANOMIPS_LO12 },
+  { BFD_RELOC_NANOMIPS_25_PCREL_S1, R_NANOMIPS_PC25_S1 },
+  { BFD_RELOC_NANOMIPS_21_PCREL_S1, R_NANOMIPS_PC21_S1 },
+  { BFD_RELOC_NANOMIPS_14_PCREL_S1, R_NANOMIPS_PC14_S1 },
+  { BFD_RELOC_NANOMIPS_11_PCREL_S1, R_NANOMIPS_PC11_S1 },
+  { BFD_RELOC_NANOMIPS_10_PCREL_S1, R_NANOMIPS_PC10_S1 },
+  { BFD_RELOC_NANOMIPS_7_PCREL_S1, R_NANOMIPS_PC7_S1 },
+  { BFD_RELOC_NANOMIPS_GPREL7_S2, R_NANOMIPS_GPREL7_S2 },
+  { BFD_RELOC_NANOMIPS_GPREL18, R_NANOMIPS_GPREL18 },
+  { BFD_RELOC_NANOMIPS_GPREL19_S2, R_NANOMIPS_GPREL19_S2 },
+  { BFD_RELOC_NANOMIPS_4_PCREL_S1,R_NANOMIPS_PC4_S1 },
+  { BFD_RELOC_NANOMIPS_PCREL_HI20, R_NANOMIPS_PCHI20 },
+  { BFD_RELOC_NANOMIPS_GPREL16_S2, R_NANOMIPS_GPREL16_S2 },
+  { BFD_RELOC_NANOMIPS_GPREL18_S3, R_NANOMIPS_GPREL18_S3 },
+  { BFD_RELOC_NANOMIPS_GOT_CALL, R_NANOMIPS_GOT_CALL },
+  { BFD_RELOC_NANOMIPS_GOT_DISP, R_NANOMIPS_GOT_DISP },
+  { BFD_RELOC_NANOMIPS_GOT_PAGE, R_NANOMIPS_GOT_PAGE },
+  { BFD_RELOC_NANOMIPS_GOT_OFST, R_NANOMIPS_GOT_OFST },
+  { BFD_RELOC_NANOMIPS_GOTPC_HI20, R_NANOMIPS_GOTPC_HI20 },
+  { BFD_RELOC_NANOMIPS_GOT_LO12, R_NANOMIPS_GOT_LO12 },
+  { BFD_RELOC_NANOMIPS_GOTPC_I32, R_NANOMIPS_GOTPC_I32 },
+  { BFD_RELOC_NANOMIPS_I32, R_NANOMIPS_I32 },
+  { BFD_RELOC_NANOMIPS_GPREL_HI20, R_NANOMIPS_GPREL_HI20 },
+  { BFD_RELOC_NANOMIPS_PC_I32, R_NANOMIPS_PC_I32 },
+  { BFD_RELOC_NANOMIPS_GPREL_I32, R_NANOMIPS_GPREL_I32 },
+  { BFD_RELOC_NANOMIPS_GPREL17_S1, R_NANOMIPS_GPREL17_S1 },
+  { BFD_RELOC_NANOMIPS_GPREL_LO12, R_NANOMIPS_GPREL_LO12 },
+  { BFD_RELOC_NANOMIPS_LO4_S2, R_NANOMIPS_LO4_S2 },
+  { BFD_RELOC_NANOMIPS_COPY, R_NANOMIPS_COPY },
+
+  { BFD_RELOC_NANOMIPS_ALIGN, R_NANOMIPS_ALIGN },
+  { BFD_RELOC_NANOMIPS_FILL, R_NANOMIPS_FILL },
+  { BFD_RELOC_NANOMIPS_MAX, R_NANOMIPS_MAX },
+  { BFD_RELOC_NANOMIPS_INSN32, R_NANOMIPS_INSN32 },
+  { BFD_RELOC_NANOMIPS_INSN16, R_NANOMIPS_INSN16 },
+  { BFD_RELOC_NANOMIPS_FIXED, R_NANOMIPS_FIXED },
+  { BFD_RELOC_NANOMIPS_RELAX, R_NANOMIPS_RELAX },
+  { BFD_RELOC_NANOMIPS_NORELAX, R_NANOMIPS_NORELAX },
+  { BFD_RELOC_NANOMIPS_SAVERESTORE, R_NANOMIPS_SAVERESTORE },
+  { BFD_RELOC_NANOMIPS_JALR32, R_NANOMIPS_JALR32 },
+  { BFD_RELOC_NANOMIPS_JALR16, R_NANOMIPS_JALR16 },
+  { BFD_RELOC_NANOMIPS_JUMPTABLE_LOAD, R_NANOMIPS_JUMPTABLE_LOAD },
+
+  { BFD_RELOC_NANOMIPS_TLS_GD, R_NANOMIPS_TLS_GD },
+  { BFD_RELOC_NANOMIPS_TLS_GD_I32, R_NANOMIPS_TLS_GD_I32 },
+  { BFD_RELOC_NANOMIPS_TLS_LD, R_NANOMIPS_TLS_LD },
+  { BFD_RELOC_NANOMIPS_TLS_LD_I32, R_NANOMIPS_TLS_LD_I32 },
+  { BFD_RELOC_NANOMIPS_TLS_DTPREL12, R_NANOMIPS_TLS_DTPREL12 },
+  { BFD_RELOC_NANOMIPS_TLS_DTPREL16, R_NANOMIPS_TLS_DTPREL16 },
+  { BFD_RELOC_NANOMIPS_TLS_DTPREL_I32, R_NANOMIPS_TLS_DTPREL_I32 },
+  { BFD_RELOC_NANOMIPS_TLS_GOTTPREL, R_NANOMIPS_TLS_GOTTPREL },
+  { BFD_RELOC_NANOMIPS_TLS_GOTTPREL_PC_I32, R_NANOMIPS_TLS_GOTTPREL_PC_I32 },
+  { BFD_RELOC_NANOMIPS_TLS_TPREL12, R_NANOMIPS_TLS_TPREL12 },
+  { BFD_RELOC_NANOMIPS_TLS_TPREL16, R_NANOMIPS_TLS_TPREL16 },
+  { BFD_RELOC_NANOMIPS_TLS_TPREL_I32, R_NANOMIPS_TLS_TPREL_I32 },
+  { BFD_RELOC_NANOMIPS_TLS_DTPMOD, R_NANOMIPS_TLS_DTPMOD },
+  { BFD_RELOC_NANOMIPS_TLS_DTPREL, R_NANOMIPS_TLS_DTPREL },
+  { BFD_RELOC_NANOMIPS_TLS_TPREL, R_NANOMIPS_TLS_TPREL },
+};
+
+/* Given a BFD reloc type, return a howto structure.  */
+
+static reloc_howto_type *
+bfd_elfNN_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+				 bfd_reloc_code_real_type code)
+{
+  unsigned int i;
+  reloc_howto_type *howto_nanomips_table;
+
+  howto_nanomips_table = elfNN_nanomips_howto_table_rela;
+
+  for (i = 0; i < sizeof (nanomips_reloc_map) / sizeof (struct elf_reloc_map);
+       i++)
+    {
+      if (nanomips_reloc_map[i].bfd_val == code)
+	return &howto_nanomips_table[(int) nanomips_reloc_map[i].elf_val];
+    }
+
+  switch (code)
+    {
+    default:
+      bfd_set_error (bfd_error_bad_value);
+      return NULL;
+
+    case BFD_RELOC_CTOR:
+      return &howto_nanomips_table[(int) R_NANOMIPS_32];
+
+    case BFD_RELOC_VTABLE_INHERIT:
+      return &elf_nanomips_gnu_vtinherit_howto;
+    case BFD_RELOC_VTABLE_ENTRY:
+      return &elf_nanomips_gnu_vtentry_howto;
+    case BFD_RELOC_NANOMIPS_EH:
+      return &elf_nanomips_eh_howto;
+    case BFD_RELOC_32_PCREL:
+      return &elf_nanomips_gnu_pcrel32;
+    }
+}
+
+/* Map a BFD relocation to its display name.  */
+
+static reloc_howto_type *
+bfd_elfNN_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+				 const char *r_name)
+{
+  unsigned int i;
+
+  for (i = 0;
+       i < (sizeof (elfNN_nanomips_howto_table_rela)
+	    / sizeof (elfNN_nanomips_howto_table_rela[0])); i++)
+    if (elfNN_nanomips_howto_table_rela[i].name != NULL
+	&& strcasecmp (elfNN_nanomips_howto_table_rela[i].name, r_name) == 0)
+      return &elfNN_nanomips_howto_table_rela[i];
+
+  if (strcasecmp (elf_nanomips_gnu_vtinherit_howto.name, r_name) == 0)
+    return &elf_nanomips_gnu_vtinherit_howto;
+  if (strcasecmp (elf_nanomips_gnu_vtentry_howto.name, r_name) == 0)
+    return &elf_nanomips_gnu_vtentry_howto;
+  if (strcasecmp (elf_nanomips_eh_howto.name, r_name) == 0)
+    return &elf_nanomips_eh_howto;
+
+  return NULL;
+}
+
+/* Given a nanoMIPS Elf_Internal_Rel, fill in an arelent structure.  */
+
+static reloc_howto_type *
+nanomips_elfNN_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
+			       unsigned int r_type,
+			       bool rela_p ATTRIBUTE_UNUSED)
+{
+  switch (r_type)
+    {
+    case R_NANOMIPS_GNU_VTINHERIT:
+      return &elf_nanomips_gnu_vtinherit_howto;
+    case R_NANOMIPS_GNU_VTENTRY:
+      return &elf_nanomips_gnu_vtentry_howto;
+    case R_NANOMIPS_EH:
+      return &elf_nanomips_eh_howto;
+    case R_NANOMIPS_PC32:
+      return &elf_nanomips_gnu_pcrel32;
+    default:
+      return &elfNN_nanomips_howto_table_rela[r_type];
+    }
+}
+
+/* Given a nanoMIPS Elf_Internal_Rela, fill in an arelent structure.  */
+
+static bool
+nanomips_info_to_howto_rela (bfd *abfd, arelent *cache_ptr,
+			     Elf_Internal_Rela *dst)
+{
+  const struct elf_backend_data *bed;
+  unsigned int r_type;
+
+  r_type = ELFNN_R_TYPE (dst->r_info);
+  bed = get_elf_backend_data (abfd);
+  cache_ptr->howto = bed->elf_backend_mips_rtype_to_howto (abfd, r_type, true);
+  cache_ptr->addend = dst->r_addend;
+  return true;
+}
+
+/* nanoMIPS ELF local labels start with '$'.  */
+
+static bool
+nanomips_elf_is_local_label_name (bfd *abfd, const char *name)
+{
+  if (name[0] == '$')
+    return true;
+
+  /* Fall back to the generic ELF local label syntax.  */
+  return _bfd_elf_is_local_label_name (abfd, name);
+}
+
+/* Set the right machine number for a nanoMIPS ELF file.  */
+
+static bool
+nanomips_elfNN_object_p (bfd *abfd)
+{
+  unsigned long mach;
+
+  if (!ABI_PNN_P (abfd))
+    return false;
+
+  mach = _bfd_elf_nanomips_mach (elf_elfheader (abfd)->e_flags);
+  bfd_default_set_arch_mach (abfd, bfd_arch_nanomips, mach);
+  return true;
+}
+
+#define ELF_ARCH			bfd_arch_nanomips
+#define ELF_TARGET_ID			NANOMIPS_ELF_DATA
+#define ELF_MACHINE_CODE		EM_NANOMIPS
+
+#define elf_backend_collect		true
+#define elf_backend_type_change_ok	true
+#define elf_info_to_howto		nanomips_info_to_howto_rela
+#define elf_backend_object_p		nanomips_elfNN_object_p
+#define elf_backend_section_processing	_bfd_nanomips_elf_section_processing
+#define elf_backend_section_from_shdr	_bfd_nanomips_elf_section_from_shdr
+#define elf_backend_fake_sections	_bfd_nanomips_elf_fake_sections
+#define elf_backend_final_write_processing \
+					_bfd_nanomips_elf_final_write_processing
+
+#define elf_backend_may_use_rela_p	1
+#define elf_backend_default_use_rela_p	1
+#define elf_backend_sign_extend_vma	true
+#define elf_backend_plt_readonly	1
+
+#define bfd_elfNN_bfd_get_relocated_section_contents \
+			_bfd_elf_nanomips_get_relocated_section_contents
+#define elf_backend_mips_rtype_to_howto	nanomips_elfNN_rtype_to_howto
+#define bfd_elfNN_bfd_print_private_bfd_data \
+					_bfd_nanomips_elf_print_private_bfd_data
+#define bfd_elfNN_mkobject		_bfd_nanomips_elf_mkobject
+#define bfd_elfNN_bfd_is_local_label_name \
+					nanomips_elf_is_local_label_name
+
+#define ELF_MAXPAGESIZE    0x1000
+#define ELF_COMMONPAGESIZE 0x1000
+
+/* Support for nanomipsNN target.  */
+
+#define TARGET_LITTLE_SYM               nanomips_elfNN_le_vec
+#define TARGET_LITTLE_NAME              "elfNN-littlenanomips"
+#define TARGET_BIG_SYM                  nanomips_elfNN_be_vec
+#define TARGET_BIG_NAME                 "elfNN-bignanomips"
+
+#define elfNN_bed                       elfNN_nanomips_bed
+
+/* Include the target file for this target.  */
+#include "elfNN-target.h"
diff --git a/bfd/elfxx-mips.h b/bfd/elfxx-mips.h
index 2c790ed5ed6..a24c30f5d55 100644
--- a/bfd/elfxx-mips.h
+++ b/bfd/elfxx-mips.h
@@ -65,6 +65,8 @@  extern bool _bfd_mips_elf_create_dynamic_sections
   (bfd *, struct bfd_link_info *);
 extern bool _bfd_mips_elf_check_relocs
   (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
+extern bool _bfd_mips_relax_section
+  (bfd *, asection *, struct bfd_link_info *, bool *again);
 extern bool _bfd_mips_elf_adjust_dynamic_symbol
   (struct bfd_link_info *, struct elf_link_hash_entry *);
 extern bool _bfd_mips_elf_always_size_sections
@@ -133,6 +135,8 @@  extern const char * _bfd_mips_fp_abi_string
   (int);
 extern bool _bfd_mips_elf_print_private_bfd_data
   (bfd *, void *);
+extern bool _bfd_nanomips_elf_print_private_bfd_data
+  (bfd *, void *);
 extern bool _bfd_mips_elf_discard_info
   (bfd *, struct elf_reloc_cookie *, struct bfd_link_info *);
 extern bool _bfd_mips_elf_write_section
@@ -165,6 +169,7 @@  extern bfd_vma _bfd_mips_elf_sign_extend
 extern void _bfd_mips_elf_merge_symbol_attribute
   (struct elf_link_hash_entry *, unsigned int, bool, bool);
 extern char *_bfd_mips_elf_get_target_dtag (bfd_vma);
+extern char *_bfd_nanomips_elf_get_target_dtag (bfd_vma);
 extern bool _bfd_mips_elf_ignore_undef_symbol
   (struct elf_link_hash_entry *);
 extern void _bfd_mips_elf_use_plts_and_copy_relocs
diff --git a/bfd/elfxx-nanomips.c b/bfd/elfxx-nanomips.c
new file mode 100644
index 00000000000..8405fe09c34
--- /dev/null
+++ b/bfd/elfxx-nanomips.c
@@ -0,0 +1,794 @@ 
+/* nanoMIPS-specific support for ELF
+   Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+   Written by Faraz Shahbazker <faraz.shahbazker@mips.com>
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+
+/* This file handles functionality common to nanoMIPS ABIs.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "elfxx-nanomips.h"
+#include "elf/nanomips.h"
+
+/* nanoMIPS ELF private object data.  */
+
+struct nanomips_elf_obj_tdata
+{
+  /* Generic ELF private object data.  */
+  struct elf_obj_tdata root;
+
+  /* Input BFD providing Tag_GNU_NANOMIPS_ABI_FP attribute for output.  */
+  bfd *abi_fp_bfd;
+
+  /* Input BFD providing Tag_GNU_NANOMIPS_ABI_MSA attribute for output.  */
+  bfd *abi_msa_bfd;
+
+  /* The abiflags for this object.  */
+  Elf_Internal_ABIFlags_v0 abiflags;
+  bool abiflags_valid;
+
+  bfd_signed_vma sdata_section[1000];
+};
+
+/* Get nanoMIPS ELF private object data from BFD's tdata.  */
+
+#define nanomips_elf_tdata(bfd) \
+  ((struct nanomips_elf_obj_tdata *) (bfd)->tdata.any)
+
+/* True if NAME is the recognized name of any SHT_NANOMIPS_ABIFLAGS section.  */
+
+#define NANOMIPS_ELF_ABIFLAGS_SECTION_NAME_P(NAME) \
+  (strcmp (NAME, ".nanoMIPS.abiflags") == 0)
+
+/* Allocate nanoMIPS ELF private object data.  */
+
+bool
+_bfd_nanomips_elf_mkobject (bfd *abfd)
+{
+  return bfd_elf_allocate_object (abfd,
+				  sizeof (struct nanomips_elf_obj_tdata),
+				  NANOMIPS_ELF_DATA);
+}
+
+/* A generic howto special_function.  This calculates and installs the
+   relocation itself, thus avoiding the oft-discussed problems in
+   bfd_perform_relocation and bfd_install_relocation.  */
+
+bfd_reloc_status_type
+_bfd_nanomips_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+				 arelent *reloc_entry, asymbol *symbol,
+				 void *data ATTRIBUTE_UNUSED,
+				 asection *input_section, bfd *output_bfd,
+				 char **error_message ATTRIBUTE_UNUSED)
+{
+  bfd_signed_vma val;
+  bfd_reloc_status_type status;
+  bool relocatable;
+
+  relocatable = (output_bfd != NULL);
+
+  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
+    return bfd_reloc_outofrange;
+
+  /* Build up the field adjustment in VAL.  */
+  val = 0;
+  if (!relocatable || (symbol->flags & BSF_SECTION_SYM) != 0)
+    {
+      /* Either we're calculating the final field value or we have a
+         relocation against a section symbol.  Add in the section's
+         offset or address.  */
+      val += symbol->section->output_section->vma;
+      val += symbol->section->output_offset;
+    }
+
+  if (!relocatable)
+    {
+      /* We're calculating the final field value.  Add in the symbol's value
+         and, if pc-relative, subtract the address of the field itself.  */
+      val += symbol->value;
+      if (reloc_entry->howto->pc_relative)
+	{
+	  val -= input_section->output_section->vma;
+	  val -= input_section->output_offset;
+	  val -= reloc_entry->address;
+	}
+    }
+
+  /* VAL is now the final adjustment.  If we're keeping this relocation
+     in the output file, and if the relocation uses a separate addend,
+     we just need to add VAL to that addend.  Otherwise we need to add
+     VAL to the relocation field itself.  */
+  if (relocatable && !reloc_entry->howto->partial_inplace)
+    reloc_entry->addend += val;
+  else
+    {
+      bfd_byte *location = (bfd_byte *) data + reloc_entry->address;
+
+      /* Add in the separate addend, if any.  */
+      val += reloc_entry->addend;
+
+      /* Add VAL to the relocation field.  */
+      status = _bfd_relocate_contents (reloc_entry->howto, abfd, val,
+				       location);
+      if (status != bfd_reloc_ok)
+	return status;
+    }
+
+  if (relocatable)
+    reloc_entry->address += input_section->output_offset;
+
+  return bfd_reloc_ok;
+}
+
+/* A negation howto special_function.  */
+
+bfd_reloc_status_type
+_bfd_nanomips_elf_negative_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+				  arelent *reloc_entry, asymbol *symbol,
+				  void *data ATTRIBUTE_UNUSED,
+				  asection *input_section, bfd *output_bfd,
+				  char **error_message ATTRIBUTE_UNUSED)
+{
+  bfd_signed_vma val;
+  bool relocatable;
+
+  relocatable = (output_bfd != NULL);
+
+  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
+    return bfd_reloc_outofrange;
+
+  /* Calculate the value of the symbol S.  */
+  val = symbol->section->output_section->vma;
+  val += symbol->section->output_offset;
+  val += symbol->value;
+
+  /* Add negated value to addend: (-S + A).  */
+  if (! relocatable )
+    reloc_entry->addend = -val + reloc_entry->addend;
+
+  if (relocatable)
+    reloc_entry->address += input_section->output_offset;
+
+  return bfd_reloc_ok;
+}
+
+/* Swap in an abiflags structure.  */
+
+void
+bfd_nanomips_elf_swap_abiflags_v0_in (bfd *abfd,
+				      const Elf_External_ABIFlags_v0 *ex,
+				      Elf_Internal_ABIFlags_v0 *in)
+{
+  in->version = H_GET_16 (abfd, ex->version);
+  in->isa_level = H_GET_8 (abfd, ex->isa_level);
+  in->isa_rev = H_GET_8 (abfd, ex->isa_rev);
+  in->gpr_size = H_GET_8 (abfd, ex->gpr_size);
+  in->cpr1_size = H_GET_8 (abfd, ex->cpr1_size);
+  in->cpr2_size = H_GET_8 (abfd, ex->cpr2_size);
+  in->fp_abi = H_GET_8 (abfd, ex->fp_abi);
+  in->isa_ext = H_GET_32 (abfd, ex->isa_ext);
+  in->ases = H_GET_32 (abfd, ex->ases);
+  in->flags1 = H_GET_32 (abfd, ex->flags1);
+  in->flags2 = H_GET_32 (abfd, ex->flags2);
+}
+
+/* Swap out an abiflags structure.  */
+
+void
+bfd_nanomips_elf_swap_abiflags_v0_out (bfd *abfd,
+				       const Elf_Internal_ABIFlags_v0 *in,
+				       Elf_External_ABIFlags_v0 *ex)
+{
+  H_PUT_16 (abfd, in->version, ex->version);
+  H_PUT_8 (abfd, in->isa_level, ex->isa_level);
+  H_PUT_8 (abfd, in->isa_rev, ex->isa_rev);
+  H_PUT_8 (abfd, in->gpr_size, ex->gpr_size);
+  H_PUT_8 (abfd, in->cpr1_size, ex->cpr1_size);
+  H_PUT_8 (abfd, in->cpr2_size, ex->cpr2_size);
+  H_PUT_8 (abfd, in->fp_abi, ex->fp_abi);
+  H_PUT_32 (abfd, in->isa_ext, ex->isa_ext);
+  H_PUT_32 (abfd, in->ases, ex->ases);
+  H_PUT_32 (abfd, in->flags1, ex->flags1);
+  H_PUT_32 (abfd, in->flags2, ex->flags2);
+}
+
+/* Map flag bits to BFD architecture.  */
+
+unsigned long
+_bfd_elf_nanomips_mach (flagword flags)
+{
+  switch (flags & EF_NANOMIPS_ARCH)
+    {
+    default:
+    case E_NANOMIPS_ARCH_32R6:
+      return bfd_mach_nanomipsisa32r6;
+
+    case E_NANOMIPS_ARCH_64R6:
+      return bfd_mach_nanomipsisa64r6;
+    }
+
+  return 0;
+}
+
+/* Work over a section just before writing it out.  This routine is
+   used by both the 32-bit and the 64-bit ABI.  */
+
+bool
+_bfd_nanomips_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED,
+				      Elf_Internal_Shdr *hdr)
+{
+  if (hdr->bfd_section != NULL)
+    {
+      const char *name = bfd_section_name (hdr->bfd_section);
+
+      /* .sbss is not handled specially here because the GNU/Linux
+         prelinker can convert .sbss from NOBITS to PROGBITS and
+         changing it back to NOBITS breaks the binary.  The entry in
+         _bfd_nanomips_elf_special_sections will ensure the correct flags
+         are set on .sbss if BFD creates it without reading it from an
+         input file, and without special handling here the flags set
+         on it in an input file will be followed.  */
+      if (strcmp (name, ".sdata") == 0
+	  || strcmp (name, ".lit8") == 0
+	  || strcmp (name, ".lit4") == 0
+	  || strncmp (name, ".sdata_", 7) == 0)
+	{
+	  hdr->sh_flags |= SHF_ALLOC | SHF_WRITE;
+	  hdr->sh_type = SHT_PROGBITS;
+	}
+      else if (strcmp (name, ".srdata") == 0)
+	{
+	  hdr->sh_flags |= SHF_ALLOC;
+	  hdr->sh_type = SHT_PROGBITS;
+	}
+      else if (strcmp (name, ".compact_rel") == 0)
+	{
+	  hdr->sh_flags = 0;
+	  hdr->sh_type = SHT_PROGBITS;
+	}
+      else if (strcmp (name, ".rtproc") == 0)
+	{
+	  if (hdr->sh_addralign != 0 && hdr->sh_entsize == 0)
+	    {
+	      unsigned int adjust;
+
+	      adjust = hdr->sh_size % hdr->sh_addralign;
+	      if (adjust != 0)
+		hdr->sh_size += hdr->sh_addralign - adjust;
+	    }
+	}
+    }
+
+  return true;
+}
+
+/* Handle a nanoMIPS specific section when reading an object file.
+   This is called when elfcode.h finds a section with an unknown type.
+   This routine supports both the 32-bit and 64-bit ELF ABI.  */
+
+bool
+_bfd_nanomips_elf_section_from_shdr (bfd *abfd, Elf_Internal_Shdr *hdr,
+				     const char *name, int shindex)
+{
+  flagword flags = 0;
+
+  /* There ought to be a place to keep ELF backend specific flags, but
+     at the moment there isn't one.  We just keep track of the
+     sections by their name, instead.   */
+  switch (hdr->sh_type)
+    {
+    case SHT_NANOMIPS_ABIFLAGS:
+      if (!NANOMIPS_ELF_ABIFLAGS_SECTION_NAME_P (name))
+	return false;
+      flags = (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_SAME_SIZE);
+      break;
+    default:
+      break;
+    }
+
+  if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
+    return false;
+
+  if (flags)
+    {
+      if (!bfd_set_section_flags (hdr->bfd_section,
+				  (bfd_section_flags (hdr->bfd_section)
+				   | flags)))
+	return false;
+    }
+
+  if (hdr->sh_type == SHT_NANOMIPS_ABIFLAGS)
+    {
+      Elf_External_ABIFlags_v0 ext;
+
+      if (! bfd_get_section_contents (abfd, hdr->bfd_section, &ext,
+				      0, sizeof ext))
+	return false;
+      bfd_nanomips_elf_swap_abiflags_v0_in
+	(abfd, &ext, &nanomips_elf_tdata (abfd)->abiflags);
+      if (nanomips_elf_tdata (abfd)->abiflags.version != 0)
+	return false;
+      nanomips_elf_tdata (abfd)->abiflags_valid = true;
+    }
+
+  return true;
+}
+
+/* Set the correct type for a nanoMIPS ELF section.  We do this by the
+   section name, which is a hack, but ought to work.  This routine is
+   used by both the 32-bit and the 64-bit ABI.  */
+
+bool
+_bfd_nanomips_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
+				 Elf_Internal_Shdr *hdr,
+				 asection *sec)
+{
+  const char *name = bfd_section_name (sec);
+
+  if (startswith (name, ".nanoMIPS.abiflags"))
+    {
+      hdr->sh_type = SHT_NANOMIPS_ABIFLAGS;
+      hdr->sh_entsize = sizeof (Elf_External_ABIFlags_v0);
+    }
+
+  /* The generic elf_fake_sections will set up REL_HDR using the default
+     kind of relocations.  */
+  return true;
+}
+
+/* Functions for the dynamic linker.  */
+
+/* Set ABFD's EF_NANOMIPS_ARCH and EF_NANOMIPS_MACH flags.  */
+
+static void
+nanomips_set_isa_flags (bfd *abfd)
+{
+  flagword val = 0;
+
+  switch (bfd_get_mach (abfd))
+    {
+    case bfd_mach_nanomipsisa32r6:
+      val = E_NANOMIPS_ARCH_32R6;
+      break;
+
+    case bfd_mach_nanomipsisa64r6:
+      val = E_NANOMIPS_ARCH_64R6;
+      break;
+    default:
+      break;
+    }
+
+  elf_elfheader (abfd)->e_flags &= ~(EF_NANOMIPS_ARCH | EF_NANOMIPS_MACH);
+  elf_elfheader (abfd)->e_flags |= val;
+}
+
+/* The final processing done just before writing out a nanoMIPS ELF
+   object file.  This gets the nanoMIPS architecture right based on the
+   machine number.  This is used by both the 32-bit and the 64-bit ABI.  */
+
+bool
+_bfd_nanomips_elf_final_write_processing (bfd *abfd)
+{
+  nanomips_set_isa_flags (abfd);
+  return _bfd_elf_final_write_processing (abfd);
+}
+
+/* Return the meaning of Tag_GNU_NANOMIPS_ABI_FP value FP, or null if
+   not known.  */
+
+const char *
+_bfd_nanomips_fp_abi_string (int fp)
+{
+  switch (fp)
+    {
+      /* These strings aren't translated because they're simply
+         option lists.  */
+    case Val_GNU_NANOMIPS_ABI_FP_DOUBLE:
+      return "-mdouble-float";
+
+    case Val_GNU_NANOMIPS_ABI_FP_SINGLE:
+      return "-msingle-float";
+
+    case Val_GNU_NANOMIPS_ABI_FP_SOFT:
+      return "-msoft-float";
+
+    default:
+      return 0;
+    }
+}
+
+/* Print the name of an ASE.  */
+
+static void
+print_nanomips_ases (FILE *file, unsigned int mask)
+{
+  if (mask & NANOMIPS_ASE_DSPR3)
+    fputs ("\n\tDSP R3 ASE", file);
+  if (mask & NANOMIPS_ASE_EVA)
+    fputs ("\n\tEnhanced VA Scheme", file);
+  if (mask & NANOMIPS_ASE_MCU)
+    fputs ("\n\tMCU (MicroController) ASE", file);
+  if (mask & NANOMIPS_ASE_MT)
+    fputs ("\n\tMT ASE", file);
+  if (mask & NANOMIPS_ASE_VIRT)
+    fputs ("\n\tVZ ASE", file);
+  if (mask & NANOMIPS_ASE_MSA)
+    fputs ("\n\tMSA ASE", file);
+  if (mask & NANOMIPS_ASE_TLB)
+    fputs ("\n\tTLB ASE", file);
+  if (mask & NANOMIPS_ASE_CRC)
+    fputs ("\n\tCRC ASE", file);
+  if ((mask & NANOMIPS_ASE_xNMS) == 0)
+    fputs ("\n\tnanoMIPS subset", file);
+  else if (mask == 0)
+    fprintf (file, "\n\t%s", _("None"));
+  else if ((mask & ~NANOMIPS_ASE_MASK) != 0)
+    fprintf (stdout, "\n\t%s (%x)", _("Unknown"), mask & ~NANOMIPS_ASE_MASK);
+}
+
+/* Print the name of an ISA extension.  None yet for nanoMIPS.  */
+
+static void
+print_nanomips_isa_ext (FILE *file, unsigned int isa_ext)
+{
+  switch (isa_ext)
+    {
+    case 0:
+      fputs (_("None"), file);
+      break;
+    default:
+      fprintf (file, "%s (%d)", _("Unknown"), isa_ext);
+      break;
+    }
+}
+
+/* Decode and print the FP ABI mode.  */
+
+static void
+print_nanomips_fp_abi_value (FILE *file, int val)
+{
+  switch (val)
+    {
+    case Val_GNU_NANOMIPS_ABI_FP_ANY:
+      fprintf (file, _("Hard or soft float\n"));
+      break;
+    case Val_GNU_NANOMIPS_ABI_FP_DOUBLE:
+      fprintf (file, _("Hard float (double precision)\n"));
+      break;
+    case Val_GNU_NANOMIPS_ABI_FP_SINGLE:
+      fprintf (file, _("Hard float (single precision)\n"));
+      break;
+    case Val_GNU_NANOMIPS_ABI_FP_SOFT:
+      fprintf (file, _("Soft float\n"));
+      break;
+    default:
+      fprintf (file, "??? (%d)\n", val);
+      break;
+    }
+}
+
+/* Map register type to size.  */
+
+static int
+get_nanomips_reg_size (int reg_size)
+{
+  return ((reg_size == AFL_REG_NONE) ? 0
+	  : (reg_size == AFL_REG_32) ? 32
+	  : (reg_size == AFL_REG_64) ? 64
+	  : (reg_size == AFL_REG_128) ? 128
+	  : -1);
+}
+
+/* Print nanoMIPS-specific ELF data.  */
+
+bool
+_bfd_nanomips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
+{
+  FILE *file = ptr;
+
+  BFD_ASSERT (abfd != NULL && ptr != NULL);
+
+  /* Print normal ELF private data.  */
+  _bfd_elf_print_private_bfd_data (abfd, ptr);
+
+  /* xgettext:c-format */
+  fprintf (file, _("private flags = %08lx:"), elf_elfheader (abfd)->e_flags);
+
+  if ((elf_elfheader (abfd)->e_flags & EF_NANOMIPS_ABI) == E_NANOMIPS_ABI_P32)
+    fprintf (file, _(" [abi=P32]"));
+  else if ((elf_elfheader (abfd)->e_flags & EF_NANOMIPS_ABI) ==
+	   E_NANOMIPS_ABI_P64)
+    fprintf (file, _(" [abi=P64]"));
+  else
+    fprintf (file, _(" [no abi set]"));
+
+  if ((elf_elfheader (abfd)->e_flags & EF_NANOMIPS_ARCH)
+      == E_NANOMIPS_ARCH_32R6)
+    fprintf (file, " [nanomips32r6]");
+  else if ((elf_elfheader (abfd)->e_flags & EF_NANOMIPS_ARCH)
+	   == E_NANOMIPS_ARCH_64R6)
+    fprintf (file, " [nanomips64r6]");
+  else
+    fprintf (file, _(" [unknown ISA]"));
+
+  if (elf_elfheader (abfd)->e_flags & EF_NANOMIPS_32BITMODE)
+    fprintf (file, " [32bitmode]");
+  else
+    fprintf (file, _(" [not 32bitmode]"));
+
+  if (elf_elfheader (abfd)->e_flags & EF_NANOMIPS_LINKRELAX)
+    fprintf (file, " [RELAXABLE]");
+
+  if (elf_elfheader (abfd)->e_flags & EF_NANOMIPS_PIC)
+    fprintf (file, " [PIC]");
+
+  if (elf_elfheader (abfd)->e_flags & EF_NANOMIPS_PID)
+    fprintf (file, " [PID]");
+
+  if (elf_elfheader (abfd)->e_flags & EF_NANOMIPS_PCREL)
+    fprintf (file, " [PCREL]");
+
+  fputc ('\n', file);
+
+  if (nanomips_elf_tdata (abfd)->abiflags_valid)
+    {
+      Elf_Internal_ABIFlags_v0 *abiflags =
+	&nanomips_elf_tdata (abfd)->abiflags;
+      fprintf (file, "\nnanoMIPS ABI Flags Version: %d\n", abiflags->version);
+      fprintf (file, "\nISA: nanoMIPS%d", abiflags->isa_level);
+      if (abiflags->isa_rev > 1)
+	fprintf (file, "r%d", abiflags->isa_rev);
+      fprintf (file, "\nGPR size: %d",
+	       get_nanomips_reg_size (abiflags->gpr_size));
+      fprintf (file, "\nCPR1 size: %d",
+	       get_nanomips_reg_size (abiflags->cpr1_size));
+      fprintf (file, "\nCPR2 size: %d",
+	       get_nanomips_reg_size (abiflags->cpr2_size));
+      fputs ("\nFP ABI: ", file);
+      print_nanomips_fp_abi_value (file, abiflags->fp_abi);
+      fputs ("ISA Extension: ", file);
+      print_nanomips_isa_ext (file, abiflags->isa_ext);
+      fputs ("\nASEs:", file);
+      print_nanomips_ases (file, abiflags->ases);
+      fprintf (file, "\nFLAGS 1: %8.8lx", abiflags->flags1);
+      fprintf (file, "\nFLAGS 2: %8.8lx", abiflags->flags2);
+      fputc ('\n', file);
+    }
+
+  return true;
+}
+
+const struct bfd_elf_special_section _bfd_nanomips_elf_special_sections[] = {
+  { STRING_COMMA_LEN (".lit4"),   0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE},
+  { STRING_COMMA_LEN (".lit8"),   0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE},
+  { STRING_COMMA_LEN (".sbss"),  -2, SHT_NOBITS,     SHF_ALLOC + SHF_WRITE},
+  { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE},
+  { NULL,                     0,  0, 0,              0 }
+};
+
+/* Merge non visibility st_other attributes.  Ensure that the
+   STO_OPTIONAL flag is copied into h->other, even if this is not a
+   definiton of the symbol.  */
+
+void
+_bfd_nanomips_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
+					  unsigned int st_other,
+					  bool definition,
+					  bool dynamic
+					  ATTRIBUTE_UNUSED)
+{
+  if ((st_other & ~ELF_ST_VISIBILITY (-1)) != 0)
+    {
+      unsigned char other;
+
+      other = (definition ? st_other : h->other);
+      other &= ~ELF_ST_VISIBILITY (-1);
+      h->other = other | ELF_ST_VISIBILITY (h->other);
+    }
+}
+
+/* Get ABI flags for a nanoMIPS BFD arch.  */
+
+Elf_Internal_ABIFlags_v0 *
+bfd_nanomips_elf_get_abiflags (bfd *abfd)
+{
+  struct nanomips_elf_obj_tdata *tdata = nanomips_elf_tdata (abfd);
+
+  return tdata->abiflags_valid ? &tdata->abiflags : NULL;
+}
+
+/* Relocate a section.  Tools like readelf/binutils needed to perform a static
+   relocation on objects to make sense debug information that contains label
+   difference relocations.  The only difference between this and the generic
+   ELF version is that correct handling of composite relocations according to
+   gABI spec.  */
+
+bfd_byte *
+_bfd_elf_nanomips_get_relocated_section_contents (bfd *abfd,
+						  struct bfd_link_info *link_info,
+						  struct bfd_link_order *link_order,
+						  bfd_byte *data,
+						  bool relocatable,
+						  asymbol **symbols)
+{
+  bfd *input_bfd = link_order->u.indirect.section->owner;
+  asection *input_section = link_order->u.indirect.section;
+  long reloc_size;
+  arelent **reloc_vector;
+  long reloc_count;
+
+  reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
+  if (reloc_size < 0)
+    return NULL;
+
+  /* Read in the section.  */
+  if (!bfd_get_full_section_contents (input_bfd, input_section, &data))
+    return NULL;
+
+  if (data == NULL)
+    return NULL;
+
+  if (reloc_size == 0)
+    return data;
+
+  reloc_vector = (arelent **) bfd_malloc (reloc_size);
+  if (reloc_vector == NULL)
+    return NULL;
+
+  reloc_count = bfd_canonicalize_reloc (input_bfd, input_section,
+					reloc_vector, symbols);
+
+  if (reloc_count < 0)
+    goto error_return;
+
+  if (reloc_count > 0)
+    {
+      arelent **parent;
+      /* offset in section of previous relocation  */
+      bfd_size_type last_address = 0;
+      /* saved result of previous relocation.  */
+      bfd_vma saved_addend = 0;
+
+      for (parent = reloc_vector; *parent != NULL; parent++)
+	{
+	  char *error_message = NULL;
+	  asymbol *symbol;
+	  bfd_reloc_status_type r;
+
+	  symbol = *(*parent)->sym_ptr_ptr;
+	  /* PR ld/19628: A specially crafted input file
+	     can result in a NULL symbol pointer here.  */
+	  if (symbol == NULL)
+	    {
+	      link_info->callbacks->einfo
+		/* xgettext:c-format */
+		(_("%X%P: %B(%A): error: relocation for offset %V has no value\n"),
+		 abfd, input_section, (* parent)->address);
+	      goto error_return;
+	    }
+
+	  if (symbol->section && discarded_section (symbol->section))
+	    {
+	      bfd_vma off;
+	      static reloc_howto_type none_howto
+		= HOWTO (0, 0, 0, 0, false, 0, complain_overflow_dont, NULL,
+			 "unused", false, 0, 0, false);
+
+	      off = (*parent)->address * bfd_octets_per_byte (input_bfd, input_section);
+	      _bfd_clear_contents ((*parent)->howto, input_bfd, input_section,
+				   data, off);
+	      (*parent)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+	      (*parent)->addend = 0;
+	      (*parent)->howto = &none_howto;
+	      r = bfd_reloc_ok;
+	    }
+	  else
+	    {
+	      if (last_address != 0 && (*parent)->address == last_address)
+		(*parent)->addend = saved_addend;
+	      else
+		saved_addend = 0;
+
+	      r = bfd_perform_relocation (input_bfd,
+					  *parent,
+					  data,
+					  input_section,
+					  relocatable ? abfd : NULL,
+					  &error_message);
+	      saved_addend = (*parent)->addend;
+	    }
+
+	  if (relocatable)
+	    {
+	      asection *os = input_section->output_section;
+
+	      /* A partial link, so keep the relocs.  */
+	      os->orelocation[os->reloc_count] = *parent;
+	      os->reloc_count++;
+	    }
+
+	  if (r != bfd_reloc_ok)
+	    {
+	      switch (r)
+		{
+		case bfd_reloc_undefined:
+		  (*link_info->callbacks->undefined_symbol)
+		    (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+		     input_bfd, input_section, (*parent)->address, true);
+		  break;
+		case bfd_reloc_dangerous:
+		  BFD_ASSERT (error_message != NULL);
+		  (*link_info->callbacks->reloc_dangerous)
+		    (link_info, error_message,
+		     input_bfd, input_section, (*parent)->address);
+		  break;
+		case bfd_reloc_overflow:
+		  (*link_info->callbacks->reloc_overflow)
+		    (link_info, NULL,
+		     bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+		     (*parent)->howto->name, (*parent)->addend,
+		     input_bfd, input_section, (*parent)->address);
+		  break;
+		case bfd_reloc_outofrange:
+		  /* PR ld/13730:
+		     This error can result when processing some partially
+		     complete binaries.  Do not abort, but issue an error
+		     message instead.  */
+		  link_info->callbacks->einfo
+		    /* xgettext:c-format */
+		    (_("%X%P: %B(%A): relocation \"%R\" goes out of range\n"),
+		     abfd, input_section, *parent);
+		  goto error_return;
+
+		case bfd_reloc_notsupported:
+		  /* PR ld/17512
+		     This error can result when processing a corrupt binary.
+		     Do not abort.  Issue an error message instead.  */
+		  link_info->callbacks->einfo
+		    /* xgettext:c-format */
+		    (_("%X%P: %B(%A): relocation \"%R\" is not supported\n"),
+		     abfd, input_section, *parent);
+		  goto error_return;
+
+		default:
+		  /* PR 17512; file: 90c2a92e.
+		     Report unexpected results, without aborting.  */
+		  link_info->callbacks->einfo
+		    /* xgettext:c-format */
+		    (_("%X%P: %B(%A): relocation \"%R\" returns an unrecognized value %x\n"),
+		     abfd, input_section, *parent, r);
+		  break;
+		}
+
+	    }
+	  last_address = (*parent)->address;
+	}
+    }
+
+  free (reloc_vector);
+  return data;
+
+error_return:
+  free (reloc_vector);
+  return NULL;
+}
diff --git a/bfd/elfxx-nanomips.h b/bfd/elfxx-nanomips.h
new file mode 100644
index 00000000000..6566db550cb
--- /dev/null
+++ b/bfd/elfxx-nanomips.h
@@ -0,0 +1,54 @@ 
+/* nanoMIPS ELF specific backend routines.
+   Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+   Written by Faraz Shahbazker <faraz.shahbazker@mips.com>
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "elf/nanomips.h"
+
+extern bool _bfd_nanomips_elf_mkobject (bfd *);
+extern bool _bfd_nanomips_elf_section_processing
+  (bfd *, Elf_Internal_Shdr *);
+extern bool _bfd_nanomips_elf_section_from_shdr
+  (bfd *, Elf_Internal_Shdr *, const char *, int);
+extern bool _bfd_nanomips_elf_fake_sections
+  (bfd *, Elf_Internal_Shdr *, asection *);
+extern bool _bfd_nanomips_elf_final_write_processing (bfd *);
+extern const char *_bfd_nanomips_fp_abi_string (int);
+extern bool _bfd_nanomips_elf_print_private_bfd_data (bfd *, void *);
+
+extern bfd_reloc_status_type _bfd_nanomips_elf_generic_reloc
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+extern bfd_reloc_status_type _bfd_nanomips_elf_negative_reloc
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+
+extern unsigned long _bfd_elf_nanomips_mach (flagword);
+extern void _bfd_nanomips_elf_merge_symbol_attribute
+  (struct elf_link_hash_entry *, unsigned int, bool, bool);
+
+extern const struct bfd_elf_special_section
+  _bfd_nanomips_elf_special_sections[];
+
+extern bfd_byte *_bfd_elf_nanomips_get_relocated_section_contents
+  (bfd *, struct bfd_link_info *, struct bfd_link_order *,
+   bfd_byte *, bool, asymbol **);
+
+#define elf_backend_special_sections _bfd_nanomips_elf_special_sections
+#define elf_backend_merge_symbol_attribute	\
+  _bfd_nanomips_elf_merge_symbol_attribute
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 05508c986ad..c48f85ea582 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1330,6 +1330,75 @@  static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_MIPS_COPY",
   "BFD_RELOC_MIPS_JUMP_SLOT",
 
+  "BFD_RELOC_NANOMIPS_HI20",
+  "BFD_RELOC_NANOMIPS_LO12",
+  "BFD_RELOC_NANOMIPS_LO4_S2",
+  "BFD_RELOC_NANOMIPS_IMM16",
+  "BFD_RELOC_NANOMIPS_NEG12",
+  "BFD_RELOC_NANOMIPS_GPREL7_S2",
+  "BFD_RELOC_NANOMIPS_GPREL18",
+  "BFD_RELOC_NANOMIPS_GPREL19_S2",
+  "BFD_RELOC_NANOMIPS_GPREL16_S2",
+  "BFD_RELOC_NANOMIPS_GPREL18_S3",
+  "BFD_RELOC_NANOMIPS_4_PCREL_S1",
+  "BFD_RELOC_NANOMIPS_7_PCREL_S1",
+  "BFD_RELOC_NANOMIPS_10_PCREL_S1",
+  "BFD_RELOC_NANOMIPS_11_PCREL_S1",
+  "BFD_RELOC_NANOMIPS_14_PCREL_S1",
+  "BFD_RELOC_NANOMIPS_21_PCREL_S1",
+  "BFD_RELOC_NANOMIPS_25_PCREL_S1",
+  "BFD_RELOC_NANOMIPS_PCREL_HI20",
+  "BFD_RELOC_NANOMIPS_GOT_CALL",
+  "BFD_RELOC_NANOMIPS_GOTPC_HI20",
+  "BFD_RELOC_NANOMIPS_GOTPC_I32",
+  "BFD_RELOC_NANOMIPS_GOT_LO12",
+  "BFD_RELOC_NANOMIPS_GOT_DISP",
+  "BFD_RELOC_NANOMIPS_GOT_PAGE",
+  "BFD_RELOC_NANOMIPS_GOT_OFST",
+  "BFD_RELOC_NANOMIPS_I32",
+  "BFD_RELOC_NANOMIPS_GPREL_HI20",
+  "BFD_RELOC_NANOMIPS_GPREL_LO12",
+  "BFD_RELOC_NANOMIPS_TLS_GD",
+  "BFD_RELOC_NANOMIPS_TLS_GD_I32",
+  "BFD_RELOC_NANOMIPS_TLS_LD",
+  "BFD_RELOC_NANOMIPS_TLS_LD_I32",
+  "BFD_RELOC_NANOMIPS_TLS_DTPREL12",
+  "BFD_RELOC_NANOMIPS_TLS_DTPREL16",
+  "BFD_RELOC_NANOMIPS_TLS_DTPREL_I32",
+  "BFD_RELOC_NANOMIPS_TLS_GOTTPREL",
+  "BFD_RELOC_NANOMIPS_TLS_GOTTPREL_PC_I32",
+  "BFD_RELOC_NANOMIPS_TLS_TPREL12",
+  "BFD_RELOC_NANOMIPS_TLS_TPREL16",
+  "BFD_RELOC_NANOMIPS_TLS_TPREL_I32",
+  "BFD_RELOC_NANOMIPS_TLS_DTPMOD",
+  "BFD_RELOC_NANOMIPS_TLS_DTPREL",
+  "BFD_RELOC_NANOMIPS_TLS_TPREL",
+  "BFD_RELOC_NANOMIPS_PC_I32",
+  "BFD_RELOC_NANOMIPS_GPREL_I32",
+  "BFD_RELOC_NANOMIPS_GPREL17_S1",
+  "BFD_RELOC_NANOMIPS_NEG",
+  "BFD_RELOC_NANOMIPS_ASHIFTR_1",
+  "BFD_RELOC_NANOMIPS_UNSIGNED_8",
+  "BFD_RELOC_NANOMIPS_UNSIGNED_16",
+  "BFD_RELOC_NANOMIPS_SIGNED_8",
+  "BFD_RELOC_NANOMIPS_SIGNED_16",
+  "BFD_RELOC_NANOMIPS_EH",
+  "BFD_RELOC_NANOMIPS_JUMP_SLOT",
+  "BFD_RELOC_NANOMIPS_ALIGN",
+  "BFD_RELOC_NANOMIPS_FILL",
+  "BFD_RELOC_NANOMIPS_MAX",
+  "BFD_RELOC_NANOMIPS_INSN32",
+  "BFD_RELOC_NANOMIPS_INSN16",
+  "BFD_RELOC_NANOMIPS_FIXED",
+  "BFD_RELOC_NANOMIPS_RELAX",
+  "BFD_RELOC_NANOMIPS_NORELAX",
+  "BFD_RELOC_NANOMIPS_SAVERESTORE",
+  "BFD_RELOC_NANOMIPS_JALR16",
+  "BFD_RELOC_NANOMIPS_JALR32",
+  "BFD_RELOC_NANOMIPS_COPY",
+  "BFD_RELOC_NANOMIPS_SIGNED_9",
+  "BFD_RELOC_NANOMIPS_JUMPTABLE_LOAD",
+
   "BFD_RELOC_MOXIE_10_PCREL",
 
   "BFD_RELOC_FT32_10",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index aab5d49bdb3..bc422fef840 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2177,6 +2177,146 @@  ENUMDOC
   MIPS ELF relocations (VxWorks and PLT extensions).
 COMMENT
 
+ENUM
+  BFD_RELOC_NANOMIPS_HI20
+ENUMX
+  BFD_RELOC_NANOMIPS_LO12
+ENUMX
+  BFD_RELOC_NANOMIPS_LO4_S2
+ENUMX
+  BFD_RELOC_NANOMIPS_IMM16
+ENUMX
+  BFD_RELOC_NANOMIPS_NEG12
+ENUMX
+  BFD_RELOC_NANOMIPS_GPREL7_S2
+ENUMX
+  BFD_RELOC_NANOMIPS_GPREL18
+ENUMX
+  BFD_RELOC_NANOMIPS_GPREL19_S2
+ENUMX
+  BFD_RELOC_NANOMIPS_GPREL16_S2
+ENUMX
+  BFD_RELOC_NANOMIPS_GPREL18_S3
+ENUMX
+  BFD_RELOC_NANOMIPS_4_PCREL_S1
+ENUMX
+  BFD_RELOC_NANOMIPS_7_PCREL_S1
+ENUMX
+  BFD_RELOC_NANOMIPS_10_PCREL_S1
+ENUMX
+  BFD_RELOC_NANOMIPS_11_PCREL_S1
+ENUMX
+  BFD_RELOC_NANOMIPS_14_PCREL_S1
+ENUMX
+  BFD_RELOC_NANOMIPS_21_PCREL_S1
+ENUMX
+  BFD_RELOC_NANOMIPS_25_PCREL_S1
+ENUMX
+  BFD_RELOC_NANOMIPS_PCREL_HI20
+ENUMX
+  BFD_RELOC_NANOMIPS_GOT_CALL
+ENUMX
+  BFD_RELOC_NANOMIPS_GOTPC_HI20
+ENUMX
+  BFD_RELOC_NANOMIPS_GOTPC_I32
+ENUMX
+  BFD_RELOC_NANOMIPS_GOT_LO12
+ENUMX
+  BFD_RELOC_NANOMIPS_GOT_DISP
+ENUMX
+  BFD_RELOC_NANOMIPS_GOT_PAGE
+ENUMX
+  BFD_RELOC_NANOMIPS_GOT_OFST
+ENUMX
+  BFD_RELOC_NANOMIPS_I32
+ENUMX
+  BFD_RELOC_NANOMIPS_GPREL_HI20
+ENUMX
+  BFD_RELOC_NANOMIPS_GPREL_LO12
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_GD
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_GD_I32
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_LD
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_LD_I32
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_DTPREL12
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_DTPREL16
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_DTPREL_I32
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_GOTTPREL
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_GOTTPREL_PC_I32
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_TPREL12
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_TPREL16
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_TPREL_I32
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_DTPMOD
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_DTPREL
+ENUMX
+  BFD_RELOC_NANOMIPS_TLS_TPREL
+ENUMX
+  BFD_RELOC_NANOMIPS_PC_I32
+ENUMX
+  BFD_RELOC_NANOMIPS_GPREL_I32
+ENUMX
+  BFD_RELOC_NANOMIPS_GPREL17_S1
+ENUMX
+  BFD_RELOC_NANOMIPS_NEG
+ENUMX
+  BFD_RELOC_NANOMIPS_ASHIFTR_1
+ENUMX
+  BFD_RELOC_NANOMIPS_UNSIGNED_8
+ENUMX
+  BFD_RELOC_NANOMIPS_UNSIGNED_16
+ENUMX
+  BFD_RELOC_NANOMIPS_SIGNED_8
+ENUMX
+  BFD_RELOC_NANOMIPS_SIGNED_16
+ENUMX
+  BFD_RELOC_NANOMIPS_EH
+ENUMX
+  BFD_RELOC_NANOMIPS_JUMP_SLOT
+ENUMX
+  BFD_RELOC_NANOMIPS_ALIGN
+ENUMX
+  BFD_RELOC_NANOMIPS_FILL
+ENUMX
+  BFD_RELOC_NANOMIPS_MAX
+ENUMX
+  BFD_RELOC_NANOMIPS_INSN32
+ENUMX
+  BFD_RELOC_NANOMIPS_INSN16
+ENUMX
+  BFD_RELOC_NANOMIPS_FIXED
+ENUMX
+  BFD_RELOC_NANOMIPS_RELAX
+ENUMX
+  BFD_RELOC_NANOMIPS_NORELAX
+ENUMX
+  BFD_RELOC_NANOMIPS_SAVERESTORE
+ENUMX
+  BFD_RELOC_NANOMIPS_JALR16
+ENUMX
+  BFD_RELOC_NANOMIPS_JALR32
+ENUMX
+  BFD_RELOC_NANOMIPS_COPY
+ENUMX
+  BFD_RELOC_NANOMIPS_SIGNED_9
+ENUMX
+  BFD_RELOC_NANOMIPS_JUMPTABLE_LOAD
+ENUMDOC
+  nanoMIPS relocations
+COMMENT
+
 ENUM
   BFD_RELOC_MOXIE_10_PCREL
 ENUMDOC
diff --git a/bfd/targets.c b/bfd/targets.c
index 3dbcd088966..264933a83eb 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -829,6 +829,10 @@  extern const bfd_target moxie_elf32_le_vec;
 extern const bfd_target msp430_elf32_vec;
 extern const bfd_target msp430_elf32_ti_vec;
 extern const bfd_target mt_elf32_vec;
+extern const bfd_target nanomips_elf32_be_vec;
+extern const bfd_target nanomips_elf32_le_vec;
+extern const bfd_target nanomips_elf64_le_vec;
+extern const bfd_target nanomips_elf64_be_vec;
 extern const bfd_target nds32_elf32_be_vec;
 extern const bfd_target nds32_elf32_le_vec;
 extern const bfd_target nds32_elf32_linux_be_vec;
@@ -1203,6 +1207,13 @@  static const bfd_target * const _bfd_target_vector[] =
 
 	&mt_elf32_vec,
 
+	&nanomips_elf32_be_vec,
+	&nanomips_elf32_le_vec,
+#ifdef BFD64
+	&nanomips_elf64_be_vec,
+	&nanomips_elf64_le_vec,
+#endif
+
 	&nds32_elf32_be_vec,
 	&nds32_elf32_le_vec,
 	&nds32_elf32_linux_be_vec,
diff --git a/binutils/readelf.c b/binutils/readelf.c
index b872876a8b6..b31a61dc568 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -139,6 +139,7 @@ 
 #include "elf/moxie.h"
 #include "elf/mt.h"
 #include "elf/msp430.h"
+#include "elf/nanomips.h"
 #include "elf/nds32.h"
 #include "elf/nfp.h"
 #include "elf/nios2.h"
@@ -1097,6 +1098,7 @@  guess_is_rela (unsigned int e_machine)
     case EM_MSP430:
     case EM_MSP430_OLD:
     case EM_MT:
+    case EM_NANOMIPS:
     case EM_NDS32:
     case EM_NIOS32:
     case EM_OR1K:
@@ -1894,6 +1896,10 @@  dump_relocations (Filedata *filedata,
 	  rtype = elf_nios2_reloc_type (type);
 	  break;
 
+	case EM_NANOMIPS:
+	  rtype = elf_nanomips_reloc_type (type);
+	  break;
+
 	case EM_TI_PRU:
 	  rtype = elf_pru_reloc_type (type);
 	  break;
@@ -2205,6 +2211,16 @@  get_mips_dynamic_type (unsigned long type)
     }
 }
 
+static const char *
+get_nanomips_dynamic_type (unsigned long type)
+{
+  switch (type)
+    {
+    default:
+      return NULL;
+    }
+}
+
 static const char *
 get_sparc64_dynamic_type (unsigned long type)
 {
@@ -2571,6 +2587,9 @@  get_dynamic_type (Filedata * filedata, unsigned long type)
 	    case EM_RISCV:
 	      result = get_riscv_dynamic_type (type);
 	      break;
+	    case EM_NANOMIPS:
+	      result = get_nanomips_dynamic_type (type);
+	      break;
 	    default:
 	      if (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
 		result = get_solaris_dynamic_type (type);
@@ -2963,7 +2982,7 @@  get_machine_name (unsigned e_machine)
     case EM_CEVA_X2:		return "CEVA X2 Processor Family";
     case EM_BPF:		return "Linux BPF";
     case EM_GRAPHCORE_IPU:	return "Graphcore Intelligent Processing Unit";
-    case EM_IMG1:		return "Imagination Technologies";
+    case EM_NANOMIPS:		return "Imagination Technologies";
       /* 250 */
     case EM_NFP:		return "Netronome Flow Processor";
     case EM_VE:			return "NEC Vector Engine";
@@ -4393,6 +4412,38 @@  get_machine_flags (Filedata * filedata, unsigned e_flags, unsigned e_machine)
 	    strcat (buf, ", OBJ-v1");
 
 	  break;
+	case EM_NANOMIPS:
+	  if (e_flags & EF_NANOMIPS_PIC)
+	    strcat (buf, ", pic");
+
+	  if (e_flags & EF_NANOMIPS_32BITMODE)
+	    strcat (buf, ", 32bitmode");
+
+	  switch ((e_flags & EF_NANOMIPS_MACH))
+	    {
+	    default: strcat (buf, _(", unknown CPU")); break;
+	    }
+
+	  switch ((e_flags & EF_NANOMIPS_ABI))
+	    {
+	    case E_NANOMIPS_ABI_P32: strcat (buf, ", p32"); break;
+	    case E_NANOMIPS_ABI_P64: strcat (buf, ", p64"); break;
+	    case 0:
+	    /* We simply ignore the field in this case to avoid confusion:
+	    MIPS ELF does not specify EF_MIPS_ABI, it is a GNU extension.
+	    This means it is likely to be an o32 file, but not for
+	    sure. */
+	    break;
+	    default: strcat (buf, _(", unknown ABI")); break;
+	    }
+
+	    switch ((e_flags & EF_NANOMIPS_ARCH))
+	    {
+	    case E_NANOMIPS_ARCH_32R6: strcat (buf, ", nanomips32r6"); break;
+	    case E_NANOMIPS_ARCH_64R6: strcat (buf, ", nanomips64r6"); break;
+	    default: strcat (buf, _(", unknown ISA")); break;
+	    }
+	    break;
 	}
     }
 
@@ -4521,6 +4572,20 @@  get_mips_segment_type (unsigned long type)
     }
 }
 
+static const char *
+get_nanomips_segment_type (unsigned long type)
+{
+  switch (type)
+    {
+    case PT_NANOMIPS_ABIFLAGS:
+      return "ABIFLAGS";
+    default:
+      break;
+    }
+
+  return NULL;
+}
+
 static const char *
 get_parisc_segment_type (unsigned long type)
 {
@@ -4675,6 +4740,9 @@  get_segment_type (Filedata * filedata, unsigned long p_type)
 	    case EM_S390_OLD:
 	      result = get_s390_segment_type (p_type);
 	      break;
+	    case EM_NANOMIPS:
+	      result = get_nanomips_segment_type (p_type);
+	      break;
 	    case EM_RISCV:
 	      result = get_riscv_segment_type (p_type);
 	      break;
@@ -10725,6 +10793,17 @@  dynamic_section_mips_val (Filedata * filedata, Elf_Internal_Dyn * entry)
     putchar ('\n');
 }
 
+static void
+dynamic_section_nanomips_val (Elf_Internal_Dyn * entry)
+{
+  switch (entry->d_tag)
+    {
+    default:
+      print_vma (entry->d_un.d_ptr, PREFIX_HEX);
+    }
+    putchar ('\n');
+}
+
 static void
 dynamic_section_parisc_val (Elf_Internal_Dyn * entry)
 {
@@ -12065,6 +12144,9 @@  the .dynstr section doesn't match the DT_STRTAB and DT_STRSZ tags\n"));
 		case EM_IA_64:
 		  dynamic_section_ia64_val (entry);
 		  break;
+		case EM_NANOMIPS:
+		  dynamic_section_nanomips_val (entry);
+		  break;
 		default:
 		  print_vma (entry->d_un.d_val, PREFIX_HEX);
 		  putchar ('\n');
@@ -14357,6 +14439,8 @@  is_32bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
       return reloc_type == 1; /* R_MSP430_32 or R_MSP320_ABS32.  */
     case EM_MT:
       return reloc_type == 2; /* R_MT_32.  */
+    case EM_NANOMIPS:
+      return reloc_type == 1; /* R_NANOMIPS_32.  */
     case EM_NDS32:
       return reloc_type == 20; /* R_NDS32_32_RELA.  */
     case EM_ALTERA_NIOS2:
@@ -14561,6 +14645,8 @@  is_64bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
       return reloc_type == 1; /* R_TILEGX_64.  */
     case EM_MIPS:
       return reloc_type == 18;	/* R_MIPS_64.  */
+    case EM_NANOMIPS:
+      return reloc_type == 2; /* R_NANOMIPS_64.  */
     default:
       return false;
     }
@@ -14668,6 +14754,8 @@  is_16bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
       /* Fall through.  */
     case EM_MSP430_OLD:
       return reloc_type == 5; /* R_MSP430_16_BYTE.  */
+    case EM_NANOMIPS:
+      return reloc_type == 7; /* R_NANOMIPS_UNSIGNED_16 */
     case EM_NDS32:
       return reloc_type == 19; /* R_NDS32_16_RELA.  */
     case EM_ALTERA_NIOS2:
@@ -14896,6 +14984,7 @@  is_none_reloc (Filedata * filedata, unsigned int reloc_type)
     case EM_MOXIE:   /* R_MOXIE_NONE.  */
     case EM_NIOS32:  /* R_NIOS_NONE.  */
     case EM_OR1K:    /* R_OR1K_NONE. */
+    case EM_NANOMIPS:    /* R_NANOMIPS_NONE.  */
     case EM_PARISC:  /* R_PARISC_NONE.  */
     case EM_PPC64:   /* R_PPC64_NONE.  */
     case EM_PPC:     /* R_PPC_NONE.  */
@@ -17480,6 +17569,71 @@  display_mips_gnu_attribute (unsigned char * p,
   return display_tag_value (tag & 1, p, end);
 }
 
+static void
+print_nanomips_fp_abi_value (int val)
+{
+  switch (val)
+    {
+    case Val_GNU_NANOMIPS_ABI_FP_ANY:
+      printf (_("Hard or soft float\n"));
+      break;
+    case Val_GNU_NANOMIPS_ABI_FP_DOUBLE:
+      printf (_("Hard float (double precision)\n"));
+      break;
+    case Val_GNU_NANOMIPS_ABI_FP_SINGLE:
+      printf (_("Hard float (single precision)\n"));
+      break;
+    case Val_GNU_NANOMIPS_ABI_FP_SOFT:
+      printf (_("Soft float\n"));
+      break;
+    default:
+      printf ("??? (%d)\n", val);
+      break;
+    }
+}
+
+static unsigned char *
+display_nanomips_gnu_attribute (unsigned char * p,
+				unsigned int tag,
+				const unsigned char * const end)
+{
+	if (tag == Tag_GNU_NANOMIPS_ABI_FP)
+	  {
+	    uint64_t val;
+
+	    READ_ULEB (val, p, end);
+	    printf ("  Tag_GNU_NANOMIPS_ABI_FP: ");
+
+	    print_nanomips_fp_abi_value (val);
+
+	    return p;
+	  }
+
+	if (tag == Tag_GNU_NANOMIPS_ABI_MSA)
+	  {
+	    uint64_t val;
+
+	    READ_ULEB (val, p, end);
+	    printf ("  Tag_GNU_NANOMIPS_ABI_MSA: ");
+
+	  switch (val)
+	    {
+	      case Val_GNU_NANOMIPS_ABI_MSA_ANY:
+		printf (_("Any MSA or not\n"));
+		break;
+	      case Val_GNU_NANOMIPS_ABI_MSA_128:
+		printf (_("128-bit MSA\n"));
+		break;
+	      default:
+		printf ("??? (%lu)\n", val);
+		break;
+	    }
+	  return p;
+	}
+
+	return display_tag_value (tag & 1, p, end);
+}
+
 static unsigned char *
 display_tic6x_attribute (unsigned char * p,
 			 const unsigned char * const end)
@@ -19317,6 +19471,350 @@  process_mips_specific (Filedata * filedata)
   return res;
 }
 
+static void
+print_nanomips_ases (unsigned int mask)
+{
+  if (mask & NANOMIPS_ASE_DSPR3)
+    fputs ("\n\tDSP R3 ASE", stdout);
+  if (mask & NANOMIPS_ASE_EVA)
+    fputs ("\n\tEnhanced VA Scheme", stdout);
+  if (mask & NANOMIPS_ASE_MCU)
+    fputs ("\n\tMCU (MicroController) ASE", stdout);
+  if (mask & NANOMIPS_ASE_MT)
+    fputs ("\n\tMT ASE", stdout);
+  if (mask & NANOMIPS_ASE_VIRT)
+    fputs ("\n\tVZ ASE", stdout);
+  if (mask & NANOMIPS_ASE_MSA)
+    fputs ("\n\tMSA ASE", stdout);
+  if (mask & NANOMIPS_ASE_TLB)
+    fputs ("\n\tTLB ASE", stdout);
+  if (mask & NANOMIPS_ASE_GINV)
+    fputs ("\n\tGINV ASE", stdout);
+ if ((mask & NANOMIPS_ASE_xNMS) == 0)
+    fputs ("\n\tnanoMIPS subset", stdout);
+  else if (mask == 0)
+    fprintf (stdout, "\n\t%s", _("None"));
+  else if ((mask & ~NANOMIPS_ASE_MASK) != 0)
+    fprintf (stdout, "\n\t%s (%x)", _("Unknown"), mask & ~NANOMIPS_ASE_MASK);
+}
+
+static void
+print_nanomips_isa_ext (unsigned int isa_ext)
+{
+  switch (isa_ext)
+    {
+    case 0:
+      fputs (_("None"), stdout);
+      break;
+    default:
+      fprintf (stdout, "%s (%d)", _("Unknown"), isa_ext);
+    }
+}
+
+static int
+get_nanomips_reg_size (int reg_size)
+{
+  return (get_mips_reg_size (reg_size));
+}
+
+static bool
+process_nanomips_specific (Filedata * filedata)
+{
+	Elf_Internal_Dyn * entry;
+	Elf_Internal_Shdr *sect = NULL;
+	size_t options_offset = 0;
+	bfd_vma pltgot = 0;
+	bfd_vma gotsym = 0;
+	bfd_vma symtabno = 0;
+
+	process_attributes (filedata, NULL, SHT_GNU_ATTRIBUTES, NULL,
+	display_nanomips_gnu_attribute);
+
+	sect = find_section (filedata, ".nanoMIPS.abiflags");
+
+	if (sect != NULL)
+	  {
+	    Elf_External_ABIFlags_v0 *abiflags_ext;
+	    Elf_Internal_ABIFlags_v0 abiflags_in;
+
+	    if (sizeof (Elf_External_ABIFlags_v0) != sect->sh_size)
+	      fputs ("\nCorrupt ABI Flags section.\n", stdout);
+	    else
+	      {
+		abiflags_ext = get_data (NULL, filedata, sect->sh_offset, 1,
+		  sect->sh_size, _("nanoMIPS ABI Flags section"));
+		if (abiflags_ext)
+		  {
+		    abiflags_in.version = BYTE_GET (abiflags_ext->version);
+		    abiflags_in.isa_level = BYTE_GET (abiflags_ext->isa_level);
+		    abiflags_in.isa_rev = BYTE_GET (abiflags_ext->isa_rev);
+		    abiflags_in.gpr_size = BYTE_GET (abiflags_ext->gpr_size);
+		    abiflags_in.cpr1_size = BYTE_GET (abiflags_ext->cpr1_size);
+		    abiflags_in.cpr2_size = BYTE_GET (abiflags_ext->cpr2_size);
+		    abiflags_in.fp_abi = BYTE_GET (abiflags_ext->fp_abi);
+		    abiflags_in.isa_ext = BYTE_GET (abiflags_ext->isa_ext);
+		    abiflags_in.ases = BYTE_GET (abiflags_ext->ases);
+		    abiflags_in.flags1 = BYTE_GET (abiflags_ext->flags1);
+		    abiflags_in.flags2 = BYTE_GET (abiflags_ext->flags2);
+
+		    printf ("\nnanoMIPS ABI Flags Version: %d\n", abiflags_in.version);
+		    printf ("\nISA: nanoMIPS%d", abiflags_in.isa_level);
+		    if (abiflags_in.isa_rev > 1)
+		      printf ("r%d", abiflags_in.isa_rev);
+		    printf ("\nGPR size: %d",
+		    get_nanomips_reg_size (abiflags_in.gpr_size));
+		    printf ("\nCPR1 size: %d",
+		    get_nanomips_reg_size (abiflags_in.cpr1_size));
+		    printf ("\nCPR2 size: %d",
+		    get_nanomips_reg_size (abiflags_in.cpr2_size));
+		    fputs ("\nFP ABI: ", stdout);
+		    print_nanomips_fp_abi_value (abiflags_in.fp_abi);
+		    fputs ("ISA Extension: ", stdout);
+		    print_nanomips_isa_ext (abiflags_in.isa_ext);
+		    fputs ("\nASEs:", stdout);
+		    print_nanomips_ases (abiflags_in.ases);
+		    printf ("\nFLAGS 1: %8.8lx", abiflags_in.flags1);
+		    printf ("\nFLAGS 2: %8.8lx", abiflags_in.flags2);
+		    fputc ('\n', stdout);
+		    free (abiflags_ext);
+		  }
+		}
+	      }
+
+	    if (!get_dynamic_section (filedata))
+	      return false;
+
+	    for (entry = filedata->dynamic_section;
+	      entry < filedata->dynamic_section + filedata->dynamic_nent && entry->d_tag != DT_NULL;
+	      ++entry)
+	      switch (entry->d_tag)
+		{
+		case DT_PLTGOT:
+		  pltgot = entry->d_un.d_ptr;
+		  break;
+		default:
+		  break;
+		}
+
+	    if (options_offset != 0)
+	      {
+		Elf_External_Options * eopt;
+		Elf_Internal_Options * iopt;
+		Elf_Internal_Options * option;
+		size_t offset;
+		int cnt;
+		sect = filedata->section_headers;
+
+		/* Find the section header so that we get the size.  */
+		sect = find_section_by_type (filedata, SHT_MIPS_OPTIONS);
+		if (sect == NULL)
+		  {
+		    error (_("No MIPS_OPTIONS header found\n"));
+		    return 0;
+		  }
+
+		eopt = (Elf_External_Options *) get_data (NULL, filedata, options_offset, 1,
+		  sect->sh_size, _("options"));
+		if (eopt)
+		  {
+		    iopt = (Elf_Internal_Options *)
+		      cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (* iopt));
+		    if (iopt == NULL)
+		      {
+			error (_("Out of memory allocatinf space for MIPS options\n"));
+			return 0;
+		      }
+
+		    offset = cnt = 0;
+		    option = iopt;
+
+		    while (offset < sect->sh_size)
+		      {
+			Elf_External_Options * eoption;
+			eoption = (Elf_External_Options *) ((char *) eopt + offset);
+
+			option->kind = BYTE_GET (eoption->kind);
+			option->size = BYTE_GET (eoption->size);
+			option->section = BYTE_GET (eoption->section);
+			option->info = BYTE_GET (eoption->info);
+
+			offset += option->size;
+
+			++option;
+			++cnt;
+		      }
+
+		    printf (_("\nSection '%s' contains %d entries:\n"),
+		    printable_section_name (filedata, sect), cnt);
+
+		    option = iopt;
+
+		    while (cnt-- > 0)
+		      {
+			size_t len;
+
+			switch (option->kind)
+			  {
+			  case ODK_NULL:
+			    /* This shouldn't happen.  */
+			    printf (" NULL       %d %x", option->section, option->info);
+			    break;
+			  case ODK_EXCEPTIONS:
+			    fputs (" EXCEPTIONS fpe_min(", stdout);
+			    process_mips_fpe_exception (option->info & OEX_FPU_MIN);
+			    fputs (") fpe_max(", stdout);
+			    process_mips_fpe_exception ((option->info & OEX_FPU_MAX) >> 8);
+			    fputs (")", stdout);
+
+			    if (option->info & OEX_PAGE0)
+			      fputs (" PAGE0", stdout);
+			    if (option->info & OEX_SMM)
+			      fputs (" SMM", stdout);
+			    if (option->info & OEX_FPDBUG)
+			      fputs (" FPDBUG", stdout);
+			    if (option->info & OEX_DISMISS)
+			      fputs (" DISMISS", stdout);
+			    break;
+			  case ODK_PAD:
+			    fputs (" PAD       ", stdout);
+			    if (option->info & OPAD_PREFIX)
+			    fputs (" PREFIX", stdout);
+			    if (option->info & OPAD_POSTFIX)
+			    fputs (" POSTFIX", stdout);
+			    if (option->info & OPAD_SYMBOL)
+			    fputs (" SYMBOL", stdout);
+			    break;
+			  case ODK_HWPATCH:
+			    fputs (" HWPATCH   ", stdout);
+			    if (option->info & OHW_R4KEOP)
+			      fputs (" R4KEOP", stdout);
+			    if (option->info & OHW_R8KPFETCH)
+			      fputs (" R8KPFETCH", stdout);
+			    if (option->info & OHW_R5KEOP)
+			      fputs (" R5KEOP", stdout);
+			    if (option->info & OHW_R5KCVTL)
+			      fputs (" R5KCVTL", stdout);
+			    break;
+			  case ODK_FILL:
+			    fputs (" FILL       ", stdout);
+			    /* XXX Print content of info word?  */
+			    break;
+			  case ODK_TAGS:
+			    fputs (" TAGS       ", stdout);
+			    /* XXX Print content of info word?  */
+			    break;
+			  case ODK_HWAND:
+			    fputs (" HWAND     ", stdout);
+			    if (option->info & OHWA0_R4KEOP_CHECKED)
+			      fputs (" R4KEOP_CHECKED", stdout);
+			    if (option->info & OHWA0_R4KEOP_CLEAN)
+			      fputs (" R4KEOP_CLEAN", stdout);
+			    break;
+			  case ODK_HWOR:
+			    fputs (" HWOR      ", stdout);
+			    if (option->info & OHWA0_R4KEOP_CHECKED)
+			      fputs (" R4KEOP_CHECKED", stdout);
+			    if (option->info & OHWA0_R4KEOP_CLEAN)
+			      fputs (" R4KEOP_CLEAN", stdout);
+			    break;
+			  case ODK_GP_GROUP:
+			    printf (" GP_GROUP  %#06x  self-contained %#06x",
+			      option->info & OGP_GROUP,
+			      (option->info & OGP_SELF) >> 16);
+			    break;
+			  case ODK_IDENT:
+			    printf (" IDENT     %#06x  self-contained %#06x",
+			      option->info & OGP_GROUP,
+			      (option->info & OGP_SELF) >> 16);
+			    break;
+			  default:
+			    /* This shouldn't happen.  */
+			    printf (" %3d ???     %d %x",
+			    option->kind, option->section, option->info);
+			  break;
+			  }
+			len = sizeof (* eopt);
+			while (len < option->size)
+			  if (((char *) option)[len] >= ' '
+			    && ((char *) option)[len] < 0x7f)
+			    printf ("%c", ((char *) option)[len++]);
+			  else
+			    printf ("\\%03o", ((char *) option)[len++]);
+
+			fputs ("\n", stdout);
+			++option;
+		      }
+		    free (eopt);
+		  }
+	      }
+
+	    if (pltgot != 0)
+	      {
+		bfd_vma ent, end;
+		size_t i, offset;
+		unsigned char * data;
+		int addr_size;
+
+		ent = pltgot;
+		addr_size = (is_32bit_elf ? 4 : 8);
+
+		if (symtabno < gotsym)
+		  {
+		    error (_("The GOT symbol offset (%lu) is greater than the symbol table size (%lu)\n"),
+		      (long) gotsym, (long) symtabno);
+		    return 0;
+		  }
+
+		end = pltgot + (symtabno - gotsym) * addr_size;
+		offset = offset_from_vma (filedata, pltgot, end - pltgot);
+		data = (unsigned char *) get_data (NULL, filedata, offset,
+		  end - pltgot, 1,
+		_("Global Offset Table data"));
+		if (data == NULL)
+		  return 0;
+
+		printf (_(" Canonical gp value: "));
+		print_vma (pltgot + 0x7ff0, LONG_HEX);
+		printf ("\n\n");
+
+		printf (_(" Reserved entries:\n"));
+		printf (_("  %*s %10s %*s Purpose\n"),
+		addr_size * 2, _("Address"), _("Access"),
+		addr_size * 2, _("Initial"));
+		ent = print_mips_got_entry (data, pltgot, ent, data + (end - pltgot));
+		printf (_(" Lazy resolver\n"));
+		if (data
+		  && (byte_get (data + ent - pltgot, addr_size)
+		  >> (addr_size * 8 - 1)) != 0)
+		  {
+		    ent = print_mips_got_entry (data, pltgot, ent, data + (end - pltgot));
+		    printf (_(" Module pointer (GNU extension)\n"));
+		  }
+		printf ("\n\n");
+		printf (_(" Entries:\n"));
+		printf ("  %*s %10s %*s %*s %-7s %3s %s\n",
+		addr_size * 2, _("Address"),
+		  _("Access"),
+		  addr_size * 2, _("Initial"),
+		  addr_size * 2, _("Sym.Val."),
+		  _("Type"),
+		  /* Note for translators: "Ndx" = abbreviated form of "Index".  */
+		  _("Ndx"), _("Name"));
+
+		for (i = gotsym; i < symtabno; i++)
+		  {
+		    ent = print_mips_got_entry (data, pltgot, ent, data + (end - pltgot));
+		    printf (" ");
+		    printf ("\n");
+		  }
+
+		if (data)
+		  free (data);
+	  }
+
+	return 1;
+}
+
 static bool
 process_nds32_specific (Filedata * filedata)
 {
@@ -22264,6 +22762,8 @@  process_arch_specific (Filedata * filedata)
       return process_attributes (filedata, "c6xabi", SHT_C6000_ATTRIBUTES,
 				 display_tic6x_attribute,
 				 display_generic_attribute);
+    case EM_NANOMIPS:
+      return process_nanomips_specific (filedata);
 
     case EM_CSKY:
       return process_attributes (filedata, "csky", SHT_CSKY_ATTRIBUTES,
diff --git a/include/dis-asm.h b/include/dis-asm.h
index d356429f3c5..1baf43cf9ec 100644
--- a/include/dis-asm.h
+++ b/include/dis-asm.h
@@ -307,6 +307,11 @@  typedef struct disassemble_info
   /* Set to true if the disassembler applied styling to the output,
      otherwise, set to false.  */
   bool created_styled_output;
+
+  /* Predict the size of an instruction.  */
+  int (* predict_insn_length)
+    (bfd_vma, int,  struct disassemble_info *);
+
 } disassemble_info;
 
 /* This struct is used to pass information about valid disassembler
@@ -366,6 +371,7 @@  typedef int (*disassembler_ftype) (bfd_vma, disassemble_info *);
 extern int print_insn_m32c		(bfd_vma, disassemble_info *);
 extern int print_insn_mep		(bfd_vma, disassemble_info *);
 extern int print_insn_s12z		(bfd_vma, disassemble_info *);
+extern int print_insn_nanomips		(bfd_vma, disassemble_info *);
 extern int print_insn_sh		(bfd_vma, disassemble_info *);
 extern int print_insn_sparc		(bfd_vma, disassemble_info *);
 extern int print_insn_rx		(bfd_vma, disassemble_info *);
@@ -380,6 +386,7 @@  extern disassembler_ftype cris_get_disassembler (bfd *);
 extern void print_aarch64_disassembler_options (FILE *);
 extern void print_i386_disassembler_options (FILE *);
 extern void print_mips_disassembler_options (FILE *);
+extern void print_nanomips_disassembler_options (FILE *);
 extern void print_nfp_disassembler_options (FILE *);
 extern void print_ppc_disassembler_options (FILE *);
 extern void print_riscv_disassembler_options (FILE *);
@@ -475,6 +482,10 @@  extern asymbol *generic_symbol_at_address
 extern bool generic_symbol_is_valid
   (asymbol *, struct disassemble_info *);
 
+/* Generic insn length, returns 2nd argument.  */
+extern int generic_predict_insn_length
+  (bfd_vma, int, struct disassemble_info *);
+
 /* Method to initialize a disassemble_info struct.  This should be
    called by all applications creating such a struct.  */
 extern void init_disassemble_info (struct disassemble_info *dinfo, void *stream,
diff --git a/include/elf/common.h b/include/elf/common.h
index 6f64f05890c..253200fa652 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -346,7 +346,7 @@ 
 #define EM_CEVA_X2	246	/* CEVA X2 Processor Family */
 #define EM_BPF		247	/* Linux BPF – in-kernel virtual machine.  */
 #define EM_GRAPHCORE_IPU 248	/* Graphcore Intelligent Processing Unit */
-#define EM_IMG1		249	/* Imagination Technologies */
+#define EM_NANOMIPS		249	/* nanoMIPS */
 #define EM_NFP		250	/* Netronome Flow Processor.  */
 #define EM_VE		251	/* NEC Vector Engine */
 #define EM_CSKY		252	/* C-SKY processor family.  */
diff --git a/include/elf/mips-common.h b/include/elf/mips-common.h
new file mode 100644
index 00000000000..1d941fa9f2d
--- /dev/null
+++ b/include/elf/mips-common.h
@@ -0,0 +1,41 @@ 
+/* MIPS ELF support for BFD.
+   Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* This file holds definitions common to the MIPS and nanoMIPS ELF ABIs.  */
+
+#ifndef _ELF_MIPS_COMMON_H
+#define _ELF_MIPS_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Values for the xxx_size bytes of an ABI flags structure.  */
+
+#define AFL_REG_NONE	     0x00	/* No registers.  */
+#define AFL_REG_32	     0x01	/* 32-bit registers.  */
+#define AFL_REG_64	     0x02	/* 64-bit registers.  */
+#define AFL_REG_128	     0x03	/* 128-bit registers.  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ELF_MIPS_COMMON_H */
diff --git a/include/elf/nanomips.h b/include/elf/nanomips.h
new file mode 100644
index 00000000000..82d081c04f8
--- /dev/null
+++ b/include/elf/nanomips.h
@@ -0,0 +1,260 @@ 
+/* nanoMIPS ELF support for BFD.
+   Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+   Written by Faraz Shahbazker <faraz.shahbazker@mips.com>
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* This file holds definitions specific to the nanoMIPS ELF ABI.  */
+
+#ifndef _ELF_NANOMIPS_H
+#define _ELF_NANOMIPS_H
+
+#include "elf/reloc-macros.h"
+#include "elf/mips.h"
+#include "elf/mips-common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+START_RELOC_NUMBERS (elf_nanomips_reloc_type)
+  RELOC_NUMBER (R_NANOMIPS_NONE, 0)
+  RELOC_NUMBER (R_NANOMIPS_32, 1)
+  RELOC_NUMBER (R_NANOMIPS_64, 2)
+  RELOC_NUMBER (R_NANOMIPS_NEG, 3)
+  RELOC_NUMBER (R_NANOMIPS_ASHIFTR_1, 4)
+  RELOC_NUMBER (R_NANOMIPS_UNSIGNED_8, 5)
+  RELOC_NUMBER (R_NANOMIPS_SIGNED_8, 6)
+  RELOC_NUMBER (R_NANOMIPS_UNSIGNED_16, 7)
+  RELOC_NUMBER (R_NANOMIPS_SIGNED_16, 8)
+  RELOC_NUMBER (R_NANOMIPS_RELATIVE, 9)
+  RELOC_NUMBER (R_NANOMIPS_GLOBAL, 10)
+  RELOC_NUMBER (R_NANOMIPS_JUMP_SLOT, 11)
+  RELOC_NUMBER (R_NANOMIPS_IRELATIVE, 12)
+
+  RELOC_NUMBER (R_NANOMIPS_PC25_S1, 13)
+  RELOC_NUMBER (R_NANOMIPS_PC21_S1, 14)
+  RELOC_NUMBER (R_NANOMIPS_PC14_S1, 15)
+  RELOC_NUMBER (R_NANOMIPS_PC11_S1, 16)
+  RELOC_NUMBER (R_NANOMIPS_PC10_S1, 17)
+  RELOC_NUMBER (R_NANOMIPS_PC7_S1, 18)
+  RELOC_NUMBER (R_NANOMIPS_PC4_S1, 19)
+
+  RELOC_NUMBER (R_NANOMIPS_GPREL19_S2, 20)
+  RELOC_NUMBER (R_NANOMIPS_GPREL18_S3, 21)
+  RELOC_NUMBER (R_NANOMIPS_GPREL18, 22)
+  RELOC_NUMBER (R_NANOMIPS_GPREL17_S1, 23)
+  RELOC_NUMBER (R_NANOMIPS_GPREL16_S2, 24)
+  RELOC_NUMBER (R_NANOMIPS_GPREL7_S2, 25)
+  RELOC_NUMBER (R_NANOMIPS_GPREL_HI20, 26)
+  RELOC_NUMBER (R_NANOMIPS_PCHI20, 27)
+
+  RELOC_NUMBER (R_NANOMIPS_HI20, 28)
+  RELOC_NUMBER (R_NANOMIPS_LO12, 29)
+  RELOC_NUMBER (R_NANOMIPS_GPREL_I32, 30)
+  RELOC_NUMBER (R_NANOMIPS_PC_I32, 31)
+  RELOC_NUMBER (R_NANOMIPS_I32, 32)
+  RELOC_NUMBER (R_NANOMIPS_GOT_DISP, 33)
+  RELOC_NUMBER (R_NANOMIPS_GOTPC_I32, 34)
+  RELOC_NUMBER (R_NANOMIPS_GOTPC_HI20, 35)
+  RELOC_NUMBER (R_NANOMIPS_GOT_LO12, 36)
+  RELOC_NUMBER (R_NANOMIPS_GOT_CALL, 37)
+  RELOC_NUMBER (R_NANOMIPS_GOT_PAGE, 38)
+  RELOC_NUMBER (R_NANOMIPS_GOT_OFST, 39)
+  RELOC_NUMBER (R_NANOMIPS_LO4_S2, 40)
+  /* Reserved for 64-bit ABI. */
+  RELOC_NUMBER (R_NANOMIPS_RESERVED1, 41)
+  RELOC_NUMBER (R_NANOMIPS_GPREL_LO12, 42)
+  RELOC_NUMBER (R_NANOMIPS_SCN_DISP, 43)
+  RELOC_NUMBER (R_NANOMIPS_COPY, 44)
+
+  RELOC_NUMBER (R_NANOMIPS_ALIGN, 64)
+  RELOC_NUMBER (R_NANOMIPS_FILL, 65)
+  RELOC_NUMBER (R_NANOMIPS_MAX, 66)
+  RELOC_NUMBER (R_NANOMIPS_INSN32, 67)
+  RELOC_NUMBER (R_NANOMIPS_FIXED, 68)
+  RELOC_NUMBER (R_NANOMIPS_NORELAX, 69)
+  RELOC_NUMBER (R_NANOMIPS_RELAX, 70)
+  RELOC_NUMBER (R_NANOMIPS_SAVERESTORE, 71)
+  RELOC_NUMBER (R_NANOMIPS_INSN16, 72)
+  RELOC_NUMBER (R_NANOMIPS_JALR32, 73)
+  RELOC_NUMBER (R_NANOMIPS_JALR16, 74)
+  RELOC_NUMBER (R_NANOMIPS_JUMPTABLE_LOAD, 75)
+  RELOC_NUMBER (R_NANOMIPS_FRAME_REG, 76)
+
+  /* TLS relocations.  */
+  RELOC_NUMBER (R_NANOMIPS_TLS_DTPMOD, 80)
+  RELOC_NUMBER (R_NANOMIPS_TLS_DTPREL, 81)
+  RELOC_NUMBER (R_NANOMIPS_TLS_TPREL, 82)
+  RELOC_NUMBER (R_NANOMIPS_TLS_GD, 83)
+  RELOC_NUMBER (R_NANOMIPS_TLS_GD_I32, 84)
+  RELOC_NUMBER (R_NANOMIPS_TLS_LD, 85)
+  RELOC_NUMBER (R_NANOMIPS_TLS_LD_I32, 86)
+  RELOC_NUMBER (R_NANOMIPS_TLS_DTPREL12, 87)
+  RELOC_NUMBER (R_NANOMIPS_TLS_DTPREL16, 88)
+  RELOC_NUMBER (R_NANOMIPS_TLS_DTPREL_I32, 89)
+  RELOC_NUMBER (R_NANOMIPS_TLS_GOTTPREL, 90)
+  RELOC_NUMBER (R_NANOMIPS_TLS_GOTTPREL_PC_I32, 91)
+  RELOC_NUMBER (R_NANOMIPS_TLS_TPREL12, 92)
+  RELOC_NUMBER (R_NANOMIPS_TLS_TPREL16, 93)
+  RELOC_NUMBER (R_NANOMIPS_TLS_TPREL_I32, 94)
+
+  FAKE_RELOC (R_NANOMIPS_max, 94)
+  /* May be used for compact unwind tables in the future.  */
+  RELOC_NUMBER (R_NANOMIPS_PC32, 248)
+  RELOC_NUMBER (R_NANOMIPS_EH, 249)
+  /* These are GNU extensions to enable C++ vtable garbage collection.  */
+  RELOC_NUMBER (R_NANOMIPS_GNU_VTINHERIT, 253)
+  RELOC_NUMBER (R_NANOMIPS_GNU_VTENTRY, 254)
+END_RELOC_NUMBERS (R_NANOMIPS_maxext)
+
+/* Processor specific flags for the ELF header e_flags field.  */
+
+/* File may be relaxed by the linker.  */
+#define EF_NANOMIPS_LINKRELAX	0x00000001
+
+/* File contains position independent code.  */
+#define EF_NANOMIPS_PIC		0x00000002
+
+/* Indicates code compiled for a 64-bit machine in 32-bit mode
+   (regs are 32-bits wide).  */
+#define EF_NANOMIPS_32BITMODE	0x00000004
+
+/* File contains position independent code.  */
+#define EF_NANOMIPS_PID		0x00000008
+
+/* File contains pure PC-relative code.  */
+#define EF_NANOMIPS_PCREL	0x00000010
+
+/* Four bit nanoMIPS architecture field.  */
+#define EF_NANOMIPS_ARCH	0xf0000000
+
+/* -march=32r6[s] code.  */
+#define E_NANOMIPS_ARCH_32R6    0x00000000
+
+/* -march=64r6 code.  */
+#define E_NANOMIPS_ARCH_64R6    0x10000000
+
+/* The ABI of the file.  */
+#define EF_NANOMIPS_ABI		0x0000F000
+
+/* nanoMIPS ABI in 32 bit mode.  */
+#define E_NANOMIPS_ABI_P32      0x00001000
+
+/* nanoMIPS ABI in 64 bit mode.  */
+#define E_NANOMIPS_ABI_P64      0x00002000
+
+/* Machine variant if we know it.  This field was invented at Cygnus
+   for MIPS.  It may be used similarly for nanoMIPS.  */
+
+#define EF_NANOMIPS_MACH	0x00FF0000
+
+
+/* Processor specific section types.  */
+
+/* ABI related flags section.  */
+#define SHT_NANOMIPS_ABIFLAGS	0x70000000
+
+
+/* Processor specific program header types.  */
+
+/* Records ABI related flags.  */
+#define PT_NANOMIPS_ABIFLAGS	0x70000000
+
+
+
+/* Object attribute tags.  */
+enum
+{
+  /* 0-3 are generic.  */
+
+  /* Floating-point ABI used by this object file.  */
+  Tag_GNU_NANOMIPS_ABI_FP = 4,
+
+  /* MSA ABI used by this object file.  */
+  Tag_GNU_NANOMIPS_ABI_MSA = 8,
+};
+
+/* Object attribute values.  */
+enum
+{
+  /* Values defined for Tag_GNU_NANOMIPS_ABI_FP.  */
+
+  /* Not tagged or not using any ABIs affected by the differences.  */
+  Val_GNU_NANOMIPS_ABI_FP_ANY = 0,
+
+  /* Using hard-float -mdouble-float.  */
+  Val_GNU_NANOMIPS_ABI_FP_DOUBLE = 1,
+
+  /* Using hard-float -msingle-float.  */
+  Val_GNU_NANOMIPS_ABI_FP_SINGLE = 2,
+
+  /* Using soft-float.  */
+  Val_GNU_NANOMIPS_ABI_FP_SOFT = 3,
+
+  /* Not tagged or not using any ABIs affected by the differences.  */
+  Val_GNU_NANOMIPS_ABI_MSA_ANY = 0,
+
+  /* Using 128-bit MSA.  */
+  Val_GNU_NANOMIPS_ABI_MSA_128 = 1,
+};
+
+/* Masks for the ases word of an ABI flags structure.
+
+   Unfortunate decisions in early development transitioning from MIPS
+   to nanoMIPS, left this horifically fragmented.  Bits marked as
+   UNUSED may be cannibalized for future ASEs;  bits marked as RESERVED
+   are intended to remain blocked.  If MIPS history is anything to go
+   by, nanoMIPS will eventually spawn enough ASEs to fill up the gaps!
+*/
+
+#define NANOMIPS_ASE_TLB          0x00000001 /* TLB control ASE.  */
+#define NANOMIPS_ASE_UNUSED1      0x00000002 /* was DSP R2 ASE.  */
+#define NANOMIPS_ASE_EVA          0x00000004 /* Enhanced VA Scheme.  */
+#define NANOMIPS_ASE_MCU          0x00000008 /* MCU (MicroController) ASE.  */
+#define NANOMIPS_ASE_UNUSED2      0x00000010 /* was MDMX ASE.  */
+#define NANOMIPS_ASE_UNUSED3      0x00000020 /* was MIPS-3D ASE.  */
+#define NANOMIPS_ASE_MT           0x00000040 /* MT ASE.  */
+#define NANOMIPS_ASE_UNUSED4      0x00000080 /* was SmartMIPS ASE.  */
+#define NANOMIPS_ASE_VIRT         0x00000100 /* VZ ASE.  */
+#define NANOMIPS_ASE_MSA          0x00000200 /* MSA ASE.  */
+#define NANOMIPS_ASE_RESERVED1    0x00000400 /* was MIPS16 ASE.  */
+#define NANOMIPS_ASE_RESERVED2    0x00000800 /* was MICROMIPS ASE.  */
+#define NANOMIPS_ASE_UNUSED6      0x00001000 /* was XPA.  */
+#define NANOMIPS_ASE_DSPR3        0x00002000 /* DSP R3 ASE.  */
+#define NANOMIPS_ASE_UNUSED5      0x00004000 /* was MIPS16 E2 Extension.  */
+#define NANOMIPS_ASE_CRC          0x00008000 /* CRC extension.  */
+#define NANOMIPS_ASE_CRYPTO       0x00010000 /* Cryptography extension.  */
+#define NANOMIPS_ASE_GINV         0x00020000 /* GINV ASE.  */
+#define NANOMIPS_ASE_xNMS         0x00040000 /* not nanoMIPS Subset.  */
+#define NANOMIPS_ASE_MASK         0x0007af4d /* All valid ASEs.  */
+
+/* nanoMIPS ELF flags routines.  */
+extern Elf_Internal_ABIFlags_v0 * bfd_nanomips_elf_get_abiflags (bfd *);
+
+extern void bfd_nanomips_elf_swap_abiflags_v0_in
+  (bfd *, const Elf_External_ABIFlags_v0 *, Elf_Internal_ABIFlags_v0 *);
+extern void bfd_nanomips_elf_swap_abiflags_v0_out
+  (bfd *, const Elf_Internal_ABIFlags_v0 *, Elf_External_ABIFlags_v0 *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ELF_NANOMIPS_H */
diff --git a/include/opcode/nanomips.h b/include/opcode/nanomips.h
new file mode 100644
index 00000000000..d77120e244d
--- /dev/null
+++ b/include/opcode/nanomips.h
@@ -0,0 +1,1453 @@ 
+/* nanomips.h.  nanoMIPS opcode list for GDB, the GNU debugger.
+   Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+   Written by Faraz Shahbazker <faraz.shahbazker@mips.com>
+
+   This file is part of GDB, GAS, and the GNU binutils.
+
+   GDB, GAS, and the GNU binutils are free software; you can redistribute
+   them and/or modify them under the terms of the GNU General Public
+   License as published by the Free Software Foundation; either version 3,
+   or (at your option) any later version.
+
+   GDB, GAS, and the GNU binutils are distributed in the hope that they
+   will be useful, but WITHOUT ANY WARRANTY; without even the implied
+   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+   the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING3.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#ifndef _NANOMIPS_H_
+#define _NANOMIPS_H_
+
+#include "bfd.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Enumerates the various types of nanoMIPS operand.  */
+enum nanomips_operand_type {
+  /* Described by nanomips_int_operand.  */
+  OP_INT,
+
+  /* Described by nanomips_mapped_int_operand.  */
+  OP_MAPPED_INT,
+
+  /* Described by nanomips_msb_operand.  */
+  OP_MSB,
+
+  /* Described by nanomips_reg_operand.  */
+  OP_REG,
+
+  /* Like OP_REG, but can be omitted if the register is the same as the
+     previous operand.  */
+  OP_OPTIONAL_REG,
+
+  /* Described by nanomips_reg_pair_operand.  */
+  OP_REG_PAIR,
+
+  /* Described by nanomips_pcrel_operand.  */
+  OP_PCREL,
+
+  /* The register list and frame size for a MIPS16 SAVE or RESTORE
+     instruction.  */
+  OP_SAVE_RESTORE_LIST,
+
+  /* A register operand that must match the destination register.  */
+  OP_REPEAT_DEST_REG,
+
+  /* A register operand that must match the previous register.  */
+  OP_REPEAT_PREV_REG,
+
+  /* Described by nanomips_prev_operand.  */
+  OP_CHECK_PREV,
+
+  /* A register operand that must not be zero.  */
+  OP_NON_ZERO_REG,
+
+ /* The floating-point register list for a nanoMIPS SAVE or RESTORE
+     instruction. */
+  OP_SAVE_RESTORE_FP_LIST,
+
+  /* Fractured upper immediate PC-offset for nanoMIPS */
+  OP_HI20_PCREL,
+
+  /* Fractured upper immediate 20-bit signed integer for nanoMIPS */
+  OP_HI20_INT,
+
+  /* Fractured upper immediate 20-bit scaled integer for nanoMIPS */
+  OP_HI20_SCALE,
+
+  /* A non-zero PC-relative offset.  */
+  OP_NON_ZERO_PCREL_S1,
+
+  /* To check a mapped register against a previous operand.  */
+  OP_MAPPED_CHECK_PREV,
+
+  /* Unsigned word operand.  */
+  OP_UINT_WORD,
+
+  /* Signed word operand.  */
+  OP_INT_WORD,
+
+  /* Immediate PC-relative word operand.  */
+  OP_PC_WORD,
+
+  /* Immediate GP-relative word operand.  */
+  OP_GPREL_WORD,
+
+  /* Don't care bits.  */
+  OP_DONT_CARE,
+
+  /* Immediate unsigned word operand, to be negated.  */
+  OP_NEG_INT,
+
+  /* Immediate (non-relocatable) integer operand.  */
+  OP_IMM_INT,
+
+  /* Immediate (non-relocatable) word operand.  */
+  OP_IMM_WORD,
+
+  /* Base register for limited types of offsets.  */
+  OP_BASE_CHECK_OFFSET,
+
+  /* Copy over bits from another part of instruction.  */
+  OP_COPY_BITS,
+
+  /* Select bits for a COP0 register.  */
+  OP_CP0SEL,
+};
+
+/* Enumerates the types of nanoMIPS register.  */
+enum nanomips_reg_operand_type {
+  /* General registers $0-$31.  Software names like $at can also be used.  */
+  OP_REG_GP,
+
+  /* Floating-point registers $f0-$f31.  */
+  OP_REG_FP,
+
+  /* DSP accumulator registers $ac0-$ac3.  */
+  OP_REG_ACC,
+
+  /* Coprocessor registers in numeric format, $0-$31.  */
+  OP_REG_COPRO,
+
+  /* Hardware registers $0-$31.  Mnemonic names like hwr_cpunum can
+     also be used in some contexts.  */
+  OP_REG_HW,
+
+  /* MSA registers $w0-$w31.  */
+  OP_REG_MSA,
+
+  /* MSA control registers $0-$31.  */
+  OP_REG_MSA_CTRL,
+
+  /* Co-processor 0 named registers.  */
+  OP_REG_CP0,
+
+  /* Co-processor 0 named registers with select.  */
+  OP_REG_CP0SEL,
+
+  /* Co-processor 0 named registers with select.  */
+  OP_REG_HWRSEL
+};
+
+/* Base class for all operands.  */
+struct nanomips_operand
+{
+  /* The type of the operand.  */
+  enum nanomips_operand_type type;
+
+  /* The operand occupies SIZE bits of the instruction, starting at LSB.  */
+  unsigned short size;
+  unsigned short lsb;
+
+  /* These are used to split a value across two different
+     parts of the instruction encoding.  */
+  unsigned int size_top;
+  unsigned int lsb_top;
+};
+
+/* Describes an integer operand with a regular encoding pattern.  */
+struct nanomips_int_operand
+{
+  struct nanomips_operand root;
+
+  /* The low ROOT.SIZE bits of MAX_VAL encodes (MAX_VAL + BIAS) << SHIFT.
+     The cyclically previous field value encodes 1 << SHIFT less than that,
+     and so on.  E.g.
+
+     - for { { T, 4, L }, 14, 0, 0 }, field values 0...14 encode themselves,
+       but 15 encodes -1.
+
+     - { { T, 8, L }, 127, 0, 2 } is a normal signed 8-bit operand that is
+       shifted left two places.
+
+     - { { T, 3, L }, 8, 0, 0 } is a normal unsigned 3-bit operand except
+       that 0 encodes 8.
+
+     - { { ... }, 0, 1, 3 } means that N encodes (N + 1) << 3.  */
+  unsigned int max_val;
+  int bias;
+  unsigned int shift;
+
+  /* True if the operand should be printed as hex rather than decimal.  */
+  bool print_hex;
+};
+
+/* Uses a lookup table to describe a small integer operand.  */
+struct nanomips_mapped_int_operand
+{
+  struct nanomips_operand root;
+
+  /* Maps each encoding value to the integer that it represents.  */
+  const int *int_map;
+
+  /* True if the operand should be printed as hex rather than decimal.  */
+  bool print_hex;
+};
+
+/* An operand that encodes the most significant bit position of a bitfield.
+   Given a bitfield that spans bits [MSB, LSB], some operands of this type
+   encode MSB directly while others encode MSB - LSB.  Each operand of this
+   type is preceded by an integer operand that specifies LSB.
+
+   The assembly form varies between instructions.  For some instructions,
+   such as EXT, the operand is written as the bitfield size.  For others,
+   such as EXTS, it is written in raw MSB - LSB form.  */
+struct nanomips_msb_operand
+{
+  struct nanomips_operand root;
+
+  /* The assembly-level operand encoded by a field value of 0.  */
+  int bias;
+
+  /* True if the operand encodes MSB directly, false if it encodes
+     MSB - LSB.  */
+  bool add_lsb;
+
+  /* The maximum value of MSB + 1.  */
+  unsigned int opsize;
+};
+
+/* Describes a single register operand.  */
+struct nanomips_reg_operand
+{
+  struct nanomips_operand root;
+
+  /* The type of register.  */
+  enum nanomips_reg_operand_type reg_type;
+
+  /* If nonnull, REG_MAP[N] gives the register associated with encoding N,
+     otherwise the encoding is the same as the register number.  */
+  const unsigned char *reg_map;
+};
+
+/* Describes an operand that which must match a condition based on the
+   previous operand.  */
+struct nanomips_check_prev_operand
+{
+  struct nanomips_operand root;
+
+  bool greater_than_ok;
+  bool less_than_ok;
+  bool equal_ok;
+  bool zero_ok;
+};
+
+/* Describes an operand that encodes a pair of registers.  */
+struct nanomips_reg_pair_operand
+{
+  struct nanomips_operand root;
+
+  /* The type of register.  */
+  enum nanomips_reg_operand_type reg_type;
+
+  /* Encoding N represents REG1_MAP[N], REG2_MAP[N].  */
+  unsigned char *reg1_map;
+  unsigned char *reg2_map;
+};
+
+/* Describes an operand that is calculated relative to a base PC.
+   The base PC is usually the address of the following instruction,
+   but the rules for MIPS16 instructions like ADDIUPC are more complicated.  */
+struct nanomips_pcrel_operand
+{
+  /* Encodes the offset.  */
+  struct nanomips_int_operand root;
+
+  /* The low ALIGN_LOG2 bits of the base PC are cleared to give PC',
+     which is then added to the offset encoded by ROOT.  */
+  unsigned int align_log2 : 8;
+
+  /* If INCLUDE_ISA_BIT, the ISA bit of the original base PC is then
+     reinstated.  This is true for jumps and branches and false for
+     PC-relative data instructions.  */
+  unsigned int include_isa_bit : 1;
+
+  /* If FLIP_ISA_BIT, the ISA bit of the result is inverted.
+     This is true for JALX and false otherwise.  */
+  unsigned int flip_isa_bit : 1;
+};
+
+/* This structure holds information for a particular instruction.  */
+
+struct nanomips_opcode
+{
+  /* The name of the instruction.  */
+  const char *name;
+  /* An optional suffix.  */
+  const char *suffix;
+  /* A string describing the arguments for this instruction.  */
+  const char *args;
+  /* The basic opcode for the instruction.  When assembling, this
+     opcode is modified by the arguments to produce the actual opcode
+     that is used.  If pinfo is INSN_MACRO, then this is 0.  */
+  unsigned long match;
+  /* If pinfo is not INSN_MACRO, then this is a bit mask for the
+     relevant portions of the opcode when disassembling.  If the
+     actual opcode anded with the match field equals the opcode field,
+     then we have found the correct instruction.  If pinfo is
+     INSN_MACRO, then this field is the macro identifier.  */
+  unsigned long mask;
+  /* For a macro, this is INSN_MACRO.  Otherwise, it is a collection
+     of bits describing the instruction, notably any relevant hazard
+     information.  */
+  unsigned long pinfo;
+  /* A collection of additional bits describing the instruction. */
+  unsigned long pinfo2;
+  /* A collection of bits describing the instruction sets of which this
+     instruction or macro is a member. */
+  unsigned long membership;
+  /* A collection of bits describing the ASE of which this instruction
+     or macro is a member.  */
+  unsigned long ase;
+};
+
+/* Return true if the assembly syntax allows OPERAND to be omitted.  */
+
+static inline bool
+nanomips_optional_operand_p (const struct nanomips_operand *operand)
+{
+  return (operand->type == OP_OPTIONAL_REG
+	  || operand->type == OP_REPEAT_PREV_REG
+	  || (operand->type != OP_INT
+	      && operand->size == 0
+	      && operand->lsb == 0));
+}
+
+/* Return a version of INSN in which the field specified by OPERAND
+   has value UVAL.  */
+
+static inline unsigned int
+nanomips_insert_operand (const struct nanomips_operand *operand,
+			 unsigned int insn, unsigned int uval)
+{
+  unsigned int mask;
+  unsigned int size_bottom = operand->size - operand->size_top;
+
+  mask = (1 << size_bottom) - 1;
+  insn &= ~(mask << operand->lsb);
+  insn |= (uval & mask) << operand->lsb;
+
+  mask = (1 << operand->size_top) - 1;
+  insn &= ~(mask << operand->lsb_top);
+  insn |= ((uval & (mask << size_bottom)) >> size_bottom) << operand->lsb_top;
+  return insn;
+}
+
+/* Extract OPERAND from instruction INSN.  */
+
+static inline unsigned int
+nanomips_extract_operand (const struct nanomips_operand *operand,
+			  unsigned int insn)
+{
+  unsigned int uval;
+  unsigned int size_bottom = operand->size - operand->size_top;
+
+  uval = (insn >> operand->lsb_top) & ((1 << operand->size_top) - 1);
+  uval <<= size_bottom;
+  uval |= (insn >> operand->lsb) & ((1 << size_bottom) - 1);
+  return uval;
+}
+
+/* UVAL is the value encoded by OPERAND.  Return it in signed form.  */
+
+static inline int
+nanomips_signed_operand (const struct nanomips_operand *operand,
+			 unsigned int uval)
+{
+  unsigned int sign_bit, mask;
+
+  mask = (1 << operand->size) - 1;
+  sign_bit = 1 << (operand->size - 1);
+  return ((uval + sign_bit) & mask) - sign_bit;
+}
+
+/* Return the integer that OPERAND encodes as UVAL.  */
+
+static inline int
+nanomips_decode_int_operand (const struct nanomips_int_operand *operand,
+			     unsigned int uval)
+{
+  uval |= (operand->max_val - uval) & -(1 << operand->root.size);
+  uval += operand->bias;
+  uval <<= operand->shift;
+  return uval;
+}
+
+/* Return the maximum value that can be encoded by OPERAND.  */
+
+static inline int
+nanomips_int_operand_max (const struct nanomips_int_operand *operand)
+{
+  return (operand->max_val + operand->bias) << operand->shift;
+}
+
+/* Return the minimum value that can be encoded by OPERAND.  */
+
+static inline int
+nanomips_int_operand_min (const struct nanomips_int_operand *operand)
+{
+  unsigned int mask;
+
+  mask = (1 << operand->root.size) - 1;
+  return nanomips_int_operand_max (operand) - (mask << operand->shift);
+}
+
+/* Return the register that OPERAND encodes as UVAL.  */
+
+static inline int
+nanomips_decode_reg_operand (const struct nanomips_reg_operand *operand,
+			     unsigned int uval)
+{
+  if (operand->reg_map)
+    uval = operand->reg_map[uval];
+  return uval;
+}
+
+/* PC-relative operand OPERAND has value UVAL and is relative to BASE_PC.
+   Return the address that it encodes.  */
+
+static inline bfd_vma
+nanomips_decode_pcrel_operand (const struct nanomips_pcrel_operand *operand,
+			       bfd_vma base_pc, unsigned int uval)
+{
+  bfd_vma addr;
+
+  addr = base_pc & -(1 << operand->align_log2);
+  addr += nanomips_decode_int_operand (&operand->root, uval);
+  if (operand->include_isa_bit)
+    addr |= base_pc & 1;
+  if (operand->flip_isa_bit)
+    addr ^= 1;
+  return addr;
+}
+
+/* Describes an operand that encapsulates a mapped register with
+   a check against the previous operand.  */
+struct nanomips_mapped_check_prev_operand
+{
+  struct nanomips_operand root;
+
+  enum nanomips_reg_operand_type reg_type;
+  const unsigned char *reg_map;
+
+  bool greater_than_ok;
+  bool less_than_ok;
+  bool equal_ok;
+  bool zero_ok;
+};
+
+/* Describes an operand that encapsulates a base register with
+   a check against the type of offset.  */
+struct nanomips_base_check_offset_operand
+{
+  struct nanomips_operand root;
+
+  enum nanomips_reg_operand_type reg_type;
+
+  bool const_ok;
+  bool expr_ok;
+};
+
+/* Return true if MO is an instruction that requires 32-bit encoding.  */
+
+static inline bool
+nanomips_opcode_32bit_p (const struct nanomips_opcode *mo)
+{
+  return mo->mask >> 16 != 0;
+}
+
+static inline int
+nanomips_operand_mask (const struct nanomips_operand *operand)
+{
+  unsigned int mask;
+
+  mask = ((1 << operand->size_top) - 1) << operand->lsb_top;
+  mask |= ((1 << (operand->size - operand->size_top)) - 1) << operand->lsb;
+  return mask;
+}
+
+/* Return the UVAL encoding of REGNO as OPERAND.  */
+
+static inline unsigned int
+nanomips_encode_reg_operand (const struct nanomips_operand *operand,
+			     int regno)
+{
+  unsigned int uval;
+  const unsigned int num_vals = 1 << operand->size;
+  const struct nanomips_reg_operand *reg_op
+    = (const struct nanomips_reg_operand *) operand;
+
+  for (uval = 0; uval < num_vals; uval++)
+    if (reg_op->reg_map[uval] == regno)
+      break;
+  return uval;
+}
+
+
+/* Re-organize HI20 bits of OPERAND encoded as UVAL.  */
+
+#define SIGNEX_VALUE(OP) {OP_INT, (unsigned short)(OP->size - 1), 0, 0, 0}
+
+static inline int
+nanomips_decode_hi20_operand (const struct nanomips_operand *operand,
+			      unsigned int uval)
+{
+  const struct nanomips_operand op_ext = SIGNEX_VALUE (operand);
+  const struct nanomips_operand op_shuffle = {OP_INT, 19, 10, 10, 0};
+  unsigned int low19 = nanomips_extract_operand (&op_shuffle, uval);
+  return nanomips_insert_operand (&op_ext, uval, low19);
+}
+
+/* Decode HI20 signed integer.  */
+
+#define SIGNED_VALUE(OP) {OP_INT, OP->size, 0, 0, 0}
+
+static inline int
+nanomips_decode_hi20_int_operand (const struct nanomips_operand *operand,
+				  unsigned int uval)
+{
+  const struct nanomips_operand op_enc = SIGNED_VALUE (operand);
+  uval = nanomips_decode_hi20_operand (operand, uval);
+  return (nanomips_signed_operand (&op_enc, uval));
+}
+
+/* Decode HI20 PCREL  */
+
+#define PCREL_VALUE(OP) { { { OP_PCREL, OP->size, 0, 0, 0}, \
+	(unsigned int)((1 << (OP->size - 1)) - 1), 0, 0, false}, 12, 0, 0}
+
+static inline bfd_vma
+nanomips_decode_hi20_pcrel_operand (const struct nanomips_operand *operand,
+				    bfd_vma base_pc, unsigned int uval)
+{
+  const struct nanomips_pcrel_operand pcrel_op = PCREL_VALUE (operand);
+  uval = nanomips_decode_hi20_operand (operand, uval);
+  return nanomips_decode_pcrel_operand (&pcrel_op, base_pc, uval << 12);
+}
+
+
+/* Return true if MO is an instruction that requires 48-bit encoding.  */
+
+static inline bool
+opcode_48bit_p (const struct nanomips_opcode *mo)
+{
+  return ((mo->mask >> 16 == 0)
+	  && ((mo->match >> 10) == 0x18));
+}
+
+/* These are the bits which may be set in the pinfo field of an
+   instructions, if it is not equal to INSN_MACRO.  */
+
+/* Writes to operand number N.  */
+#define INSN_WRITE_SHIFT            0
+#define INSN_WRITE_1                0x00000001
+#define INSN_WRITE_2                0x00000002
+#define INSN_WRITE_ALL              0x00000003
+/* Reads from operand number N.  */
+#define INSN_READ_SHIFT             2
+#define INSN_READ_1                 0x00000004
+#define INSN_READ_2                 0x00000008
+#define INSN_READ_3                 0x00000010
+#define INSN_READ_ALL               0x0000001c
+/* Modifies general purpose register 31.  */
+#define INSN_WRITE_GPR_31           0x00000020
+/* Reads coprocessor register other than floating point register.  */
+#define INSN_COP                    0x00000040
+/* Instruction loads value from memory.  */
+#define INSN_LOAD_MEMORY	    0x00000080
+/* Reads the accumulator register.  */
+#define INSN_READ_ACC		    0x00000100
+/* Modifies the HI register.  */
+#define INSN_WRITE_ACC		    0x00000200
+/* Instruction stores value into memory.  */
+#define INSN_STORE_MEMORY	0x00000400
+/* Instruction uses single precision floating point.  */
+#define INSN_FP_S		0x00000800
+/* Instruction uses double precision floating point.  */
+#define INSN_FP_D		0x00001000
+/* A user-defined instruction.  */
+#define INSN_UDI                    0x00002000
+/* Instruction is actually a macro.  It should be ignored by the
+   disassembler, and requires special treatment by the assembler.  */
+#define INSN_MACRO                  0xffffffff
+
+/* These are the bits which may be set in the pinfo2 field of an
+   instruction. */
+
+/* Instruction is a simple alias (I.E. "move" for daddu/addu/or) */
+#define	INSN2_ALIAS		    0x00000001
+/* Macro uses single-precision floating-point instructions.  This should
+   only be set for macros.  For instructions, FP_S in pinfo carries the
+   same information.  */
+#define INSN2_M_FP_S		    0x00000002
+/* Macro uses double-precision floating-point instructions.  This should
+   only be set for macros.  For instructions, FP_D in pinfo carries the
+   same information.  */
+#define INSN2_M_FP_D		    0x00000004
+/* Is an unconditional branch insn. */
+#define INSN2_UNCOND_BRANCH	    0x00000008
+/* Is a conditional branch insn. */
+#define INSN2_COND_BRANCH	    0x00000010
+/* This indicates delayed branch converted to compact branch.  */
+#define INSN2_CONVERTED_TO_COMPACT  0x00000020
+/* Marks the LI macro expansion as special, temporary.  */
+#define INSN2_MACRO		    0x00000040
+/* Marks the legacy/downgraded MTTGPR format, temporary.  */
+#define INSN2_MTTGPR_RC1	    0x00000080
+
+/* Masks used to mark instructions to indicate which MIPS ISA level
+   they were introduced in.  INSN_ISA_MASK masks an enumeration that
+   specifies the base ISA level(s).  The remainder of a 32-bit
+   word constructed using these macros is a bitmask of the remaining
+   INSN_* values below.  */
+
+#define INSN_ISA_MASK		  0x00000003ul
+
+/* We cannot start at zero due to ISA_UNKNOWN below.  */
+#define INSN_ISAN32R6   1
+#define INSN_ISAN64R6	2
+
+#define ISA_UNKNOWN	0               /* Gas internal use.  */
+
+#define ISA_NANOMIPS32R6	INSN_ISAN32R6
+#define ISA_NANOMIPS64R6	INSN_ISAN64R6
+
+/* CPU defines, use instead of hardcoding processor number. Keep this
+   in sync with bfd/archures.c in order for machine selection to work.  */
+#define CPU_UNKNOWN	0               /* Gas internal use.  */
+
+#define CPU_NANOMIPS32R6 32
+#define CPU_NANOMIPS64R6 64
+
+#define ISAF(X) (1 << (INSN_ISA##X - 1))
+
+/* The same information in table form: bit INSN_ISA<X> - 1 of index
+   INSN_UPTO<Y> - 1 is set if ISA Y includes ISA X.  */
+static const unsigned int nanomips_isa_table[] = {
+  ISAF(N32R6),
+  ISAF(N32R6) | ISAF(N64R6)
+};
+#undef ISAF
+
+/* DSP ASE */
+#define ASE_DSP			0x00000001
+#define ASE_DSP64		0x00000002
+/* Enhanced VA Scheme */
+#define ASE_EVA			0x00000004
+/* MCU (MicroController) ASE */
+#define ASE_MCU			0x00000008
+/* MT ASE */
+#define ASE_MT			0x00000010
+/* Virtualization ASE */
+#define ASE_VIRT		0x00000020
+#define ASE_VIRT64		0x00000040
+/* MSA Extension  */
+#define ASE_MSA			0x00000080
+#define ASE_MSA64		0x00000100
+/* Cyclic redundancy check (CRC) ASE */
+#define ASE_CRC			0x00000200
+#define ASE_CRC64		0x00000400
+/* Global INValidate Extension. */
+#define ASE_GINV		0x00000800
+/* The Virtualization ASE has Global INValidate extension instructions
+   which are only valid when both ASEs are enabled. */
+#define ASE_GINV_VIRT		0x00001000
+/* Excluded for low power instruction subset for nanoMIPS.  */
+#define ASE_xNMS		0x00002000
+/* TLB control ASE.  */
+#define ASE_TLB			0x00004000
+
+static inline bool
+nanomips_cpu_is_member (int cpu, unsigned int mask)
+{
+  switch (cpu)
+    {
+    case CPU_NANOMIPS32R6:
+      return (mask & INSN_ISA_MASK) == INSN_ISAN32R6;
+
+    case CPU_NANOMIPS64R6:
+      return ((mask & INSN_ISA_MASK) == INSN_ISAN32R6)
+	     || ((mask & INSN_ISA_MASK) == INSN_ISAN64R6);
+
+    default:
+      return false;
+    }
+}
+
+/* Test for membership in an ISA including chip specific ISAs.  INSN
+   is pointer to an element of the opcode table; ISA is the specified
+   ISA/ASE bitmask to test against; and CPU is the CPU specific ISA to
+   test, or zero if no CPU specific ISA test is desired.  Return true
+   if instruction INSN is available to the given ISA and CPU. */
+static inline bool
+nanomips_opcode_is_member (const struct nanomips_opcode *insn,
+			   int isa, int ase, int cpu)
+{
+  /* Test for ISA level compatibility.  */
+  if ((isa & INSN_ISA_MASK) != 0
+      && (insn->membership & INSN_ISA_MASK) != 0
+      && ((nanomips_isa_table[(isa & INSN_ISA_MASK) - 1]
+	   >> ((insn->membership & INSN_ISA_MASK) - 1)) & 1) != 0)
+    return true;
+
+  /* Test for ASE compatibility.  */
+  if (insn->ase != 0 && (ase & insn->ase) == insn->ase)
+    return true;
+
+  /* Test for processor-specific extensions.  */
+  if (nanomips_cpu_is_member (cpu, insn->membership))
+    return true;
+
+  return false;
+}
+
+/* This is a list of macro expanded instructions.
+
+   _I appended means immediate
+   _A appended means target address of a jump
+   _AB appended means address with (possibly zero) base register
+   _AC appended means either symbolic address with no base register
+   or constant offset with base register.
+   _D appended means 64 bit floating point constant
+   _S appended means 32 bit floating point constant.  */
+
+enum
+{
+  M_ABS,
+  M_ACLR_AC,
+  M_ADD_I,
+  M_ADDU_I,
+  M_AND_I,
+  M_ASET_AC,
+  M_BEQ,
+  M_BEQ_I,
+  M_BGE,
+  M_BGE_I,
+  M_BGEU,
+  M_BGEU_I,
+  M_BGEZ,
+  M_BGT,
+  M_BGT_I,
+  M_BGTU,
+  M_BGTU_I,
+  M_BGTZ,
+  M_BLE,
+  M_BLE_I,
+  M_BLEU,
+  M_BLEU_I,
+  M_BLEZ,
+  M_BLT,
+  M_BLT_I,
+  M_BLTU,
+  M_BLTU_I,
+  M_BLTZ,
+  M_BNE,
+  M_BNE_I,
+  M_CACHE_AC,
+  M_CACHEE_AC,
+  M_DABS,
+  M_DADD_I,
+  M_DADDU_I,
+  M_DLA_AB,
+  M_DLI,
+  M_DMUL,
+  M_DMUL_I,
+  M_DSUB_I,
+  M_DSUBU_I,
+  M_J_A,
+  M_JAL_A,
+  M_JRADDIUSP,
+  M_LA_AB,
+  M_LB_AC,
+  M_LBE_AC,
+  M_LBU_AC,
+  M_LBUE_AC,
+  M_LBX_AB,
+  M_LBUX_AB,
+  M_LD_AC,
+  M_LDC1_AC,
+  M_LDC1X_AB,
+  M_LDC2_AC,
+  M_LDM_AC,
+  M_LDX_AB,
+  M_LH_AC,
+  M_LHE_AC,
+  M_LHU_AC,
+  M_LHUE_AC,
+  M_LHUX_AB,
+  M_LHX_AB,
+  M_LI,
+  M_LI_D,
+  M_LI_DD,
+  M_LI_S,
+  M_LI_SS,
+  M_LL_AC,
+  M_LLD_AC,
+  M_LLE_AC,
+  M_LLDP_AC,
+  M_LLWP_AC,
+  M_LW_AC,
+  M_LWC1_AC,
+  M_LWC1X_AB,
+  M_LWC2_AC,
+  M_LWE_AC,
+  M_LWM_AC,
+  M_LWU_AC,
+  M_LWUX_AB,
+  M_LWX_AB,
+  M_MUL,
+  M_MUL_I,
+  M_NOR_I,
+  M_OR_I,
+  M_PREF_AC,
+  M_PREFE_AC,
+  M_REM_3I,
+  M_DROL,
+  M_ROL,
+  M_DROL_I,
+  M_ROL_I,
+  M_ROR_I,
+  M_SC_AC,
+  M_SCD_AC,
+  M_SCE_AC,
+  M_SCDP_AC,
+  M_SCWP_AC,
+  M_SD_AC,
+  M_SDC1_AC,
+  M_SDC1X_AB,
+  M_SDC2_AC,
+  M_SDM_AC,
+  M_SDX_AB,
+  M_SEQ,
+  M_SEQ_I,
+  M_SGE,
+  M_SGE_I,
+  M_SGEU,
+  M_SGEU_I,
+  M_SGT,
+  M_SGT_I,
+  M_SGTU,
+  M_SGTU_I,
+  M_SLE,
+  M_SLE_I,
+  M_SLEU,
+  M_SLEU_I,
+  M_SLT_I,
+  M_SLTU_I,
+  M_SNE,
+  M_SNE_I,
+  M_SB_AC,
+  M_SBE_AC,
+  M_SBX_AB,
+  M_SH_AC,
+  M_SHE_AC,
+  M_SHX_AB,
+  M_SW_AC,
+  M_SWE_AC,
+  M_SWX_AB,
+  M_SWC1_AC,
+  M_SWC1X_AB,
+  M_SWC2_AC,
+  M_SWM_AC,
+  M_SUB_I,
+  M_SUBU_I,
+  M_TEQ_I,
+  M_TNE_I,
+  M_ULD_AC,
+  M_ULH_AC,
+  M_ULW_AC,
+  M_USH_AC,
+  M_USW_AC,
+  M_USD_AC,
+  M_XOR_I,
+  M_BGEZAL,
+  M_BLTZAL,
+  M_EXT,
+  M_INS,
+  M_MOD_I,
+  M_MODU_I,
+  M_DMOD_I,
+  M_DMODU_I,
+  M_DIV_I,
+  M_DIVU_I,
+  M_DDIV_I,
+  M_DDIVU_I,
+  M_NANOMIPS_NUM_MACROS
+};
+
+/* These are the bit masks and shift counts used for the different fields
+   in the nanoMIPS instruction formats.  No masks are provided for the
+   fixed portions of an instruction, since they are not needed.  */
+
+#define NANOMIPSOP_MASK_RS		0x1f
+#define NANOMIPSOP_SH_RS		16
+#define NANOMIPSOP_MASK_RT		0x1f
+#define NANOMIPSOP_SH_RT		21
+#define NANOMIPSOP_MASK_RD		0x1f
+#define NANOMIPSOP_SH_RD		11
+#define NANOMIPSOP_SH_ME		1
+#define NANOMIPSOP_SH_MC		4
+#define NANOMIPSOP_SH_MD		7
+#define NANOMIPSOP_SH_MP		5
+#define NANOMIPSOP_SH_MM		7
+
+#define NANOMIPSOP_SH_CP0SEL		5
+#define NANOMIPSOP_MASK_CP0SEL		0x1f
+#define NANOMIPSOP_SH_HWRSEL		5
+#define NANOMIPSOP_MASK_HWRSEL		0x1f
+
+/* Describes a COP0 named register with a fixed select.  */
+struct nanomips_cp0_name
+{
+  const char *name;
+  unsigned int num;
+  unsigned int sel;
+};
+
+/* The reference list of COP0 named register with fixed selects.  */
+static const struct nanomips_cp0_name nanomips_cp0_3264r6[] = {
+    {"$index",		 0, 0},
+    {"$mvpcontrol",	 0, 1},
+    {"$mvpconf0",	 0, 2},
+    {"$mvpconf1",	 0, 3},
+    {"$vpcontrol",	 0, 4},
+    {"$random", 	 1, 0},
+    {"$vpecontrol",	 1, 1},
+    {"$vpeconf0",	 1, 2},
+    {"$vpeconf1",	 1, 3},
+    {"$yqmask", 	 1, 4},
+    {"$vpeschedule",	 1, 5},
+    {"$vpeschefback",	 1, 6},
+    {"$vpeopt", 	 1, 7},
+    {"$entrylo0",	 2, 0},
+    {"$tcstatus",	 2, 1},
+    {"$tcbind", 	 2, 2},
+    {"$tcrestart",	 2, 3},
+    {"$tchalt", 	 2, 4},
+    {"$tccontext",	 2, 5},
+    {"$tcschedule",	 2, 6},
+    {"$tcschefback",	 2, 7},
+    {"$entrylo1",	 3, 0},
+    {"$globalnumber",	 3, 1},
+    {"$tcopt",		 3, 7},
+    {"$context",	 4, 0},
+    {"$contextconfig",	 4, 1},
+    {"$userlocal",	 4, 2},
+    {"$xcontextconfig",  4, 3},
+    {"$debugcontextid",  4, 4},
+    {"$memorymapid",	 4, 5},
+    {"$pagemask",	 5, 0},
+    {"$pagegrain",	 5, 1},
+    {"$segctl0",	 5, 2},
+    {"$segctl1",	 5, 3},
+    {"$segctl2",	 5, 4},
+    {"$pwbase", 	 5, 5},
+    {"$pwfield",	 5, 6},
+    {"$pwsize", 	 5, 7},
+    {"$wired",		 6, 0},
+    {"$srsconf0",	 6, 1},
+    {"$srsconf1",	 6, 2},
+    {"$srsconf2",	 6, 3},
+    {"$srsconf3",	 6, 4},
+    {"$srsconf4",	 6, 5},
+    {"$pwctl",		 6, 6},
+    {"$hwrena", 	 7, 0},
+    {"$badvaddr",	 8, 0},
+    {"$badinst",	 8, 1},
+    {"$badinstrp",	 8, 2},
+    {"$badinstrx",	 8, 3},
+    {"$count",		 9, 0},
+    {"$entryhi",	10, 0},
+    {"$guestctl1",	10, 4},
+    {"$guestctl2",	10, 5},
+    {"$guestctl3",	10, 6},
+    {"$compare",	11, 0},
+    {"$guestctl0ext",	11, 4},
+    {"$status", 	12, 0},
+    {"$intctl", 	12, 1},
+    {"$srsctl", 	12, 2},
+    {"$srsmap", 	12, 3},
+    {"$view_ipl",	12, 4},
+    {"$srsmap2",	12, 5},
+    {"$guestctl0",	12, 6},
+    {"$gtoffset",	12, 7},
+    {"$cause",		13, 0},
+    {"$view_ripl",	13, 4},
+    {"$nestedexc",	13, 5},
+    {"$epc",		14, 0},
+    {"$nestedepc",	14, 2},
+    {"$prid",		15, 0},
+    {"$ebase",		15, 1},
+    {"$cdmmbase",	15, 2},
+    {"$cmgcrbase",	15, 3},
+    {"$bevva",		15, 4},
+    {"$config", 	16, 0},
+    {"$config1",	16, 1},
+    {"$config2",	16, 2},
+    {"$config3",	16, 3},
+    {"$config4",	16, 4},
+    {"$config5",	16, 5},
+    {"$lladdr", 	17, 0},
+    {"$maar", 		17, 1},
+    {"$maari",		17, 2},
+    {"$watchlo0",	18, 0},
+    {"$watchlo1",	18, 1},
+    {"$watchlo2",	18, 2},
+    {"$watchlo3",	18, 3},
+    {"$watchlo4",	18, 4},
+    {"$watchlo5",	18, 5},
+    {"$watchlo6",	18, 6},
+    {"$watchlo7",	18, 7},
+    {"$watchlo8",	18, 8},
+    {"$watchlo9",	18, 9},
+    {"$watchlo10",	18, 10},
+    {"$watchlo11",	18, 11},
+    {"$watchlo12",	18, 12},
+    {"$watchlo13",	18, 13},
+    {"$watchlo14",	18, 14},
+    {"$watchlo15",	18, 15},
+    {"$watchhi0",	19, 0},
+    {"$watchhi1",	19, 1},
+    {"$watchhi2",	19, 2},
+    {"$watchhi3",	19, 3},
+    {"$watchhi4",	19, 4},
+    {"$watchhi5",	19, 5},
+    {"$watchhi6",	19, 6},
+    {"$watchhi7",	19, 7},
+    {"$watchhi8",	19, 8},
+    {"$watchhi9",	19, 9},
+    {"$watchhi10",	19, 10},
+    {"$watchhi11",	19, 11},
+    {"$watchhi12",	19, 12},
+    {"$watchhi13",	19, 13},
+    {"$watchhi14",	19, 14},
+    {"$watchhi15",	19, 15},
+    {"$xcontext",	20, 0},
+    {"$debug",		23, 0},
+    {"$tracecontrol",	23, 1},
+    {"$tracecontrol2",	23, 2},
+    {"$usertracedata1", 23, 3},
+    {"$traceibpc",	23, 4},
+    {"$tracedbpc",	23, 5},
+    {"$debug2", 	23, 6},
+    {"$depc",		24, 0},
+    {"$tracecontrol3",	24, 2},
+    {"$usertracedata2", 24, 3},
+    {"$perfctl0",	25, 0},
+    {"$perfcnt0",	25, 1},
+    {"$perfctl1",	25, 2},
+    {"$perfcnt1",	25, 3},
+    {"$perfctl2",	25, 4},
+    {"$perfcnt2",	25, 5},
+    {"$perfctl3",	25, 6},
+    {"$perfcnt3",	25, 7},
+    {"$perfctl4",	25, 8},
+    {"$perfcnt4",	25, 9},
+    {"$perfctl5",	25, 10},
+    {"$perfcnt5",	25, 11},
+    {"$perfctl6",	25, 12},
+    {"$perfcnt6",	25, 13},
+    {"$perfctl7",	25, 14},
+    {"$perfcnt7",	25, 15},
+    {"$errctl", 	26, 0},
+    {"$cacheerr",	27, 0},
+    {"$itaglo", 	28, 0},
+    {"$idatalo", 	28, 1},
+    {"$dtaglo", 	28, 2},
+    {"$ddatalo", 	28, 3},
+    {"$itaghi", 	29, 0},
+    {"$idatahi", 	29, 1},
+    {"$dtaghi", 	29, 2},
+    {"$ddatahi", 	29, 3},
+    {"$errorepc",	30, 0},
+    {"$desave", 	31, 0},
+    {"$kscratch1",	31, 2},
+    {"$kscratch2",	31, 3},
+    {"$kscratch3",	31, 4},
+    {"$kscratch4",	31, 5},
+    {"$kscratch5",	31, 6},
+    {"$kscratch6",	31, 7},
+    {NULL, 0, 0}
+};
+
+/* Describes a CP0 named register which permits various select values.  */
+  struct nanomips_cp0_select
+{
+  const char *name;
+  unsigned int num;
+  unsigned int selmask;
+};
+
+/* Currently recognized CP0 select patterns.  */
+
+#define NANOMIPS_CP0SEL_MASK_EVEN	0x55555555
+#define NANOMIPS_CP0SEL_MASK_ODD	0xaaaaaaaa
+#define NANOMIPS_CP0SEL_MASK_ANY	0xffffffff
+#define NANOMIPS_CP0SEL_MASK_EVEN16	0x5555
+#define NANOMIPS_CP0SEL_MASK_ODD16	0xaaaa
+#define NANOMIPS_CP0SEL_MASK_ANY16	0xffff
+
+/* The reference list of CP0 named register with variable selects.  */
+static const struct nanomips_cp0_select nanomips_cp0sel_3264r6[] = {
+    {"$watchlo",	18, NANOMIPS_CP0SEL_MASK_ANY16},
+    {"$watchhi",	19, NANOMIPS_CP0SEL_MASK_ANY16},
+    {"$perfctl",	25, NANOMIPS_CP0SEL_MASK_EVEN16},
+    {"$perfcnt",	25, NANOMIPS_CP0SEL_MASK_ANY16},
+    {"$taglo",		28, NANOMIPS_CP0SEL_MASK_EVEN},
+    {"$datalo", 	28, NANOMIPS_CP0SEL_MASK_ODD},
+    {"$taghi",		29, NANOMIPS_CP0SEL_MASK_EVEN},
+    {"$datahi", 	29, NANOMIPS_CP0SEL_MASK_ODD},
+    {NULL, 0, 0}
+};
+
+
+/* Describes a HWR named register with a fixed select.  If the HWR name
+   is remapped from an existing CP0 register name, its cp0_num and cp0_sel
+   fields will provide the mapping, else they will both be invalid.  */
+
+struct nanomips_hwr_name
+{
+  const char *name;
+  unsigned int num;
+  unsigned int sel;
+  unsigned int cp0_num;
+  unsigned int cp0_sel;
+};
+
+#define INV_RNUM 0xffffffff
+#define INV_SEL 0xffffffff
+
+ /* The reference list of named hardware register with fixed selects.  */
+static const struct nanomips_hwr_name nanomips_hwr_names_3264r6[] = {
+    {"$cpunum",		0,	0,	INV_RNUM,	INV_SEL},
+    {"$synci_step",	1,	0,	INV_RNUM,	INV_SEL},
+    {"$cc",		2,	0,	9,		0},
+    {"$count",		2,	0,	9,		0},
+    {"$ccres",		3,	0,	INV_RNUM, 	INV_SEL},
+    {"$perfctl0",	4,	0,	25,		0},
+    {"$perfcnt0",	4,	1,	25,		1},
+    {"$perfctl1",	4,	2,	25,		2},
+    {"$perfcnt1",	4,	3,	25,		3},
+    {"$perfctl2",	4,	4,	25,		4},
+    {"$perfcnt2",	4,	5,	25,		5},
+    {"$perfctl3",	4,	6,	25,		6},
+    {"$perfcnt3",	4,	7,	25,		7},
+    {"$perfctl4",	4,	8,	25,		8},
+    {"$perfcnt4",	4,	9,	25,		9},
+    {"$perfctl5",	4,	10,	25,		10},
+    {"$perfcnt5",	4,	11,	25,		11},
+    {"$perfctl6",	4,	12,	25,		12},
+    {"$perfcnt6",	4,	13,	25,		13},
+    {"$perfctl7",	4,	14,	25,		14},
+    {"$perfcnt7",	4,	15,	25,		15},
+    {"$perfctl",	4,	0,	25,		0},
+    {"$perfcnt",	4,	1,	25,		1},
+    {"$xnp",		5,	0,	INV_RNUM,	INV_SEL},
+    {"$userlocal",	29,	0,	4,		2},
+    {NULL, 		0,	0,	INV_RNUM,	INV_SEL}
+};
+
+#define NANOMIPS_CP0SEL_PERFCNT 25
+#define NANOMIPS_HWRSEL_PERFCNT 4
+
+/* Don't care stubs in operand formats need special handling.  */
+#define NANOMIPS_MIN_DONTCARE_FMT 'A'
+#define NANOMIPS_MAX_DONTCARE_FMT 'Q'
+
+#define IS_NANOMIPS_DONTCARE_FMT(x) ((x)[0] == '-'			\
+				     && (x)[1] >= NANOMIPS_MIN_DONTCARE_FMT \
+				     && (x)[1] <= NANOMIPS_MAX_DONTCARE_FMT)
+
+/* These are the characters which may appears in the args field of a nanoMIPS
+   instruction.  They appear in the order in which the fields appear when the
+   instruction is used.  Commas and parentheses in the args string are ignored
+   when assembling, and written into the output when disassembling.
+
+   Operands for 16-bit nanoMIPS instructions.
+
+   "ma" must be $28
+   "mb" 5-bit non-zero GP register at bit 5
+   "mc" 3-bit nanoMIPS registers 4-7, 16-19 bit 4
+        The same register used as both source and target.
+   "md" 3-bit nanoMIPS registers 4-7, 16-19 at bit 7
+   "me" 3-bit nanoMIPS registers 4-7, 16-19 at bit 1
+   "mf" 3-bit nanoMIPS register 4-7, 16-19 at bit 7.
+        Must be larger than the last seen register.
+   "mg" 3-bit nanoMIPS register 4-7, 16-19 at bit 4.
+	Must be smaller than the last seen register.
+   "mh" 3-bit nanoMIPS register 4-7, 16-19 at bit 7.
+        Must be at least as large as the last seen register.
+   "mi" 3-bit nanoMIPS register 4-7, 16-19 at bit 4.
+	May be at most as large as the last seen register.
+
+   "mj" 5-bit nanoMIPS registers at bit 0
+   "mk" must be the same as the destination register
+   "ml" 3-bit nanoMIPS registers 4-7, 16-19 at bit 4
+   "mm" 3-bit nanoMIPS registers 0, 4-7, 17-19 at bit 7
+   "mn"	5-bit encoding of a save/restore register list
+   "mp" 5-bit nanoMIPS registers at bit 5
+   "mq" 2-bit pair at bits [8,3] maps to ($a0,$a1), ($a1,$a2), ($a2,$a3)
+        or ($a3,$a4)
+   "mr" 2-bit pair at bits [8,3] maps to ($a1,$a0), ($a2,$a1), ($a3,$a2)
+        or ($a4,$a3)
+   "ms" must be $29
+   "mt" must be the same as the previous register
+   "mu"	4-bit encoding of nanoMIPS destination register at bit 5
+   "mv"	4-bit encoding of nanoMIPS destination register at bit 0
+   "mw"	4-bit encoding of nanoMIPS source register at bit 5
+   "mx"	4-bit encoding of nanoMIPS source register at bit 0
+   "my" must be $31
+   "mz" must be literal 0
+
+   "mA" 7-bit relocatable GP offset (0 .. 127) << 2
+   "mB" 3-bit immediate at bit 0 (0, 4, 8, 12, 16, 20, 24, 28)
+   "mC" 4-bit immediate at bit 0 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+        65535, 14, 15)
+   "mD" 10-bit signed branch address, split & scaled at bit 0 [S9:1,S10]
+   "mE" 7-bit signed branch address, split & scaled at bit 0 [S6:1,S7]
+   "mF" 4-bit unsigned branch address, scaled at bit 0 [U4:U1]
+   "mG" 4-bit scaled immediate at bit 4, (0 .. 15) << 4
+   "mH" 2-bit scaled immediate at bit 1, (0 .. 3) << 1
+   "mI" 7-bit immediate at bit 0, (-1 .. 126)
+   "mJ" 4-bit scaled immediate at bit 0, (0 .. 15) << 2
+   "mK" 3-bit BREAK/SDBBP code at bit 0
+   "mL" 2-bit immediate at bit 0, (0 .. 3)
+   "mM" 3-bit immediate at bit 0, (1 .. 8)
+   "mN" 2-bit split scaled immediate at bits 8 & 3 (0 .. 3) << 2
+   "mO" 7-bit immediate GP offset at bit 0, (0 .. 127) << 2
+   "mP"	2-bit SYSCALL/HYPCALL code at bit 0
+   "mQ"	4-bit immediate signed offset, (s3,s2:s0)
+   "mR" 5-bit immediate at bit 0, (0 .. 31) << 2
+   "mS" 6-bit immediate at bit 0, (0 .. 63) << 2
+   "mZ" must be zero
+
+   Operands for 32-bit nanoMIPS instructions.
+
+   "+1"	18-bit unsigned GP-relative offset, (u17:u0)
+   "+2"	18-bit scaled GP-relative offset, (u18:u2) << 2
+   "+3"	21-bit scaled GP-relative offset, (u18:u1) << 1
+   "+4" 18-bit GP-relative offset, (0 .. 2^18-1) << 3
+   "+5"	4-bit encoding of nanoMIPS source register at bit 21
+   "+6" 5-bit mask encoding, corresponding to (1 << X) - 1
+   "+7" 1-bit register at bit 24, (0,1) => ($a0,$a1)
+   "+8" 23-bit un-spec'ed value at bit 3 for UDIs.
+   "+9" 7-bit immediate at bit 11, (0 .. 127)
+
+   "+A" 5-bit INS/EXT/DINS/DEXT/DINSM/DEXTM position, which becomes
+        LSB.
+   "+B" 5-bit INS/DINS size, which becomes MSB
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 0 < (pos+size) <= 32.
+   "+C" 5-bit EXT/DEXT size, which becomes MSBD.
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 0 < (pos+size) <= 32.
+   "+D"	4-bit encoding of a floating point save/restore register list
+   "+E" 5-bit DINSU/DEXTU position, which becomes LSB-32.
+   "+F" 5-bit DINSM/DINSU size, which becomes MSB-32.
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 32 < (pos+size) <= 64.
+   "+G" 5-bit DEXTM size, which becomes MSBD-32.
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 32 < (pos+size) <= 64.
+   "+H" 5-bit DEXTU size, which becomes MSBD.
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 32 < (pos+size) <= 64.
+   "+I" 5-bit EXTW/EXTD/PREPEND position, which becomes LSB.
+   "+J" 19-bit BREAK/SDBBP function code at bit 0
+   "+K"	Tri-part upper 20-bits of immediate value.
+   "+L" 10-bit WAIT code at bit 16
+   "+M"	18-bit SYSCALL/HYPCALL code at bit 0
+   "+N" 9-bit immediate at bit 3, (0 .. 511) << 3
+
+   "+i"	5-bit SYNC code type at bit 16, (0..31)
+   "+j"	9-bit signed offset (s7:s0,s8), (-256 .. 255)
+   "+k" 5-bit nanoMIPS registers at bit 3
+   "+p"	9-bit scaled signed offset, (s7:s2) << 2 for LL/SC*
+   "+q" 9-bit scaled signed offset, (s7:s3) << 3 for LLD/SCD*
+   "+r"	21-bit PC-relative branch offset (s19:s1,s20) << 1
+   "+s"	21-bit immediate offset for PC-relative operation ((s19:s1,s20) + 2) << 1
+   "+t" 5-bit non-zero GP register at bit 21
+   "+u"	25-bit PC-relative branch offset (s24:s1,s25) << 1
+   "+v"	5-bit mapping of R6 ALIGN byte-wise shift to EXTW bit-wise shift.
+   "+w"	2-bit shift for scaled address calculation at bit 9, (0..3)
+   "+*"	4-bit ROTX shift at bit 7, (0 .. 15) << 1
+   "+|"	1-bit ROTX stripe at bit 6, (0 .. 1)
+
+   "."	21-bit scaled GP-relative offset, (u21:u2) << 2
+   "<"	5-bit immediate shift value for bit operations, (0..31)
+   "|"	3-bit Element count for load/store multiple, (1..8)
+   "~"	11-bit branch offset, (s9:s1,s10) << 1
+   "^"	5-bit trap code at bit 11, (0..31)
+   "b"	5-bit base register at bit 16 for label or symbolic offsets
+   "c"	5-bit base register at bit 16, either used with immediate offset
+	or skipped with symbolic offset.
+   "d"	5-bit destination register specifier at bit 11
+   "g"	12-bit unsigned immediate at bit 0, (0..4095)
+   "h"	12-bit negative immediate at bit 0, (-4095..0)
+   "i"	12-bit unsigned immediate at bit 0, (0..4095)
+   "j"	16-bit unsigned immediate at bit 0, (0..65535)
+   "k"	5-bit cache operation code at bit 21, (0..31)
+   "n"	11-bit encoding of save/restore register list
+   "o"	12-bit offset at bit 0, (0..4095)
+   "p"	14-bit PC-relative branch offset (s13:s1,s14) << 1
+   "r"	5-bit same register at bit 16, used as both source and target
+   "s"	5-bit source register specifier at bit 16
+   "t"	5-bit target register specifier at bit 21
+   "u" 	Tri-part upper 20 bits of address
+   "x" 	Tri-part upper 20 bits of address, scaled by 12 bits
+   "v"	5-bit same register used as both source and destination at bit 15
+   "w"	5-bit same register used as both target and destination at bit 21
+   "z"	must be zero register
+
+   Used in special matching contexts:
+   "-A"	5 don't care bits at bit 16
+   "-B"	1 don't care bit at bit 10
+   "-C"	12 don't care bits at bit 0
+   "-D"	1 don't care bit at bit 17
+   "-E"	3 don't care bits at bit 13
+   "-F"	10 don't care bits at bit 16
+   "-G"	8 split don't care bits, 3 at bit 9 and 5 at bit 7
+   "-H"	9 don't care bits at bit 17
+   "-I"	5 don't care bits at bit 21
+   "-J"	3 don't care bits at bit 23
+   "-K"	2 split don't care bits, 1 at bit 2 and 1 at bit 15
+   "-L"	3 don't care bits at bit 6
+   "-M"	3 don't care bits at bit 9
+   "-N"	6 don't care bits at bit 10
+   "-O"	1 don't care bit at bit 12
+   "-P"	8 split don't care bits, 4 at bit 10 and 4 at bit 22
+   "-Q"	1 don't care bit at bit 11
+
+   "-i" Ignored register operand, internally used for macro expansions.
+   "-m" Place-holder to copy 5 bits from bit 11 to bit 21
+   "-n" Place-holder to copy 5 bits from bit 11 to bit 16
+
+   Exclusively for 48-bit nanoMIPS instructions:
+
+   "+O" Signed GP-relative 32-bit offset in instruction byte order
+   "+P" Immediate signed 32-bit value in instruction byte order
+   "+Q"	Unsigned 32-bit value or address in instruction byte order
+   "+R" Signed 32-bit value in instruction byte order
+   "+S" Signed PC-relative 32-bit offset in instruction byte order
+
+   DSP instructions:
+   "0"	5-bit shift value for DSP accumulator at bit 16, (0..63)
+   "1"	5-bit position for DSP bit operations at bit 11
+   "2" 5-bit size for DSP bit operations at bit 16
+   "3" 3-bit byte vector shift at bit 13, (0..7)
+   "4" 4-bit hword vector shift at bit 12, (0..15)
+   "5" 8-bit unsigned immediate at bit 13, (0..255)
+   "7" 2-bit DSP accumulator register at bit 14, (0..3)
+   "8" 7-bit DSP control mask at bit 14, (0x3f)
+   "@" 10-bit signed immediate at bit 11, (0..1023)
+
+   Coprocessor instructions:
+   "E" 5-bit target register
+   "G" 5-bit source register
+   "H" 5-bit sel field for (D)MTC* and (D)MFC*
+   "J" 5-bit select code at bit 11 for named COP1 registers, (0..31)
+   "K"	10-bit register+select encoding at bit 11 for named h/w register
+   "O"	10-bit register+select encoding at bit 11 for named COP1 register
+   "P"	5-bit named COP1 register at bit 16
+   "Q"	5-bit select code at bit 11
+   "U"	5-bit named HW register at bit 16
+
+   MT instructions:
+   "!"	1-bit u-mode for move to/from thread registers at bit 10, (0,1)
+   "$"	1-bit high-mode for move to/from thread registers at bit 3, (0,1)
+   "*"	2-bit accumulator register at bit 18, (0..3)
+
+   GINV instructions
+   "+;"	2-bit global invalidate operation type at bit 21, (0..3)
+
+   Floating point instructions:
+   "D" 5-bit destination register
+   "R" 5-bit fr destination register
+   "S" 5-bit fs source 1 register
+   "T" 5-bit ft source 2 register
+   "V" 5-bit same register used as floating source and destination or target
+
+   Macro instructions:
+   "A" general 32 bit expression
+   "I" 32-bit immediate (value placed in imm_expr).
+   "F" 64-bit floating point constant in memory
+   "L" 64-bit floating point constant in memory
+   "f" 32-bit floating point constant in memory
+   "l" 32-bit floating point constant in memory
+
+   CP2 instructions:
+   "C" 23-bit coprocessor function code at bit 3
+
+   MCU instructions:
+   "\"	3-bit position for atomic set/clear operations, (0..7)
+
+
+   Other:
+   "()" parens surrounding optional value
+   ","  separates operands
+   "+"  start of extension sequence
+
+   Characters used so far, for quick reference when adding more:
+   "12345 78 0"
+   ".<\|~@^!$*"
+   "A CDEFGHIJKL  OP RSTUV    "
+   " bcde ghijk  nop rstuvwx z"
+
+   Extension character sequences used so far ("+" followed by the
+   following), for quick reference when adding more:
+   "123456789
+   "*|;"
+   "ABCDEFGHIJKLMNOPQRS       "
+   "        ij     pqrstuvw   "
+
+   Extension character sequences used so far ("m" followed by the
+   following), for quick reference when adding more:
+   ""
+   ""
+   "ABCDEFGHIJKLMNOPQRS      Z"
+   "abcdefghijklmn pqrstuvwxyz"
+
+   Extension character sequences used so far ("-" followed by the
+   following), for quick reference when adding more:
+   ""
+   ""
+   "ABCDEFGHIJKLMNOPQ         "
+   "        i   mn            "
+*/
+
+extern const struct nanomips_operand *decode_nanomips_operand (const char *);
+extern const struct nanomips_opcode nanomips_opcodes[];
+extern const int bfd_nanomips_num_opcodes;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NANOMIPS_H_ */
diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am
index 578fdc056c5..242fb95df04 100644
--- a/opcodes/Makefile.am
+++ b/opcodes/Makefile.am
@@ -214,6 +214,8 @@  TARGET32_LIBOPCODES_CFILES = \
 	mt-dis.c \
 	mt-ibld.c \
 	mt-opc.c \
+	nanomips-dis.c \
+	nanomips-opc.c \
 	nds32-asm.c \
 	nds32-dis.c \
 	nios2-dis.c \
diff --git a/opcodes/Makefile.in b/opcodes/Makefile.in
index 2db307e8d7c..3f60ed59ca4 100644
--- a/opcodes/Makefile.in
+++ b/opcodes/Makefile.in
@@ -597,6 +597,12 @@  TARGET32_LIBOPCODES_CFILES = \
 	mep-opc.c \
 	metag-dis.c \
 	microblaze-dis.c \
+	micromips-opc.c \
+	mips-dis.c \
+	mips-opc.c \
+	mips16-opc.c \
+	mmix-dis.c \
+	mmix-opc.c \
 	moxie-dis.c \
 	moxie-opc.c \
 	msp430-decode.c \
@@ -606,6 +612,8 @@  TARGET32_LIBOPCODES_CFILES = \
 	mt-dis.c \
 	mt-ibld.c \
 	mt-opc.c \
+	nanomips-dis.c \
+	nanomips-opc.c \
 	nds32-asm.c \
 	nds32-dis.c \
 	nios2-dis.c \
@@ -991,6 +999,8 @@  distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mt-dis.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mt-ibld.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mt-opc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nanomips-dis.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nanomips-opc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nds32-asm.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nds32-dis.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nfp-dis.Plo@am__quote@
diff --git a/opcodes/configure b/opcodes/configure
index 8717d99ca26..8c8bb61f63a 100755
--- a/opcodes/configure
+++ b/opcodes/configure
@@ -12558,6 +12558,7 @@  if test x${all_targets} = xfalse ; then
 	bfd_mn10300_arch)	ta="$ta m10300-dis.lo m10300-opc.lo" ;;
 	bfd_mt_arch)		ta="$ta mt-asm.lo mt-desc.lo mt-dis.lo mt-ibld.lo mt-opc.lo" using_cgen=yes ;;
 	bfd_msp430_arch)	ta="$ta msp430-dis.lo msp430-decode.lo" ;;
+	bfd_nanomips_arch)	ta="$ta nanomips-dis.lo nanomips-opc.lo" ;;
 	bfd_nds32_arch)		ta="$ta nds32-asm.lo nds32-dis.lo" ;;
 	bfd_nfp_arch)		ta="$ta nfp-dis.lo" ;;
 	bfd_nios2_arch)		ta="$ta nios2-dis.lo nios2-opc.lo" ;;
diff --git a/opcodes/configure.ac b/opcodes/configure.ac
index 1beb72e87e0..2efb1338b36 100644
--- a/opcodes/configure.ac
+++ b/opcodes/configure.ac
@@ -306,6 +306,7 @@  if test x${all_targets} = xfalse ; then
 	bfd_mn10300_arch)	ta="$ta m10300-dis.lo m10300-opc.lo" ;;
 	bfd_mt_arch)		ta="$ta mt-asm.lo mt-desc.lo mt-dis.lo mt-ibld.lo mt-opc.lo" using_cgen=yes ;;
 	bfd_msp430_arch)	ta="$ta msp430-dis.lo msp430-decode.lo" ;;
+	bfd_nanomips_arch)	ta="$ta nanomips-dis.lo nanomips-opc.lo" ;;
 	bfd_nds32_arch)		ta="$ta nds32-asm.lo nds32-dis.lo" ;;
 	bfd_nfp_arch)		ta="$ta nfp-dis.lo" ;;
 	bfd_nios2_arch)		ta="$ta nios2-dis.lo nios2-opc.lo" ;;
diff --git a/opcodes/dis-buf.c b/opcodes/dis-buf.c
index b3f7c981312..3edf4675932 100644
--- a/opcodes/dis-buf.c
+++ b/opcodes/dis-buf.c
@@ -99,3 +99,12 @@  generic_symbol_is_valid (asymbol * sym ATTRIBUTE_UNUSED,
 {
   return true;
 }
+
+/* Just return size of previous instruction.  */
+
+int
+generic_predict_insn_length (bfd_vma addr ATTRIBUTE_UNUSED, int previous,
+			     struct disassemble_info *info ATTRIBUTE_UNUSED)
+{
+  return previous;
+}
diff --git a/opcodes/dis-init.c b/opcodes/dis-init.c
index f796aaa260b..f425933448e 100644
--- a/opcodes/dis-init.c
+++ b/opcodes/dis-init.c
@@ -43,6 +43,7 @@  init_disassemble_info (struct disassemble_info *info, void *stream,
   info->print_address_func = generic_print_address;
   info->symbol_at_address_func = generic_symbol_at_address;
   info->symbol_is_valid = generic_symbol_is_valid;
+  info->predict_insn_length = generic_predict_insn_length;
   info->display_endian = BFD_ENDIAN_UNKNOWN;
   info->created_styled_output = false;
 }
diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c
index 93052e75088..205795003a9 100644
--- a/opcodes/disassemble.c
+++ b/opcodes/disassemble.c
@@ -359,6 +359,11 @@  disassembler (enum bfd_architecture a,
       disassemble = print_insn_mn10300;
       break;
 #endif
+#ifdef ARCH_nanomips
+    case bfd_arch_nanomips:
+      disassemble = print_insn_nanomips;
+      break;
+#endif
 #ifdef ARCH_nios2
     case bfd_arch_nios2:
       if (big)
@@ -576,6 +581,9 @@  disassembler_usage (FILE *stream ATTRIBUTE_UNUSED)
 #ifdef ARCH_nfp
   print_nfp_disassembler_options (stream);
 #endif
+#ifdef ARCH_nanomips
+  print_nanomips_disassembler_options (stream);
+#endif
 #ifdef ARCH_powerpc
   print_ppc_disassembler_options (stream);
 #endif
@@ -747,6 +755,11 @@  disassemble_init_for_target (struct disassemble_info * info)
       disassemble_init_nds32 (info);
       break;
  #endif
+#ifdef ARCH_nanomips
+    case bfd_arch_nanomips:
+      info->disassembler_needs_relocs = true;
+      break;
+#endif
     default:
       break;
     }
diff --git a/opcodes/nanomips-dis.c b/opcodes/nanomips-dis.c
new file mode 100644
index 00000000000..7f206199c96
--- /dev/null
+++ b/opcodes/nanomips-dis.c
@@ -0,0 +1,1470 @@ 
+/* Print nanoMIPS instructions for GDB, the GNU debugger, or for objdump.
+   Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+   Written by Faraz Shahbazker <faraz.shahbazker@mips.com>
+
+   This file is part of the GNU opcodes library.
+
+   This library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   It is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "dis-asm.h"
+#include "libiberty.h"
+#include "opcode/nanomips.h"
+#include "opintl.h"
+
+#if !defined(EMBEDDED_ENV)
+#include "elf-bfd.h"
+#include "elf/nanomips.h"
+#endif
+
+
+/* FIXME: These should be shared with gdb somehow.  */
+
+static const char * const nanomips_gpr_names_numeric[32] = {
+  "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
+  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
+  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
+  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
+};
+
+static const char * const nanomips_gpr_names_symbolic[32] = {
+  "zero", "at",   "t4",   "t5",   "a0",   "a1",   "a2",   "a3",
+  "a4",   "a5",   "a6",   "a7",   "t0",   "t1",   "t2",   "t3",
+  "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
+  "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "fp",   "ra"
+};
+
+static const char * const nanomips_fpr_names_numeric[32] = {
+  "$f0",  "$f1",  "$f2",  "$f3",  "$f4",  "$f5",  "$f6",  "$f7",
+  "$f8",  "$f9",  "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
+  "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
+  "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
+};
+
+static const char * const nanomips_fpr_names_64[32] = {
+  "fv0",  "ft12", "fv1",  "ft13", "ft0",  "ft1",  "ft2",  "ft3",
+  "ft4",  "ft5",  "ft6",  "ft7",  "fa0",  "fa1",  "fa2",  "fa3",
+  "fa4",  "fa5",  "fa6",  "fa7",  "ft8",  "ft9",  "ft10", "ft11",
+  "fs0",  "fs1",  "fs2",  "fs3",  "fs4",  "fs5",  "fs6",  "fs7"
+};
+
+static const char * const nanomips_cp1_names_numeric[32] = {
+  "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
+  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
+  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
+  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
+};
+
+static const char * const nanomips_cp1_names_3264r6[32] = {
+  "c1_fir",       "c1_ufr",       "$2",           "$3",
+  "c1_unfr",      "$5",           "$6",           "$7",
+  "$8",           "$9",           "$10",          "$11",
+  "$12",          "$13",          "$14",          "$15",
+  "$16",          "$17",          "$18",          "$19",
+  "$20",          "$21",          "$22",          "$23",
+  "$24",          "c1_fccr",      "c1_fexr",      "$27",
+  "c1_fenr",      "$29",          "$30",          "c1_fcsr"
+};
+
+static const char * const msa_control_names[32] = {
+  "msa_ir",	"msa_csr",	"msa_access",	"msa_save",
+  "msa_modify",	"msa_request",	"msa_map",	"msa_unmap",
+  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
+  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
+  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
+};
+
+/* The empty-list of CP0 registers serves as an indicator to fall-back to
+   numeric register names.  */
+static const struct nanomips_cp0_name nanomips_cp0_numeric[] = {
+  {NULL, 0, 0}
+};
+static const struct nanomips_cp0_select nanomips_cp0sel_numeric[] = {
+  {NULL, 0, 0}
+};
+
+/* The empty-list of HWR registers serves as an indicator to fall-back to
+   numeric register names.  */
+static const struct nanomips_hwr_name nanomips_hwr_names_numeric[] = {
+  {NULL, 0, 0, 0, 0}
+};
+
+struct nanomips_abi_choice
+{
+  const char *name;
+  const char *const *gpr_names;
+  const char *const *fpr_names;
+};
+
+struct nanomips_abi_choice nanomips_abi_choices[] = {
+  {"numeric", nanomips_gpr_names_numeric, nanomips_fpr_names_numeric},
+  {"p32", nanomips_gpr_names_symbolic, nanomips_fpr_names_64},
+  {"p64", nanomips_gpr_names_symbolic, nanomips_fpr_names_64},
+};
+
+struct nanomips_arch_choice
+{
+  const char *name;
+  int bfd_mach_valid;
+  unsigned long bfd_mach;
+  int processor;
+  int isa;
+  int ase;
+  const struct nanomips_cp0_name *cp0_names;
+  const struct nanomips_cp0_select *cp0sel_names;
+  const char *const *cp1_names;
+  const struct nanomips_hwr_name *hwr_names;
+};
+
+const struct nanomips_arch_choice nanomips_arch_choices[] = {
+  {"numeric", 0, 0, 0, 0, 0,
+   nanomips_cp0_numeric, nanomips_cp0sel_numeric, nanomips_cp1_names_numeric,
+   nanomips_hwr_names_numeric},
+
+  {"32r6", 1, bfd_mach_nanomipsisa32r6, CPU_NANOMIPS32R6, ISA_NANOMIPS32R6,
+   (ASE_EVA | ASE_MSA | ASE_VIRT | ASE_MCU | ASE_MT | ASE_DSP | ASE_xNMS
+    | ASE_TLB | ASE_GINV | ASE_CRC),
+   nanomips_cp0_3264r6, nanomips_cp0sel_3264r6, nanomips_cp1_names_3264r6,
+   nanomips_hwr_names_3264r6},
+
+  {"32r6s", 1, bfd_mach_nanomipsisa32r6, CPU_NANOMIPS32R6, ISA_NANOMIPS32R6,
+   (ASE_EVA | ASE_MSA | ASE_VIRT | ASE_MCU | ASE_MT | ASE_DSP | ASE_TLB
+    | ASE_GINV | ASE_CRC),
+   nanomips_cp0_3264r6, nanomips_cp0sel_3264r6, nanomips_cp1_names_3264r6,
+   nanomips_hwr_names_3264r6},
+
+  {"64r6", 1, bfd_mach_nanomipsisa64r6, CPU_NANOMIPS64R6, ISA_NANOMIPS64R6,
+   (ASE_EVA | ASE_MSA | ASE_MSA64 | ASE_VIRT | ASE_MCU | ASE_MT | ASE_DSP
+    | ASE_DSP64 | ASE_xNMS | ASE_TLB | ASE_GINV | ASE_CRC | ASE_CRC64),
+   nanomips_cp0_3264r6, nanomips_cp0sel_3264r6, nanomips_cp1_names_3264r6,
+   nanomips_hwr_names_3264r6},
+};
+
+/* ISA and processor type to disassemble for, and register names to use.
+   set_default_nanomips_dis_options and parse_nanomips_dis_options fill in
+   these values.  */
+
+static int nanomips_processor;
+static int nanomips_ase;
+static int nanomips_isa;
+static const char *const *nanomips_gpr_names;
+static const char *const *nanomips_fpr_names;
+static const struct nanomips_cp0_name *nanomips_cp0_names;
+static const struct nanomips_cp0_select *nanomips_cp0sel_names;
+static const char *const *nanomips_cp1_names;
+static const struct nanomips_hwr_name *nanomips_hwr_names;
+
+/* Other options */
+static int no_aliases;	/* If set, disassemble as most general inst.  */
+static bool show_arch_insn; 	/* Mnemonics with suffix.  */
+static bool show_mttgpr_rc1 = false; /* RC1 style MTTGPR format.  */
+
+
+/* Map ABI name to nanomips_abi_choice descriptor.  */
+
+static const struct nanomips_abi_choice *
+choose_abi_by_name (const char *name, unsigned int namelen)
+{
+  const struct nanomips_abi_choice *c;
+  unsigned int i;
+
+  for (i = 0, c = NULL; i < ARRAY_SIZE (nanomips_abi_choices) && c == NULL;
+       i++)
+    if (strncmp (nanomips_abi_choices[i].name, name, namelen) == 0
+	&& strlen (nanomips_abi_choices[i].name) == namelen)
+      c = &nanomips_abi_choices[i];
+
+  return c;
+}
+
+/* Map architecture name to nanomips_arch_choice descriptor.  */
+
+static const struct nanomips_arch_choice *
+choose_arch_by_name (const char *name, unsigned int namelen)
+{
+  const struct nanomips_arch_choice *c = NULL;
+  unsigned int i;
+
+  for (i = 0, c = NULL; i < ARRAY_SIZE (nanomips_arch_choices) && c == NULL;
+       i++)
+    if (strncmp (nanomips_arch_choices[i].name, name, namelen) == 0
+	&& strlen (nanomips_arch_choices[i].name) == namelen)
+      c = &nanomips_arch_choices[i];
+
+  return c;
+}
+
+/* Map BFD architecture to nanomips_arch_choice descriptor.  */
+
+static const struct nanomips_arch_choice *
+choose_arch_by_number (unsigned long mach)
+{
+  static unsigned long hint_bfd_mach;
+  static const struct nanomips_arch_choice *hint_arch_choice;
+  const struct nanomips_arch_choice *c;
+  unsigned int i;
+
+  /* We optimize this because even if the user specifies no
+     flags, this will be done for every instruction!  */
+  if (hint_bfd_mach == mach
+      && hint_arch_choice != NULL
+      && hint_arch_choice->bfd_mach == hint_bfd_mach)
+    return hint_arch_choice;
+
+  for (i = 0, c = NULL; i < ARRAY_SIZE (nanomips_arch_choices) && c == NULL;
+       i++)
+    {
+      if (nanomips_arch_choices[i].bfd_mach_valid
+	  && nanomips_arch_choices[i].bfd_mach == mach)
+	{
+	  c = &nanomips_arch_choices[i];
+	  hint_bfd_mach = mach;
+	  hint_arch_choice = c;
+	}
+    }
+  return c;
+}
+
+/* Select default descriptors and initial mode for the default
+   architecture.  */
+
+static void
+set_default_nanomips_dis_options (struct disassemble_info *info)
+{
+  const struct nanomips_arch_choice *chosen_arch;
+
+  nanomips_isa = ISA_NANOMIPS32R6;
+  nanomips_processor = CPU_NANOMIPS32R6;
+  nanomips_isa = true;
+  nanomips_ase = 0;
+  nanomips_fpr_names = nanomips_fpr_names_numeric;
+  nanomips_cp0_names = nanomips_cp0_numeric;
+  nanomips_cp0sel_names = nanomips_cp0sel_numeric;
+  nanomips_cp1_names = nanomips_cp1_names_numeric;
+  nanomips_hwr_names = nanomips_hwr_names_numeric;
+  no_aliases = 0;
+  show_arch_insn = false;
+
+  nanomips_gpr_names = nanomips_gpr_names_symbolic;
+
+  /* Set ISA, architecture, and cp0 register names as best we can.  */
+  chosen_arch = choose_arch_by_number (info->mach);
+  if (chosen_arch != NULL)
+    {
+      nanomips_processor = chosen_arch->processor;
+      nanomips_isa = chosen_arch->isa;
+      nanomips_ase = chosen_arch->ase;
+      nanomips_cp0_names = chosen_arch->cp0_names;
+      nanomips_cp0sel_names = chosen_arch->cp0sel_names;
+      nanomips_cp1_names = chosen_arch->cp1_names;
+      nanomips_hwr_names = chosen_arch->hwr_names;
+    }
+}
+
+/* Parse and translate a command-line options to internal state.  */
+
+static void
+parse_nanomips_dis_option (const char *option, unsigned int len)
+{
+  unsigned int i, optionlen, vallen;
+  const char *val;
+  const struct nanomips_abi_choice *chosen_abi;
+  const struct nanomips_arch_choice *chosen_arch;
+
+  /* Try to match options that are simple flags */
+  if (startswith (option, "show-arch-insn"))
+    {
+      show_arch_insn = true;
+      return;
+    }
+
+  if (startswith (option, "no-aliases"))
+    {
+      no_aliases = 1;
+      return;
+    }
+
+  if (startswith (option, "show-mttgpr-rc1"))
+    {
+      show_mttgpr_rc1 = true;
+      return;
+    }
+
+  if (startswith (option, "msa"))
+    {
+      nanomips_ase |= ASE_MSA;
+      if ((nanomips_isa & INSN_ISA_MASK) == ISA_NANOMIPS64R6)
+	nanomips_ase |= ASE_MSA64;
+      return;
+    }
+
+  if (startswith (option, "virt"))
+    {
+      nanomips_ase |= ASE_VIRT;
+
+      if (nanomips_isa & ISA_NANOMIPS64R6)
+	nanomips_ase |= ASE_VIRT64;
+
+      if (nanomips_ase & ASE_GINV)
+	nanomips_ase |= ASE_GINV_VIRT;
+    }
+
+  if (startswith (option, "ginv"))
+    {
+      nanomips_ase |= ASE_GINV;
+      if (nanomips_ase & ASE_VIRT)
+	nanomips_ase |= ASE_GINV_VIRT;
+      return;
+    }
+
+  /* Look for the = that delimits the end of the option name.  */
+  for (i = 0; i < len; i++)
+    if (option[i] == '=')
+      break;
+
+  if (i == 0)		/* Invalid option: no name before '='.  */
+    return;
+  if (i == len)		/* Invalid option: no '='.  */
+    return;
+  if (i == (len - 1))	/* Invalid option: no value after '='.  */
+    return;
+
+  optionlen = i;
+  val = option + (optionlen + 1);
+  vallen = len - (optionlen + 1);
+
+  if (strncmp ("gpr-names", option, optionlen) == 0
+      && strlen ("gpr-names") == optionlen)
+    {
+      chosen_abi = choose_abi_by_name (val, vallen);
+      if (chosen_abi != NULL)
+	nanomips_gpr_names = chosen_abi->gpr_names;
+      return;
+    }
+
+  if (strncmp ("fpr-names", option, optionlen) == 0
+      && strlen ("fpr-names") == optionlen)
+    {
+      chosen_abi = choose_abi_by_name (val, vallen);
+      if (chosen_abi != NULL)
+	nanomips_fpr_names = chosen_abi->fpr_names;
+      return;
+    }
+
+  if (strncmp ("cp0-names", option, optionlen) == 0
+      && strlen ("cp0-names") == optionlen)
+    {
+      chosen_arch = choose_arch_by_name (val, vallen);
+      if (chosen_arch != NULL)
+	{
+	  nanomips_cp0_names = chosen_arch->cp0_names;
+	  nanomips_cp0sel_names = chosen_arch->cp0sel_names;
+	}
+      return;
+    }
+
+  if (strncmp ("cp1-names", option, optionlen) == 0
+      && strlen ("cp1-names") == optionlen)
+    {
+      chosen_arch = choose_arch_by_name (val, vallen);
+      if (chosen_arch != NULL)
+	nanomips_cp1_names = chosen_arch->cp1_names;
+      return;
+    }
+
+  if (strncmp ("hwr-names", option, optionlen) == 0
+      && strlen ("hwr-names") == optionlen)
+    {
+      chosen_arch = choose_arch_by_name (val, vallen);
+      if (chosen_arch != NULL)
+	nanomips_hwr_names = chosen_arch->hwr_names;
+      return;
+    }
+
+  if (strncmp ("reg-names", option, optionlen) == 0
+      && strlen ("reg-names") == optionlen)
+    {
+      /* We check both ABI and ARCH here unconditionally, so
+         that "numeric" will do the desirable thing: select
+         numeric register names for all registers.  Other than
+         that, a given name probably won't match both.  */
+      chosen_abi = choose_abi_by_name (val, vallen);
+      if (chosen_abi != NULL)
+	{
+	  nanomips_gpr_names = chosen_abi->gpr_names;
+	  nanomips_fpr_names = chosen_abi->fpr_names;
+	}
+      chosen_arch = choose_arch_by_name (val, vallen);
+      if (chosen_arch != NULL)
+	{
+	  nanomips_cp0_names = chosen_arch->cp0_names;
+	  nanomips_cp0sel_names = chosen_arch->cp0sel_names;
+	  nanomips_cp1_names = chosen_arch->cp1_names;
+	  nanomips_hwr_names = chosen_arch->hwr_names;
+	}
+      return;
+    }
+
+  /* Invalid option.  */
+}
+
+/* Loop to parse nanoMIPS-specific command-line options.  */
+
+static void
+parse_nanomips_dis_options (const char *options)
+{
+  const char *option_end;
+
+  if (options == NULL)
+    return;
+
+  while (*options != '\0')
+    {
+      /* Skip empty options.  */
+      if (*options == ',')
+	{
+	  options++;
+	  continue;
+	}
+
+      /* We know that *options is neither NUL or a comma.  */
+      option_end = options + 1;
+      while (*option_end != ',' && *option_end != '\0')
+	option_end++;
+
+      parse_nanomips_dis_option (options, option_end - options);
+
+      /* Go on to the next one.  If option_end points to a comma, it
+         will be skipped above.  */
+      options = option_end;
+    }
+}
+
+/* Look-up and print the symbolic name of a named CP0 register with
+   a fixed select value.  Fall-back to numeric format if no match is
+   found.  */
+
+static void
+print_cp0_reg (struct disassemble_info *info, int regno)
+{
+  int i;
+  unsigned int selnum = regno & NANOMIPSOP_MASK_CP0SEL;
+  unsigned int cp0_regno = regno >> NANOMIPSOP_SH_CP0SEL;
+
+  if (nanomips_cp0_names != nanomips_cp0_numeric)
+    for (i = cp0_regno; nanomips_cp0_names[i].name; i++)
+      {
+	if (nanomips_cp0_names[i].num == cp0_regno
+	    && nanomips_cp0_names[i].sel == selnum)
+	  {
+	    info->fprintf_func (info->stream, "%s",
+				nanomips_cp0_names[i].name + 1);
+	    return;
+	  }
+      }
+
+  /* A select value of 0 is deemed optional.  */
+  if (selnum == 0)
+    info->fprintf_func (info->stream, "$%d", cp0_regno);
+  else
+    info->fprintf_func (info->stream, "$%d,%d", cp0_regno, selnum);
+}
+
+/* Look-up and print the symbolic name of a named CP0 register with
+   a variable select value.  Fall-back to numeric format if no match is
+   found.  */
+
+static void
+print_cp0sel_reg (struct disassemble_info *info, unsigned int regno,
+		  unsigned int selnum)
+{
+  int i;
+
+  for (i = 0; nanomips_cp0sel_names[i].name; i++)
+    {
+      if (nanomips_cp0sel_names[i].num == regno
+	  && ((1 << selnum) & nanomips_cp0sel_names[i].selmask) != 0)
+	{
+	  info->fprintf_func (info->stream, "%s,%d",
+			      nanomips_cp0sel_names[i].name + 1, selnum);
+	  return;
+	}
+    }
+
+  /* A select value of 0 is deemed optional.  */
+  if (selnum == 0)
+    info->fprintf_func (info->stream, "$%d", regno);
+  else
+    info->fprintf_func (info->stream, "$%d,%d", regno, selnum);
+}
+
+/* Look-up and print the symbolic name of a named CP0 register with
+   a fixed select value.  Fall-back to numeric format if no match is
+   found.  */
+
+static void
+print_hwr_reg (struct disassemble_info *info, int regno)
+{
+  int i;
+  unsigned int selnum = regno & NANOMIPSOP_MASK_CP0SEL;
+  unsigned int hwr_regno = regno >> NANOMIPSOP_SH_HWRSEL;
+
+  if (nanomips_hwr_names != nanomips_hwr_names_numeric)
+    for (i = 0; nanomips_hwr_names[i].name; i++)
+      {
+	if (nanomips_hwr_names[i].num == hwr_regno
+	    && nanomips_hwr_names[i].sel == selnum)
+	  {
+	    info->fprintf_func (info->stream, "%s",
+				nanomips_hwr_names[i].name + 1);
+	    return;
+	  }
+      }
+
+  /* A select value of 0 is deemed optional.  */
+  if (selnum == 0)
+    info->fprintf_func (info->stream, "$%d", hwr_regno);
+  else
+    info->fprintf_func (info->stream, "$%d,%d", hwr_regno, selnum);
+}
+
+/* Print register REGNO, of type TYPE, for instruction OPCODE.  */
+
+static void
+print_reg (struct disassemble_info *info,
+	   const struct nanomips_opcode *opcode,
+	   enum nanomips_reg_operand_type type, int regno)
+{
+  switch (type)
+    {
+    case OP_REG_GP:
+      info->fprintf_func (info->stream, "%s", nanomips_gpr_names[regno]);
+      break;
+
+    case OP_REG_FP:
+      info->fprintf_func (info->stream, "%s", nanomips_fpr_names[regno]);
+      break;
+
+    case OP_REG_ACC:
+      info->fprintf_func (info->stream, "$ac%d", regno);
+      break;
+
+    case OP_REG_COPRO:
+      if (opcode->name[strlen (opcode->name) - 1] == '1')
+	info->fprintf_func (info->stream, "%s", nanomips_cp1_names[regno]);
+      else
+	info->fprintf_func (info->stream, "$%d", regno);
+      break;
+
+    case OP_REG_HW:
+    case OP_REG_HWRSEL:
+      print_hwr_reg (info, regno);
+      break;
+
+    case OP_REG_MSA:
+      info->fprintf_func (info->stream, "$w%d", regno);
+      break;
+
+    case OP_REG_MSA_CTRL:
+      info->fprintf_func (info->stream, "%s", msa_control_names[regno]);
+      break;
+
+    case OP_REG_CP0:
+      print_cp0_reg (info, regno);
+      break;
+
+    case OP_REG_CP0SEL:
+      /* Need to check select bits againt mask, defer output to next operand.  */
+      break;
+    }
+}
+
+/* Used to track the state carried over from previous operands in
+   an instruction.  */
+
+struct nanomips_print_arg_state
+{
+  /* The value of the last OP_INT seen.  We only use this for OP_MSB,
+     where the value is known to be unsigned and small.  */
+  unsigned int last_int;
+
+  /* The type and number of the last OP_REG seen.  We only use this for
+     OP_REPEAT_DEST_REG and OP_REPEAT_PREV_REG.  */
+  enum nanomips_reg_operand_type last_reg_type;
+  unsigned int last_regno;
+  unsigned int dest_regno;
+  unsigned int seen_dest;
+};
+
+/* Initialize STATE for the start of an instruction.  */
+
+static inline void
+init_print_arg_state (struct nanomips_print_arg_state *state)
+{
+  memset (state, 0, sizeof (*state));
+}
+
+/* Record information about a register operand.  */
+
+static void
+nanomips_seen_register (struct nanomips_print_arg_state *state,
+			unsigned int regno,
+			enum nanomips_reg_operand_type reg_type)
+{
+  state->last_reg_type = reg_type;
+  state->last_regno = regno;
+
+  if (!state->seen_dest)
+    {
+      state->seen_dest = 1;
+      state->dest_regno = regno;
+    }
+}
+
+/* Pretty-print a save/restore register list.  */
+
+static void
+nanomips_print_save_restore (struct disassemble_info *info,
+			     unsigned int uval, bool mode16)
+{
+  const fprintf_ftype infprintf = info->fprintf_func;
+  void *is = info->stream;
+  char *comma = ",";
+  unsigned int pending = 0;
+  unsigned int freg, fp, gp, ra;
+  int count;
+  fp = gp = ra = 0;
+
+  if (mode16)
+    {
+      freg = 30 | (uval >> 4);
+      count = uval & 0xf;
+    }
+  else
+    {
+      freg = (uval >> 6) & 0x1f;
+      count = (uval >> 1) & 0xf;
+      if (count > 0)
+	gp = uval & 1;
+    }
+
+  if (freg == 30 && count > 0)
+    fp = 1;
+  if ((freg == 31 && count > 0) || (freg == 30 && count > 1))
+    ra = 1;
+
+  if (freg + count == 45)
+    gp = 1;
+
+  count = count - gp;
+  if (fp && count > 0)
+    {
+      freg = (freg & 0x10) | ((freg + 1) % 32);
+      count--;
+    }
+
+  if (ra && count > 0)
+    {
+      freg = (freg & 0x10) | ((freg + 1) % 32);
+      count--;
+    }
+
+  if (fp)
+    {
+      infprintf (is, "%s", nanomips_gpr_names[30]);
+      pending = 1;
+    }
+
+  if (ra)
+    {
+      infprintf (is, "%s%s", (pending ? comma : ""), nanomips_gpr_names[31]);
+      pending = 1;
+    }
+
+  if (count > 0)
+    {
+      if (count > 1)
+	infprintf (is, "%s%s-%s", (pending ? comma : ""),
+		   nanomips_gpr_names[freg],
+		   nanomips_gpr_names[freg + count - 1]);
+      else
+	infprintf (is, "%s%s", (pending ? comma : ""),
+		   nanomips_gpr_names[freg]);
+      pending = 1;
+    }
+
+  if (gp)
+    infprintf (is, "%s%s", (pending ? comma : ""), nanomips_gpr_names[28]);
+}
+
+/* Pretty-print save/restore floating-point register list.  */
+
+static void
+nanomips_print_save_restore_fp (struct disassemble_info *info,
+				unsigned int count)
+{
+  const fprintf_ftype infprintf = info->fprintf_func;
+  void *is = info->stream;
+
+  if (count == 1)
+    infprintf (is, "%s", nanomips_fpr_names[0]);
+  else
+    infprintf (is, "%s-%s", nanomips_fpr_names[0],
+	       nanomips_fpr_names[count - 1]);
+}
+
+/* Print operand OPERAND of OPCODE, using STATE to track inter-operand state.
+   UVAL is the encoding of the operand (shifted into bit 0) and BASE_PC is
+   the base address for OP_PCREL operands.  */
+
+static void
+print_insn_arg (struct disassemble_info *info,
+		struct nanomips_print_arg_state *state,
+		const struct nanomips_opcode *opcode,
+		const struct nanomips_operand *operand,
+		bfd_vma base_pc, unsigned int uval)
+{
+  const fprintf_ftype infprintf = info->fprintf_func;
+  void *is = info->stream;
+
+  switch (operand->type)
+    {
+    case OP_INT:
+    case OP_IMM_INT:
+      {
+	const struct nanomips_int_operand *int_op;
+
+	int_op = (const struct nanomips_int_operand *) operand;
+	uval = nanomips_decode_int_operand (int_op, uval);
+	state->last_int = uval;
+	if (int_op->print_hex)
+	  infprintf (is, "0x%x", uval);
+	else
+	  infprintf (is, "%d", uval);
+      }
+      break;
+
+    case OP_MAPPED_INT:
+      {
+	const struct nanomips_mapped_int_operand *mint_op;
+
+	mint_op = (const struct nanomips_mapped_int_operand *) operand;
+	uval = mint_op->int_map[uval];
+	state->last_int = uval;
+	if (mint_op->print_hex)
+	  infprintf (is, "0x%x", uval);
+	else
+	  infprintf (is, "%d", uval);
+      }
+      break;
+
+    case OP_MSB:
+      {
+	const struct nanomips_msb_operand *msb_op;
+
+	msb_op = (const struct nanomips_msb_operand *) operand;
+	uval += msb_op->bias;
+	if (msb_op->add_lsb)
+	  uval -= state->last_int;
+	infprintf (is, "%d", uval);
+      }
+      break;
+
+    case OP_REG:
+    case OP_OPTIONAL_REG:
+    case OP_MAPPED_CHECK_PREV:
+    case OP_BASE_CHECK_OFFSET:
+      {
+	const struct nanomips_reg_operand *reg_op;
+
+	reg_op = (const struct nanomips_reg_operand *) operand;
+	uval = nanomips_decode_reg_operand (reg_op, uval);
+	print_reg (info, opcode, reg_op->reg_type, uval);
+
+	nanomips_seen_register (state, uval, reg_op->reg_type);
+      }
+      break;
+
+    case OP_REG_PAIR:
+      {
+	const struct nanomips_reg_pair_operand *pair_op;
+
+	pair_op = (const struct nanomips_reg_pair_operand *) operand;
+	print_reg (info, opcode, pair_op->reg_type, pair_op->reg1_map[uval]);
+	infprintf (is, ",");
+	print_reg (info, opcode, pair_op->reg_type, pair_op->reg2_map[uval]);
+      }
+      break;
+
+    case OP_PCREL:
+      {
+	const struct nanomips_pcrel_operand *pcrel_op;
+
+	pcrel_op = (const struct nanomips_pcrel_operand *) operand;
+	info->target = nanomips_decode_pcrel_operand (pcrel_op, base_pc, uval);
+
+	/* Preserve the ISA bit for the GDB disassembler,
+	   otherwise clear it.  */
+	if (info->flavour != bfd_target_unknown_flavour)
+	  info->target &= -2;
+
+	(*info->print_address_func) (info->target, info);
+      }
+      break;
+
+    case OP_NON_ZERO_PCREL_S1:
+      {
+	const struct nanomips_pcrel_operand pcrel_op = {
+	  {{OP_PCREL, operand->size, operand->lsb, 0, 0},
+	   (1 << operand->size) - 1, 0, 1, true}, 0, 0, 0
+	};
+
+	if ((info->flags & INSN_HAS_RELOC) == 0)
+	  info->target = nanomips_decode_pcrel_operand (&pcrel_op, base_pc,
+							uval);
+	else
+	  info->target = 0;
+	(*info->print_address_func) (info->target, info);
+      }
+      break;
+
+    case OP_CHECK_PREV:
+    case OP_NON_ZERO_REG:
+      {
+	print_reg (info, opcode, OP_REG_GP, uval & 31);
+	nanomips_seen_register (state, uval, OP_REG_GP);
+      }
+      break;
+
+    case OP_SAVE_RESTORE_LIST:
+      nanomips_print_save_restore (info, uval, opcode->mask >> 16 == 0);
+      break;
+
+    case OP_SAVE_RESTORE_FP_LIST:
+      nanomips_print_save_restore_fp (info, uval + 1);
+      break;
+
+    case OP_REPEAT_PREV_REG:
+      print_reg (info, opcode, state->last_reg_type, state->last_regno);
+      break;
+
+    case OP_REPEAT_DEST_REG:
+      print_reg (info, opcode, state->last_reg_type, state->dest_regno);
+      break;
+
+    case OP_HI20_PCREL:
+      {
+	if ((info->flags & INSN_HAS_RELOC) == 0)
+	  {
+	    uval = nanomips_decode_hi20_int_operand (operand, uval);
+	    infprintf (is, "0x%x", uval & 0xfffff);
+	  }
+	else
+	  {
+	    info->target = nanomips_decode_hi20_pcrel_operand (operand, base_pc,
+							       uval);
+	    infprintf (is, "%%pcrel_hi(");
+	    (*info->print_address_func) (info->target, info);
+	    infprintf (is, ")");
+	  }
+      }
+      break;
+
+    case OP_HI20_SCALE:
+      {
+	uval = nanomips_decode_hi20_int_operand (operand, uval);
+	state->last_int = uval;
+	infprintf (is, "0x%x", uval & 0xfffff);
+      }
+      break;
+
+    case OP_HI20_INT:
+      {
+	uval = nanomips_decode_hi20_int_operand (operand, uval);
+	state->last_int = uval;
+	if ((info->flags & INSN_HAS_RELOC) != 0 || uval == 0)
+	  infprintf (is, "0x%x", uval & 0xfffff);
+	else
+	  infprintf (is, "%%hi(0x%x)", (uval & 0xfffff) << 12);
+      }
+      break;
+
+    case OP_IMM_WORD:
+      {
+	const struct nanomips_int_operand *int_op;
+	int_op = (const struct nanomips_int_operand *) operand;
+	state->last_int = ((uval >> 16) & 0xffff) | (uval << 16);
+	state->last_int += int_op->bias;
+	infprintf (is, "%d", state->last_int);
+      }
+      break;
+
+    case OP_INT_WORD:
+    case OP_GPREL_WORD:
+      {
+	state->last_int = ((uval >> 16) & 0xffff) | (uval << 16);
+	infprintf (is, "%d", state->last_int);
+      }
+      break;
+
+    case OP_UINT_WORD:
+      {
+	state->last_int = ((uval >> 16) & 0xffff) | (uval << 16);
+	infprintf (is, "0x%x", state->last_int);
+      }
+      break;
+
+    case OP_PC_WORD:
+      {
+	info->target = base_pc + (((uval >> 16) & 0xffff) | (uval << 16));
+	(*info->print_address_func) (info->target, info);
+      }
+      break;
+
+    case OP_NEG_INT:
+      infprintf (is, "-%d", uval);
+      break;
+
+    case OP_CP0SEL:
+      if (no_aliases)
+	infprintf (is, ",%d", uval);
+      else
+	print_cp0sel_reg (info, state->last_regno, uval);
+      break;
+
+    case OP_DONT_CARE:
+    case OP_COPY_BITS:
+    default:
+      break;
+    }
+}
+
+/* Check if register+select map to a valid CP0 select sequence.  */
+
+static bool
+validate_cp0_reg_operand (unsigned int uval)
+{
+  int i;
+  unsigned int regno, selnum;
+  regno = uval >> NANOMIPSOP_SH_CP0SEL;
+  selnum = uval & NANOMIPSOP_MASK_CP0SEL;
+
+  for (i = 0; nanomips_cp0_3264r6[i].name; i++)
+    if (regno == nanomips_cp0_3264r6[i].num
+	&& selnum == nanomips_cp0_3264r6[i].sel)
+      break;
+    else if (regno < nanomips_cp0_3264r6[i].num)
+      return false;
+
+  if (nanomips_cp0_3264r6[i].name == NULL)
+    return false;
+
+  return true;
+}
+
+/* Validate the arguments for INSN, which is described by OPCODE.
+   Use DECODE_OPERAND to get the encoding of each operand.  */
+
+static bool
+validate_insn_args (const struct nanomips_opcode *opcode,
+		    const struct nanomips_operand *(*decode_operand) (const char *),
+		    unsigned int insn, struct disassemble_info *info)
+{
+  struct nanomips_print_arg_state state;
+  const struct nanomips_operand *operand;
+  const char *s;
+  unsigned int uval;
+
+  init_print_arg_state (&state);
+  for (s = opcode->args; *s; ++s)
+    {
+      switch (*s)
+	{
+	case ',':
+	case '(':
+	case ')':
+	  break;
+
+	case '#':
+	  ++s;
+	  break;
+
+	default:
+	  operand = decode_operand (s);
+
+	  if (!operand)
+	    continue;
+
+	  uval = nanomips_extract_operand (operand, insn);
+	  switch (operand->type)
+	    {
+	    case OP_REG:
+	    case OP_OPTIONAL_REG:
+	    case OP_BASE_CHECK_OFFSET:
+	      {
+		const struct nanomips_reg_operand *reg_op;
+
+		reg_op = (const struct nanomips_reg_operand *) operand;
+
+		if (operand->type == OP_REG
+		    && reg_op->reg_type == OP_REG_CP0
+		    && !validate_cp0_reg_operand (uval))
+		  return false;
+
+		uval = nanomips_decode_reg_operand (reg_op, uval);
+		nanomips_seen_register (&state, uval, reg_op->reg_type);
+	      }
+	      break;
+
+	    case OP_CHECK_PREV:
+	      {
+		const struct nanomips_check_prev_operand *prev_op
+		  = (const struct nanomips_check_prev_operand *) operand;
+
+		if (!prev_op->zero_ok && uval == 0)
+		  return false;
+
+		if (((prev_op->less_than_ok && uval < state.last_regno)
+		     || (prev_op->greater_than_ok && uval > state.last_regno)
+		     || (prev_op->equal_ok && uval == state.last_regno)))
+		  break;
+
+		return false;
+	      }
+
+	    case OP_MAPPED_CHECK_PREV:
+	      {
+		const struct nanomips_mapped_check_prev_operand *prev_op =
+		  (const struct nanomips_mapped_check_prev_operand *) operand;
+		unsigned int last_uval =
+		  nanomips_encode_reg_operand (operand, state.last_regno);
+
+		if (((prev_op->less_than_ok && uval < last_uval)
+		     || (prev_op->greater_than_ok && uval > last_uval)
+		     || (prev_op->equal_ok && uval == last_uval)))
+		  break;
+
+		return false;
+	      }
+
+	    case OP_NON_ZERO_REG:
+	      if (uval == 0)
+		return false;
+	      break;
+
+	    case OP_NON_ZERO_PCREL_S1:
+	      if (uval == 0 && (info->flags & INSN_HAS_RELOC) == 0)
+		return false;
+	      break;
+
+	    case OP_SAVE_RESTORE_LIST:
+	      {
+		/* The operand for SAVE/RESTORE is split into 3 pieces
+		   rather than just 2 but we only support a 2-way split
+		   decode the last bit of the instruction here.  */
+		if (opcode->mask >> 16 != 0 && ((insn >> 20) & 0x1) != 0)
+		  return false;
+	      }
+	      break;
+
+	    case OP_IMM_INT:
+	    case OP_IMM_WORD:
+	    case OP_NEG_INT:
+	    case OP_INT:
+	    case OP_MAPPED_INT:
+	    case OP_MSB:
+	    case OP_REG_PAIR:
+	    case OP_PCREL:
+	    case OP_REPEAT_PREV_REG:
+	    case OP_REPEAT_DEST_REG:
+	    case OP_SAVE_RESTORE_FP_LIST:
+	    case OP_HI20_INT:
+	    case OP_HI20_PCREL:
+	    case OP_INT_WORD:
+	    case OP_UINT_WORD:
+	    case OP_PC_WORD:
+	    case OP_GPREL_WORD:
+	    case OP_DONT_CARE:
+	    case OP_HI20_SCALE:
+	    case OP_COPY_BITS:
+	    case OP_CP0SEL:
+	      break;
+	    }
+
+	  if (*s == 'm' || *s == '+' || *s == '-' || *s == '`')
+	    ++s;
+	}
+    }
+  return true;
+}
+
+/* Print the arguments for INSN, which is described by OPCODE.
+   Use DECODE_OPERAND to get the encoding of each operand.  Use BASE_PC
+   as the base of OP_PCREL operands, adjusting by LENGTH if the OP_PCREL
+   operand is for a branch or jump.  */
+
+static void
+print_insn_args (struct disassemble_info *info,
+		 const struct nanomips_opcode *opcode,
+		 const struct nanomips_operand *(*decode_operand) (const char *),
+		 uint64_t insn, bfd_vma insn_pc, unsigned int length)
+{
+  const fprintf_ftype infprintf = info->fprintf_func;
+  void *is = info->stream;
+  struct nanomips_print_arg_state state;
+  const struct nanomips_operand *operand;
+  const char *s;
+  bool pending_sep = false;
+  bool pending_space = true;
+
+  init_print_arg_state (&state);
+  for (s = opcode->args; *s; ++s)
+    {
+      switch (*s)
+	{
+	case ',':
+	  pending_sep = true;
+	  break;
+	case '(':
+	  if (pending_sep)
+	    {
+	      infprintf (is, ",");
+	      pending_sep = false;
+	    }
+	  /* fall-through */
+	case ')':
+	  infprintf (is, "%c", *s);
+	  break;
+
+	case '#':
+	  ++s;
+	  infprintf (is, "%c%c", *s, *s);
+	  break;
+
+	default:
+	  operand = decode_operand (s);
+	  if (!operand)
+	    {
+	      /* xgettext:c-format */
+	      infprintf (is,
+			 _("# internal error, undefined operand in `%s %s'"),
+			 opcode->name, opcode->args);
+	      return;
+	    }
+
+	  /* Defer printing the comma separator for CP0-select values since
+	     the preceding register output is also defered.  */
+	  if (operand->type != OP_DONT_CARE
+	      && operand->type != OP_CP0SEL
+	      && pending_sep)
+	    {
+	      infprintf (is, ",");
+	      pending_sep = false;
+	    }
+
+	  if (operand->type != OP_DONT_CARE && pending_space)
+	    infprintf (is, "\t");
+	  pending_space = false;
+
+	  {
+	    bfd_vma base_pc = 0;
+	    bool have_reloc = ((info->flags & INSN_HAS_RELOC) != 0);
+
+	    if (!have_reloc)
+	      base_pc = insn_pc;
+
+	    if ((operand->type == OP_PCREL
+		 || operand->type == OP_HI20_PCREL
+		 || operand->type == OP_NON_ZERO_PCREL_S1
+		 || operand->type == OP_PC_WORD)
+		&& !have_reloc)
+	      base_pc += length;
+
+	    if (operand->type == OP_INT_WORD
+		|| operand->type == OP_UINT_WORD
+		|| operand->type == OP_PC_WORD
+		|| operand->type == OP_GPREL_WORD
+		|| operand->type == OP_IMM_WORD)
+	      print_insn_arg (info, &state, opcode, operand, base_pc,
+			      insn >> 32);
+	    else if (operand->type != OP_DONT_CARE)
+	      print_insn_arg (info, &state, opcode, operand, base_pc,
+			      nanomips_extract_operand (operand, insn));
+	  }
+	  if (*s == 'm' || *s == '+' || *s == '-' || *s == '`')
+	    ++s;
+	  break;
+	}
+    }
+}
+
+
+enum match_kind
+{
+  MATCH_NONE,
+  MATCH_FULL,
+  MATCH_SHORT
+};
+
+/* Disassemble nanoMIPS instructions.  */
+
+static int
+_print_insn_nanomips (bfd_vma memaddr_base, struct disassemble_info *info)
+{
+  const fprintf_ftype infprintf = info->fprintf_func;
+  const struct nanomips_opcode *op, *opend;
+  void *is = info->stream;
+  bfd_byte buffer[2];
+  uint64_t higher = 0;
+  unsigned int length;
+  int status;
+  uint64_t insn;
+
+  bfd_vma memaddr = memaddr_base;
+
+  info->bytes_per_chunk = 2;
+  info->display_endian = info->endian;
+  info->insn_info_valid = 1;
+  info->branch_delay_insns = 0;
+  info->data_size = 0;
+  info->insn_type = dis_nonbranch;
+  info->target = 0;
+  info->target2 = 0;
+
+  status = (*info->read_memory_func) (memaddr, buffer, 2, info);
+  if (status != 0)
+    {
+      (*info->memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+
+  length = 2;
+
+  if (info->endian == BFD_ENDIAN_BIG)
+    insn = bfd_getb16 (buffer);
+  else
+    insn = bfd_getl16 (buffer);
+
+  if ((insn & 0xfc00) == 0x6000)
+    {
+      unsigned imm;
+      /* This is a 48-bit nanoMIPS instruction. */
+      status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
+      if (status != 0)
+	{
+	  infprintf (is, "0x%x (expected 48 bits, got only 16): ",
+		     (unsigned) insn);
+	  (*info->memory_error_func) (status, memaddr + 2, info);
+	  return -1;
+	}
+      if (info->endian == BFD_ENDIAN_BIG)
+	imm = bfd_getb16 (buffer);
+      else
+	imm = bfd_getl16 (buffer);
+      higher = (imm << 16);
+
+      status = (*info->read_memory_func) (memaddr + 4, buffer, 2, info);
+      if (status != 0)
+	{
+	  infprintf (is, "0x%x (expected 48 bits, got only 32): ",
+		     (unsigned) insn);
+	  (*info->memory_error_func) (status, memaddr + 4, info);
+	  return -1;
+	}
+
+      if (info->endian == BFD_ENDIAN_BIG)
+	imm = bfd_getb16 (buffer);
+      else
+	imm = bfd_getl16 (buffer);
+      higher = higher | imm;
+
+      length += 4;
+    }
+  else if ((insn & 0x1000) == 0x0)
+    {
+      /* This is a 32-bit nanoMIPS instruction.  */
+      higher = insn;
+
+      status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
+      if (status != 0)
+	{
+	  infprintf (is, "0x%x (expected 32 bits, got only 16): ",
+		     (unsigned) higher);
+	  (*info->memory_error_func) (status, memaddr + 2, info);
+	  return -1;
+	}
+
+      if (info->endian == BFD_ENDIAN_BIG)
+	insn = bfd_getb16 (buffer);
+      else
+	insn = bfd_getl16 (buffer);
+
+      insn = insn | (higher << 16);
+
+      length += 2;
+    }
+
+  /* FIXME: Should probably use a hash table on the major opcode here.  */
+  const struct nanomips_opcode *opcodes;
+  int num_opcodes;
+  struct nanomips_operand const *(*decode) (const char *);
+
+  opcodes = nanomips_opcodes;
+  num_opcodes = bfd_nanomips_num_opcodes;
+  decode = decode_nanomips_operand;
+
+  opend = opcodes + num_opcodes;
+  for (op = opcodes; op < opend; op++)
+    {
+      if (op->pinfo != INSN_MACRO
+	  && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
+	  && (show_mttgpr_rc1 || (op->pinfo2 & INSN2_MTTGPR_RC1) == 0)
+	  && (insn & op->mask) == op->match
+	  && ((length == 2 && (op->mask & 0xffff0000) == 0)
+	      || (length == 6
+		  && (op->mask & 0xffff0000) == 0)
+	      || (length == 4 && (op->mask & 0xffff0000) != 0)))
+	{
+	  if (!nanomips_opcode_is_member (op, nanomips_isa, nanomips_ase,
+					  nanomips_processor)
+	      || (op->pinfo2 & INSN2_CONVERTED_TO_COMPACT))
+	    continue;
+
+	  if (!validate_insn_args (op, decode, insn, info))
+	    continue;
+
+	  infprintf (is, "%s%s", op->name,
+		     (show_arch_insn ? op->suffix : ""));
+
+	  if (length == 6)
+	    insn |= (higher << 32);
+
+	  if (op->args[0])
+	    print_insn_args (info, op, decode, insn, memaddr, length);
+
+	  /* Figure out instruction type and branch delay information.  */
+	  if ((op->pinfo2 & INSN2_UNCOND_BRANCH) != 0)
+	    {
+	      if ((op->pinfo & (INSN_WRITE_GPR_31 | INSN_WRITE_1)) != 0)
+		info->insn_type = dis_jsr;
+	      else
+		info->insn_type = dis_branch;
+	    }
+	  else if ((op->pinfo2 & INSN2_COND_BRANCH) != 0)
+	    {
+	      if ((op->pinfo & INSN_WRITE_GPR_31) != 0)
+		info->insn_type = dis_condjsr;
+	      else
+		info->insn_type = dis_condbranch;
+	    }
+	  else if ((op->pinfo & (INSN_STORE_MEMORY | INSN_LOAD_MEMORY)) != 0)
+	    info->insn_type = dis_dref;
+
+	  return length;
+	}
+    }
+
+  infprintf (is, "0x%x", (unsigned) insn);
+  info->insn_type = dis_noninsn;
+
+  return length;
+}
+
+/* Set up the options and disassemble.  */
+
+int
+print_insn_nanomips (bfd_vma memaddr, struct disassemble_info *info)
+{
+  set_default_nanomips_dis_options (info);
+  parse_nanomips_dis_options (info->disassembler_options);
+
+  return _print_insn_nanomips (memaddr, info);
+}
+
+/* Print description of nanoMIPS-specific command-line options.  */
+
+void
+print_nanomips_disassembler_options (FILE *stream)
+{
+  unsigned int i;
+
+  fprintf (stream, _("\n\
+The following nanoMIPS specific disassembler options are supported for use\n\
+with the -M switch (multiple options should be separated by commas):\n"));
+
+  fprintf (stream, _("\n\
+  no-aliases     Use canonical instruction forms.\n"));
+
+  fprintf (stream, _("\n\
+  show-arch-insn Print extended mnemonics in disassembly including\n\
+                 suffix as in the architecture reference manual.\n"));
+
+  fprintf (stream, _("\n\
+  show-mttgpr-rc1 Disassemble MTTGPR as RC1 style (deprecated) format.\n"));
+
+  fprintf (stream, _("\n\
+  msa            Recognize MSA instructions.\n"));
+
+  fprintf (stream, _("\n\
+  virt           Recognize the virtualization ASE instructions.\n"));
+
+  fprintf (stream, _("\n\
+  mxu            Recognize the MXU ASE instructions.\n"));
+
+  fprintf (stream, _("\n\
+  gpr-names=ABI            Print GPR names according to  specified ABI.\n\
+                           Default: based on binary being disassembled.\n"));
+
+  fprintf (stream, _("\n\
+  fpr-names=ABI            Print FPR names according to specified ABI.\n\
+                           Default: numeric.\n"));
+
+  fprintf (stream, _("\n\
+  cp0-names=ARCH           Print CP0 register names according to\n\
+                           specified architecture.\n\
+                           Default: based on binary being disassembled.\n"));
+
+  fprintf (stream, _("\n\
+  hwr-names=ARCH           Print HWR names according to specified \n\
+			   architecture.\n\
+                           Default: based on binary being disassembled.\n"));
+
+  fprintf (stream, _("\n\
+  reg-names=ABI            Print GPR and FPR names according to\n\
+                           specified ABI.\n"));
+
+  fprintf (stream, _("\n\
+  reg-names=ARCH           Print CP0 register and HWR names according to\n\
+                           specified architecture.\n"));
+
+  fprintf (stream, _("\n\
+  For the options above, the following values are supported for \"ABI\":\n\
+   "));
+  for (i = 0; i < ARRAY_SIZE (nanomips_abi_choices); i++)
+    fprintf (stream, " %s", nanomips_abi_choices[i].name);
+  fprintf (stream, _("\n"));
+
+  fprintf (stream, _("\n\
+  For the options above, The following values are supported for \"ARCH\":\n\
+   "));
+  for (i = 0; i < ARRAY_SIZE (nanomips_arch_choices); i++)
+    if (*nanomips_arch_choices[i].name != '\0')
+      fprintf (stream, " %s", nanomips_arch_choices[i].name);
+  fprintf (stream, _("\n"));
+
+  fprintf (stream, _("\n"));
+}
diff --git a/opcodes/nanomips-formats.h b/opcodes/nanomips-formats.h
new file mode 100644
index 00000000000..1144604abe6
--- /dev/null
+++ b/opcodes/nanomips-formats.h
@@ -0,0 +1,265 @@ 
+/* nanomips-formats.h
+   Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+   Written by Faraz Shahbazker <faraz.shahbazker@mips.com>
+
+   This library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   It is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING3. If not,
+   see <http://www.gnu.org/licenses/>.  */
+
+#include "libiberty.h"
+
+#define INT_BIAS(SIZE, LSB, MAX_VAL, BIAS, SHIFT, PRINT_HEX)		\
+  {									\
+    static const struct nanomips_int_operand op = {			\
+      { OP_INT, SIZE, LSB, 0, 0 }, MAX_VAL, BIAS, SHIFT, PRINT_HEX	\
+    };									\
+    return &op.root;							\
+  }
+
+#define INT_ADJ(SIZE, LSB, MAX_VAL, SHIFT, PRINT_HEX)	\
+  INT_BIAS(SIZE, LSB, MAX_VAL, 0, SHIFT, PRINT_HEX)
+
+#define UINT(SIZE, LSB)					\
+  INT_ADJ(SIZE, LSB, (1 << (SIZE)) - 1, 0, false)
+
+#define SINT(SIZE, LSB)					\
+  INT_ADJ(SIZE, LSB, (1 << ((SIZE) - 1)) - 1, 0, false)
+
+#define HINT(SIZE, LSB)					\
+  INT_ADJ(SIZE, LSB, (1 << (SIZE)) - 1, 0, true)
+
+#define BIT(SIZE, LSB, BIAS)						\
+  {									\
+    static const struct nanomips_int_operand op = {			\
+      { OP_INT, SIZE, LSB, 0, 0 }, (1 << (SIZE)) - 1, BIAS, 0, false	\
+    };									\
+    return &op.root;							\
+  }
+
+#define MAPPED_INT(SIZE, LSB, MAP, PRINT_HEX)			\
+  {								\
+    typedef char ATTRIBUTE_UNUSED				\
+      static_assert[(1 << (SIZE)) == ARRAY_SIZE (MAP)];		\
+    static const struct nanomips_mapped_int_operand op = {	\
+      { OP_MAPPED_INT, SIZE, LSB, 0, 0 }, MAP, PRINT_HEX	\
+    };								\
+    return &op.root;						\
+  }
+
+#define MSB(SIZE, LSB, BIAS, ADD_LSB, OPSIZE)			\
+  {								\
+    static const struct nanomips_msb_operand op = {		\
+      { OP_MSB, SIZE, LSB, 0, 0 }, BIAS, ADD_LSB, OPSIZE	\
+    };								\
+    return &op.root;						\
+  }
+
+#define REG(SIZE, LSB, BANK)				\
+  {							\
+    static const struct nanomips_reg_operand op = {	\
+      { OP_REG, SIZE, LSB, 0, 0 }, OP_REG_##BANK, 0	\
+    };							\
+    return &op.root;					\
+  }
+
+#define OPTIONAL_REG(SIZE, LSB, BANK)				\
+  {								\
+    static const struct nanomips_reg_operand op = {		\
+      { OP_OPTIONAL_REG, SIZE, LSB, 0, 0 }, OP_REG_##BANK, 0	\
+    };								\
+    return &op.root;						\
+  }
+
+#define MAPPED_REG(SIZE, LSB, BANK, MAP)		\
+  {							\
+    typedef char ATTRIBUTE_UNUSED			\
+      static_assert[(1 << (SIZE)) == ARRAY_SIZE (MAP)]; \
+    static const struct nanomips_reg_operand op = {	\
+      { OP_REG, SIZE, LSB, 0, 0 }, OP_REG_##BANK, MAP	\
+    };							\
+    return &op.root;					\
+  }
+
+#define SPLIT_MAPPED_REG(SIZE, LSB, SIZE_T, LSB_T, BANK, MAP)	\
+  {								\
+    typedef char ATTRIBUTE_UNUSED				\
+      static_assert[(1 << (SIZE)) == ARRAY_SIZE (MAP)];		\
+    static const struct nanomips_reg_operand op = {		\
+      { OP_REG, SIZE, LSB, SIZE_T, LSB_T }, OP_REG_##BANK, MAP	\
+    };								\
+    return &op.root;						\
+  }
+
+#define OPTIONAL_MAPPED_REG(SIZE, LSB, BANK, MAP)		\
+  {								\
+    typedef char ATTRIBUTE_UNUSED				\
+      static_assert[(1 << (SIZE)) == ARRAY_SIZE (MAP)];		\
+    static const struct nanomips_reg_operand op = {		\
+      { OP_OPTIONAL_REG, SIZE, LSB, 0, 0 }, OP_REG_##BANK, MAP	\
+    };								\
+    return &op.root;						\
+  }
+
+#define REG_PAIR(SIZE, LSB, BANK, MAP)					\
+  {									\
+    typedef char ATTRIBUTE_UNUSED					\
+      static_assert1[(1 << (SIZE)) == ARRAY_SIZE (MAP##1)];		\
+    typedef char ATTRIBUTE_UNUSED					\
+      static_assert2[(1 << (SIZE)) == ARRAY_SIZE (MAP##2)];		\
+    static const struct nanomips_reg_pair_operand op = {		\
+      { OP_REG_PAIR, SIZE, LSB, 0, 0 }, OP_REG_##BANK, MAP##1, MAP##2	\
+    };									\
+    return &op.root;							\
+  }
+
+#define PCREL(SIZE, LSB, IS_SIGNED, SHIFT, ALIGN_LOG2, INCLUDE_ISA_BIT, \
+              FLIP_ISA_BIT)						\
+  {									\
+    static const struct nanomips_pcrel_operand op = {			\
+      { { OP_PCREL, SIZE, LSB, 0, 0 },					\
+	(1 << ((SIZE) - (IS_SIGNED))) - 1, 0, SHIFT, true },		\
+      ALIGN_LOG2, INCLUDE_ISA_BIT, FLIP_ISA_BIT				\
+    };									\
+    return &op.root.root;						\
+  }
+
+#define JUMP(SIZE, LSB, SHIFT)					\
+  PCREL (SIZE, LSB, false, SHIFT, SIZE + SHIFT, true, false)
+
+#define JALX(SIZE, LSB, SHIFT)					\
+  PCREL (SIZE, LSB, false, SHIFT, SIZE + SHIFT, true, true)
+
+#define BRANCH(SIZE, LSB, SHIFT)			\
+  PCREL (SIZE, LSB, true, SHIFT, 0, true, false)
+
+#define SPECIAL(SIZE, LSB, TYPE)					\
+  {									\
+    static const struct nanomips_operand op = { OP_##TYPE, SIZE, LSB, 0, 0 }; \
+    return &op;								\
+  }
+
+#define PREV_CHECK(SIZE, LSB, GT_OK, LT_OK, EQ_OK, ZERO_OK)		\
+  {									\
+    static const struct nanomips_check_prev_operand op = {		\
+      { OP_CHECK_PREV, SIZE, LSB, 0, 0 }, GT_OK, LT_OK, EQ_OK, ZERO_OK	\
+    };									\
+    return &op.root;							\
+  }
+
+#define IMM_INT_BIAS(SIZE, LSB, MAX_VAL, BIAS, SHIFT, PRINT_HEX)	\
+  {									\
+    static const struct nanomips_int_operand op = {			\
+      { OP_IMM_INT, SIZE, LSB, 0, 0 }, MAX_VAL, BIAS, SHIFT, PRINT_HEX	\
+    };									\
+    return &op.root;							\
+  }
+
+#define IMM_INT_ADJ(SIZE, LSB, MAX_VAL, SHIFT, PRINT_HEX)	\
+  IMM_INT_BIAS(SIZE, LSB, MAX_VAL, 0, SHIFT, PRINT_HEX)
+
+#define UINT_SPLIT(SIZE, LSB, SHIFT, SIZE_TOP, LSB_TOP)	\
+  {							\
+    static const struct nanomips_int_operand op = {	\
+      { OP_INT, SIZE, LSB, SIZE_TOP, LSB_TOP },		\
+      (1 << (SIZE)) - 1, 0, SHIFT, 0			\
+    };							\
+    return &op.root;					\
+  }
+
+#define SINT_SPLIT(SIZE, LSB, SHIFT, SIZE_TOP, LSB_TOP, BIAS)	\
+  {								\
+    static const struct nanomips_int_operand op = {		\
+      { OP_INT, SIZE, LSB, SIZE_TOP, LSB_TOP },			\
+      (1 << ((SIZE) -1)) - 1, BIAS, SHIFT, 0			\
+    };								\
+    return &op.root;						\
+  }
+
+#define IMM_SINT_SPLIT(SIZE, LSB, SHIFT, SIZE_TOP, LSB_TOP, BIAS)	\
+  {									\
+    static const struct nanomips_int_operand op = {			\
+      { OP_IMM_INT, SIZE, LSB, SIZE_TOP, LSB_TOP },			\
+      (1 << ((SIZE) -1)) - 1, BIAS, SHIFT, false			\
+    };									\
+    return &op.root;							\
+  }
+
+#define HINT_SPLIT(SIZE, LSB, SIZE_T, LSB_T)	\
+  SINT_SPLIT(SIZE, LSB, 0, SIZE_T, LSB_T)
+
+#define SPLIT_MAPPED_REG_PAIR(SIZE, LSB, SIZE_T, LSB_T, BANK, MAP1, MAP2) \
+  {									\
+    typedef char ATTRIBUTE_UNUSED					\
+      static_assert1[(1 << (SIZE)) == ARRAY_SIZE (MAP1)];		\
+    typedef char ATTRIBUTE_UNUSED					\
+      static_assert2[(1 << (SIZE)) == ARRAY_SIZE (MAP2)];		\
+    static const struct nanomips_reg_pair_operand op = {		\
+      { OP_REG_PAIR, SIZE, LSB, SIZE_T, LSB_T }, OP_REG_##BANK,		\
+      MAP1, MAP2							\
+    };									\
+    return &op.root;							\
+  }
+
+#define BRANCH_UNORD_SPLIT(SIZE, SHIFT)			\
+  {							\
+    static const struct nanomips_pcrel_operand op = {	\
+      { { OP_PCREL, SIZE, 1, 1, 0 },			\
+	(1 << ((SIZE) - 1)) - 1, 0, SHIFT, true },	\
+      0, false, false					\
+    };							\
+    return &op.root.root;				\
+  }
+
+#define BRANCH_SPLIT(SIZE, LSB, SHIFT, SIZE_TOP, LSB_TOP)	\
+  {								\
+    static const struct nanomips_pcrel_operand op = {		\
+      { { OP_PCREL, SIZE, 1, SIZE_TOP, LSB_TOP },		\
+	(1 << ((SIZE) - 1)) - 1, LSB, SHIFT, true },		\
+      0, false, false						\
+    };								\
+    return &op.root.root;					\
+  }
+
+#define SPECIAL_SPLIT(SIZE, LSB, SIZE_T, LSB_T, TYPE)			\
+  {									\
+    static const struct nanomips_operand op = { OP_##TYPE, SIZE, LSB, SIZE_T, LSB_T }; \
+    return &op;								\
+  }
+
+#define SPECIAL_WORD(BIAS, TYPE)					\
+  {									\
+    static const struct nanomips_int_operand op = { { OP_##TYPE, 0, 0, 0, 0 }, \
+						    0x7fffffff, BIAS, 0, false }; \
+    return &op.root;							\
+  }
+
+#define MAPPED_PREV_CHECK(SIZE, LSB, BANK, MAP, GT_OK, LT_OK, EQ_OK, ZERO_OK) \
+  {									\
+    typedef char ATTRIBUTE_UNUSED					\
+      static_assert[(1 << (SIZE)) == ARRAY_SIZE (MAP)];			\
+    static const struct nanomips_mapped_check_prev_operand op = {	\
+      { OP_MAPPED_CHECK_PREV, SIZE, LSB, 0, 0 }, OP_REG_##BANK, MAP,	\
+      GT_OK, LT_OK, EQ_OK, ZERO_OK					\
+    };									\
+    return &op.root;							\
+  }
+
+#define BASE_OFFSET_CHECK(SIZE, LSB, CONST_OK, EXPR_OK)			\
+  {									\
+    static const struct nanomips_base_check_offset_operand op = {	\
+      { OP_BASE_CHECK_OFFSET, SIZE, LSB, 0, 0 }, OP_REG_GP,		\
+      CONST_OK, EXPR_OK							\
+    };									\
+    return &op.root;							\
+  }
diff --git a/opcodes/nanomips-opc.c b/opcodes/nanomips-opc.c
new file mode 100644
index 00000000000..aa82c5c021c
--- /dev/null
+++ b/opcodes/nanomips-opc.c
@@ -0,0 +1,1073 @@ 
+/* nanomips-opc.c.  nanoMIPS opcode table.
+   Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+   Written by Faraz Shahbazker <faraz.shahbazker@mips.com>
+
+   This file is part of the GNU opcodes library.
+
+   This library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   It is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING.  If not, write to the
+   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "opcode/nanomips.h"
+#include "nanomips-formats.h"
+
+static unsigned char reg_0_map[] = { 0 };
+static unsigned char reg_28_map[] = { 28 };
+static unsigned char reg_29_map[] = { 29 };
+static unsigned char reg_31_map[] = { 31 };
+static unsigned char reg_m16_map[] = { 16, 17, 18, 19, 4, 5, 6, 7 };
+static unsigned char reg_q_map[] = { 0, 17, 18, 19, 4, 5, 6, 7 };
+
+static unsigned char reg_4to5_map[] = {
+  8, 9, 10, 11, 4, 5, 6, 7,
+  16, 17, 18, 19, 20, 21, 22, 23
+};
+
+static unsigned char reg_4to5_srcmap[] = {
+  8, 9, 10, 0, 4, 5, 6, 7,
+  16, 17, 18, 19, 20, 21, 22, 23
+};
+
+static unsigned char reg_4or5_map[] = { 4, 5 };
+
+static unsigned char reg_gpr2d_map1[] = { 4, 5, 6, 7 };
+static unsigned char reg_gpr2d_map2[] = { 5, 6, 7, 8 };
+
+static int int_b_map[] = {
+  0, 4, 8, 12, 16, 20, 24, 28
+};
+
+static int int_c_map[] = {
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 255, 65535, 14, 15
+};
+
+static int word_byte_map[] = {
+  0, 0, 0, 0, 0, 0, 0, 0,
+  3, 0, 0, 0, 0, 0, 0, 0,
+  2, 0, 0, 0, 0, 0, 0, 0,
+  1, 0, 0, 0, 0, 0, 0, 0
+};
+
+static int int_mask_map[] = {
+  0x1, 0x3, 0x7, 0xf,
+  0x1f, 0x3f, 0x7f, 0xff,
+  0x1ff, 0x3ff, 0x7ff, 0xfff,
+  0x1fff, 0x3fff, 0x7fff, 0xffff,
+  0x1ffff, 0x3ffff, 0x7ffff, 0xfffff,
+  0x1fffff, 0x3fffff, 0x7fffff, 0xffffff,
+  0x1ffffff,0x3ffffff,0x7ffffff,0xfffffff,
+  0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff
+};
+
+/* Return the nanomips_operand structure for the operand at the
+   beginning of P.  */
+
+/* FIXME: Unused cases left commented in-place for quick reminder
+   of which character strings are unused.  */
+const struct nanomips_operand *
+decode_nanomips_operand (const char *p)
+{
+  switch (p[0])
+    {
+    case 'm':
+      switch (p[1])
+	{
+	case 'a': MAPPED_REG (0, 0, GP, reg_28_map);
+	case 'b': SPECIAL (5, 5, NON_ZERO_REG);
+	case 'c': OPTIONAL_MAPPED_REG (3, 4, GP, reg_m16_map);
+	case 'd': MAPPED_REG (3, 7, GP, reg_m16_map);
+	case 'e': MAPPED_REG (3, 1, GP, reg_m16_map);
+	case 'f': MAPPED_PREV_CHECK (3, 7, GP, reg_m16_map, true, false, false, false);
+	case 'g': MAPPED_PREV_CHECK (3, 4, GP, reg_m16_map, false, true, false, false);
+	case 'h': MAPPED_PREV_CHECK (3, 7, GP, reg_m16_map, false, true, true, false);
+	case 'i': MAPPED_PREV_CHECK (3, 4, GP, reg_m16_map, true, false, true, false);
+	case 'j': REG (5, 0, GP);
+	case 'k': SPECIAL (0, 0, REPEAT_DEST_REG);
+	case 'l': MAPPED_REG (3, 4, GP, reg_m16_map);
+	case 'm': MAPPED_REG (3, 7, GP, reg_q_map);
+	case 'n': SPECIAL_SPLIT (5, 0, 1, 9, SAVE_RESTORE_LIST);
+	case 'p': REG (5, 5, GP);
+	case 'q': SPLIT_MAPPED_REG_PAIR (2, 8, 1, 3, GP, reg_gpr2d_map1,
+					 reg_gpr2d_map2);
+	case 'r': SPLIT_MAPPED_REG_PAIR (2, 8, 1, 3, GP, reg_gpr2d_map2,
+					 reg_gpr2d_map1);
+	case 's': MAPPED_REG (0, 0, GP, reg_29_map);
+	case 't': SPECIAL (0, 0, REPEAT_PREV_REG);
+	case 'u': SPLIT_MAPPED_REG (4, 5, 1, 9, GP, reg_4to5_map);
+	case 'v': SPLIT_MAPPED_REG (4, 0, 1, 4, GP, reg_4to5_map);
+	case 'w': SPLIT_MAPPED_REG (4, 5, 1, 9, GP, reg_4to5_srcmap);
+	case 'x': SPLIT_MAPPED_REG (4, 0, 1, 4, GP, reg_4to5_srcmap);
+	case 'y': MAPPED_REG (0, 0, GP, reg_31_map);
+	case 'z': UINT (0, 0); 	/* Literal 0 */
+	case 'A': INT_ADJ (7, 0, 127, 2, false);	 /* (0 .. 127) << 2 */
+	case 'B': MAPPED_INT (3, 0, int_b_map, false);
+	case 'C': MAPPED_INT (4, 0, int_c_map, true);
+	case 'D': BRANCH_UNORD_SPLIT (10, 1);
+	case 'E': BRANCH_UNORD_SPLIT (7, 1);
+	case 'F': SPECIAL (4, 0, NON_ZERO_PCREL_S1);
+	case 'G': INT_ADJ (4, 4, 15, 4, false);
+	case 'H': INT_ADJ (2, 1, 3, 1, false);	 /* (0 .. 3) << 1 */
+	case 'I': INT_ADJ (7, 0, 126, 0, false); /* (-1 .. 126) */
+	case 'J': INT_ADJ (4, 0, 15, 2, false);	 /* (0 .. 15) << 2 */
+	case 'K': HINT (3, 0);
+	case 'L': UINT (2, 0);	 /* (0 .. 3) */
+	case 'M': INT_ADJ (3, 0, 8, 0, false);   /* (1 .. 8) */
+	case 'N': UINT_SPLIT (2, 8, 2, 1, 3); /* split encoded 2-bit offset << 2 */
+	case 'O': IMM_INT_ADJ (7, 0, 127, 2, false);	 /* (0 .. 127) << 2 */
+	case 'P': HINT (2, 0);
+	case 'Q': SINT_SPLIT (4, 0, 0, 1, 4, 0);
+	case 'R': INT_ADJ (5, 0, 31, 2, false);	 /* (0 .. 31) << 2 */
+	case 'S': INT_ADJ (6, 0, 63, 2, false);	 /* (0 .. 63) << 2 */
+	case 'Z': UINT (0, 0);			 /* 0 only */
+	}
+      break;
+
+    case '-':
+      switch (p[1])
+	{
+	case 'i': REG (0, 0, GP); /* Ignored register operand.  */
+	case 'm': SPECIAL_SPLIT (5, 11, 5, 21, COPY_BITS);
+	case 'n': SPECIAL_SPLIT (5, 11, 5, 16, COPY_BITS);
+	case 'A': SPECIAL (5, 16, DONT_CARE);
+	case 'B': SPECIAL (1, 10, DONT_CARE);
+	case 'C': SPECIAL (12, 0, DONT_CARE);
+	case 'D': SPECIAL (1, 17, DONT_CARE);
+	case 'E': SPECIAL (3, 13, DONT_CARE);
+	case 'F': SPECIAL (10, 16, DONT_CARE);
+	case 'G': SPECIAL_SPLIT (8, 9, 5, 16, DONT_CARE);
+	case 'H': SPECIAL (9, 17, DONT_CARE);
+	case 'I': SPECIAL (5, 21, DONT_CARE);
+	case 'J': SPECIAL (3, 23, DONT_CARE);
+	case 'K': SPECIAL_SPLIT (2, 2, 1, 15, DONT_CARE);
+	case 'L': SPECIAL (3, 6, DONT_CARE);
+	case 'M': SPECIAL (3, 9, DONT_CARE);
+	case 'N': SPECIAL (6, 10, DONT_CARE);
+	case 'O': SPECIAL (1, 12, DONT_CARE);
+	case 'P': SPECIAL_SPLIT (8, 10, 4, 22, DONT_CARE);
+	case 'Q': SPECIAL (1, 11, DONT_CARE);
+	}
+      break;
+
+    case '+':
+      switch (p[1])
+	{
+	case 'A': BIT (5, 0, 0);		 /* (0 .. 31) */
+	case 'B': MSB (5, 6, 1, true, 32);	 /* (1 .. 32), 32-bit op */
+	case 'C': MSB (5, 6, 1, false, 32);	 /* (1 .. 32), 32-bit op */
+	case 'D': SPECIAL (4, 16, SAVE_RESTORE_FP_LIST);
+	case 'E': BIT (5, 0, 32);		 /* (32 .. 63) */
+	case 'F': MSB (5, 6, 33, true, 64);	 /* (33 .. 64), 64-bit op */
+	case 'G': MSB (5, 6, 33, false, 64);	 /* (33 .. 64), 64-bit op */
+	case 'H': MSB (5, 6, 1, false, 64);	 /* (1 .. 32), 64-bit op */
+	case 'I': BIT (5, 6, 0); /* (0 .. 31) */
+	case 'J': HINT (19, 0);
+	case 'K': SPECIAL_SPLIT (20, 2, 1, 0, HI20_PCREL); /* tri-part 20-bit */
+	case 'L': HINT (10, 16);
+	case 'M': HINT (18, 0);
+	case 'N': INT_ADJ (9, 3, 511, 3, false);	/* 9-bit << 3 */
+	case 'O': SPECIAL_WORD (0, GPREL_WORD);
+	case 'P': SPECIAL_WORD (6, IMM_WORD);
+	case 'Q': SPECIAL_WORD (0, UINT_WORD);
+	case 'R': SPECIAL_WORD (0, INT_WORD);
+	case 'S': SPECIAL_WORD (0, PC_WORD);
+
+	case 'i': HINT (5, 16);
+	case 'j': SINT_SPLIT (9, 0, 0, 1, 15, 0);
+	case 'p': SINT_SPLIT (7, 2, 2, 1, 15, 0); /* split 7-bit signed << 2 */
+	case 'q': SINT_SPLIT (6, 3, 3, 1, 15, 0); /* split 6-bit signed << 3 */
+	case 'r': BRANCH_UNORD_SPLIT (21, 1); /* split 21-bit signed << 1 */
+	case 's': IMM_SINT_SPLIT (21, 1, 1, 1, 0, 2); /* split (21-bit signed + 2) << 1 */
+	case 't': SPECIAL (5, 21, NON_ZERO_REG);
+	case 'u': BRANCH_UNORD_SPLIT (25, 1);
+	case 'v': MAPPED_INT (5, 6, word_byte_map, false);
+	case 'w': BIT (2, 9, 0);		/* (0 .. 3) */
+
+	case '*': INT_ADJ (4, 7, 15, 1, false); /* (0 .. 15) << 1 */
+	case '|': UINT (1, 6);			/* 0/1 */
+	case ';': UINT (2, 21);			/* (0 .. 3) */
+	case '1': UINT (18, 0);
+	case '2': INT_ADJ (16, 2, (1<<16) - 1, 2, false);
+	case '3': INT_ADJ (17, 1, (1<<17) - 1, 1, false);
+	case '4': INT_ADJ (18, 3, (1<<18)-1, 3, false); /* 18-bit << 3 */
+	case '5': SPLIT_MAPPED_REG (4, 21, 1, 25, GP, reg_4to5_srcmap);
+	case '6': MAPPED_INT (5, 6, int_mask_map, true);
+	case '7': MAPPED_REG (1, 24, GP, reg_4or5_map);
+	case '8': HINT (23, 3);
+	case '9': UINT (7, 11);
+	}
+      break;
+
+    case '.': INT_ADJ (19, 2, (1<<19) - 1, 2, false);
+    case '<': BIT (5, 0, 0);			 /* (0 .. 31) */
+/*     case '>': BIT (5, 11, 32);			 /\* (32 .. 63) *\/ */
+    case '\\': BIT (3, 21, 0);			 /* (0 .. 7) */
+    case '|': INT_ADJ (3, 12, 8, 0, false);	/* 1 .. 8 */
+    case '~': BRANCH_UNORD_SPLIT (11, 1);	/* split 11-bit signed << 1 */
+    case '@': SINT (10, 11);
+    case '^': HINT (5, 11);
+    case '!': UINT (1, 10);
+    case '$': UINT (1, 3);
+    case '*': REG (2, 18, ACC);
+/*     case '&': REG (2, 23, ACC); */
+
+    case '0': SINT (6, 16);
+    case '1': BIT (5, 11, 0);			 /* (0 .. 31) */
+    case '2': BIT (5, 16, 0);		/* (0 .. 31) */
+    case '3': BIT (3, 13, 0);
+    case '4': BIT (4, 12, 0);
+    case '5': HINT (8, 13);
+    case '7': REG (2, 14, ACC);
+    case '8': HINT (7, 14);
+
+    case 'C': HINT (23, 3);
+    case 'D': REG (5, 11, FP);
+    case 'E': REG (5, 21, COPRO);
+    case 'G': REG (5, 16, COPRO);
+    case 'H': UINT (5, 11);
+    case 'J': SPECIAL (5, 11, CP0SEL);
+    case 'K': REG (10, 11, HW);
+/*     case 'M': REG (3, 13, CCC); */
+/*     case 'N': REG (3, 18, CCC); */
+    case 'O': REG (10, 11, CP0);
+    case 'P': REG (5, 16, CP0SEL);
+/*     case 'Q': UINT (5, 11); */
+    case 'R': REG (5, 11, FP);
+    case 'S': REG (5, 16, FP);
+    case 'T': REG (5, 21, FP);
+    case 'U': REG (5, 16, HWRSEL);
+    case 'V': OPTIONAL_REG (5, 16, FP);
+
+/*     case 'a': JUMP (26, 0, 1); */
+    case 'b': REG (5, 16, GP);
+    case 'c': BASE_OFFSET_CHECK (5, 16, true, false);
+    case 'd': REG (5, 11, GP);
+    case 'e': REG (5, 3, GP);
+    case 'g': HINT (12, 0);
+    case 'h': SPECIAL (12, 0, NEG_INT);
+    case 'i': UINT (12, 0);
+    case 'j': UINT (16, 0);
+    case 'k': HINT (5, 21);
+    case 'n': SPECIAL_SPLIT (11, 2, 10, 16, SAVE_RESTORE_LIST);
+    case 'o': UINT (12, 0);
+    case 'p': BRANCH_UNORD_SPLIT (14, 1);
+/*     case 'q': BRANCH_UNORD_SPLIT (20, 1); - unused */
+    case 'r': OPTIONAL_REG (5, 16, GP);
+    case 's': REG (5, 16, GP);
+    case 't': REG (5, 21, GP);
+    case 'u': SPECIAL_SPLIT (20, 2, 1, 0, HI20_INT);  /* tri-part 20-bit */
+    case 'v': OPTIONAL_REG (5, 16, GP);
+    case 'w': OPTIONAL_REG (5, 21, GP);
+    case 'x': SPECIAL_SPLIT (20, 2, 1, 0, HI20_SCALE);  /* tri-part 20-bit */
+    case 'z': MAPPED_REG (0, 0, GP, reg_0_map);
+    }
+  return 0;
+}
+
+#define LM	INSN_LOAD_MEMORY
+#define SM	INSN_STORE_MEMORY
+
+#define WR_1	INSN_WRITE_1
+#define WR_2	INSN_WRITE_2
+#define RD_1	INSN_READ_1
+#define RD_2	INSN_READ_2
+#define RD_3	INSN_READ_3
+#define MOD_1	(WR_1|RD_1)
+#define MOD_2	(WR_2|RD_2)
+#define FP_S	INSN_FP_S
+#define FP_D	INSN_FP_D
+
+ /* Write dsp accumulators */
+#define WR_a	INSN_WRITE_ACC
+ /* Read dsp accumulators */
+#define RD_a	INSN_READ_ACC
+
+/* Flags used in pinfo2.  */
+#define CTC	INSN2_CONVERTED_TO_COMPACT
+#define UBR	INSN2_UNCOND_BRANCH
+#define CBR	INSN2_COND_BRANCH
+#define ALIAS	INSN2_ALIAS
+
+/* For 32-bit nanoMIPS instructions.  */
+#define WR_31	INSN_WRITE_GPR_31
+
+/* nanoMIPS DSP ASE support.  */
+#define D32	ASE_DSP
+
+/* nanoMIPS MT ASE support.  */
+#define MT32	ASE_MT
+
+/* nanoMIPS MCU (MicroController) ASE support.  */
+#define MC	ASE_MCU
+
+/* nanoMIPS Enhanced VA Scheme.  */
+#define EVA	ASE_EVA
+
+/* MSA support.  */
+#define MSA     ASE_MSA
+#define MSA64   ASE_MSA64
+
+/* eXtended Physical Address (XPA) support.  */
+#define XPA     ASE_XPA
+
+/* Global INValidate extension.  */
+#define GINV	ASE_GINV
+
+/* Cyclic redundancy check instruction (CRC) support.  */
+#define CRC	ASE_CRC
+
+/* nanoMIPS instruction subset.  */
+#define xNMS	ASE_xNMS
+/* TLB manipulations.  */
+#define TLB	ASE_TLB
+
+/* Base ISA for nanoMIPS. */
+#define I38	INSN_ISAN32R6
+#define I70	INSN_ISAN64R6
+
+const struct nanomips_opcode nanomips_opcodes[] = {
+/* These instructions appear first so that the disassembler will find
+   them first.  The assemblers uses a hash table based on the
+   instruction name anyhow.  */
+/* name,	suffix,		args,		match,		mask,	     pinfo	pinfo2,	 membership, ase */
+/* Pure macros */
+{"la",		"",		"t,A(b)",	0,    (int) M_LA_AB,	INSN_MACRO,		0,	I38,	0},
+{"dla", 	"",		"t,A(b)",	0,    (int) M_DLA_AB,	INSN_MACRO,		0,	I38,	0},
+/* Precedence=1 */
+{"aluipc",	"",		"t,+K", 	0xe0000002, 0xfc000002, WR_1,			0,	I38,	0}, /* ALUIPC */
+{"break",	"[16]", 	"",		0x1010, 	0xffff,	0,		INSN2_ALIAS,	I38,	0},
+{"break",	"[16]", 	"mK",		0x1010, 	0xfff8,	0,			0,	I38,	0},
+{"break",	"[32]", 	"",		0x00100000, 0xffffffff,		0,	INSN2_ALIAS,	I38,	0},
+{"break",	"[32]", 	"+J",		0x00100000, 0xfff80000,		0,		0,	I38,	0},
+{"dvp", 	"",		"-A",		0x20000390, 0xffe0ffff,		0,	INSN2_ALIAS,	I38,	0}, /* DVP */
+{"dvp", 	"",		"t,-A", 	0x20000390, 0xfc00ffff,		WR_1,		0,	I38,	0},
+{"nop", 	"[16]", 	"",		0x9008,		0xffff,		0,		0,	I38,	0}, /* NOP[16] */
+{"nop", 	"[32]", 	"",		0x8000c000, 0xffffffff,		0,		0,	I38,	0}, /* NOP */
+{"sdbbp",	"[16]", 	"",		0x1018,		0xffff,		0,	INSN2_ALIAS,	I38,	0},
+{"sdbbp",	"[16]", 	"mK",		0x1018,		0xfff8,		0,		0,	I38,	0},
+{"sdbbp",	"[32]", 	"",		0x00180000, 0xffffffff,		0,	INSN2_ALIAS,	I38,	0},
+{"sdbbp",	"[32]", 	"+J",		0x00180000, 0xfff80000,		0,		0,	I38,	0},
+{"move",	"",		"mb,mj",	0x1000,		0xfc00,	WR_1|RD_2,		0,	I38,	0}, /* preceded by BREAK, SDBBP */
+{"move",	"",		"d,s",		0x20000290, 0xffe007ff, WR_1|RD_2,	INSN2_ALIAS,	I38,	0}, /* OR */
+{"move",	"",		"d,s",		0x20000150, 0xffe007ff, WR_1|RD_2,	INSN2_ALIAS,	I38,	0}, /* ADDU */
+{"sigrie",	"",		"+J",		0x00000000, 0xfff80000,	0,			0,	I38,	0},
+{"synci",	"[u12]",	"o(b)", 	0x87e03000, 0xffe0f000,	RD_2,			0,	I38,	0}, /* SYNCI[U12] */
+{"synci",	"[s9]", 	"+j(b)",	0xa7e01800, 0xffe07f00,	RD_2,			0,	I38,	0}, /* SYNCI[S9] */
+{"syncie",	"",		"+j(b)",	0xa7e01a00, 0xffe07f00,	RD_2,			0,	0,	EVA},
+{"jrc", 	"[16]", 	"mp",		0xd800, 	0xfc1f,	RD_1,			0,	I38,	0}, /* JRC[16] */
+{"jrc", 	"[32]", 	"s",		0x48000000, 0xffe0ffff,	RD_1,		INSN2_ALIAS,	I38,	0}, /* JALRC */
+{"jalrc",	"[16]", 	"mp",		0xd810, 	0xfc1f,	WR_31|RD_1,		0,	I38,	0}, /* JALRC[16] */
+{"jalrc",	"[16]", 	"my,mp",	0xd810, 	0xfc1f,	WR_31|RD_1,	INSN2_ALIAS,	I38,	0}, /* JALRC[16] */
+{"jalrc",	"[32]", 	"s",		0x4be00000, 0xffe0ffff,	RD_1,		INSN2_ALIAS,	I38,	0}, /* JALRC[32] */
+{"jalrc",	"[32]", 	"t,s,-C",	0x48000000, 0xfc00f000,	WR_1|RD_2,		0,	I38,	0},
+{"jalrc",	"",		"mp,-i",	0xd810, 	0xfc1f,	WR_31|RD_1,	INSN2_ALIAS,	I38,	0}, /* JALRC[16] */
+{"jalrc",	"",		"s,-i", 	0x4be00000, 0xffe0ffff,	RD_1,		INSN2_ALIAS,	I38,	0}, /* JALRC[32] */
+{"jr",		"",		"mp",		0xd800, 	0xfc1f,	RD_1,	    INSN2_ALIAS|UBR|CTC, I38,	0}, /* JRC */
+{"jr",		"",		"s",		0x48000000, 0xffe0ffff,	RD_1,	    INSN2_ALIAS|UBR|CTC, I38,	0}, /* JALRC */
+{"jalr",	"",		"my,mp",	0xd810, 	0xfc1f,	WR_31|RD_1, INSN2_ALIAS|UBR|CTC, I38,	0}, /* JALRC[16] */
+{"jalr",	"",		"mp",		0xd810, 	0xfc1f,	WR_31|RD_1, INSN2_ALIAS|UBR|CTC, I38,	0}, /* JALRC[16] */
+{"jalr",	"",		"s",		0x4be00000, 0xffe0ffff,	RD_1,	    INSN2_ALIAS|UBR|CTC, I38,	0}, /* JALRC */
+{"jalr",	"",		"t,s",		0x48000000, 0xfc00ffff,	WR_1|RD_2,  INSN2_ALIAS|UBR|CTC, I38,	0}, /* JALRC */
+{"lui", 	"",		"t,u",		0xe0000000, 0xfc000002,	WR_1,			0,	I38,	0},
+{"li",		"[16]", 	"md,mI",	0xd000, 	0xfc00,	WR_1,			0,	I38,	0}, /* LI[16] */
+{"li",		"",		"mb,mZ",	0x1000, 	0xfc1f,	WR_1,		INSN2_ALIAS,	I38,	0}, /* MOVE[16] */
+{"li",		"[32]", 	"+t,j", 	0x00000000, 0xfc1f0000,	WR_1,		INSN2_ALIAS,	I38,	0}, /* ADDIU[32] */
+{"li",		"[neg]",	 "t,h", 	0x80008000, 0xfc1ff000,	WR_1,		INSN2_ALIAS,	I38,	0}, /* ADDIU[NEG] */
+{"li",		"",		"t,x",		0xe0000000, 0xfc000002,	WR_1,		INSN2_ALIAS,	I38,	0}, /* LUI */
+{"li",		"[48]", 	"mp,+Q",	0x6000, 	0xfc1f,	WR_1,			0,	0,	xNMS}, /* LI[48] */
+{"li",		"",		"+t,A", 	0,		(int) M_LI,	INSN_MACRO,	INSN2_MACRO,	I38,	0},
+{"ext", 	"",		"t,r,+A,+C",	0x8000f000, 0xfc00f820,	WR_1|RD_2,		0,	0,	xNMS},
+{"ext", 	"",		"t,r,+A,+C",	0,	   (int) M_EXT,	INSN_MACRO,		0,	I38,	0},
+
+/* Precedence=0 */
+{"abs", 	"",		"d,v",		0,	   (int) M_ABS,	INSN_MACRO,		0,	I38,	0},
+{"absq_s.ph",	"",		"t,s",		0x2000113f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"absq_s.qb",	"",		"t,s",		0x2000013f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"absq_s.w",	"",		"t,s",		0x2000213f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"add", 	"",		"d,v,t,-B",	0x20000110, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	xNMS},
+{"add", 	"",		"t,r,I",	0,    (int) M_ADD_I,	INSN_MACRO,		0,	0,	xNMS},
+{"addi",	"",		"t,r,I",	0,    (int) M_ADD_I,	INSN_MACRO,		0,	0,	xNMS},
+{"addiu",	"[r1.sp]",	"md,ms,mS",	0x7040, 	0xfc40,	WR_1|RD_2,		0,	I38,	0}, /* ADDIU[R1.SP] */
+{"addiu",	"[r2]", 	"md,mc,mB",	0x9000, 	0xfc08,	WR_1|RD_2,		0,	I38,	0}, /* ADDIU[R2] */
+{"addiu",	"[rs5]",	"mp,mk,mQ",	0x9008, 	0xfc08,	MOD_1,		INSN2_ALIAS,	I38,	0}, /* ADDIU[RS5] */
+{"addiu",	"[rs5]",	"mp,mQ",	0x9008, 	0xfc08,	MOD_1,			0,	I38,	0}, /* ADDIU[RS5], preceded by NOP[16] */
+{"addiu",	"[gp.b]",	"t,ma,+1",	0x440c0000, 0xfc1c0000,	WR_1|RD_2,		0,	I38,	0}, /* ADDIU[GP.B] */
+{"addiu",	"[gp.w]",	"t,ma,.",	0x40000000, 0xfc000003,	WR_1|RD_2,		0,	I38,	0}, /* ADDIU[GP.W] */
+{"addiu",	"[32]", 	"+t,r,j",	0x00000000, 0xfc000000,	WR_1|RD_2,		0,	I38,	0}, /* preceded by SIGRIE */
+{"addiu",	"[neg]",	"t,r,h",	0x80008000, 0xfc00f000,	WR_1|RD_2,		0,	I38,	0}, /* ADDIU[NEG] */
+{"addiu",	"[48]", 	"mp,mt,+R",	0x6001, 	0xfc1f,	MOD_1,			0,	0,	xNMS}, /* ADDIU[48] */
+{"addiu",	"[gp48]",	"mp,ma,+O",	0x6002, 	0xfc1f,	WR_1|RD_2,		0,	0,	xNMS}, /* ADDIU[GP48] */
+{"lapc",	"[32]", 	"t,+r", 	0x04000000, 0xfc000000, WR_1,		INSN2_ALIAS,	I38,	0}, /* ADDIUPC */
+{"lapc",	"[48]", 	"mp,+S",	0x6003, 	0xfc1f,	WR_1,		INSN2_ALIAS,	0,	xNMS}, /* ADDIUPC[48] */
+{"lapc.h",	"",		"t,+r", 	0x04000000, 0xfc000000, WR_1,		INSN2_ALIAS,	I38,	0}, /* ADDIUPC */
+{"lapc.b",	"",		"mp,+S",	0x6003, 	0xfc1f,	WR_1,		INSN2_ALIAS,	0,	xNMS}, /* ADDIUPC[48] */
+{"addiupc",	"[32]", 	"t,+s", 	0x04000000, 0xfc000000, WR_1,			0,	I38,	0},
+{"addiupc",	"[48]", 	"mp,+P",	0x6003, 	0xfc1f,	WR_1,			0,	0,	xNMS}, /* ADDIUPC[48] */
+{"addiu.b",	"",		"t,ma,+1",	0x440c0000, 0xfc1c0000,	WR_1|RD_2,	INSN2_ALIAS,	I38,	0}, /* ADDIU[GP.B] */
+{"addiu.w",	"",		"t,ma,.",	0x40000000, 0xfc000003,	WR_1|RD_2,	INSN2_ALIAS,	I38,	0}, /* ADDIU[GP.W] */
+{"addiu.b32",	"",		"mp,ma,+O",	0x6002, 	0xfc1f,	WR_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* ADDIU[GP48] */
+{"addq.ph",	"",		"d,s,t",	0x2000000d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"addqh.ph",	"",		"d,s,t",	0x2000004d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"addqh.w",	"",		"d,s,t",	0x2000008d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"addqh_r.ph",	"",		"d,s,t",	0x2000044d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"addqh_r.w",	"",		"d,s,t",	0x2000048d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"addq_s.ph",	"",		"d,s,t",	0x2000040d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"addq_s.w",	"",		"d,s,t,-B",	0x20000305, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"addsc",	"",		"d,s,t,-B",	0x20000385, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"addu",	"[16]", 	"me,mc,md",	0xb000,		0xfc01, WR_1|RD_2|RD_3,		0,	I38,	0}, /* ADDU[16] */
+{"addu",	"[4x4]",	"mu,mt,mv",	0x3c00,		0xfd08,	MOD_1|RD_3,		0,	0,	xNMS}, /* ADDU[4X4] */
+{"addu",	"[4x4]",	"mu,mv,mk",	0x3c00,		0xfd08,	MOD_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* ADDU[4X4] */
+{"addu",	"[32]", 	"d,v,t,-B",	0x20000150, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"addu",	"",		"t,r,I",	0,    (int) M_ADDU_I,	INSN_MACRO,		0,	I38,	0},
+{"addu.ph",	"",		"d,s,t",	0x2000010d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"addu.qb",	"",		"d,s,t",	0x200000cd, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"adduh.qb",	"",		"d,s,t",	0x2000014d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"adduh_r.qb",	"",		"d,s,t",	0x2000054d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"addu_s.ph",	"",		"d,s,t",	0x2000050d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"addu_s.qb",	"",		"d,s,t",	0x200004cd, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"addwc",	"",		"d,s,t,-B",	0x200003c5, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"extw",	"",		"d,s,t,+I",	0x2000001f, 0xfc00003f, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"align",	"",		"mb,-i,mj,mz",	0x1000, 	0xfc00,	WR_1|RD_3,	INSN2_ALIAS,	I38,	0}, /* MOVE[16] */
+{"align",	"",		"d,-i,s,mz",	0x20000290, 0xffe007ff, WR_1|RD_3,	INSN2_ALIAS,	I38,	0}, /* MOVE[32] */
+{"align",	"",		"d,s,t,+v",	0x2000001f, 0xfc00003f, WR_1|RD_2|RD_3,	INSN2_ALIAS,	I38,	0}, /* EXTW */
+{"and", 	"[16]", 	"md,mk,ml",	0x5008,		0xfc0f,	MOD_1|RD_3,	INSN2_ALIAS,	I38,	0}, /* AND[16] */
+{"and", 	"[16]", 	"md,ml,mk",	0x5008,		0xfc0f,	MOD_1|RD_2,	INSN2_ALIAS,	I38,	0}, /* AND[16] */
+{"and", 	"[16]", 	"md,ml",	0x5008,		0xfc0f,	MOD_1|RD_2,		0,	I38,	0}, /* AND[16] */
+{"and", 	"[32]", 	"d,v,t,-B",	0x20000250, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"and", 	"[32]", 	"t,r,I",	0,    (int) M_AND_I,	INSN_MACRO,		0,	I38,	0},
+{"andi",	"[16]", 	"md,mc,mC",	0xf000,		0xfc00,	WR_1|RD_2,		0,	I38,	0}, /* ANDI[16] */
+{"andi",	"[32]", 	"t,r,g",	0x80002000, 0xfc00f000,	WR_1|RD_2,		0,	I38,	0},
+{"andi",	"",		"t,r,+6",	0x8000f000, 0xfc00f83f,	WR_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* EXT */
+{"append",	"",		"t,s,1",	0x20000215, 0xfc0007ff,	WR_1|RD_2,		0,	0,	D32},
+{"balc",	"[16]", 	"mD",		0x3800, 	0xfc00,		WR_31,		0,	I38,	0}, /* BALC[16] */
+{"balc",	"[32]", 	"+u",		0x2a000000, 0xfe000000,		WR_31,		0,	I38,	0},
+{"bal", 	"",		"mD",		0x3800, 	0xfc00,	WR_31,	INSN2_ALIAS|UBR|CTC,	I38,	0}, /* BALC[16] */
+{"bal", 	"",		"+u",		0x2a000000, 0xfe000000,	WR_31,	INSN2_ALIAS|UBR|CTC,	I38,	0}, /* BALC */
+{"balign",	"",		"d,-m,s,+v",	0x2000001f, 0xfc00003f, WR_1|RD_3,	INSN2_ALIAS,	0,	D32}, /* EXTW */
+{"balrsc",	"",		"+t,s,-C", 	0x48008000, 0xfc00f000,	WR_1|RD_2,		0,	I38,	0},
+{"balrsc",	"",		"s",		0x4be08000, 0xffe0ffff,	RD_1|WR_31,	INSN2_ALIAS,	I38,	0}, /* BALRSC */
+{"bbeqzc",	"",		"t,1,~,-D",	0xc8040000, 0xfc1d0000,	RD_1,			0,	0,	xNMS},
+{"bbnezc",	"",		"t,1,~,-D",	0xc8140000, 0xfc1d0000,	RD_1,			0,	0,	xNMS},
+{"bc",		"[16]", 	"mD",		0x1800, 	0xfc00,	0,			0,	I38,	0}, /* BC[16] */
+{"bc",		"[32]", 	"+u",		0x28000000, 0xfe000000,	0,			0,	I38,	0},
+{"b",		"",		"mD",		0x1800, 	0xfc00,	0,	INSN2_ALIAS|UBR|CTC,	I38,	0}, /* BC[16] */
+{"b",		"",		"+u",		0x28000000, 0xfe000000,	0,	INSN2_ALIAS|UBR|CTC,	I38,	0}, /* BC */
+{"beqzc",	"[16]", 	"md,mE",	0x9800, 	0xfc00,	RD_1,			0,	I38,	0}, /* BEQZC[16] */
+{"beqzc",	"[32]", 	"t,p",		0x88000000, 0xfc1fc000,	RD_1,		INSN2_ALIAS,	I38,	0}, /* BEQC */
+{"beqzc",	"[32]", 	"s,p",		0x88000000, 0xffe0c000,	RD_1,		INSN2_ALIAS,	I38,	0}, /* BEQC */
+{"beqz",	"",		"md,mE",	0x9800, 	0xfc00,	RD_1,	INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BEQZC[16] */
+{"beqz",	"",		"t,p",		0x88000000, 0xfc1fc000,	RD_1,	INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BEQC */
+{"beqz",	"",		"s,p",		0x88000000, 0xffe0c000,	RD_1,	INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BEQC */
+{"beqc",	"[16]", 	"md,z,mE",	0x9800, 	0xfc00,	RD_1,		INSN2_ALIAS,	I38,	0}, /* BEQZC[16] */
+{"beqc",	"[16]", 	"z,md,mE",	0x9800, 	0xfc00,	RD_1,		INSN2_ALIAS,	I38,	0}, /* BEQZC[16] */
+{"beqc",	"[16]", 	"ml,mf,mF",	0xd800, 	0xfc00,	RD_1|RD_2,		0,	0,	xNMS}, /* BEQC[16], with rs3<rt3 && u[4:1]!=0 */
+{"beqc",	"[16]", 	"md,mg,mF",	0xd800, 	0xfc00,	RD_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* BEQC[16], with operands commutated */
+{"beqc",	"[32]", 	"s,t,p",	0x88000000, 0xfc00c000,	RD_1|RD_2,		0,	I38,	0},
+{"beq", 	"",		"md,z,mE",	0x9800, 	0xfc00,	RD_1,	INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BEQZC[16] */
+{"beq", 	"",		"z,md,mE",	0x9800, 	0xfc00,	RD_1,	INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BEQZC[16] */
+{"beq", 	"",		"ml,mf,mF",	0xd800, 	0xfc00,	RD_1|RD_2, INSN2_ALIAS|CBR|CTC,	0,	xNMS}, /* BEQC[16], with rs3<rt3 && u[4:1]!=0 */
+{"beq", 	"",		"md,mg,mF",	0xd800, 	0xfc00,	RD_1|RD_2, INSN2_ALIAS|CBR|CTC,	0,	xNMS}, /* BEQC[16], with operands commutated */
+{"beq", 	"",		"s,t,p",	0x88000000, 0xfc00c000,	RD_1|RD_2, INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BEQC */
+{"beq", 	"",		"s,I,p",	0,    (int) M_BEQ_I,	INSN_MACRO,		0,	I38,	0},
+{"beqic",	"",		"t,+9,~",	0xc8000000, 0xfc1c0000,	RD_1,			0,	I38,	0},
+{"blezc",	"",		"t,p",		0x88008000, 0xfc1fc000,	RD_1,		INSN2_ALIAS,	I38,	0}, /* BGEC $0, t */
+{"blez",	"",		"t,p",		0x88008000, 0xfc1fc000,	RD_1,	INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BGEC $0, t */
+{"bgezc",	"",		"s,p",		0x88008000, 0xffe0c000,	RD_1,		INSN2_ALIAS,	I38,	0}, /* BGEC s, $0 */
+{"bgez",	"",		"s,p",		0x88008000, 0xffe0c000,	RD_1,	INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BGEC s, $0 */
+{"bgec",	"",		"s,t,p",	0x88008000, 0xfc00c000,	RD_1|RD_2,		0,	I38,	0},
+{"bge", 	"",		"s,t,p",	0x88008000, 0xfc00c000,	RD_1|RD_2, INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BGEC */
+{"bge", 	"",		"s,I,p",	0,    (int) M_BGE_I,	INSN_MACRO,		0,	I38,	0},
+{"bgt", 	"",		"s,t,p",	0,    (int) M_BGT,	INSN_MACRO,		0,	I38,	0},
+{"bgt", 	"",		"s,I,p",	0,    (int) M_BGT_I,	INSN_MACRO,		0,	I38,	0},
+{"bgtu",	"",		"s,t,p",	0,    (int) M_BGTU,	INSN_MACRO,		0,	I38,	0},
+{"bgtu",	"",		"s,I,p",	0,    (int) M_BGTU_I,	INSN_MACRO,		0,	I38,	0},
+{"ble", 	"",		"s,t,p",	0,    (int) M_BLE,	INSN_MACRO,		0,	I38,	0},
+{"ble", 	"",		"s,I,p",	0,    (int) M_BLE_I,	INSN_MACRO,		0,	I38,	0},
+{"bleu",	"",		"s,t,p",	0,    (int) M_BLEU,	INSN_MACRO,		0,	I38,	0},
+{"bleu",	"",		"s,I,p",	0,    (int) M_BLEU_I,	INSN_MACRO,		0,	I38,	0},
+{"bgezal",	"",		"s,p",		0,    (int) M_BGEZAL,	INSN_MACRO,		0,	I38,	0},
+{"bgeic",	"",		"t,+9,~",	0xc8080000, 0xfc1c0000,	RD_1,			0,	I38,	0},
+{"bgeuc",	"",		"s,t,p",	0x8800c000, 0xfc00c000,	RD_1|RD_2,		0,	I38,	0},
+{"bgeu",	"",		"s,t,p",	0x8800c000, 0xfc00c000,	RD_1|RD_2, INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BGEUC */
+{"bgeu",	"",		"s,I,p",	0,    (int) M_BGEU_I,	INSN_MACRO,		0,	I38,	0},
+{"bgeiuc",	"",		"t,+9,~",	0xc80c0000, 0xfc1c0000,	RD_1,			0,	I38,	0},
+{"bitrev",	"",		"t,r",		0x2000313f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32}, /* ROTX t,s,7,8,1 */
+{"bitrevb",	"",		"t,r",		0x8000d247, 0xfc00ffff,	WR_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* ROTX t,s,7,8,1 */
+{"bitrevh",	"",		"t,r",		0x8000d40f, 0xfc00ffff,	WR_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* ROTX t,s,15,16 */
+{"bitrevw",	"",		"t,r",		0x8000d01f, 0xfc00ffff,	WR_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* ROTX t,s,31,0*/
+{"bitswap",	"",		"t,r",		0x8000d247, 0xfc00ffff,	WR_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* ROTX t,s,7,8,1*/
+{"bgtzc",	"",		"t,p",		0xa8008000, 0xfc1fc000,	RD_1,		INSN2_ALIAS,	I38,	0}, /* BLTC $0, t */
+{"bgtz",	"",		"t,p",		0xa8008000, 0xfc1fc000,	RD_1, 	INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BLTC $0, t */
+{"bltzc",	"",		"s,p",		0xa8008000, 0xffe0c000,	RD_1,		INSN2_ALIAS,	I38,	0}, /* BLTC s, $0 */
+{"bltz",	"",		"s,p",		0xa8008000, 0xffe0c000,	RD_1,	INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BLTC s, $0 */
+{"bltc",	"",		"s,t,p",	0xa8008000, 0xfc00c000,	RD_1|RD_2,		0,	I38,	0},
+{"blt", 	"",		"s,t,p",	0xa8008000, 0xfc00c000,	RD_1|RD_2, INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BLTC */
+{"blt", 	"",		"s,I,p",	0,    (int) M_BLT_I,	INSN_MACRO,		0,	I38,	0},
+{"bltzal",	"",		"s,p",		0,    (int) M_BLTZAL,	INSN_MACRO,		0,	I38,	0},
+{"bltic",	"",		"t,+9,~",	0xc8180000, 0xfc1c0000,		RD_1,		0,	I38,	0},
+{"bltuc",	"",		"s,t,p",	0xa800c000, 0xfc00c000,	RD_1|RD_2,		0,	I38,	0},
+{"bltu",	"",		"s,t,p",	0xa800c000, 0xfc00c000,	RD_1|RD_2, INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BLTUC */
+{"bltu",	"",		"s,I,p",	0,    (int) M_BLTU_I,	INSN_MACRO,		0,	I38,	0},
+{"bltiuc",	"",		"t,+9,~",	0xc81c0000, 0xfc1c0000, RD_1,			0,	I38,	0},
+{"bnezc",	"[16]", 	"md,mE",	0xb800, 	0xfc00, RD_1,			0,	I38,	0}, /* BNEZC[16] */
+{"bnezc",	"[32]", 	"t,p",		0xa8000000, 0xfc1fc000, RD_1,		INSN2_ALIAS,	I38,	0}, /* BNEC */
+{"bnezc",	"[32]", 	"s,p",		0xa8000000, 0xffe0c000, RD_1,		INSN2_ALIAS,	I38,	0}, /* BNEC */
+{"bnez",	"",		"md,mE",	0xb800, 	0xfc00, RD_1,	INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BNEZC[16] */
+{"bnez",	"",		"t,p",		0xa8000000, 0xfc1fc000, RD_1,	INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BNEC */
+{"bnez",	"",		"s,p",		0xa8000000, 0xffe0c000,	RD_1,		INSN2_ALIAS,	I38,	0}, /* BNEC */
+{"bnec",	"[16]", 	"md,z,mE",	0xb800, 	0xfc00,	RD_1,		INSN2_ALIAS,	I38,	0}, /* BNEZC[16] */
+{"bnec",	"[16]", 	"z,md,mE",	0xb800, 	0xfc00,	RD_2,		INSN2_ALIAS,	I38,	0}, /* BNEZC[16] */
+{"bnec",	"[16]", 	"ml,mh,mF",	0xd800, 	0xfc00,	RD_1|RD_2,		0,	0,	xNMS}, /* BNEC[16], with rs3>=rt3 && u[4:1]!=0 */
+{"bnec",	"[16]", 	"md,mi,mF",	0xd800, 	0xfc00,	RD_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* BNEC[16], with operands commutated */
+{"bnec",	"[32]", 	"s,t,p",	0xa8000000, 0xfc00c000,	RD_1|RD_2,		0,	I38,	0},
+{"bne", 	"",		"md,z,mE",	0xb800, 	0xfc00,	RD_1, INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BNEZC[16] */
+{"bne", 	"",		"z,md,mE",	0xb800, 	0xfc00,	RD_2, INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BNEZC[16] */
+{"bne", 	"",		"ml,mh,mF",	0xd800, 	0xfc00,	RD_1|RD_2, INSN2_ALIAS|CBR|CTC,	0,	xNMS}, /* BNEC[16], with rs3>=rt3 && u[4:1]!=0 */
+{"bne", 	"",		"md,mi,mF",	0xd800, 	0xfc00,	RD_1|RD_2, INSN2_ALIAS|CBR|CTC,	0,	xNMS}, /* BNEC[16], with operands commutated */
+{"bne", 	"",		"s,t,p",	0xa8000000, 0xfc00c000,	RD_1|RD_2, INSN2_ALIAS|CBR|CTC,	I38,	0}, /* BNEC */
+{"bne", 	"",		"s,I,p",	0,    (int) M_BNE_I,	INSN_MACRO,		0,	I38,	0},
+{"bneic",	"",		"t,+9,~",	0xc8100000, 0xfc1c0000,	RD_1,			0,	I38,	0},
+{"bposge32c",	"",		"p,-I",		0x88044000, 0xfc1fc000,	0,			0,	0,	D32},
+{"bposge32",	"",		"p",		0x88044000, 0xffffc000,	0,	INSN2_ALIAS|CBR|CTC,	0,	D32}, /* BPOSGE32C */
+{"brsc",	"",		"s,-C",		0x48008000, 0xffe0f000,	RD_1,			0,	I38,	0},
+{"byterevh",	"",		"t,r",		0x8000d608, 0xfc00ffff,	WR_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* ROTX t,s,8,24 */
+{"byterevw",	"",		"t,r",		0x8000d218, 0xfc00ffff,	WR_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* ROTX t,s,24,8 */
+{"cache",	"",		"k,+j(b)",	0xa4003900, 0xfc007f00,	RD_3,			0,	I38,	0},
+{"cache",	"",		"k,A(c)",	0,    (int) M_CACHE_AC,	INSN_MACRO,		0,	I38,	0},
+{"cachee",	"",		"k,+j(b)",	0xa4003a00, 0xfc007f00,	RD_3,			0,	0,	EVA},
+{"cachee",	"",		"k,A(c)",	0,    (int) M_CACHEE_AC, INSN_MACRO,		0,	0,	EVA},
+{"cfc1",	"",		"t,G",		0xa000103b, 0xfc00ffff,	WR_1|RD_2,	INSN2_ALIAS,	I38,	0},
+{"cfc1",	"",		"t,S",		0xa000103b, 0xfc00ffff,	WR_1|RD_2,		0,	I38,	0},
+{"cftc1",	"",		"t,G",		0x20001e30, 0xfc00ffff,	WR_1|RD_2,	INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"cftc1",	"",		"t,S",		0x20001e30, 0xfc00ffff,	WR_1|RD_2,	INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"cftc2",	"",		"t,G",		0x20002e30, 0xfc00ffff,	WR_1|RD_2,	INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"clo", 	"",		"t,s",		0x20004b3f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	xNMS},
+{"clz", 	"",		"t,s",		0x20005b3f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	xNMS},
+{"cmp.eq.ph",	"",		"s,t,-N",	0x20000005, 0xfc0003ff,	WR_1|RD_2,		0,	0,	D32},
+{"cmp.le.ph",	"",		"s,t,-N",	0x20000085, 0xfc0003ff,	WR_1|RD_2,		0,	0,	D32},
+{"cmp.lt.ph",	"",		"s,t,-N",	0x20000045, 0xfc0003ff,	WR_1|RD_2,		0,	0,	D32},
+{"cmpgdu.eq.qb", "",		"d,s,t,-B",	0x20000185, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"cmpgdu.le.qb", "",		"d,s,t,-B",	0x20000205, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"cmpgdu.lt.qb", "",		"d,s,t,-B",	0x200001c5, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"cmpgu.eq.qb", "",		"d,s,t,-B",	0x200000c5, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"cmpgu.le.qb", "",		"d,s,t,-B",	0x20000145, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"cmpgu.lt.qb", "",		"d,s,t,-B",	0x20000105, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"cmpu.eq.qb",	"",		"s,t,-N",	0x20000245, 0xfc0003ff,	WR_1|RD_2,		0,	0,	D32},
+{"cmpu.le.qb",	"",		"s,t,-N",	0x200002c5, 0xfc0003ff,	WR_1|RD_2,		0,	0,	D32},
+{"cmpu.lt.qb",	"",		"s,t,-N",	0x20000285, 0xfc0003ff,	WR_1|RD_2,		0,	0,	D32},
+{"cop2_1",	"",		"C",		0x20000002, 0xfc000007,		0,		0,	I38,	0},
+{"crc32b",	"",		"t,r,-E",	0x200003e8, 0xfc001fff,	WR_1|RD_2,		0,	0,	CRC},
+{"crc32h",	"",		"t,r,-E",	0x200007e8, 0xfc001fff,	WR_1|RD_2,		0,	0,	CRC},
+{"crc32w",	"",		"t,r,-E",	0x20000be8, 0xfc001fff,	WR_1|RD_2,		0,	0,	CRC},
+{"crc32cb",	"",		"t,r,-E",	0x200013e8, 0xfc001fff,	WR_1|RD_2,		0,	0,	CRC},
+{"crc32ch",	"",		"t,r,-E",	0x200017e8, 0xfc001fff,	WR_1|RD_2,		0,	0,	CRC},
+{"crc32cw",	"",		"t,r,-E",	0x20001be8, 0xfc001fff,	WR_1|RD_2,		0,	0,	CRC},
+{"ctc1",	"",		"t,G",		0xa000183b, 0xfc00ffff,	RD_1|WR_2,	INSN2_ALIAS,	I38,	0},
+{"ctc1",	"",		"t,S",		0xa000183b, 0xfc00ffff,	RD_1|WR_2,		0,	I38,	0},
+{"cttc1",	"",		"t,G",		0x20001e70, 0xfc00ffff,	RD_1|WR_2,	INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"cttc1",	"",		"t,S",		0x20001e70, 0xfc00ffff,	RD_1|WR_2,	INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"cttc2",	"",		"t,G",		0x20002e70, 0xfc00ffff,	RD_1|WR_2,	INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"dabs",	"",		"d,v",		0,	  (int) M_DABS,	INSN_MACRO,		0,	I38,	0},
+{"daddiu",	"[neg]",	"t,r,h",	0x80008000, 0xfc00f000,	WR_1|RD_2,		0,	I38,	0}, /* DADDIU[NEG] */
+{"deret",	"",		"-F",		0x2000e37f, 0xfc00ffff,		0,		0,	I38,	0},
+{"di",		"",		"",		0x2000477f, 0xffffffff,	0,		INSN2_ALIAS,	I38,	0},
+{"di",		"",		"w,-A",		0x2000477f, 0xfc00ffff,	WR_1,			0,	I38,	0},
+{"div", 	"",		"d,v,t,-B",	0x20000118, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"div", 	"",		"d,v,I",	0,    (int) M_DIV_I,	INSN_MACRO,		0,	I38,	0},
+{"divu",	"",		"d,v,t,-B",	0x20000198, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"divu",	"",		"d,v,I",	0,    (int) M_DIVU_I,	INSN_MACRO,		0,	I38,	0},
+{"dmt", 	"",		"",		0x20010ab0, 0xffffffff,	0,		INSN2_ALIAS,	0,	MT32},
+{"dmt", 	"",		"t",		0x20010ab0, 0xfc1fffff,	WR_1,			0,	0,	MT32},
+{"dpa.w.ph",	"",		"7,s,t",	0x200000bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dpaqx_s.w.ph", "",		"7,s,t",	0x200022bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dpaqx_sa.w.ph","",		"7,s,t",	0x200032bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dpaq_s.w.ph", "",		"7,s,t",	0x200002bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dpaq_sa.l.w", "",		"7,s,t",	0x200012bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dpau.h.qbl",	"",		"7,s,t",	0x200020bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dpau.h.qbr",	"",		"7,s,t",	0x200030bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dpax.w.ph",	"",		"7,s,t",	0x200010bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dps.w.ph",	"",		"7,s,t",	0x200004bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dpsqx_s.w.ph", "",		"7,s,t",	0x200026bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dpsqx_sa.w.ph", "",		"7,s,t",	0x200036bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dpsq_s.w.ph", "",		"7,s,t",	0x200006bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dpsq_sa.l.w", "",		"7,s,t",	0x200016bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dpsu.h.qbl",	"",		"7,s,t",	0x200024bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dpsu.h.qbr",	"",		"7,s,t",	0x200034bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dpsx.w.ph",	"",		"7,s,t",	0x200014bf, 0xfc003fff,	MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"dvpe",	"",		"",		0x20000ab0, 0xffffffff,	0,		INSN2_ALIAS,	0,	MT32}, /* DVPE */
+{"dvpe",	"",		"t",		0x20000ab0, 0xfc1fffff,	WR_1,			0,	0,	MT32},
+{"ehb", 	"",		"-G",		0x8000c003, 0xffe0f1ff,	0,			0,	I38,	0},
+{"ei",		"",		"",		0x2000577f, 0xffffffff,	0,		INSN2_ALIAS,	I38,	0},
+{"ei",		"",		"t,-A",		0x2000577f, 0xfc00ffff,	WR_1,			0,	I38,	0},
+{"emt", 	"",		"",		0x20010eb0, 0xffffffff,	0,		INSN2_ALIAS,	0,	MT32},
+{"emt", 	"",		"t",		0x20010eb0, 0xfc1fffff, WR_1,			0,	0,	MT32},
+{"eret",	"",		"-H",		0x2000f37f, 0xfc01ffff,	0,			0,	I38,	0},
+{"eretnc",	"",		"-H",		0x2001f37f, 0xfc01ffff,	0,			0,	I38,	0},
+{"evpe",	"",		"",		0x20000eb0, 0xffffffff,	0,		INSN2_ALIAS,	0,	MT32}, /* EVPE */
+{"evpe",	"",		"t",		0x20000eb0, 0xfc1fffff,	WR_1,			0,	0,	MT32},
+{"evp", 	"",		"-A",		0x20000790, 0xffe0ffff,	0,		INSN2_ALIAS,	I38,	0}, /* EVP */
+{"evp", 	"",		"t,-A",		0x20000790, 0xfc00ffff,	WR_1,			0,	I38,	0},
+{"extp",	"",		"t,7,2",	0x2000267f, 0xfc003fff,	WR_1|RD_2,		0,	0,	D32},
+{"extpdp",	"",		"t,7,2",	0x2000367f, 0xfc003fff,	WR_1|RD_2,		0,	0,	D32},
+{"extpdpv",	"",		"t,7,s",	0x200038bf, 0xfc003fff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"extpv",	"",		"t,7,s",	0x200028bf, 0xfc003fff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"extr.w",	"",		"t,7,2",	0x20000e7f, 0xfc003fff,	WR_1|RD_2,		0,	0,	D32},
+{"extrv.w",	"",		"t,7,s",	0x20000ebf, 0xfc003fff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"extrv_r.w",	"",		"t,7,s",	0x20001ebf, 0xfc003fff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"extrv_rs.w",	"",		"t,7,s",	0x20002ebf, 0xfc003fff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"extrv_s.h",	"",		"t,7,s",	0x20003ebf, 0xfc003fff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"extr_r.w",	"",		"t,7,2",	0x20001e7f, 0xfc003fff,	WR_1|RD_2,		0,	0,	D32},
+{"extr_rs.w",	"",		"t,7,2",	0x20002e7f, 0xfc003fff,	WR_1|RD_2,		0,	0,	D32},
+{"extr_s.h",	"",		"t,7,2",	0x20003e7f, 0xfc003fff,	WR_1|RD_2,		0,	0,	D32},
+{"fork",	"",		"d,s,t,-B",	0x20000228, 0xfc0003ff,	WR_1|RD_2|RD_3,		0,	0,	MT32},
+{"ginvi",	"",		"s,-I",		0x20001f7f, 0xfc00ffff, RD_1,			0,	0,	GINV},
+{"ginvt",	"",		"s,+;,-J", 	0x20000f7f, 0xfc00ffff, RD_1,			0,	0,	GINV},
+{"ins", 	"",		"t,r,+A,+B",	0x8000e000, 0xfc00f820,	WR_1|RD_2,		0,	0,	xNMS},
+{"ins", 	"",		"t,r,+A,+B",	0,    (int) M_INS,	INSN_MACRO,		0,	I38,	0},
+{"insv",	"",		"t,s",		0x2000413f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"j",		"",		"mp",		0xd800, 	0xfc1f,	RD_1,	INSN2_ALIAS|UBR|CTC,	I38,	0},
+{"j",		"",		"+u",		0x28000000, 0xfe000000,	0, 	INSN2_ALIAS|UBR|CTC,	I38,	0}, /* BC */
+{"j",		"",		"s",		0x48000000, 0xffe0ffff,	RD_1,	INSN2_ALIAS|UBR|CTC,	I38,	0}, /* JALRC */
+{"jrc.hb",	"",		"s",		0x48001000, 0xffe0ffff,	RD_1,		INSN2_ALIAS,	I38,	0}, /* JALRC.HB */
+{"jr.hb",	"",		"s",		0x48001000, 0xffe0ffff,	RD_1,	INSN2_ALIAS|UBR|CTC,	I38,	0}, /* JALRC.HB */
+{"jalrc.hb",	"",		"s",		0x4be01000, 0xffe0ffff,	RD_1,		INSN2_ALIAS,	I38,	0}, /* JALRC.HB */
+{"jalrc.hb",	"",		"t,s,-C",	0x48001000, 0xfc00f000,	WR_1|RD_2,		0,	I38,	0},
+{"jalr.hb",	"",		"s",		0x4be01000, 0xffe0ffff,	RD_1,	INSN2_ALIAS|UBR|CTC,	I38,	0}, /* JALRC.HB */
+{"jalr.hb",	"",		"t,s",		0x48001000, 0xfc00ffff,	WR_1|RD_2, INSN2_ALIAS|UBR|CTC,	I38,	0}, /* JALRC.HB */
+/* SVR4 PIC code requires special handling for jal, so it must be a macro.  */
+{"jal", 	"",		"my,mp",	0xd810, 	0xfc1f,	WR_31|RD_1, INSN2_ALIAS|UBR|CTC, I38,	0}, /* JALRC[16] */
+{"jal", 	"",		"mp",		0xd810, 	0xfc1f,	WR_31|RD_1, INSN2_ALIAS|UBR|CTC, I38,	0}, /* JALRC[16] */
+{"jal", 	"",		"s",		0x4be00000, 0xffe0ffff,	RD_1,	INSN2_ALIAS|UBR|CTC,	I38,	0}, /* JALRC */
+{"jal", 	"",		"t,s",		0x48000000, 0xfc00ffff,	WR_1|RD_2, INSN2_ALIAS|UBR|CTC, I38,	0}, /* JALRC */
+{"jal", 	"",		"A",		0,    (int) M_JAL_A,	INSN_MACRO,		0,	I38,	0},
+{"jal", 	"",		"+u",		0x2a000000, 0xfe000000,	WR_31,	INSN2_ALIAS|UBR|CTC,	I38,	0}, /* BALC */
+{"lb",		"[16]", 	"md,mL(ml)",	0x5c00, 	0xfc0c,	WR_1|RD_3,		0,	I38,	0}, /* LB[16] */
+{"lb",		"[gp]", 	"t,+1(ma)",	0x44000000, 0xfc1c0000,	WR_1|RD_3,		0,	I38,	0}, /* LB[GP] */
+{"lb",		"[u12]",	"t,o(b)",	0x84000000, 0xfc00f000,	WR_1|RD_3,		0,	I38,	0}, /* LB[U12] */
+{"lb",		"[s9]", 	"t,+j(b)",	0xa4000000, 0xfc007f00,	WR_1|RD_3,		0,	I38,	0}, /* LB[S9] */
+{"lb",		"",		"t,A(c)",	0,	(int) M_LB_AC,	INSN_MACRO,		0,	I38,	0},
+{"lb",		"",		"t,A(b)",	0,	(int) M_LBX_AB,	INSN_MACRO,		0,	I38,	0},
+{"lbe", 	"", 		"t,+j(b)",	0xa4000200, 0xfc007f00,	WR_1|RD_3,		0,	0,	EVA},
+{"lbe", 	"", 		"t,A(c)",	0,	(int) M_LBE_AC,	INSN_MACRO,		0,	0,	EVA},
+{"lbu", 	"[16]", 	"md,mL(ml)",	0x5c08, 	0xfc0c,	WR_1|RD_3,		0,	I38,	0}, /* LBU[16] */
+{"lbu", 	"[gp]", 	"t,+1(ma)",	0x44080000, 0xfc1c0000,	WR_1|RD_3,		0,	I38,	0}, /* LBU[GP] */
+{"lbu", 	"[u12]",	"t,o(b)",	0x84002000, 0xfc00f000,	WR_1|RD_3,		0,	I38,	0}, /* LBU[U12] */
+{"lbu", 	"[s9]", 	"t,+j(b)",	0xa4001000, 0xfc007f00,	WR_1|RD_3,		0,	I38,	0}, /* LBU[S9] */
+{"lbu", 	"",		"t,A(c)",	0,	(int) M_LBU_AC,	INSN_MACRO,		0,	I38,	0},
+{"lbu", 	"",		"t,A(b)",	0,     (int) M_LBUX_AB,	INSN_MACRO,		0,	I38,	0},
+{"lbue",	"",		"t,+j(b)",	0xa4001200, 0xfc007f00,	WR_1|RD_3,		0,	0,	EVA},
+{"lbue",	"",		"t,A(c)",	0,     (int) M_LBUE_AC,	INSN_MACRO,		0,	0,	EVA},
+{"lbux",	"",		"d,s(t)",	0x20000107, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"lbx", 	"",		"d,s(t)",	0x20000007, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"ld",		"",		"t,A(c)",	0,	(int) M_LD_AC,	INSN_MACRO,		0,	I38,	0},
+{"ld",		"",		"t,A(b)",	0,	(int) M_LDX_AB,	INSN_MACRO,		0,	I38,	0},
+{"lh",		"[16]", 	"md,mH(ml)",	0x7c00, 	0xfc09,	WR_1|RD_3,		0,	I38,	0}, /* LH[16] */
+{"lh",		"[gp]", 	"t,+3(ma)",	0x44100000, 0xfc1c0001,	WR_1|RD_3,		0,	I38,	0}, /* LH[GP] */
+{"lh",		"[u12]",	 "t,o(b)",	0x84004000, 0xfc00f000,	WR_1|RD_3,		0,	I38,	0}, /* LH[U12] */
+{"lh",		"[s9]", 	"t,+j(b)",	0xa4002000, 0xfc007f00,	WR_1|RD_3,		0,	I38,	0}, /* LH[S9] */
+{"lh",		"",		"t,A(c)",	0,	(int) M_LH_AC,	INSN_MACRO,		0,	I38,	0},
+{"lh",		"",		"t,A(b)",	0,	(int) M_LHX_AB,	INSN_MACRO,		0,	I38,	0},
+{"lhe", 	"",		"t,+j(b)",	0xa4002200, 0xfc007f00,	WR_1|RD_3,		0,	0,	EVA},
+{"lhe", 	"",		"t,A(c)",	0,	(int) M_LHE_AC,	INSN_MACRO,		0,	0,	EVA},
+{"lhu", 	"[16]", 	"md,mH(ml)",	0x7c08,		0xfc09,	WR_1|RD_3,		0,	I38,	0}, /* LHU[16] */
+{"lhu", 	"[gp]", 	"t,+3(ma)",	0x44100001, 0xfc1c0001,	WR_1|RD_3,		0,	I38,	0}, /* LHU[GP] */
+{"lhu", 	"[u12]",	 "t,o(b)",	0x84006000, 0xfc00f000,	WR_1|RD_3,		0,	I38,	0}, /* LHU[U12] */
+{"lhu", 	"[s9]", 	"t,+j(b)",	0xa4003000, 0xfc007f00,	WR_1|RD_3,		0,	I38,	0}, /* LHU[S9] */
+{"lhu", 	"",		"t,A(c)",	0,	(int) M_LHU_AC,	INSN_MACRO,		0,	I38,	0},
+{"lhu", 	"",		"t,A(b)",	0,     (int) M_LHUX_AB,	INSN_MACRO,		0,	I38,	0},
+{"lhue",	"",		"t,+j(b)",	0xa4003200, 0xfc007f00,	WR_1|RD_3,		0,	0,	EVA},
+{"lhue",	"",		"t,A(c)",	0,     (int) M_LHUE_AC,	INSN_MACRO,		0,	0,	EVA},
+{"lhux",	"",		"d,s(t)",	0x20000307, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"lhuxs",	"",		"d,s(t)",	0x20000347, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"lhx", 	"",		"d,s(t)",	0x20000207, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"lhxs",	"",		"d,s(t)",	0x20000247, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"li.d",	"",		"t,F",		0,	(int) M_LI_D,	INSN_MACRO,		0,	I38,	0},
+{"li.s",	"",		"t,f",		0,	(int) M_LI_S,	INSN_MACRO,		0,	I38,	0},
+{"ll",		"",		"t,+p(b)",	0xa4005100, 0xfc007f03,	WR_1|RD_3,		0,	I38,	0},
+{"ll",		"",		"t,A(c)",	0,	(int) M_LL_AC,	INSN_MACRO,		0,	I38,	0},
+{"lle", 	"",		"t,+p(b)",	0xa4005200, 0xfc007f03,	WR_1|RD_3,		0,	0,	EVA},
+{"lle", 	"",		"t,A(c)",	0,	(int) M_LLE_AC,	INSN_MACRO,		0,	0,	EVA},
+{"llwp",	"",		"t,e,(b),-K",	0xa4005101, 0xfc007f03, WR_1|WR_2|RD_3,		0,	0,	xNMS},
+{"llwp",	"",		"t,e,A(c)",	0,	(int) M_LLWP_AC, INSN_MACRO,		0,	0,	xNMS},
+{"llwpe",	"",		"t,e,(b),-K",	0xa4005201, 0xfc007f03, WR_1|WR_2|RD_3,		0,	0,	EVA},
+{"llwpe",	"",		"t,e,A(c)",	0,	(int) M_LLWP_AC, INSN_MACRO,		0,	0,	EVA},
+{"lsa", 	"",		"d,v,t,+w,-L",	0x2000000f, 0xfc00003f, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"lw",		"[16]", 	"md,mJ(ml)",	0x1400, 	0xfc00,	WR_1|RD_3,		0,	I38,	0}, /* LW[16] */
+{"lw",		"[4x4]",	"mu,mN(mv)",	0x7400, 	0xfc00,	WR_1|RD_3,		0,	0,	xNMS}, /* LW[4X4] */
+{"lw",		"[sp]", 	"mp,mR(ms)",	0x3400, 	0xfc00,	WR_1|RD_3,		0,	I38,	0}, /* LW[SP] */
+{"lw",		"[gp16]",	"md,mO(ma)",	0x5400, 	0xfc00,	WR_1|RD_3,		0,	I38,	0}, /* LW[GP16] */
+{"lw",		"[gp]", 	"t,.(ma)",	0x40000002, 0xfc000003,	WR_1|RD_3,		0,	I38,	0}, /* LW[GP] */
+{"lw",		"[gp16]",	"md,mA(ma)",	0x5400, 	0xfc00,	WR_1|RD_3,		0,	I38,	0}, /* LW[GP16] */
+{"lw",		"[u12]",	"t,o(b)",	0x84008000, 0xfc00f000,	WR_1|RD_3,		0,	I38,	0}, /* LW[U12] */
+{"lw",		"[s9]", 	"t,+j(b)",	0xa4004000, 0xfc007f00,	WR_1|RD_3,		0,	I38,	0}, /* LW[S9] */
+{"lw",		"",		"t,A(c)",	0,	(int) M_LW_AC,	INSN_MACRO,		0,	I38,	0},
+{"lw",		"",		"t,A(b)",	0,	(int) M_LWX_AB,	INSN_MACRO,		0,	I38,	0},
+{"lwe", 	"",		"t,+j(b)",	0xa4004200, 0xfc007f00,	WR_1|RD_3,		0,	0,	EVA},
+{"lwe", 	"",		"t,A(c)",	0,	(int) M_LWE_AC,	INSN_MACRO,		0,	0,	EVA},
+{"lwm", 	"",		"t,+j(b),|",	0xa4000400, 0xfc000f00,	WR_1|RD_3,		0,	0,	xNMS}, /* LWM */
+{"lwpc",	"[48]", 	"mp,+S",	0x600b, 	0xfc1f,	WR_1,			0,	0,	xNMS}, /* LWPC[48] */
+{"lwx", 	"",		"d,s(t)",	0x20000407, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"lwxs",	"[16]", 	"me,ml(md)",	0x5001, 	0xfc01, WR_1|RD_2|RD_3,		0,	I38,	0}, /* LWXS[16] */
+{"lwxs",	"[32]", 	"d,s(t)",	0x20000447, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"madd",	"[dsp]",	"7,s,t",	0x20000abf, 0xfc003fff, MOD_1|RD_2|RD_3,	0,	0,	D32}, /* MADD[DSP] */
+{"maddu",	"[dsp]",	"7,s,t",	0x20001abf, 0xfc003fff, MOD_1|RD_2|RD_3,	0,	0,	D32}, /* MADDU[DSP] */
+{"maq_s.w.phl", "",		"7,s,t",	0x20001a7f, 0xfc003fff, MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"maq_s.w.phr", "",		"7,s,t",	0x20000a7f, 0xfc003fff, MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"maq_sa.w.phl", "",		"7,s,t",	0x20003a7f, 0xfc003fff, MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"maq_sa.w.phr", "",		"7,s,t",	0x20002a7f, 0xfc003fff, MOD_1|RD_2|RD_3,	0,	0,	D32},
+{"mfc0",	"",		"t,O",		0x20000030, 0xfc0007ff,	WR_1,		INSN2_ALIAS,	I38,	0}, /* MFC0 with named register */
+{"mfc0",	"",		"t,P,J",	0x20000030, 0xfc0007ff,	WR_1,		INSN2_ALIAS,	I38,	0}, /* MFC0 with named register & select */
+{"mfc0",	"",		"t,G,J,-B",	0x20000030, 0xfc0003ff,	WR_1,			0,	I38,	0},
+{"mfhc0",	"",		"t,O",		0x20000038, 0xfc0007ff,	WR_1,		INSN2_ALIAS,	I38,	0}, /* MFHC0 with named register */
+{"mfhc0",	"",		"t,P,J",	0x20000038, 0xfc0007ff,	WR_1,		INSN2_ALIAS,	I38,	0}, /* MFHC0 with named register & select*/
+{"mfhc0",	"",		"t,G,J,-B",	0x20000038, 0xfc0003ff,	WR_1,			0,	I38,	0},
+{"mfhi",	"[dsp]",	"t,7,-A",	0x2000007f, 0xfc003fff,	WR_1|RD_2,		0,	0,	D32}, /* MFHI[DSP] */
+{"mflo",	"[dsp]",	"t,7,-A",	0x2000107f, 0xfc003fff,	WR_1|RD_2,		0,	0,	D32}, /* MFLO[DSP] */
+{"mftc0",	"",		"t,O",		0x20000230, 0xfc0007ff,	WR_1,		INSN2_ALIAS,	0,	MT32}, /* MFTR with named register */
+{"mftc0",	"",		"t,P,J",	0x20000230, 0xfc0007ff,	WR_1,		INSN2_ALIAS,	0,	MT32}, /* MFTR with named register & select */
+{"mfthc0",	"",		"t,O",		0x20000238, 0xfc0007ff,	WR_1,		INSN2_ALIAS,	0,	MT32}, /* MFTR with named register */
+{"mfthc0",	"",		"t,P,J",	0x20000238, 0xfc0007ff,	WR_1,		INSN2_ALIAS,	0,	MT32}, /* MFTR with named register & select*/
+{"mftc1",	"",		"t,S",		0x20001630, 0xfc00ffff,	WR_1|RD_2|FP_S,	INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"mftc1",	"",		"t,G",		0x20001630, 0xfc00ffff,	WR_1|RD_2|FP_S,	INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"mftc2",	"",		"t,G",		0x20002630, 0xfc00ffff,	WR_1,		INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"mftdsp",	"",		"t",		0x20100e30, 0xfc1fffff,	WR_1,		INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"mftgpr",	"",		"t,s",		0x20000630, 0xfc00ffff,	WR_1|RD_2,	INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"mfthc1",	"",		"t,S",		0x20001638, 0xfc00ffff,	WR_1|RD_2|FP_D,	INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"mfthc1",	"",		"t,G",		0x20001638, 0xfc00ffff,	WR_1|RD_2|FP_D,	INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"mfthc2",	"",		"t,G",		0x20002638, 0xfc00ffff,	WR_1,		INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"mfthi",	"",		"t",		0x20010e30, 0xfc1fffff,	WR_1|RD_a,	INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"mfthi",	"",		"t,*",		0x20010e30, 0xfc13ffff,	WR_1|RD_a,	INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"mftlo",	"",		"t",		0x20000e30, 0xfc1fffff,	WR_1|RD_a,	INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"mftlo",	"",		"t,*",		0x20000e30, 0xfc13ffff,	WR_1|RD_a,	INSN2_ALIAS,	0,	MT32}, /* MFTR */
+{"mftr",	"",		"t,s,!,H,$",	0x20000230, 0xfc0003f7,	WR_1,			0,	0,	MT32},
+{"mod", 	"",		"d,v,t,-B",	0x20000158, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"mod", 	"",		"d,v,I",	0,	(int) M_MOD_I,	INSN_MACRO,		0,	I38,	0},
+{"modsub",	"",		"d,s,t,-B",	0x20000295, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"modu",	"",		"d,v,t,-B",	0x200001d8, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"modu",	"",		"d,v,I",	0,	(int) M_MODU_I,	INSN_MACRO,		0,	I38,	0},
+{"move.balc",	"",		"+7,+5,+r",	0x08000000, 0xfc000000,	WR_1|RD_2,		0,	0,	xNMS},
+{"move.bal",	"",		"+7,+5,+r",	0x08000000, 0xfc000000,	WR_1|RD_2,	INSN2_ALIAS|UBR|CTC, 0,	xNMS}, /* MOVE.BALC */
+{"movep",	"",		"mq,mx,mw",	0xbc00, 	0xfc00,	WR_1|RD_2|RD_3,		0,	0,	xNMS}, /* MOVEP */
+{"movep",	"",		"mr,mw,mx",	0xbc00, 	0xfc00,	WR_1|RD_2|RD_3,	INSN2_ALIAS,	0,	xNMS}, /* MOVEP */
+{"movep",	"[rev]",	"mv,mu,mq",	0xfc00, 	0xfc00,	WR_1|WR_2|RD_3,		0,	0,	xNMS}, /* MOVEP[REV] */
+{"movep",	"[rev]",	"mu,mv,mr",	0xfc00, 	0xfc00,	WR_1|WR_2|RD_3,	INSN2_ALIAS,	0,	xNMS}, /* MOVEP[REV] */
+{"movn",	"",		"d,v,t",	0x20000610, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"movz",	"",		"d,v,t",	0x20000210, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"msub",	"[dsp]",	"7,s,t",	0x20002abf, 0xfc003fff,MOD_1|RD_2|RD_3,		0,	0,	D32}, /* MSUB[DSP] */
+{"msubu",	"[dsp]",	"7,s,t",	0x20003abf, 0xfc003fff,MOD_1|RD_2|RD_3,		0,	0,	D32}, /* MSUBU[DSP] */
+{"mtc0",	"",		"t,O",		0x20000070, 0xfc0007ff,	RD_1,		INSN2_ALIAS,	I38,	0}, /* MTC0 with named register */
+{"mtc0",	"",		"t,P,J",	0x20000070, 0xfc0007ff,	RD_1,		INSN2_ALIAS,	I38,	0}, /* MTCO with named register & select */
+{"mtc0",	"",		"t,G,J,-B",	0x20000070, 0xfc0003ff,	RD_1,			0,	I38,	0},
+{"mthc0",	"",		"t,O",		0x20000078, 0xfc0007ff,	RD_1,		INSN2_ALIAS,	I38,	0}, /* MTHC0 with named register */
+{"mthc0",	"",		"t,P,J",	0x20000078, 0xfc0007ff,	RD_1,		INSN2_ALIAS,	I38,	0}, /* MTHC0 with named register & select */
+{"mthc0",	"",		"t,G,J,-B",	0x20000078, 0xfc0003ff,	RD_1,			0,	I38,	0},
+{"mthi",	"[dsp]",	"s,7,-I",	0x2000207f, 0xfc003fff,	WR_1|RD_2,		0,	0,	D32}, /* MTHI[DSP] */
+{"mthlip",	"",		"s,7,-I",	0x2000027f, 0xfc003fff,	WR_1|RD_2,		0,	0,	D32},
+{"mtlo",	"[dsp]",	"s,7,-I",	0x2000307f, 0xfc003fff,	WR_1|RD_2,		0,	0,	D32}, /* MTLO[DSP] */
+{"mttc0",	"",		"t,O",		0x20000270, 0xfc0007ff,	RD_1,		INSN2_ALIAS,	0,	MT32}, /* MTTR with named register */
+{"mttc0",	"",		"t,P,J",	0x20000270, 0xfc0007ff,	RD_1,		INSN2_ALIAS,	0,	MT32}, /* MTTR with named register & select */
+{"mtthc0",	"",		"t,O",		0x20000278, 0xfc0007ff,	RD_1,		INSN2_ALIAS,	0,	MT32}, /* MTTR with named register*/
+{"mtthc0",	"",		"t,P,J",	0x20000278, 0xfc0007ff,	RD_1,		INSN2_ALIAS,	0,	MT32}, /* MTTR with named register & select */
+{"mttc1",	"",		"t,S",		0x20001670, 0xfc00ffff,	RD_1|WR_2|FP_S,	INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"mttc1",	"",		"t,G",		0x20001670, 0xfc00ffff,	RD_1|WR_2|FP_S,	INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"mttc2",	"",		"t,G",		0x20002670, 0xfc00ffff,	RD_1,		INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"mttgpr",	"",		"s,t",		0x20000670, 0xfc00ffff,	RD_1|WR_2, INSN2_ALIAS|INSN2_MTTGPR_RC1, 0, MT32}, /* MTTR */
+{"mttgpr",	"",		"t,s",		0x20000670, 0xfc00ffff,	RD_1|WR_2,	INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"mtthc1",	"",		"t,S",		0x20001678, 0xfc00ffff,	RD_1|WR_2|FP_D,	INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"mtthc1",	"",		"t,G",		0x20001678, 0xfc00ffff,	RD_1|WR_2|FP_D,	INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"mtthc2",	"",		"t,G",		0x20002678, 0xfc00ffff,	RD_1,		INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"mtthi",	"",		"t",		0x20010e70, 0xfc1fffff,	RD_1|WR_a,	INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"mtthi",	"",		"t,*",		0x20010e70, 0xfc13ffff,	RD_1|WR_a,	INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"mttlo",	"",		"t",		0x20000e70, 0xfc1fffff,	RD_1|WR_a,	INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"mttlo",	"",		"t,*",		0x20000e70, 0xfc13ffff,	RD_1|WR_a,	INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"mttdsp",	"",		"t",		0x20100e70, 0xfc1fffff,	RD_1,		INSN2_ALIAS,	0,	MT32}, /* MTTR */
+{"mttr",	"",		"t,s,!,H,$",	0x20000270, 0xfc0003f7,	RD_1,			0,	0,	MT32},
+{"muh", 	"",		"d,v,t,-B",	0x20000058, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"muhu",	"",		"d,v,t,-B",	0x200000d8, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"mul", 	"[4x4]",	"mu,mt,mv",	0x3c08, 	0xfd08,	MOD_1|RD_3,		0,	0,	xNMS}, /* MUL[4X4] */
+{"mul", 	"[4x4]",	"mu,mv,mk",	0x3c08, 	0xfd08,	MOD_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* MUL[4X4] */
+{"mul", 	"[32]", 	"d,v,t,-B",	0x20000018, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"mul", 	"",		"d,v,I",	0,	(int) M_MUL_I,	INSN_MACRO,		0,	I38,	0},
+{"mul.ph",	"",		"d,s,t",	0x2000002d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"muleq_s.w.phl", "",		"d,s,t,-B",	0x20000025, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"muleq_s.w.phr", "",		"d,s,t,-B",	0x20000065, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"muleu_s.ph.qbl", "",		"d,s,t,-B",	0x20000095, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"muleu_s.ph.qbr", "",		"d,s,t,-B",	0x200000d5, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"mulq_rs.ph",	"",		"d,s,t,-B",	0x20000115, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"mulq_rs.w",	"",		"d,s,t,-B",	0x20000195, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"mulq_s.ph",	"",		"d,s,t,-B",	0x20000155, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"mulq_s.w",	"",		"d,s,t,-B",	0x200001d5, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"mulsa.w.ph",	"",		"7,s,t",	0x20002cbf, 0xfc003fff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"mulsaq_s.w.ph", "",		"7,s,t",	0x20003cbf, 0xfc003fff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"mult",	"[dsp]",	"7,s,t",	0x20000cbf, 0xfc003fff, WR_1|RD_2|RD_3,		0,	0,	D32}, /* MULT[DSP] */
+{"multu",	"[dsp]",	"7,s,t",	0x20001cbf, 0xfc003fff, WR_1|RD_2|RD_3,		0,	0,	D32}, /* MULTU[DSP] */
+{"mulu",	"",		"d,v,t,-B",	0x20000098, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"mul_s.ph",	"",		"d,s,t",	0x2000042d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"neg", 	"",		"d,w",		0x20000190, 0xfc1f07ff, WR_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* SUB */
+{"negu",	"",		"d,w",		0x200001d0, 0xfc1f07ff, WR_1|RD_2,	INSN2_ALIAS,	I38,	0}, /* SUBU */
+{"not", 	"[16]", 	"md,ml",	0x5000, 	0xfc0f,	WR_1|RD_2,		0,	I38,	0}, /* NOT[16] */
+{"not", 	"[32]", 	"d,v",		0x200002d0, 0xffe007ff, WR_1|RD_2,	INSN2_ALIAS,	I38,	0}, /* NOR */
+{"nor", 	"",		"d,v,t,-B",	0x200002d0, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"nor", 	"",		"t,r,I",	0,    (int) M_NOR_I,	INSN_MACRO,		0,	I38,	0},
+{"or",		"[16]", 	"md,mk,ml",	0x500c, 	0xfc0f,	WR_1|RD_3,	INSN2_ALIAS,	I38,	0}, /* OR[16] */
+{"or",		"[16]", 	"md,ml,mk",	0x500c, 	0xfc0f,	WR_1|RD_2,	INSN2_ALIAS,	I38,	0}, /* OR[16] */
+{"or",		"[16]", 	"md,ml",	0x500c, 	0xfc0f,	WR_1|RD_2,		0,	I38,	0}, /* OR[16] */
+{"or",		"[32]", 	"d,v,t,-B",	0x20000290, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"or",		"",		"t,r,I",	0,	(int) M_OR_I,	INSN_MACRO,		0,	I38,	0},
+{"ori", 	"",		"t,r,g",	0x80000000, 0xfc00f000,	WR_1|RD_2,		0,	I38,	0},
+{"pause",	"",		"-M",		0x8000c005, 0xfffff1ff,	0,			0,	I38,	0},
+{"packrl.ph",	"",		"d,s,t,-B",	0x200001ad, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"pick.ph",	"",		"d,s,t,-B",	0x2000022d, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"pick.qb",	"",		"d,s,t,-B",	0x200001ed, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"preceq.w.phl", "",		"t,s",		0x2000513f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"preceq.w.phr", "",		"t,s",		0x2000613f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"precequ.ph.qbl", "",		"t,s",		0x2000713f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"precequ.ph.qbla", "", 	"t,s",		0x2000733f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"precequ.ph.qbr", "",		"t,s",		0x2000913f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"precequ.ph.qbra", "", 	"t,s",		0x2000933f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"preceu.ph.qbl", "",		"t,s",		0x2000b13f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"preceu.ph.qbla", "",		"t,s",		0x2000b33f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"preceu.ph.qbr", "",		"t,s",		0x2000d13f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"preceu.ph.qbra", "",		"t,s",		0x2000d33f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"precr.qb.ph", "",		"d,s,t,-B",	0x2000006d, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"precrq.ph.w", "",		"d,s,t,-B",	0x200000ed, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"precrq.qb.ph", "",		"d,s,t,-B",	0x200000ad, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"precrqu_s.qb.ph", "", 	"d,s,t,-B",	0x2000016d, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"precrq_rs.ph.w", "",		"d,s,t,-B",	0x2000012d, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"precr_sra.ph.w", "",		"t,s,1",	0x200003cd, 0xfc0007ff,	WR_1|RD_2,		0,	0,	D32},
+{"precr_sra_r.ph.w", "",	"t,s,1",	0x200007cd, 0xfc0007ff,	WR_1|RD_2,		0,	0,	D32},
+{"pref",	"[u12]",	"k,o(b)",	0x84003000, 0xfc00f000,	RD_3,			0,	I38,	0}, /* PREF[U12] */
+{"pref",	"[s9]", 	"k,+j(b)",	0xa4001800, 0xfc007f00,	RD_3,			0,	I38,	0}, /* PREF[S9], preceded by SYNCI[S9] */
+{"pref",	"",		"k,A(c)",	0,     (int) M_PREF_AC,	INSN_MACRO,		0,	I38,	0},
+{"prefe",	"",		"k,+j(b)",	0xa4001a00, 0xfc007f00,	RD_3,			0,	0,	EVA}, /* preceded by SYNCIE */
+{"prefe",	"",		"k,A(c)",	0,    (int) M_PREFE_AC,	INSN_MACRO,		0,	0,	EVA},
+{"prepend",	"",		"d,-n,t,+I",	0x2000001f, 0xfc00003f, WR_1|RD_3,	INSN2_ALIAS,	0,	D32}, /* EXTW */
+{"raddu.w.qb",	"",		"t,s",		0x2000f13f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"rddsp",	"",		"t",		0x201fc67f, 0xfc1fffff,	WR_1,		INSN2_ALIAS,	0,	D32},
+{"rddsp",	"",		"t,8",		0x2000067f, 0xfc003fff,	WR_1,			0,	0,	D32},
+{"rdhwr",	"",		"t,K",		0x200001c0, 0xfc0007ff,	WR_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* RDHWR with sel=0 */
+{"rdhwr",	"",		"t,U,J",	0x200001c0, 0xfc0007ff,	WR_1|RD_2,	INSN2_ALIAS,	0,	xNMS},
+{"rdhwr",	"",		"t,G,H,-B",	0x200001c0, 0xfc0003ff,	WR_1|RD_2,		0,	0,	xNMS}, /* RDWHR */
+{"rdpgpr",	"",		"t,s",		0x2000e17f, 0xfc00ffff,	WR_1|RD_2,		0,	I38,	0},
+{"rem", 	"",		"d,v,t",	0x20000158, 0xfc0007ff, WR_1|RD_2|RD_3,	INSN2_ALIAS,	I38,	0}, /* MOD */
+{"rem", 	"",		"d,v,I",	0,	(int) M_REM_3I,	INSN_MACRO,		0,	I38,	0},
+{"remu",	"",		"d,v,t",	0x200001d8, 0xfc0007ff, WR_1|RD_2|RD_3,	INSN2_ALIAS,	I38,	0}, /* MODU */
+{"repl.ph",	"",		"t,@,-B",	0x2000003d, 0xfc0003ff,	WR_1,			0,	0,	D32},
+{"repl.qb",	"",		"t,5,-O",	0x200005ff, 0xfc000fff,	WR_1,			0,	0,	D32},
+{"replv.ph",	"",		"t,s",		0x2000033f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"replv.qb",	"",		"t,s",		0x2000133f, 0xfc00ffff,	WR_1|RD_2,		0,	0,	D32},
+{"restore",	"[32]", 	"+N,n", 	0x80003002, 0xfc00f003,	0,			0,	I38,	0},
+{"restore.jrc", "[16]", 	"mG",		0x1d00, 	0xff0f,	0,			0,	I38,	0}, /* RESTORE.JRC[16] */
+{"restore.jrc", "[16]", 	"mG,mn",	0x1d00, 	0xfd00,	0,			0,	I38,	0}, /* RESTORE.JRC[16], preceded by RESTORE[16] */
+{"restore.jrc", "[32]", 	"+N",		0x80003003, 0xfffff007,	0,			0,	I38,	0}, /* RESTORE.JRC[32] */
+{"restore.jrc", "[32]", 	"+N,n", 	0x80003003, 0xfc00f003,	0,			0,	I38,	0},
+{"jraddiusp",	"",		"mG",		0x1d00, 	0xff0f,	0,		INSN2_ALIAS,	I38,	0}, /* RESTORE.JRC[16] */
+{"jraddiusp",	"",		"+N",		0x80003003, 0xfffff007,	0,		INSN2_ALIAS,	I38,	0}, /* RESTORE.JRC[32] */
+{"jraddiusp",	"",		"I",		0,   (int) M_JRADDIUSP,	INSN_MACRO,		0,	I38,	0},
+{"rol", 	"",		"d,v,t",	0,	(int) M_ROL,	INSN_MACRO,		0,	I38,	0},
+{"rol", 	"",		"d,v,I",	0,	(int) M_ROL_I,	INSN_MACRO,		0,	I38,	0},
+{"rotrv",	"",		"d,s,t,-B",	0x200000d0, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"rotr",	"",		"t,r,<,-M",	0x8000c0c0, 0xfc00f1e0,	WR_1|RD_2,		0,	I38,	0},
+{"rotr",	"",		"d,v,t",	0x200000d0, 0xfc0007ff, WR_1|RD_2|RD_3,	INSN2_ALIAS,	I38,	0}, /* ROTRV */
+{"ror", 	"",		"t,r,<",	0x8000c0c0, 0xfc00ffe0,	WR_1|RD_2,	INSN2_ALIAS,	I38,	0}, /* ROTR */
+{"ror", 	"",		"d,v,t",	0x200000d0, 0xfc0007ff, WR_1|RD_2|RD_3,	INSN2_ALIAS,	I38,	0}, /* ROTRV */
+{"ror", 	"",		"d,v,I",	0,    (int) M_ROR_I,	INSN_MACRO,		0,	I38,	0},
+{"rorv",	"",		"t,r,<",	0x8000c0c0, 0xfc00ffe0,	WR_1|RD_2,	INSN2_ALIAS,	I38,	0}, /* ROTR */
+{"rorv",	"",		"d,v,t",	0x200000d0, 0xfc0007ff, WR_1|RD_2|RD_3,	INSN2_ALIAS,	I38,	0}, /* ROTRV */
+{"rotl",	"",		"d,v,t",	0,    (int) M_ROL,	INSN_MACRO,		0,	I38,	0},
+{"rotl",	"",		"d,v,I",	0,    (int) M_ROL_I,	INSN_MACRO,		0,	I38,	0},
+{"wsbh",	"",		"t,r",		0x8000d608, 0xfc00ffff,	WR_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* ROTX t,s,8,24*/
+{"rotx",	"",		"t,r,<,+*",	0x8000d000, 0xfc00f860, WR_1|RD_2,	INSN2_ALIAS,	0,	xNMS},
+{"rotx",	"",		"t,r,<,+*,+|",	0x8000d000, 0xfc00f820, WR_1|RD_2,		0,	0,	xNMS},
+{"save",	"[16]", 	"mG",		0x1c00, 	0xff0f,	0,			0,	I38,	0}, /* SAVE[16] */
+{"save",	"[16]", 	"mG,mn",	0x1c00, 	0xfd00,	0,			0,	I38,	0}, /* SAVE[16] */
+{"save",	"[32]", 	"+N,n",		0x80003000, 0xfc00f003,	0,			0,	I38,	0},
+{"sb",		"[16]", 	"mm,mL(ml)",	0x5c04, 	0xfc0c,	RD_1|RD_3,		0,	I38,	0}, /* SB[16] */
+{"sb",		"[gp]", 	"t,+1(ma)",	0x44040000, 0xfc1c0000,	RD_1|RD_3,		0,	I38,	0}, /* SB[GP] */
+{"sb",		"[u12]",	"t,o(b)",	0x84001000, 0xfc00f000,	RD_1|RD_3,		0,	I38,	0}, /* SB[U12] */
+{"sb",		"[s9]", 	"t,+j(b)",	0xa4000800, 0xfc007f00,	RD_1|RD_3,		0,	I38,	0}, /* SB[S9] */
+{"sb",		"",		"t,A(c)",	0,	(int) M_SB_AC,	INSN_MACRO,		0,	I38,	0},
+{"sb",		"",		"t,A(b)",	0,	(int) M_SBX_AB,	INSN_MACRO,		0,	0,	xNMS},
+{"sbe", 	"",		"t,+j(b)",	0xa4000a00, 0xfc007f00,	RD_1|RD_3,		0,	0,	EVA},
+{"sbe", 	"",		"t,A(c)",	0,	(int) M_SBE_AC,	INSN_MACRO,		0,	0,	EVA},
+{"sbx", 	"",		"d,s(t)",	0x20000087, 0xfc0007ff, RD_1|RD_2|RD_3,		0,	0,	xNMS},
+{"sc",		"",		"t,+p(b)",	0xa4005900, 0xfc007f03,	MOD_1|RD_3,		0,	I38,	0},
+{"sc",		"",		"t,A(c)",	0,	(int) M_SC_AC,	INSN_MACRO,		0,	I38,	0},
+{"sce", 	"",		"t,+p(b)",	0xa4005a00, 0xfc007f03,	MOD_1|RD_3,		0,	0,	EVA},
+{"sce", 	"",		"t,A(c)",	0,	(int) M_SCE_AC,	INSN_MACRO,		0,	0,	EVA},
+{"scwp",	"",		"t,e,(b),-K",	0xa4005901, 0xfc007f03,	MOD_1|WR_2|RD_3,		0,	0,	xNMS},
+{"scwp",	"",		"t,e,A(c)",	0,     (int) M_SCWP_AC,	INSN_MACRO,		0,	0,	xNMS},
+{"scwpe",	"",		"t,e,(b),-K",	0xa4005a01, 0xfc007f03,	MOD_1|WR_2|RD_3,		0,	0,	EVA},
+{"scwpe",	"",		"t,e,A(c)",	0,     (int) M_SCWP_AC,	INSN_MACRO,		0,	0,	EVA},
+{"sd",		"",		"t,A(c)",	0,	(int) M_SD_AC,	INSN_MACRO,		0,	I38,	0},
+{"sd",		"",		"t,A(b)",	0,	(int) M_SDX_AB,	INSN_MACRO,		0,	I38,	0},
+{"seb", 	"", 		"t,r,-N",	0x20000008, 0xfc0003ff,	WR_1|RD_2,		0,	0,	xNMS},
+{"seh", 	"", 		"t,r,-N",	0x20000048, 0xfc0003ff,	WR_1|RD_2,		0,	I38,	0},
+{"seqi",	"",		"t,r,i",	0x80006000, 0xfc00f000, WR_1|RD_2,		0,	I38,	0},
+{"seq", 	"", 		"d,v,t",	0,	(int) M_SEQ,	INSN_MACRO,		0,	I38,	0},
+{"seq", 	"", 		"d,v,I",	0,	(int) M_SEQ_I,	INSN_MACRO,		0,	I38,	0},
+{"sge", 	"", 		"d,v,t",	0,	(int) M_SGE,	INSN_MACRO,		0,	I38,	0},
+{"sge", 	"", 		"d,v,I",	0,	(int) M_SGE_I,	INSN_MACRO,		0,	I38,	0},
+{"sgeu",	"",		"d,v,t",	0,	(int) M_SGEU,	INSN_MACRO,		0,	I38,	0},
+{"sgeu",	"",		"d,v,I",	0,     (int) M_SGEU_I,	INSN_MACRO,		0,	I38,	0},
+{"sgt", 	"", 		"d,v,t",	0,	(int) M_SGT,	INSN_MACRO,		0,	I38,	0},
+{"sgt", 	"", 		"d,v,I",	0,	(int) M_SGT_I,	INSN_MACRO,		0,	I38,	0},
+{"sgtu",	"",		"d,v,t",	0,	(int) M_SGTU,	INSN_MACRO,		0,	I38,	0},
+{"sgtu",	"",		"d,v,I",	0,     (int) M_SGTU_I,	INSN_MACRO,		0,	I38,	0},
+{"sh",		"[16]", 	"mm,mH(ml)",	0x7c01, 	0xfc09,	RD_1|RD_3,		0,	I38,	0}, /* SH[16] */
+{"sh",		"[gp]", 	"t,+3(ma)",	0x44140000, 0xfc1c0001,	RD_1|RD_3,		0,	I38,	0}, /* SH[GP] */
+{"sh",		"[u12]",	 "t,o(b)",	0x84005000, 0xfc00f000,	RD_1|RD_3,		0,	I38,	0}, /* SH[U12] */
+{"sh",		"[s9]", 	"t,+j(b)",	0xa4002800, 0xfc007f00,	RD_1|RD_3,		0,	I38,	0}, /* SH[S9] */
+{"sh",		"",		"t,A(c)", 	0,	(int) M_SH_AC,	INSN_MACRO,	0,	I38,	0},
+{"sh",		"",		"t,A(b)", 	0,	(int) M_SHX_AB,	INSN_MACRO,	0,	0,	xNMS}, /* SHX */
+{"she", 	"",		"t,+j(b)",	0xa4002a00, 0xfc007f00,	RD_1|RD_3,		0,	0,	EVA},
+{"she", 	"",		"t,A(c)",	0,	(int) M_SHE_AC,	INSN_MACRO,		0,	0,	EVA},
+{"shilo",	"",		"7,0,-P",	0x2000001d, 0xfc0003ff,	MOD_1,			0,	0,	D32},
+{"shilov",	"",		"7,s,-I",	0x2000127f, 0xfc003fff,	MOD_1|RD_2,		0,	0,	D32},
+{"shll.ph",	"",		"t,s,4",	0x200003b5, 0xfc000fff,	WR_1|RD_2,		0,	0,	D32},
+{"shll.qb",	"",		"t,s,3",	0x2000087f, 0xfc001fff,	WR_1|RD_2,		0,	0,	D32},
+{"shllv.ph",	"",		"d,t,s",	0x2000038d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"shllv.qb",	"",		"d,t,s,-B",	0x20000395, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"shllv_s.ph",	"",		"d,t,s",	0x2000078d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"shllv_s.w",	"",		"d,t,s,-B",	0x200003d5, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"shll_s.ph",	"",		"t,s,4",	0x20000bb5, 0xfc000fff,	WR_1|RD_2,		0,	0,	D32},
+{"shll_s.w",	"",		"t,s,1,-B",	0x200003f5, 0xfc0003ff,	WR_1|RD_2,		0,	0,	D32},
+{"shra.ph",	"",		"t,s,4",	0x20000335, 0xfc000fff,	WR_1|RD_2,		0,	0,	D32},
+{"shra.qb",	"",		"t,s,3",	0x200001ff, 0xfc001fff,	WR_1|RD_2,		0,	0,	D32},
+{"shrav.ph",	"",		"d,t,s",	0x2000018d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"shrav.qb",	"",		"d,t,s",	0x200001cd, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"shrav_r.ph",	"",		"d,t,s",	0x2000058d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"shrav_r.qb",	"",		"d,t,s",	0x200005cd, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"shrav_r.w",	"",		"d,t,s,-B",	0x200002d5, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"shra_r.ph",	"",		"t,s,4,-Q",	0x20000735, 0xfc0007ff,	WR_1|RD_2,		0,	0,	D32},
+{"shra_r.qb",	"",		"t,s,3",	0x200011ff, 0xfc001fff,	WR_1|RD_2,		0,	0,	D32},
+{"shra_r.w",	"",		"t,s,1,-B",	0x200002f5, 0xfc0003ff,	WR_1|RD_2,		0,	0,	D32},
+{"shrl.ph",	"",		"t,s,4",	0x200003ff, 0xfc000fff,	WR_1|RD_2,		0,	0,	D32},
+{"shrl.qb",	"",		"t,s,3",	0x2000187f, 0xfc001fff,	WR_1|RD_2,		0,	0,	D32},
+{"shrlv.ph",	"",		"d,t,s,-B",	0x20000315, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"shrlv.qb",	"",		"d,t,s,-B",	0x20000355, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"shx", 	"",		"d,s(t)",	0x20000287, 0xfc0007ff, RD_1|RD_2|RD_3,		0,	0,	xNMS},
+{"shxs",	"",		"d,s(t)",	0x200002c7, 0xfc0007ff, RD_1|RD_2|RD_3,		0,	0,	xNMS},
+{"sync_wmb",	"",		"",		0x8004c006, 0xffffffff,		0,	INSN2_ALIAS,	I38,	0}, /* SYNC */
+{"sync_mb",	"",		"",		0x8010c006, 0xffffffff,		0,	INSN2_ALIAS,	I38,	0}, /* SYNC */
+{"sync_acquire", "",		"",		0x8011c006, 0xffffffff,		0,	INSN2_ALIAS,	I38,	0}, /* SYNC */
+{"sync_release", "",		"",		0x8012c006, 0xffffffff,		0,	INSN2_ALIAS,	I38,	0}, /* SYNC */
+{"sync_rmb",	"",		"",		0x8013c006, 0xffffffff,		0,	INSN2_ALIAS,	I38,	0}, /* SYNC */
+{"sync_ginv",	"",		"",		0x8014c006, 0xffffffff,		0,	INSN2_ALIAS,	0,	GINV}, /* SYNC */
+{"sync",	"",		"",		0x8000c006, 0xffffffff,		0,	INSN2_ALIAS,	I38,	0}, /* SYNC */
+{"sync",	"",		"+i,-M",	0x8000c006, 0xffe0f1ff,		0,		0,	I38,	0},
+{"sle", 	"",		"d,v,t",	0,	(int) M_SLE,	INSN_MACRO,		0,	I38,	0},
+{"sle", 	"",		"d,v,I",	0,	(int) M_SLE_I,	INSN_MACRO,		0,	I38,	0},
+{"sleu",	"",		"d,v,t",	0,	(int) M_SLEU,	INSN_MACRO,		0,	I38,	0},
+{"sleu",	"",		"d,v,I",	0,	(int) M_SLEU_I,	INSN_MACRO,		0,	I38,	0},
+{"sllv",	"",		"d,s,t,-B",	0x20000010, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"sll", 	"[16]", 	"md,mc,mM",	0x3000,		0xfc08,	WR_1|RD_2,		0,	I38,	0}, /* SLL[16] */
+{"sll", 	"[32]", 	"t,r,<,-M",	0x8000c000, 0xfc00f1e0,	WR_1|RD_2,		0,	I38,	0}, /* preceded by EHB, PAUSE, SYNC */
+{"sll", 	"[32]", 	"d,v,t",	0x20000010, 0xfc0007ff, WR_1|RD_2|RD_3,	INSN2_ALIAS,	I38,	0}, /* SLLV */
+{"slt", 	"",		"d,v,t,-B",	0x20000350, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"slt", 	"",		"d,v,I",	0,	(int) M_SLT_I,	INSN_MACRO,		0,	I38,	0},
+{"slti",	"",		"t,r,i",	0x80004000, 0xfc00f000,	WR_1|RD_2,		0,	I38,	0},
+{"sltiu",	"",		"t,r,i",	0x80005000, 0xfc00f000,	WR_1|RD_2,		0,	I38,	0},
+{"sltu",	"",		"d,v,t,-B",	0x20000390, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0}, /* preceded by DVP */
+{"sltu",	"",		"d,v,I",	0,	(int) M_SLTU_I,	INSN_MACRO,		0,	I38,	0},
+{"sne", 	"",		"d,v,t",	0,	(int) M_SNE,	INSN_MACRO,		0,	I38,	0},
+{"sne", 	"",		"d,v,I",	0,	(int) M_SNE_I,	INSN_MACRO,		0,	I38,	0},
+{"sov", 	"",		"d,v,t,-B",	0x200003d0, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"srav",	"",		"d,s,t,-B",	0x20000090, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"sra", 	"",		"t,r,<,-M",	0x8000c080, 0xfc00f1e0,	WR_1|RD_2,		0,	I38,	0},
+{"sra", 	"",		"d,v,t",	0x20000090, 0xfc0007ff, WR_1|RD_2|RD_3,	INSN2_ALIAS,	I38,	0}, /* SRAV */
+{"srlv",	"",		"d,s,t,-B",	0x20000050, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"srl", 	"[16]", 	"md,mc,mM",	0x3008, 	0xfc08,	WR_1|RD_2,		0,	I38,	0}, /* SRL[16] */
+{"srl", 	"[32]", 	"t,r,<,-M",	0x8000c040, 0xfc00f1e0,	WR_1|RD_2,		0,	I38,	0},
+{"srl", 	"[32]", 	"d,v,t",	0x20000050, 0xfc0007ff, WR_1|RD_2|RD_3,	INSN2_ALIAS,	I38,	0}, /* SRLV */
+{"sub", 	"",		"d,v,t,-B",	0x20000190, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	xNMS},
+{"sub", 	"",		"t,r,I",	0,	(int) M_SUB_I,	INSN_MACRO,		0,	0,	xNMS},
+{"subq.ph",	"",		"d,s,t",	0x2000020d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"subqh.ph",	"",		"d,s,t",	0x2000024d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"subqh.w",	"",		"d,s,t",	0x2000028d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"subqh_r.ph",	"",		"d,s,t",	0x2000064d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"subqh_r.w",	"",		"d,s,t",	0x2000068d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"subq_s.ph",	"",		"d,s,t",	0x2000060d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"subq_s.w",	"",		"d,s,t,-B",	0x20000345, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"subu",	"[16]", 	"me,mc,md",	0xb001, 	0xfc01, WR_1|RD_2|RD_3,		0,	I38,	0}, /* SUBU[16] */
+{"subu",	"[32]", 	"d,v,t,-B",	0x200001d0, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"subu",	"",		"d,v,I",	0,	(int) M_SUBU_I,	INSN_MACRO,		0,	I38,	0},
+{"subu.ph",	"",		"d,s,t",	0x2000030d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"subu.qb",	"",		"d,s,t",	0x200002cd, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"subuh.qb",	"",		"d,s,t",	0x2000034d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"subuh_r.qb",	"",		"d,s,t",	0x2000074d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"subu_s.ph",	"",		"d,s,t",	0x2000070d, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"subu_s.qb",	"",		"d,s,t",	0x200006cd, 0xfc0007ff, WR_1|RD_2|RD_3,		0,	0,	D32},
+{"sw",		"[16]", 	"mm,mJ(ml)",	0x9400, 	0xfc00,	RD_1|RD_3,		0,	I38,	0}, /* SW[16] */
+{"sw",		"[sp]", 	"mp,mR(ms)",	0xb400, 	0xfc00,	RD_1|RD_3,		0,	I38,	0}, /* SW[SP] */
+{"sw",		"[4x4]",	"mw,mN(mv)",	0xf400, 	0xfc00,	RD_1|RD_3,		0,	0,	xNMS}, /* SW[4X4] */
+{"sw",		"[gp16]",	"mm,mO(ma)",	0xd400, 	0xfc00,	RD_1|RD_3,		0,	I38,	0}, /* SW[GP16] */
+{"sw",		"[gp]", 	"t,.(ma)",	0x40000003, 0xfc000003,	RD_1|RD_3,		0,	I38,	0}, /* SW[GP] */
+{"sw",		"[gp16]",	"mm,mA(ma)",	0xd400, 	0xfc00,	RD_1|RD_3,		0,	I38,	0}, /* SW[GP16] */
+{"sw",		"[u12]",	"t,o(b)",	0x84009000, 0xfc00f000,	RD_1|RD_3,		0,	I38,	0}, /* SW[U12] */
+{"sw",		"[s9]", 	"t,+j(b)",	0xa4004800, 0xfc007f00,	RD_1|RD_3,		0,	I38,	0}, /* SW[S9] */
+{"sw",		"",		"t,A(c)",	0,	 (int) M_SW_AC,	INSN_MACRO,		0,	I38,	0},
+{"sw",		"",		"t,A(b)",	0,	(int) M_SWX_AB,	INSN_MACRO,		0,	0,	xNMS}, /* SWX */
+{"swe", 	"",		"t,+j(b)",	0xa4004a00, 0xfc007f00,	RD_1|RD_3,		0,	0,	EVA},
+{"swe", 	"",		"t,A(c)",	0,      (int) M_SWE_AC,	INSN_MACRO,		0,	0,	EVA},
+{"swm", 	"",		"t,+j(b),|",	0xa4000c00, 0xfc000f00,	RD_1|RD_3,		0,	0,	xNMS}, /* SWM */
+{"swpc",	"[48]", 	"mp,+S",	0x600f, 	0xfc1f,	WR_1,			0,	0,	xNMS}, /* SWPC[48] */
+{"swx", 	"",		"d,s(t)",	0x20000487, 0xfc0007ff, RD_1|RD_2|RD_3,		0,	0,	xNMS},
+{"swxs",	"",		"d,s(t)",	0x200004c7, 0xfc0007ff, RD_1|RD_2|RD_3,		0,	0,	xNMS},
+{"syscall",	"[16]", 	"",		0x1008, 	0xffff,		0,	INSN2_ALIAS,	I38,	0}, /* SYSCALL[16] */
+{"syscall",	"[16]", 	"mP",		0x1008, 	0xfffc,		0,		0,	I38,	0}, /* SYSCALL[16] */
+{"syscall",	"[32]", 	"",		0x00080000, 0xffffffff,		0,	INSN2_ALIAS,	I38,	0},
+{"syscall",	"[32]", 	"+M",		0x00080000, 0xfffc0000,		0,		0,	I38,	0},
+{"teq", 	"",		"s,t",		0x20000000, 0xfc00ffff,	RD_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* TEQ */
+{"teq", 	"",		"s,t,^",	0x20000000, 0xfc0007ff,	RD_1|RD_2,		0,	0,	xNMS}, /* TEQ */
+{"teq", 	"",		"s,I",		0, 	 (int) M_TEQ_I,	INSN_MACRO,		0,	0,	xNMS},
+{"tne", 	"",		"s,t",		0x20000400, 0xfc00ffff,	RD_1|RD_2,	INSN2_ALIAS,	0,	xNMS}, /* TNE */
+{"tne", 	"",		"s,t,^",	0x20000400, 0xfc0007ff,	RD_1|RD_2,		0,	0,	xNMS}, /* TNE */
+{"tne", 	"",		"s,I",		0, 	 (int) M_TNE_I,	INSN_MACRO,		0,	0,	xNMS},
+{"tlbinv",	"",		"-F",		0x2000077f, 0xfc00ffff,		0,		0,	0,	TLB},
+{"tlbinvf",	"",		"-F",		0x2000177f, 0xfc00ffff,		0,		0,	0,	TLB},
+{"tlbp",	"",		"-F",		0x2000037f, 0xfc00ffff,		0,		0,	0,	TLB},
+{"tlbr",	"",		"-F",		0x2000137f, 0xfc00ffff,		0,		0,	0,	TLB},
+{"tlbwi",	"",		"-F",		0x2000237f, 0xfc00ffff,		0,		0,	0,	TLB},
+{"tlbwr",	"",		"-F",		0x2000337f, 0xfc00ffff,		0,		0,	0,	TLB},
+{"ualh",	"",		"t,+j(b)",	0xa4002100, 0xfc007f00,	WR_1|RD_3,		0,	0,	xNMS},
+{"ualw",	"",		"t,+j(b)",	0xa4001500, 0xfc007f00,	WR_1|RD_3,	INSN2_ALIAS,	0,	xNMS}, /* UALWM */
+{"ualwm",	"",		"t,+j(b),|",	0xa4000500, 0xfc000f00,	WR_1|RD_3,		0,	0,	xNMS}, /* UALWM */
+{"uash",	"",		"t,+j(b)",	0xa4002900, 0xfc007f00,	RD_1|RD_3,		0,	0,	xNMS},
+{"uasw",	"",		"t,+j(b)",	0xa4001d00, 0xfc007f00,	RD_1|RD_3,	INSN2_ALIAS,	0,	xNMS}, /* UASWM */
+{"uaswm",	"",		"t,+j(b),|",	0xa4000d00, 0xfc000f00,	RD_1|RD_3,		0,	0,	xNMS}, /* UASWM */
+{"uld", 	"",		"t,A(c)",	0,	(int) M_ULD_AC,	INSN_MACRO,		0,	0,	xNMS},
+{"ulh", 	"",		"t,A(c)",	0,	(int) M_ULH_AC,	INSN_MACRO,		0,	0,	xNMS},
+{"ulw", 	"",		"t,A(c)",	0,	(int) M_ULW_AC,	INSN_MACRO,		0,	0,	xNMS},
+{"usd", 	"",		"t,A(c)",	0,	(int) M_USD_AC,	INSN_MACRO,		0,	0,	xNMS},
+{"ush", 	"",		"t,A(c)",	0,	(int) M_USH_AC,	INSN_MACRO,		0,	0,	xNMS},
+{"usw", 	"",		"t,A(c)",	0,	(int) M_USW_AC,	INSN_MACRO,		0,	0,	xNMS},
+{"wait",	"",		"",		0x2000c37f, 0xffffffff,		0,	INSN2_ALIAS,	I38,	0},
+{"wait",	"",		"+L",		0x2000c37f, 0xfc00ffff,		0,		0,	I38,	0},
+{"wrdsp",	"",		"t",		0x201fd67f, 0xfc1fffff,	RD_1,		INSN2_ALIAS,	0,	D32},
+{"wrdsp",	"",		"t,8",		0x2000167f, 0xfc003fff,	RD_1,			0,	0,	D32},
+{"wrpgpr",	"",		"t,r",		0x2000f17f, 0xfc00ffff,	WR_1|RD_2,		0,	I38,	0},
+{"xor", 	"[16]", 	"md,mk,ml",	0x5004, 	0xfc0f,	WR_1|RD_3,	INSN2_ALIAS,	I38,	0}, /* XOR[16] */
+{"xor", 	"[16]", 	"md,ml,mk",	0x5004, 	0xfc0f,	WR_1|RD_2,	INSN2_ALIAS,	I38,	0}, /* XOR[16] */
+{"xor", 	"[16]", 	"md,ml",	0x5004, 	0xfc0f,	WR_1|RD_2,		0,	I38,	0}, /* XOR[16] */
+{"xor", 	"[32]", 	"d,v,t,-B",	0x20000310, 0xfc0003ff, WR_1|RD_2|RD_3,		0,	I38,	0},
+{"xor", 	"",		"t,r,I",	0,	(int) M_XOR_I,	INSN_MACRO,		0,	I38,	0},
+{"xori",	"",		"t,r,g",	0x80001000, 0xfc00f000,	WR_1|RD_2,		0,	I38,	0},
+{"yield",	"",		"s",		0x20000268, 0xffe0ffff,	RD_1,		INSN2_ALIAS,	0,	MT32},
+{"yield",	"",		"t,s,-N",	0x20000268, 0xfc0003ff,	WR_1|RD_2,		0,	0,	MT32},
+};
+
+const int bfd_nanomips_num_opcodes =
+  ((sizeof nanomips_opcodes) / (sizeof (nanomips_opcodes[0])));