public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v6 0/3] Add support for nanoMIPS architecture
@ 2023-05-10 14:18 Aleksandar Rikalo
  2023-05-10 14:18 ` [PATCH v6 1/3] BFD changes for nanoMIPS support Aleksandar Rikalo
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Aleksandar Rikalo @ 2023-05-10 14:18 UTC (permalink / raw)
  To: binutils; +Cc: nickc, macro, dragan.mladjenovic, lei.wang

This series introduces a subset of nanoMIPS functionalities. It's a pre-requirement for nanoMIPS support for GDB/SIM.

Almost complete series is a "green patch" - it adds things, so the probability of making regressions of existing functionalities is minimal.

Compared to the previous series version (v5), there are no functional impacts but changes are split into smaller parts.
Patches can be safely merged one at a time while respecting the existing order.

Aleksandar Rikalo (3):
  BFD changes for nanoMIPS support
  Opcodes changes for nanoMIPS support
  Readelf for nanoMIPS

 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/nanomips.h     |  262 +++++++
 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     | 1466 ++++++++++++++++++++++++++++++++++++
 opcodes/nanomips-formats.h |  265 +++++++
 opcodes/nanomips-opc.c     | 1073 ++++++++++++++++++++++++++
 31 files changed, 7761 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/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

-- 
2.25.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v6 1/3] BFD changes for nanoMIPS support
  2023-05-10 14:18 [PATCH v6 0/3] Add support for nanoMIPS architecture Aleksandar Rikalo
@ 2023-05-10 14:18 ` Aleksandar Rikalo
  2023-05-11  0:42   ` Hans-Peter Nilsson
  2023-05-10 14:18 ` [PATCH v6 2/3] Opcodes " Aleksandar Rikalo
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: Aleksandar Rikalo @ 2023-05-10 14:18 UTC (permalink / raw)
  To: binutils; +Cc: nickc, macro, dragan.mladjenovic, lei.wang

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     |    2 +-
 include/elf/common.h   |    2 +-
 include/elf/nanomips.h |  262 ++++++++
 19 files changed, 2956 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/nanomips.h

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..140337d7bec 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -2963,7 +2963,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 "nanoMIPS";
       /* 250 */
     case EM_NFP:		return "Netronome Flow Processor";
     case EM_VE:			return "NEC Vector Engine";
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/nanomips.h b/include/elf/nanomips.h
new file mode 100644
index 00000000000..b04c7343af2
--- /dev/null
+++ b/include/elf/nanomips.h
@@ -0,0 +1,262 @@
+/* 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"
+
+#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.  */
+
+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 */
-- 
2.25.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v6 2/3] Opcodes changes for nanoMIPS support
  2023-05-10 14:18 [PATCH v6 0/3] Add support for nanoMIPS architecture Aleksandar Rikalo
  2023-05-10 14:18 ` [PATCH v6 1/3] BFD changes for nanoMIPS support Aleksandar Rikalo
@ 2023-05-10 14:18 ` Aleksandar Rikalo
  2023-05-10 14:18 ` [PATCH v6 3/3] Readelf for nanoMIPS Aleksandar Rikalo
  2023-05-18 10:34 ` [PATCH v6 0/3] Add support for nanoMIPS architecture Tsing
  3 siblings, 0 replies; 8+ messages in thread
From: Aleksandar Rikalo @ 2023-05-10 14:18 UTC (permalink / raw)
  To: binutils; +Cc: nickc, macro, dragan.mladjenovic, lei.wang

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>
---
 include/dis-asm.h          |   11 +
 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     | 1466 ++++++++++++++++++++++++++++++++++++
 opcodes/nanomips-formats.h |  265 +++++++
 opcodes/nanomips-opc.c     | 1073 ++++++++++++++++++++++++++
 12 files changed, 4305 insertions(+)
 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

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/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..ef69d11c8bb
--- /dev/null
+++ b/opcodes/nanomips-dis.c
@@ -0,0 +1,1466 @@
+/* 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
+
+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;
+    }
+
+  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])));
-- 
2.25.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v6 3/3] Readelf for nanoMIPS
  2023-05-10 14:18 [PATCH v6 0/3] Add support for nanoMIPS architecture Aleksandar Rikalo
  2023-05-10 14:18 ` [PATCH v6 1/3] BFD changes for nanoMIPS support Aleksandar Rikalo
  2023-05-10 14:18 ` [PATCH v6 2/3] Opcodes " Aleksandar Rikalo
@ 2023-05-10 14:18 ` Aleksandar Rikalo
  2023-05-18 10:34 ` [PATCH v6 0/3] Add support for nanoMIPS architecture Tsing
  3 siblings, 0 replies; 8+ messages in thread
From: Aleksandar Rikalo @ 2023-05-10 14:18 UTC (permalink / raw)
  To: binutils; +Cc: nickc, macro, dragan.mladjenovic, lei.wang

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>
---
 binutils/readelf.c | 500 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 500 insertions(+)

diff --git a/binutils/readelf.c b/binutils/readelf.c
index 140337d7bec..20ecbb67b35 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);
@@ -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,
-- 
2.25.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 1/3] BFD changes for nanoMIPS support
  2023-05-10 14:18 ` [PATCH v6 1/3] BFD changes for nanoMIPS support Aleksandar Rikalo
@ 2023-05-11  0:42   ` Hans-Peter Nilsson
  2023-05-12 17:01     ` Aleksandar Rikalo
  0 siblings, 1 reply; 8+ messages in thread
From: Hans-Peter Nilsson @ 2023-05-11  0:42 UTC (permalink / raw)
  To: Aleksandar Rikalo; +Cc: binutils

On Wed, 10 May 2023, Aleksandar Rikalo wrote:
> 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>

Random spotting: I see a "Written by ..." note at the top of 
several files with a name not in the above co-authored-by list.
If the person quit, me thinks attribution in the list is still 
in order.

brgds, H-P

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v6 1/3] BFD changes for nanoMIPS support
  2023-05-11  0:42   ` Hans-Peter Nilsson
@ 2023-05-12 17:01     ` Aleksandar Rikalo
  2023-05-19 22:25       ` Maciej W. Rozycki
  0 siblings, 1 reply; 8+ messages in thread
From: Aleksandar Rikalo @ 2023-05-12 17:01 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: binutils

[-- Attachment #1: Type: text/plain, Size: 291 bytes --]

> Random spotting: I see a "Written by ..." note at the top of
> several files with a name not in the above co-authored-by list.
> If the person quit, me thinks attribution in the list is still
> in order.

> brgds, H-P

Will be fixed. Thank You for noticing that.

--Aleksandar


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 0/3] Add support for nanoMIPS architecture
  2023-05-10 14:18 [PATCH v6 0/3] Add support for nanoMIPS architecture Aleksandar Rikalo
                   ` (2 preceding siblings ...)
  2023-05-10 14:18 ` [PATCH v6 3/3] Readelf for nanoMIPS Aleksandar Rikalo
@ 2023-05-18 10:34 ` Tsing
  3 siblings, 0 replies; 8+ messages in thread
From: Tsing @ 2023-05-18 10:34 UTC (permalink / raw)
  To: aleksandar.rikalo; +Cc: binutils

[-- Attachment #1: Type: text/plain, Size: 1182 bytes --]

Hi.

I can confirm these patches can compile and could be run normally.
But the tests were omitted in this patch, so I could not confirm if the patches work.
Do we need to add `#define ARCH_nanomips` in the front part like the official one? 
If so, definitions of `ARCH_nanomips` should be added in the `opcodes/disassemble.c` file.
 
Comparing with the patch v5, I can see you have deleted the file `include/elf/mips-common.h`
and moved its main contents to `include/elf/nanomips.h`. This should be fine, 
but in my opinion, the two FIXMEs in file `opcodes/nanomips-dis.c` should be kept:
"/* FIXME: These should be shared with gdb somehow. */" and
"/* FIXME: Should probably use a hash table on the major opcode here. */" 
as these behaviors were not fixed.

Thanks.
Tsing

>This series introduces a subset of nanoMIPS functionalities. It's a pre-requirement for nanoMIPS support for GDB/SIM.
>
>Almost complete series is a "green patch" - it adds things, so the probability of making regressions of existing functionalities is minimal.
>
>Compared to the previous series version (v5), there are no functional impacts but changes are split into smaller parts.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 1/3] BFD changes for nanoMIPS support
  2023-05-12 17:01     ` Aleksandar Rikalo
@ 2023-05-19 22:25       ` Maciej W. Rozycki
  0 siblings, 0 replies; 8+ messages in thread
From: Maciej W. Rozycki @ 2023-05-19 22:25 UTC (permalink / raw)
  To: Aleksandar Rikalo; +Cc: Hans-Peter Nilsson, binutils

On Fri, 12 May 2023, Aleksandar Rikalo wrote:

> > Random spotting: I see a "Written by ..." note at the top of
> > several files with a name not in the above co-authored-by list.
> > If the person quit, me thinks attribution in the list is still
> > in order.
> 
> Will be fixed. Thank You for noticing that.

 Right, Faraz was the big contributor to this port, and may well deserve 
to be named the author of the changes in this series (via a `From:' tag).

  Maciej

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2023-05-19 22:25 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-10 14:18 [PATCH v6 0/3] Add support for nanoMIPS architecture Aleksandar Rikalo
2023-05-10 14:18 ` [PATCH v6 1/3] BFD changes for nanoMIPS support Aleksandar Rikalo
2023-05-11  0:42   ` Hans-Peter Nilsson
2023-05-12 17:01     ` Aleksandar Rikalo
2023-05-19 22:25       ` Maciej W. Rozycki
2023-05-10 14:18 ` [PATCH v6 2/3] Opcodes " Aleksandar Rikalo
2023-05-10 14:18 ` [PATCH v6 3/3] Readelf for nanoMIPS Aleksandar Rikalo
2023-05-18 10:34 ` [PATCH v6 0/3] Add support for nanoMIPS architecture Tsing

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).