public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 1/3] bfd: Add support for nanoMIPS architecture
       [not found] <20220429155813.388328-1-aleksandar.rikalo@syrmia.com>
@ 2022-04-29 15:58 ` Aleksandar Rikalo
  2022-05-01 22:56   ` Maciej W. Rozycki
  2022-04-29 15:58 ` [PATCH 2/3] sim: Add nanoMIPS port Aleksandar Rikalo
  2022-04-29 15:58 ` [PATCH 3/3] gdb: " Aleksandar Rikalo
  2 siblings, 1 reply; 13+ messages in thread
From: Aleksandar Rikalo @ 2022-04-29 15:58 UTC (permalink / raw)
  To: gdb-patches

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       | 1558 ++++++++++++++++++++++++++++++++++++
 bfd/elfxx-mips.h           |    5 +
 bfd/elfxx-nanomips.c       |  825 +++++++++++++++++++
 bfd/elfxx-nanomips.h       |   54 ++
 bfd/libbfd.h               |   69 ++
 bfd/reloc.c                |  140 ++++
 bfd/targets.c              |   11 +
 binutils/readelf.c         |  523 ++++++++++++
 include/dis-asm.h          |   15 +
 include/elf/common.h       |    1 +
 include/elf/mips-common.h  |   41 +
 include/elf/nanomips.h     |  260 ++++++
 include/opcode/nanomips.h  | 1453 +++++++++++++++++++++++++++++++++
 opcodes/ChangeLog          |   17 +
 opcodes/Makefile.am        |    8 +
 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     | 1505 ++++++++++++++++++++++++++++++++++
 opcodes/nanomips-formats.h |  265 ++++++
 opcodes/nanomips-opc.c     | 1073 +++++++++++++++++++++++++
 33 files changed, 8054 insertions(+)
 create mode 100644 bfd/cpu-nanomips.c
 create mode 100644 bfd/elfnn-nanomips.c
 create mode 100644 bfd/elfxx-nanomips.c
 create mode 100644 bfd/elfxx-nanomips.h
 create mode 100644 include/elf/mips-common.h
 create mode 100644 include/elf/nanomips.h
 create mode 100644 include/opcode/nanomips.h
 create mode 100644 opcodes/nanomips-dis.c
 create mode 100644 opcodes/nanomips-formats.h
 create mode 100644 opcodes/nanomips-opc.c

diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index f2f70590e88..f2d951c2124 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 \
@@ -545,6 +546,7 @@ BFD64_BACKENDS = \
 	coff64-rs6000.lo \
 	elf32-ia64.lo \
 	elf32-mips.lo \
+	elf32-nanomips.lo \
 	elf32-score.lo \
 	elf32-score7.lo \
 	elf64-alpha.lo \
@@ -562,6 +564,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 \
@@ -602,6 +606,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 \
@@ -615,6 +620,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 \
@@ -681,6 +687,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
 
 CFILES = $(SOURCE_CFILES) $(BUILD_CFILES)
@@ -898,6 +905,18 @@ pe-aarch64igen.c: peXXigen.c
 	$(AM_V_at)echo "#line 1 \"peXXigen.c\"" > $@
 	$(AM_V_GEN)$(SED) -e s/XX/peAArch64/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 3068560c48b..2e30994c6f2 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -609,6 +609,7 @@ ALL_MACHINES = \
 	cpu-moxie.lo \
 	cpu-msp430.lo \
 	cpu-mt.lo \
+	cpu-nanomips.lo \
 	cpu-nds32.lo \
 	cpu-nfp.lo \
 	cpu-nios2.lo \
@@ -1014,6 +1015,7 @@ BFD64_BACKENDS = \
 	coff64-rs6000.lo \
 	elf32-ia64.lo \
 	elf32-mips.lo \
+	elf32-nanomips.lo \
 	elf32-score.lo \
 	elf32-score7.lo \
 	elf64-alpha.lo \
@@ -1031,6 +1033,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 \
@@ -1071,6 +1075,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 \
@@ -1084,6 +1089,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 \
@@ -1149,6 +1155,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
 
 CFILES = $(SOURCE_CFILES) $(BUILD_CFILES)
@@ -1614,6 +1621,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@
@@ -1655,6 +1663,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@
@@ -1668,6 +1677,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@
@@ -2413,6 +2423,18 @@ pe-aarch64igen.c: peXXigen.c
 	$(AM_V_at)echo "#line 1 \"peXXigen.c\"" > $@
 	$(AM_V_GEN)$(SED) -e s/XX/peAArch64/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 bcd2b1cf48b..fa806db0afd 100644
--- a/bfd/archures.c
+++ b/bfd/archures.c
@@ -566,6 +566,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
 .  };
 */
@@ -666,6 +669,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;
@@ -755,6 +759,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 50e26fc691d..eab3afdbde7 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -1927,6 +1927,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
   };
 
@@ -2664,6 +2667,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 5a690742eb3..8b73021f90b 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -206,6 +206,7 @@ m68*)		 targ_archs=bfd_m68k_arch ;;
 s12z*)         targ_archs=bfd_s12z_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 ;;
 nfp)		 targ_archs=bfd_nfp_arch ;;
 nios2*)          targ_archs=bfd_nios2_arch ;;
@@ -1002,6 +1003,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 ee2bbe69c87..9bcac2eff58 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -13509,6 +13509,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 8004c3ef4bf..085054b262b 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -582,6 +582,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..2ee15cf1f35
--- /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 c7c0a793b15..3b7101a41e4 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -520,6 +520,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..ac3d143b27e
--- /dev/null
+++ b/bfd/elfnn-nanomips.c
@@ -0,0 +1,1558 @@
+/* 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;
+}
+\f
+/* 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);
+}
+\f
+/* 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_mips_mach (elf_elfheader (abfd)->e_flags);
+  bfd_default_set_arch_mach (abfd, bfd_arch_nanomips, mach);
+  return true;
+}
+\f
+#if ARCH_SIZE == 32
+# define PRSTATUS_SIZE			256
+# define PRSTATUS_OFFSET_PR_CURSIG	12
+# define PRSTATUS_OFFSET_PR_PID		24
+# define PRSTATUS_OFFSET_PR_REG		72
+# define ELF_GREGSET_T_SIZE		180
+# define PRPSINFO_SIZE			128
+# define PRPSINFO_OFFSET_PR_PID		16
+# define PRPSINFO_OFFSET_PR_FNAME	32
+# define PRPSINFO_OFFSET_PR_PSARGS	48
+#else
+# define PRSTATUS_SIZE			480
+# define PRSTATUS_OFFSET_PR_CURSIG	12
+# define PRSTATUS_OFFSET_PR_PID		32
+# define PRSTATUS_OFFSET_PR_REG		112
+# define ELF_GREGSET_T_SIZE		360
+# define PRPSINFO_SIZE			136
+# define PRPSINFO_OFFSET_PR_PID		24
+# define PRPSINFO_OFFSET_PR_FNAME	40
+# define PRPSINFO_OFFSET_PR_PSARGS	56
+#endif
+
+static bool
+nanomips_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
+{
+  size_t size;
+  int offset;
+
+  switch (note->descsz)
+    {
+    default:
+      return false;
+
+    case PRSTATUS_SIZE: /* sizeof(struct elf_prstatus) on Linux/nanoMIPS.  */
+      /* pr_cursig */
+      elf_tdata (abfd)->core->signal
+	= bfd_get_16 (abfd, note->descdata + PRSTATUS_OFFSET_PR_CURSIG);
+
+      /* pr_pid */
+      elf_tdata (abfd)->core->lwpid
+	= bfd_get_32 (abfd, note->descdata + PRSTATUS_OFFSET_PR_PID);
+
+      /* pr_reg */
+      offset = PRSTATUS_OFFSET_PR_REG;
+      size = ELF_GREGSET_T_SIZE;
+      break;
+    }
+
+  /* Make a ".reg/999" section.  */
+  return _bfd_elfcore_make_pseudosection (abfd, ".reg", size,
+					  note->descpos + offset);
+}
+
+static bool
+nanomips_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
+{
+  switch (note->descsz)
+    {
+    default:
+      return false;
+
+    case PRPSINFO_SIZE: /* sizeof(struct elf_prpsinfo) on Linux/nanoMIPS.  */
+      /* pr_pid */
+      elf_tdata (abfd)->core->pid
+	= bfd_get_32 (abfd, note->descdata + PRPSINFO_OFFSET_PR_PID);
+
+      /* pr_fname */
+      elf_tdata (abfd)->core->program = _bfd_elfcore_strndup
+	(abfd, note->descdata + PRPSINFO_OFFSET_PR_FNAME, 16);
+
+      /* pr_psargs */
+      elf_tdata (abfd)->core->command = _bfd_elfcore_strndup
+	(abfd, note->descdata + PRPSINFO_OFFSET_PR_PSARGS, 80);
+      break;
+    }
+
+  /* Note that for some reason, a spurious space is tacked
+     onto the end of the args in some (at least one anyway)
+     implementations, so strip it off if it exists.  */
+
+  {
+    char *command = elf_tdata (abfd)->core->command;
+    int n = strlen (command);
+
+    if (0 < n && command[n - 1] == ' ')
+      command[n - 1] = '\0';
+  }
+
+  return true;
+}
+
+/* Write Linux core PRSTATUS note into core file.  */
+
+static char *
+nanomips_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type,
+			      ...)
+{
+  switch (note_type)
+    {
+    default:
+      return NULL;
+
+    case NT_PRPSINFO:
+      BFD_FAIL ();
+      return NULL;
+
+    case NT_PRSTATUS:
+      {
+        char data[PRSTATUS_SIZE];
+        va_list ap;
+        long pid;
+        int cursig;
+        const void *greg;
+
+        va_start (ap, note_type);
+        memset (data, 0, PRSTATUS_OFFSET_PR_REG);
+        pid = va_arg (ap, long);
+        bfd_put_32 (abfd, pid, data + PRSTATUS_OFFSET_PR_PID);
+        cursig = va_arg (ap, int);
+        bfd_put_16 (abfd, cursig, data + PRSTATUS_OFFSET_PR_CURSIG);
+        greg = va_arg (ap, const void *);
+        memcpy (data + PRSTATUS_OFFSET_PR_REG, greg, ELF_GREGSET_T_SIZE);
+        memset (data + PRSTATUS_OFFSET_PR_REG + ELF_GREGSET_T_SIZE, 0,
+		PRSTATUS_SIZE - (PRSTATUS_OFFSET_PR_REG + ELF_GREGSET_T_SIZE));
+        va_end (ap);
+        return elfcore_write_note (abfd, buf, bufsiz,
+                                   "CORE", note_type, data, sizeof (data));
+      }
+    }
+}
+\f
+
+#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_grok_prstatus	nanomips_elf_grok_prstatus
+#define elf_backend_grok_psinfo		nanomips_elf_grok_psinfo
+#define elf_backend_write_core_note	nanomips_elf_write_core_note
+
+#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 3be69524c01..1799686c954 100644
--- a/bfd/elfxx-mips.h
+++ b/bfd/elfxx-mips.h
@@ -50,6 +50,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
@@ -116,6 +118,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
@@ -146,6 +150,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..34ca23e32aa
--- /dev/null
+++ b/bfd/elfxx-nanomips.c
@@ -0,0 +1,825 @@
+/* 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)
+\f
+
+
+/* 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)
+\f
+
+/* 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);
+}
+\f
+
+
+/* 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;
+}
+\f
+
+/* 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);
+}
+\f
+
+/* Map flag bits to BFD architecture.  */
+
+unsigned long
+_bfd_elf_mips_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;
+}
+
+/* Return printable name for ABI.  */
+
+static inline char *
+elf_nanomips_abi_name (bfd *abfd)
+{
+  flagword flags;
+
+  flags = elf_elfheader (abfd)->e_flags;
+  switch (flags & EF_NANOMIPS_ABI)
+    {
+    case 0:
+      return "none";
+    case E_NANOMIPS_ABI_P32:
+      return "P32";
+    case E_NANOMIPS_ABI_P64:
+      return "P64";
+    default:
+      return "unknown abi";
+    }
+}
+\f
+
+/* 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;
+}
+\f
+
+/* 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);
+}
+\f
+
+/* 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..6d441842d6f
--- /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_mips_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 8c02e29eebd..201b18d5d4a 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1314,6 +1314,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 5098e0ab09f..9f3e9f01dfe 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2376,6 +2376,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 05dd8236d91..6914d2d2be9 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -823,6 +823,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;
@@ -1198,6 +1202,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 d45e0920788..9ba45bb2803 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"
@@ -1101,6 +1102,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:
@@ -1911,6 +1913,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;
@@ -2224,6 +2230,17 @@ get_mips_dynamic_type (unsigned long type)
     }
 }
 
+static const char *
+get_nanomips_dynamic_type (unsigned long type)
+{
+  switch (type)
+    {
+    case DT_NANOMIPS_GOTNO: return "NANOMIPS_GOTNO";
+    default:
+      return NULL;
+    }
+}
+
 static const char *
 get_sparc64_dynamic_type (unsigned long type)
 {
@@ -2589,6 +2606,8 @@ get_dynamic_type (Filedata * filedata, unsigned long type)
 	      break;
 	    case EM_RISCV:
 	      result = get_riscv_dynamic_type (type);
+	    case EM_NANOMIPS:
+	      result = get_nanomips_dynamic_type (type);
 	      break;
 	    default:
 	      if (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
@@ -2884,6 +2903,7 @@ get_machine_name (unsigned e_machine)
     case EM_ALTERA_NIOS2:	return "Altera Nios II";
     case EM_CRX:		return "National Semiconductor CRX microprocessor";
     case EM_XGATE:		return "Motorola XGATE embedded processor";
+    case EM_NANOMIPS:		return "Mips nanoMIPS";
     case EM_C166:
     case EM_XC16X:		return "Infineon Technologies xc16x";
     case EM_M16C:		return "Renesas M16C series microprocessors";
@@ -4409,6 +4429,38 @@ get_machine_flags (Filedata * filedata, unsigned e_flags, unsigned e_machine)
 	    strcat (buf, ", DOUBLE-FLOAT");
 
 	  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;
 	}
     }
 
@@ -4536,6 +4588,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)
 {
@@ -4687,6 +4753,8 @@ get_segment_type (Filedata * filedata, unsigned long p_type)
 	    case EM_S390:
 	    case EM_S390_OLD:
 	      result = get_s390_segment_type (p_type);
+	    case EM_NANOMIPS:
+	      result = get_nanomips_segment_type (p_type);
 	      break;
 	    case EM_RISCV:
 	      result = get_riscv_segment_type (p_type);
@@ -10646,6 +10714,21 @@ 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)
+    {
+    case DT_NANOMIPS_GOTNO:
+      print_vma (entry->d_un.d_ptr, DEC);
+      break;
+
+    default:
+      print_vma (entry->d_un.d_ptr, PREFIX_HEX);
+    }
+    putchar ('\n');
+}
+
 static void
 dynamic_section_parisc_val (Elf_Internal_Dyn * entry)
 {
@@ -11989,6 +12072,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');
@@ -14271,6 +14357,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:
@@ -14476,6 +14564,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;
     }
@@ -14583,6 +14673,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:
@@ -14815,6 +14907,8 @@ 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.  */
+      return reloc_type == 0;
     case EM_PARISC:  /* R_PARISC_NONE.  */
     case EM_PPC64:   /* R_PPC64_NONE.  */
     case EM_PPC:     /* R_PPC_NONE.  */
@@ -17311,6 +17405,75 @@ 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,
+          int tag,
+          const unsigned char * const end)
+{
+  if (tag == Tag_GNU_NANOMIPS_ABI_FP)
+    {
+      unsigned int len;
+      int val;
+
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_GNU_NANOMIPS_ABI_FP: ");
+
+      print_nanomips_fp_abi_value (val);
+
+      return p;
+   }
+
+  if (tag == Tag_GNU_NANOMIPS_ABI_MSA)
+    {
+      unsigned int len;
+      int val;
+
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      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 ("??? (%d)\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)
@@ -19147,6 +19310,364 @@ 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_XPA)
+    fputs ("\n\tXPA 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 int
+process_nanomips_specific (FILE * file)
+{
+  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 (file, NULL, SHT_GNU_ATTRIBUTES, NULL,
+          display_nanomips_gnu_attribute);
+
+  sect = find_section (".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, file, 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 (dynamic_section == NULL)
+    /* No information available.  */
+    return 0;
+
+  for (entry = dynamic_section;
+       entry < dynamic_section + dynamic_nent && entry->d_tag != DT_NULL;
+       ++entry)
+    switch (entry->d_tag)
+      {
+      case DT_PLTGOT:
+  pltgot = entry->d_un.d_ptr;
+  break;
+      case DT_NANOMIPS_GOTNO:
+  symtabno = entry->d_un.d_val;
+  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 = section_headers;
+
+      /* Find the section header so that we get the size.  */
+      sect = find_section_by_type (SHT_MIPS_OPTIONS);
+      /* PR 17533 file: 012-277276-0.004.  */
+      if (sect == NULL)
+  {
+    error (_("No MIPS_OPTIONS header found\n"));
+    return 0;
+  }
+
+      eopt = (Elf_External_Options *) get_data (NULL, file, 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 (sect), cnt);
+
+    option = iopt;
+
+    while (cnt-- > 0)
+      {
+        size_t len;
+
+        switch (option->kind)
+    {
+    case ODK_NULL:
+      /* This shouldn't happen.  */
+      printf (" NULL       %d %lx", 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  %#06lx  self-contained %#06lx",
+        option->info & OGP_GROUP,
+        (option->info & OGP_SELF) >> 16);
+      break;
+    case ODK_IDENT:
+      printf (" IDENT     %#06lx  self-contained %#06lx",
+        option->info & OGP_GROUP,
+        (option->info & OGP_SELF) >> 16);
+      break;
+    default:
+      /* This shouldn't happen.  */
+      printf (" %3d ???     %d %lx",
+        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 (file, pltgot, end - pltgot);
+      data = (unsigned char *) get_data (NULL, file, 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);
+      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);
+    printf (_(" Module pointer (GNU extension)\n"));
+  }
+      printf ("\n");
+
+      printf ("\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);
+    printf (" ");
+
+    printf ("\n");
+  }
+
+      if (data)
+  free (data);
+    }
+
+  return 1;
+}
+
 static bool
 process_nds32_specific (Filedata * filedata)
 {
@@ -22027,6 +22548,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 (file);
 
     case EM_CSKY:
       return process_attributes (filedata, "csky", SHT_CSKY_ATTRIBUTES,
diff --git a/include/dis-asm.h b/include/dis-asm.h
index 4f91df12498..17f0a644e84 100644
--- a/include/dis-asm.h
+++ b/include/dis-asm.h
@@ -300,6 +300,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
@@ -358,6 +363,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 *);
@@ -372,6 +378,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 *);
@@ -467,6 +474,14 @@ 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 *);
+
+extern int nanomips_predict_insn_length (bfd_vma memaddr_base,
+   int previous_octect ATTRIBUTE_UNUSED,
+   struct disassemble_info *info);
+
 /* Method to initialize a disassemble_info struct.  This should be
    called by all applications creating such a struct.  */
 extern void init_disassemble_info (struct disassemble_info *dinfo, void *stream,
diff --git a/include/elf/common.h b/include/elf/common.h
index e4bc53e35b4..8a98dd81630 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -346,6 +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_NANOMIPS  249   /* MIPS Tech nanoMIPS architecture.  */
 #define EM_IMG1		249	/* Imagination Technologies */
 #define EM_NFP		250	/* Netronome Flow Processor.  */
 #define EM_VE		251	/* NEC Vector Engine */
diff --git a/include/elf/mips-common.h b/include/elf/mips-common.h
new file mode 100644
index 00000000000..1d941fa9f2d
--- /dev/null
+++ b/include/elf/mips-common.h
@@ -0,0 +1,41 @@
+/* MIPS ELF support for BFD.
+   Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* This file holds definitions common to the MIPS and nanoMIPS ELF ABIs.  */
+
+#ifndef _ELF_MIPS_COMMON_H
+#define _ELF_MIPS_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Values for the xxx_size bytes of an ABI flags structure.  */
+
+#define AFL_REG_NONE	     0x00	/* No registers.  */
+#define AFL_REG_32	     0x01	/* 32-bit registers.  */
+#define AFL_REG_64	     0x02	/* 64-bit registers.  */
+#define AFL_REG_128	     0x03	/* 128-bit registers.  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ELF_MIPS_COMMON_H */
diff --git a/include/elf/nanomips.h b/include/elf/nanomips.h
new file mode 100644
index 00000000000..82d081c04f8
--- /dev/null
+++ b/include/elf/nanomips.h
@@ -0,0 +1,260 @@
+/* nanoMIPS ELF support for BFD.
+   Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+   Written by Faraz Shahbazker <faraz.shahbazker@mips.com>
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* This file holds definitions specific to the nanoMIPS ELF ABI.  */
+
+#ifndef _ELF_NANOMIPS_H
+#define _ELF_NANOMIPS_H
+
+#include "elf/reloc-macros.h"
+#include "elf/mips.h"
+#include "elf/mips-common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+START_RELOC_NUMBERS (elf_nanomips_reloc_type)
+  RELOC_NUMBER (R_NANOMIPS_NONE, 0)
+  RELOC_NUMBER (R_NANOMIPS_32, 1)
+  RELOC_NUMBER (R_NANOMIPS_64, 2)
+  RELOC_NUMBER (R_NANOMIPS_NEG, 3)
+  RELOC_NUMBER (R_NANOMIPS_ASHIFTR_1, 4)
+  RELOC_NUMBER (R_NANOMIPS_UNSIGNED_8, 5)
+  RELOC_NUMBER (R_NANOMIPS_SIGNED_8, 6)
+  RELOC_NUMBER (R_NANOMIPS_UNSIGNED_16, 7)
+  RELOC_NUMBER (R_NANOMIPS_SIGNED_16, 8)
+  RELOC_NUMBER (R_NANOMIPS_RELATIVE, 9)
+  RELOC_NUMBER (R_NANOMIPS_GLOBAL, 10)
+  RELOC_NUMBER (R_NANOMIPS_JUMP_SLOT, 11)
+  RELOC_NUMBER (R_NANOMIPS_IRELATIVE, 12)
+
+  RELOC_NUMBER (R_NANOMIPS_PC25_S1, 13)
+  RELOC_NUMBER (R_NANOMIPS_PC21_S1, 14)
+  RELOC_NUMBER (R_NANOMIPS_PC14_S1, 15)
+  RELOC_NUMBER (R_NANOMIPS_PC11_S1, 16)
+  RELOC_NUMBER (R_NANOMIPS_PC10_S1, 17)
+  RELOC_NUMBER (R_NANOMIPS_PC7_S1, 18)
+  RELOC_NUMBER (R_NANOMIPS_PC4_S1, 19)
+
+  RELOC_NUMBER (R_NANOMIPS_GPREL19_S2, 20)
+  RELOC_NUMBER (R_NANOMIPS_GPREL18_S3, 21)
+  RELOC_NUMBER (R_NANOMIPS_GPREL18, 22)
+  RELOC_NUMBER (R_NANOMIPS_GPREL17_S1, 23)
+  RELOC_NUMBER (R_NANOMIPS_GPREL16_S2, 24)
+  RELOC_NUMBER (R_NANOMIPS_GPREL7_S2, 25)
+  RELOC_NUMBER (R_NANOMIPS_GPREL_HI20, 26)
+  RELOC_NUMBER (R_NANOMIPS_PCHI20, 27)
+
+  RELOC_NUMBER (R_NANOMIPS_HI20, 28)
+  RELOC_NUMBER (R_NANOMIPS_LO12, 29)
+  RELOC_NUMBER (R_NANOMIPS_GPREL_I32, 30)
+  RELOC_NUMBER (R_NANOMIPS_PC_I32, 31)
+  RELOC_NUMBER (R_NANOMIPS_I32, 32)
+  RELOC_NUMBER (R_NANOMIPS_GOT_DISP, 33)
+  RELOC_NUMBER (R_NANOMIPS_GOTPC_I32, 34)
+  RELOC_NUMBER (R_NANOMIPS_GOTPC_HI20, 35)
+  RELOC_NUMBER (R_NANOMIPS_GOT_LO12, 36)
+  RELOC_NUMBER (R_NANOMIPS_GOT_CALL, 37)
+  RELOC_NUMBER (R_NANOMIPS_GOT_PAGE, 38)
+  RELOC_NUMBER (R_NANOMIPS_GOT_OFST, 39)
+  RELOC_NUMBER (R_NANOMIPS_LO4_S2, 40)
+  /* Reserved for 64-bit ABI. */
+  RELOC_NUMBER (R_NANOMIPS_RESERVED1, 41)
+  RELOC_NUMBER (R_NANOMIPS_GPREL_LO12, 42)
+  RELOC_NUMBER (R_NANOMIPS_SCN_DISP, 43)
+  RELOC_NUMBER (R_NANOMIPS_COPY, 44)
+
+  RELOC_NUMBER (R_NANOMIPS_ALIGN, 64)
+  RELOC_NUMBER (R_NANOMIPS_FILL, 65)
+  RELOC_NUMBER (R_NANOMIPS_MAX, 66)
+  RELOC_NUMBER (R_NANOMIPS_INSN32, 67)
+  RELOC_NUMBER (R_NANOMIPS_FIXED, 68)
+  RELOC_NUMBER (R_NANOMIPS_NORELAX, 69)
+  RELOC_NUMBER (R_NANOMIPS_RELAX, 70)
+  RELOC_NUMBER (R_NANOMIPS_SAVERESTORE, 71)
+  RELOC_NUMBER (R_NANOMIPS_INSN16, 72)
+  RELOC_NUMBER (R_NANOMIPS_JALR32, 73)
+  RELOC_NUMBER (R_NANOMIPS_JALR16, 74)
+  RELOC_NUMBER (R_NANOMIPS_JUMPTABLE_LOAD, 75)
+  RELOC_NUMBER (R_NANOMIPS_FRAME_REG, 76)
+
+  /* TLS relocations.  */
+  RELOC_NUMBER (R_NANOMIPS_TLS_DTPMOD, 80)
+  RELOC_NUMBER (R_NANOMIPS_TLS_DTPREL, 81)
+  RELOC_NUMBER (R_NANOMIPS_TLS_TPREL, 82)
+  RELOC_NUMBER (R_NANOMIPS_TLS_GD, 83)
+  RELOC_NUMBER (R_NANOMIPS_TLS_GD_I32, 84)
+  RELOC_NUMBER (R_NANOMIPS_TLS_LD, 85)
+  RELOC_NUMBER (R_NANOMIPS_TLS_LD_I32, 86)
+  RELOC_NUMBER (R_NANOMIPS_TLS_DTPREL12, 87)
+  RELOC_NUMBER (R_NANOMIPS_TLS_DTPREL16, 88)
+  RELOC_NUMBER (R_NANOMIPS_TLS_DTPREL_I32, 89)
+  RELOC_NUMBER (R_NANOMIPS_TLS_GOTTPREL, 90)
+  RELOC_NUMBER (R_NANOMIPS_TLS_GOTTPREL_PC_I32, 91)
+  RELOC_NUMBER (R_NANOMIPS_TLS_TPREL12, 92)
+  RELOC_NUMBER (R_NANOMIPS_TLS_TPREL16, 93)
+  RELOC_NUMBER (R_NANOMIPS_TLS_TPREL_I32, 94)
+
+  FAKE_RELOC (R_NANOMIPS_max, 94)
+  /* May be used for compact unwind tables in the future.  */
+  RELOC_NUMBER (R_NANOMIPS_PC32, 248)
+  RELOC_NUMBER (R_NANOMIPS_EH, 249)
+  /* These are GNU extensions to enable C++ vtable garbage collection.  */
+  RELOC_NUMBER (R_NANOMIPS_GNU_VTINHERIT, 253)
+  RELOC_NUMBER (R_NANOMIPS_GNU_VTENTRY, 254)
+END_RELOC_NUMBERS (R_NANOMIPS_maxext)
+
+/* Processor specific flags for the ELF header e_flags field.  */
+
+/* File may be relaxed by the linker.  */
+#define EF_NANOMIPS_LINKRELAX	0x00000001
+
+/* File contains position independent code.  */
+#define EF_NANOMIPS_PIC		0x00000002
+
+/* Indicates code compiled for a 64-bit machine in 32-bit mode
+   (regs are 32-bits wide).  */
+#define EF_NANOMIPS_32BITMODE	0x00000004
+
+/* File contains position independent code.  */
+#define EF_NANOMIPS_PID		0x00000008
+
+/* File contains pure PC-relative code.  */
+#define EF_NANOMIPS_PCREL	0x00000010
+
+/* Four bit nanoMIPS architecture field.  */
+#define EF_NANOMIPS_ARCH	0xf0000000
+
+/* -march=32r6[s] code.  */
+#define E_NANOMIPS_ARCH_32R6    0x00000000
+
+/* -march=64r6 code.  */
+#define E_NANOMIPS_ARCH_64R6    0x10000000
+
+/* The ABI of the file.  */
+#define EF_NANOMIPS_ABI		0x0000F000
+
+/* nanoMIPS ABI in 32 bit mode.  */
+#define E_NANOMIPS_ABI_P32      0x00001000
+
+/* nanoMIPS ABI in 64 bit mode.  */
+#define E_NANOMIPS_ABI_P64      0x00002000
+
+/* Machine variant if we know it.  This field was invented at Cygnus
+   for MIPS.  It may be used similarly for nanoMIPS.  */
+
+#define EF_NANOMIPS_MACH	0x00FF0000
+
+\f
+/* Processor specific section types.  */
+
+/* ABI related flags section.  */
+#define SHT_NANOMIPS_ABIFLAGS	0x70000000
+
+\f
+/* Processor specific program header types.  */
+
+/* Records ABI related flags.  */
+#define PT_NANOMIPS_ABIFLAGS	0x70000000
+
+\f
+
+/* Object attribute tags.  */
+enum
+{
+  /* 0-3 are generic.  */
+
+  /* Floating-point ABI used by this object file.  */
+  Tag_GNU_NANOMIPS_ABI_FP = 4,
+
+  /* MSA ABI used by this object file.  */
+  Tag_GNU_NANOMIPS_ABI_MSA = 8,
+};
+
+/* Object attribute values.  */
+enum
+{
+  /* Values defined for Tag_GNU_NANOMIPS_ABI_FP.  */
+
+  /* Not tagged or not using any ABIs affected by the differences.  */
+  Val_GNU_NANOMIPS_ABI_FP_ANY = 0,
+
+  /* Using hard-float -mdouble-float.  */
+  Val_GNU_NANOMIPS_ABI_FP_DOUBLE = 1,
+
+  /* Using hard-float -msingle-float.  */
+  Val_GNU_NANOMIPS_ABI_FP_SINGLE = 2,
+
+  /* Using soft-float.  */
+  Val_GNU_NANOMIPS_ABI_FP_SOFT = 3,
+
+  /* Not tagged or not using any ABIs affected by the differences.  */
+  Val_GNU_NANOMIPS_ABI_MSA_ANY = 0,
+
+  /* Using 128-bit MSA.  */
+  Val_GNU_NANOMIPS_ABI_MSA_128 = 1,
+};
+
+/* Masks for the ases word of an ABI flags structure.
+
+   Unfortunate decisions in early development transitioning from MIPS
+   to nanoMIPS, left this horifically fragmented.  Bits marked as
+   UNUSED may be cannibalized for future ASEs;  bits marked as RESERVED
+   are intended to remain blocked.  If MIPS history is anything to go
+   by, nanoMIPS will eventually spawn enough ASEs to fill up the gaps!
+*/
+
+#define NANOMIPS_ASE_TLB          0x00000001 /* TLB control ASE.  */
+#define NANOMIPS_ASE_UNUSED1      0x00000002 /* was DSP R2 ASE.  */
+#define NANOMIPS_ASE_EVA          0x00000004 /* Enhanced VA Scheme.  */
+#define NANOMIPS_ASE_MCU          0x00000008 /* MCU (MicroController) ASE.  */
+#define NANOMIPS_ASE_UNUSED2      0x00000010 /* was MDMX ASE.  */
+#define NANOMIPS_ASE_UNUSED3      0x00000020 /* was MIPS-3D ASE.  */
+#define NANOMIPS_ASE_MT           0x00000040 /* MT ASE.  */
+#define NANOMIPS_ASE_UNUSED4      0x00000080 /* was SmartMIPS ASE.  */
+#define NANOMIPS_ASE_VIRT         0x00000100 /* VZ ASE.  */
+#define NANOMIPS_ASE_MSA          0x00000200 /* MSA ASE.  */
+#define NANOMIPS_ASE_RESERVED1    0x00000400 /* was MIPS16 ASE.  */
+#define NANOMIPS_ASE_RESERVED2    0x00000800 /* was MICROMIPS ASE.  */
+#define NANOMIPS_ASE_UNUSED6      0x00001000 /* was XPA.  */
+#define NANOMIPS_ASE_DSPR3        0x00002000 /* DSP R3 ASE.  */
+#define NANOMIPS_ASE_UNUSED5      0x00004000 /* was MIPS16 E2 Extension.  */
+#define NANOMIPS_ASE_CRC          0x00008000 /* CRC extension.  */
+#define NANOMIPS_ASE_CRYPTO       0x00010000 /* Cryptography extension.  */
+#define NANOMIPS_ASE_GINV         0x00020000 /* GINV ASE.  */
+#define NANOMIPS_ASE_xNMS         0x00040000 /* not nanoMIPS Subset.  */
+#define NANOMIPS_ASE_MASK         0x0007af4d /* All valid ASEs.  */
+
+/* nanoMIPS ELF flags routines.  */
+extern Elf_Internal_ABIFlags_v0 * bfd_nanomips_elf_get_abiflags (bfd *);
+
+extern void bfd_nanomips_elf_swap_abiflags_v0_in
+  (bfd *, const Elf_External_ABIFlags_v0 *, Elf_Internal_ABIFlags_v0 *);
+extern void bfd_nanomips_elf_swap_abiflags_v0_out
+  (bfd *, const Elf_Internal_ABIFlags_v0 *, Elf_External_ABIFlags_v0 *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ELF_NANOMIPS_H */
diff --git a/include/opcode/nanomips.h b/include/opcode/nanomips.h
new file mode 100644
index 00000000000..d77120e244d
--- /dev/null
+++ b/include/opcode/nanomips.h
@@ -0,0 +1,1453 @@
+/* nanomips.h.  nanoMIPS opcode list for GDB, the GNU debugger.
+   Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+   Written by Faraz Shahbazker <faraz.shahbazker@mips.com>
+
+   This file is part of GDB, GAS, and the GNU binutils.
+
+   GDB, GAS, and the GNU binutils are free software; you can redistribute
+   them and/or modify them under the terms of the GNU General Public
+   License as published by the Free Software Foundation; either version 3,
+   or (at your option) any later version.
+
+   GDB, GAS, and the GNU binutils are distributed in the hope that they
+   will be useful, but WITHOUT ANY WARRANTY; without even the implied
+   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+   the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING3.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#ifndef _NANOMIPS_H_
+#define _NANOMIPS_H_
+
+#include "bfd.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Enumerates the various types of nanoMIPS operand.  */
+enum nanomips_operand_type {
+  /* Described by nanomips_int_operand.  */
+  OP_INT,
+
+  /* Described by nanomips_mapped_int_operand.  */
+  OP_MAPPED_INT,
+
+  /* Described by nanomips_msb_operand.  */
+  OP_MSB,
+
+  /* Described by nanomips_reg_operand.  */
+  OP_REG,
+
+  /* Like OP_REG, but can be omitted if the register is the same as the
+     previous operand.  */
+  OP_OPTIONAL_REG,
+
+  /* Described by nanomips_reg_pair_operand.  */
+  OP_REG_PAIR,
+
+  /* Described by nanomips_pcrel_operand.  */
+  OP_PCREL,
+
+  /* The register list and frame size for a MIPS16 SAVE or RESTORE
+     instruction.  */
+  OP_SAVE_RESTORE_LIST,
+
+  /* A register operand that must match the destination register.  */
+  OP_REPEAT_DEST_REG,
+
+  /* A register operand that must match the previous register.  */
+  OP_REPEAT_PREV_REG,
+
+  /* Described by nanomips_prev_operand.  */
+  OP_CHECK_PREV,
+
+  /* A register operand that must not be zero.  */
+  OP_NON_ZERO_REG,
+
+ /* The floating-point register list for a nanoMIPS SAVE or RESTORE
+     instruction. */
+  OP_SAVE_RESTORE_FP_LIST,
+
+  /* Fractured upper immediate PC-offset for nanoMIPS */
+  OP_HI20_PCREL,
+
+  /* Fractured upper immediate 20-bit signed integer for nanoMIPS */
+  OP_HI20_INT,
+
+  /* Fractured upper immediate 20-bit scaled integer for nanoMIPS */
+  OP_HI20_SCALE,
+
+  /* A non-zero PC-relative offset.  */
+  OP_NON_ZERO_PCREL_S1,
+
+  /* To check a mapped register against a previous operand.  */
+  OP_MAPPED_CHECK_PREV,
+
+  /* Unsigned word operand.  */
+  OP_UINT_WORD,
+
+  /* Signed word operand.  */
+  OP_INT_WORD,
+
+  /* Immediate PC-relative word operand.  */
+  OP_PC_WORD,
+
+  /* Immediate GP-relative word operand.  */
+  OP_GPREL_WORD,
+
+  /* Don't care bits.  */
+  OP_DONT_CARE,
+
+  /* Immediate unsigned word operand, to be negated.  */
+  OP_NEG_INT,
+
+  /* Immediate (non-relocatable) integer operand.  */
+  OP_IMM_INT,
+
+  /* Immediate (non-relocatable) word operand.  */
+  OP_IMM_WORD,
+
+  /* Base register for limited types of offsets.  */
+  OP_BASE_CHECK_OFFSET,
+
+  /* Copy over bits from another part of instruction.  */
+  OP_COPY_BITS,
+
+  /* Select bits for a COP0 register.  */
+  OP_CP0SEL,
+};
+
+/* Enumerates the types of nanoMIPS register.  */
+enum nanomips_reg_operand_type {
+  /* General registers $0-$31.  Software names like $at can also be used.  */
+  OP_REG_GP,
+
+  /* Floating-point registers $f0-$f31.  */
+  OP_REG_FP,
+
+  /* DSP accumulator registers $ac0-$ac3.  */
+  OP_REG_ACC,
+
+  /* Coprocessor registers in numeric format, $0-$31.  */
+  OP_REG_COPRO,
+
+  /* Hardware registers $0-$31.  Mnemonic names like hwr_cpunum can
+     also be used in some contexts.  */
+  OP_REG_HW,
+
+  /* MSA registers $w0-$w31.  */
+  OP_REG_MSA,
+
+  /* MSA control registers $0-$31.  */
+  OP_REG_MSA_CTRL,
+
+  /* Co-processor 0 named registers.  */
+  OP_REG_CP0,
+
+  /* Co-processor 0 named registers with select.  */
+  OP_REG_CP0SEL,
+
+  /* Co-processor 0 named registers with select.  */
+  OP_REG_HWRSEL
+};
+
+/* Base class for all operands.  */
+struct nanomips_operand
+{
+  /* The type of the operand.  */
+  enum nanomips_operand_type type;
+
+  /* The operand occupies SIZE bits of the instruction, starting at LSB.  */
+  unsigned short size;
+  unsigned short lsb;
+
+  /* These are used to split a value across two different
+     parts of the instruction encoding.  */
+  unsigned int size_top;
+  unsigned int lsb_top;
+};
+
+/* Describes an integer operand with a regular encoding pattern.  */
+struct nanomips_int_operand
+{
+  struct nanomips_operand root;
+
+  /* The low ROOT.SIZE bits of MAX_VAL encodes (MAX_VAL + BIAS) << SHIFT.
+     The cyclically previous field value encodes 1 << SHIFT less than that,
+     and so on.  E.g.
+
+     - for { { T, 4, L }, 14, 0, 0 }, field values 0...14 encode themselves,
+       but 15 encodes -1.
+
+     - { { T, 8, L }, 127, 0, 2 } is a normal signed 8-bit operand that is
+       shifted left two places.
+
+     - { { T, 3, L }, 8, 0, 0 } is a normal unsigned 3-bit operand except
+       that 0 encodes 8.
+
+     - { { ... }, 0, 1, 3 } means that N encodes (N + 1) << 3.  */
+  unsigned int max_val;
+  int bias;
+  unsigned int shift;
+
+  /* True if the operand should be printed as hex rather than decimal.  */
+  bool print_hex;
+};
+
+/* Uses a lookup table to describe a small integer operand.  */
+struct nanomips_mapped_int_operand
+{
+  struct nanomips_operand root;
+
+  /* Maps each encoding value to the integer that it represents.  */
+  const int *int_map;
+
+  /* True if the operand should be printed as hex rather than decimal.  */
+  bool print_hex;
+};
+
+/* An operand that encodes the most significant bit position of a bitfield.
+   Given a bitfield that spans bits [MSB, LSB], some operands of this type
+   encode MSB directly while others encode MSB - LSB.  Each operand of this
+   type is preceded by an integer operand that specifies LSB.
+
+   The assembly form varies between instructions.  For some instructions,
+   such as EXT, the operand is written as the bitfield size.  For others,
+   such as EXTS, it is written in raw MSB - LSB form.  */
+struct nanomips_msb_operand
+{
+  struct nanomips_operand root;
+
+  /* The assembly-level operand encoded by a field value of 0.  */
+  int bias;
+
+  /* True if the operand encodes MSB directly, false if it encodes
+     MSB - LSB.  */
+  bool add_lsb;
+
+  /* The maximum value of MSB + 1.  */
+  unsigned int opsize;
+};
+
+/* Describes a single register operand.  */
+struct nanomips_reg_operand
+{
+  struct nanomips_operand root;
+
+  /* The type of register.  */
+  enum nanomips_reg_operand_type reg_type;
+
+  /* If nonnull, REG_MAP[N] gives the register associated with encoding N,
+     otherwise the encoding is the same as the register number.  */
+  const unsigned char *reg_map;
+};
+
+/* Describes an operand that which must match a condition based on the
+   previous operand.  */
+struct nanomips_check_prev_operand
+{
+  struct nanomips_operand root;
+
+  bool greater_than_ok;
+  bool less_than_ok;
+  bool equal_ok;
+  bool zero_ok;
+};
+
+/* Describes an operand that encodes a pair of registers.  */
+struct nanomips_reg_pair_operand
+{
+  struct nanomips_operand root;
+
+  /* The type of register.  */
+  enum nanomips_reg_operand_type reg_type;
+
+  /* Encoding N represents REG1_MAP[N], REG2_MAP[N].  */
+  unsigned char *reg1_map;
+  unsigned char *reg2_map;
+};
+
+/* Describes an operand that is calculated relative to a base PC.
+   The base PC is usually the address of the following instruction,
+   but the rules for MIPS16 instructions like ADDIUPC are more complicated.  */
+struct nanomips_pcrel_operand
+{
+  /* Encodes the offset.  */
+  struct nanomips_int_operand root;
+
+  /* The low ALIGN_LOG2 bits of the base PC are cleared to give PC',
+     which is then added to the offset encoded by ROOT.  */
+  unsigned int align_log2 : 8;
+
+  /* If INCLUDE_ISA_BIT, the ISA bit of the original base PC is then
+     reinstated.  This is true for jumps and branches and false for
+     PC-relative data instructions.  */
+  unsigned int include_isa_bit : 1;
+
+  /* If FLIP_ISA_BIT, the ISA bit of the result is inverted.
+     This is true for JALX and false otherwise.  */
+  unsigned int flip_isa_bit : 1;
+};
+
+/* This structure holds information for a particular instruction.  */
+
+struct nanomips_opcode
+{
+  /* The name of the instruction.  */
+  const char *name;
+  /* An optional suffix.  */
+  const char *suffix;
+  /* A string describing the arguments for this instruction.  */
+  const char *args;
+  /* The basic opcode for the instruction.  When assembling, this
+     opcode is modified by the arguments to produce the actual opcode
+     that is used.  If pinfo is INSN_MACRO, then this is 0.  */
+  unsigned long match;
+  /* If pinfo is not INSN_MACRO, then this is a bit mask for the
+     relevant portions of the opcode when disassembling.  If the
+     actual opcode anded with the match field equals the opcode field,
+     then we have found the correct instruction.  If pinfo is
+     INSN_MACRO, then this field is the macro identifier.  */
+  unsigned long mask;
+  /* For a macro, this is INSN_MACRO.  Otherwise, it is a collection
+     of bits describing the instruction, notably any relevant hazard
+     information.  */
+  unsigned long pinfo;
+  /* A collection of additional bits describing the instruction. */
+  unsigned long pinfo2;
+  /* A collection of bits describing the instruction sets of which this
+     instruction or macro is a member. */
+  unsigned long membership;
+  /* A collection of bits describing the ASE of which this instruction
+     or macro is a member.  */
+  unsigned long ase;
+};
+
+/* Return true if the assembly syntax allows OPERAND to be omitted.  */
+
+static inline bool
+nanomips_optional_operand_p (const struct nanomips_operand *operand)
+{
+  return (operand->type == OP_OPTIONAL_REG
+	  || operand->type == OP_REPEAT_PREV_REG
+	  || (operand->type != OP_INT
+	      && operand->size == 0
+	      && operand->lsb == 0));
+}
+
+/* Return a version of INSN in which the field specified by OPERAND
+   has value UVAL.  */
+
+static inline unsigned int
+nanomips_insert_operand (const struct nanomips_operand *operand,
+			 unsigned int insn, unsigned int uval)
+{
+  unsigned int mask;
+  unsigned int size_bottom = operand->size - operand->size_top;
+
+  mask = (1 << size_bottom) - 1;
+  insn &= ~(mask << operand->lsb);
+  insn |= (uval & mask) << operand->lsb;
+
+  mask = (1 << operand->size_top) - 1;
+  insn &= ~(mask << operand->lsb_top);
+  insn |= ((uval & (mask << size_bottom)) >> size_bottom) << operand->lsb_top;
+  return insn;
+}
+
+/* Extract OPERAND from instruction INSN.  */
+
+static inline unsigned int
+nanomips_extract_operand (const struct nanomips_operand *operand,
+			  unsigned int insn)
+{
+  unsigned int uval;
+  unsigned int size_bottom = operand->size - operand->size_top;
+
+  uval = (insn >> operand->lsb_top) & ((1 << operand->size_top) - 1);
+  uval <<= size_bottom;
+  uval |= (insn >> operand->lsb) & ((1 << size_bottom) - 1);
+  return uval;
+}
+
+/* UVAL is the value encoded by OPERAND.  Return it in signed form.  */
+
+static inline int
+nanomips_signed_operand (const struct nanomips_operand *operand,
+			 unsigned int uval)
+{
+  unsigned int sign_bit, mask;
+
+  mask = (1 << operand->size) - 1;
+  sign_bit = 1 << (operand->size - 1);
+  return ((uval + sign_bit) & mask) - sign_bit;
+}
+
+/* Return the integer that OPERAND encodes as UVAL.  */
+
+static inline int
+nanomips_decode_int_operand (const struct nanomips_int_operand *operand,
+			     unsigned int uval)
+{
+  uval |= (operand->max_val - uval) & -(1 << operand->root.size);
+  uval += operand->bias;
+  uval <<= operand->shift;
+  return uval;
+}
+
+/* Return the maximum value that can be encoded by OPERAND.  */
+
+static inline int
+nanomips_int_operand_max (const struct nanomips_int_operand *operand)
+{
+  return (operand->max_val + operand->bias) << operand->shift;
+}
+
+/* Return the minimum value that can be encoded by OPERAND.  */
+
+static inline int
+nanomips_int_operand_min (const struct nanomips_int_operand *operand)
+{
+  unsigned int mask;
+
+  mask = (1 << operand->root.size) - 1;
+  return nanomips_int_operand_max (operand) - (mask << operand->shift);
+}
+
+/* Return the register that OPERAND encodes as UVAL.  */
+
+static inline int
+nanomips_decode_reg_operand (const struct nanomips_reg_operand *operand,
+			     unsigned int uval)
+{
+  if (operand->reg_map)
+    uval = operand->reg_map[uval];
+  return uval;
+}
+
+/* PC-relative operand OPERAND has value UVAL and is relative to BASE_PC.
+   Return the address that it encodes.  */
+
+static inline bfd_vma
+nanomips_decode_pcrel_operand (const struct nanomips_pcrel_operand *operand,
+			       bfd_vma base_pc, unsigned int uval)
+{
+  bfd_vma addr;
+
+  addr = base_pc & -(1 << operand->align_log2);
+  addr += nanomips_decode_int_operand (&operand->root, uval);
+  if (operand->include_isa_bit)
+    addr |= base_pc & 1;
+  if (operand->flip_isa_bit)
+    addr ^= 1;
+  return addr;
+}
+
+/* Describes an operand that encapsulates a mapped register with
+   a check against the previous operand.  */
+struct nanomips_mapped_check_prev_operand
+{
+  struct nanomips_operand root;
+
+  enum nanomips_reg_operand_type reg_type;
+  const unsigned char *reg_map;
+
+  bool greater_than_ok;
+  bool less_than_ok;
+  bool equal_ok;
+  bool zero_ok;
+};
+
+/* Describes an operand that encapsulates a base register with
+   a check against the type of offset.  */
+struct nanomips_base_check_offset_operand
+{
+  struct nanomips_operand root;
+
+  enum nanomips_reg_operand_type reg_type;
+
+  bool const_ok;
+  bool expr_ok;
+};
+
+/* Return true if MO is an instruction that requires 32-bit encoding.  */
+
+static inline bool
+nanomips_opcode_32bit_p (const struct nanomips_opcode *mo)
+{
+  return mo->mask >> 16 != 0;
+}
+
+static inline int
+nanomips_operand_mask (const struct nanomips_operand *operand)
+{
+  unsigned int mask;
+
+  mask = ((1 << operand->size_top) - 1) << operand->lsb_top;
+  mask |= ((1 << (operand->size - operand->size_top)) - 1) << operand->lsb;
+  return mask;
+}
+
+/* Return the UVAL encoding of REGNO as OPERAND.  */
+
+static inline unsigned int
+nanomips_encode_reg_operand (const struct nanomips_operand *operand,
+			     int regno)
+{
+  unsigned int uval;
+  const unsigned int num_vals = 1 << operand->size;
+  const struct nanomips_reg_operand *reg_op
+    = (const struct nanomips_reg_operand *) operand;
+
+  for (uval = 0; uval < num_vals; uval++)
+    if (reg_op->reg_map[uval] == regno)
+      break;
+  return uval;
+}
+
+
+/* Re-organize HI20 bits of OPERAND encoded as UVAL.  */
+
+#define SIGNEX_VALUE(OP) {OP_INT, (unsigned short)(OP->size - 1), 0, 0, 0}
+
+static inline int
+nanomips_decode_hi20_operand (const struct nanomips_operand *operand,
+			      unsigned int uval)
+{
+  const struct nanomips_operand op_ext = SIGNEX_VALUE (operand);
+  const struct nanomips_operand op_shuffle = {OP_INT, 19, 10, 10, 0};
+  unsigned int low19 = nanomips_extract_operand (&op_shuffle, uval);
+  return nanomips_insert_operand (&op_ext, uval, low19);
+}
+
+/* Decode HI20 signed integer.  */
+
+#define SIGNED_VALUE(OP) {OP_INT, OP->size, 0, 0, 0}
+
+static inline int
+nanomips_decode_hi20_int_operand (const struct nanomips_operand *operand,
+				  unsigned int uval)
+{
+  const struct nanomips_operand op_enc = SIGNED_VALUE (operand);
+  uval = nanomips_decode_hi20_operand (operand, uval);
+  return (nanomips_signed_operand (&op_enc, uval));
+}
+
+/* Decode HI20 PCREL  */
+
+#define PCREL_VALUE(OP) { { { OP_PCREL, OP->size, 0, 0, 0}, \
+	(unsigned int)((1 << (OP->size - 1)) - 1), 0, 0, false}, 12, 0, 0}
+
+static inline bfd_vma
+nanomips_decode_hi20_pcrel_operand (const struct nanomips_operand *operand,
+				    bfd_vma base_pc, unsigned int uval)
+{
+  const struct nanomips_pcrel_operand pcrel_op = PCREL_VALUE (operand);
+  uval = nanomips_decode_hi20_operand (operand, uval);
+  return nanomips_decode_pcrel_operand (&pcrel_op, base_pc, uval << 12);
+}
+
+
+/* Return true if MO is an instruction that requires 48-bit encoding.  */
+
+static inline bool
+opcode_48bit_p (const struct nanomips_opcode *mo)
+{
+  return ((mo->mask >> 16 == 0)
+	  && ((mo->match >> 10) == 0x18));
+}
+
+/* These are the bits which may be set in the pinfo field of an
+   instructions, if it is not equal to INSN_MACRO.  */
+
+/* Writes to operand number N.  */
+#define INSN_WRITE_SHIFT            0
+#define INSN_WRITE_1                0x00000001
+#define INSN_WRITE_2                0x00000002
+#define INSN_WRITE_ALL              0x00000003
+/* Reads from operand number N.  */
+#define INSN_READ_SHIFT             2
+#define INSN_READ_1                 0x00000004
+#define INSN_READ_2                 0x00000008
+#define INSN_READ_3                 0x00000010
+#define INSN_READ_ALL               0x0000001c
+/* Modifies general purpose register 31.  */
+#define INSN_WRITE_GPR_31           0x00000020
+/* Reads coprocessor register other than floating point register.  */
+#define INSN_COP                    0x00000040
+/* Instruction loads value from memory.  */
+#define INSN_LOAD_MEMORY	    0x00000080
+/* Reads the accumulator register.  */
+#define INSN_READ_ACC		    0x00000100
+/* Modifies the HI register.  */
+#define INSN_WRITE_ACC		    0x00000200
+/* Instruction stores value into memory.  */
+#define INSN_STORE_MEMORY	0x00000400
+/* Instruction uses single precision floating point.  */
+#define INSN_FP_S		0x00000800
+/* Instruction uses double precision floating point.  */
+#define INSN_FP_D		0x00001000
+/* A user-defined instruction.  */
+#define INSN_UDI                    0x00002000
+/* Instruction is actually a macro.  It should be ignored by the
+   disassembler, and requires special treatment by the assembler.  */
+#define INSN_MACRO                  0xffffffff
+
+/* These are the bits which may be set in the pinfo2 field of an
+   instruction. */
+
+/* Instruction is a simple alias (I.E. "move" for daddu/addu/or) */
+#define	INSN2_ALIAS		    0x00000001
+/* Macro uses single-precision floating-point instructions.  This should
+   only be set for macros.  For instructions, FP_S in pinfo carries the
+   same information.  */
+#define INSN2_M_FP_S		    0x00000002
+/* Macro uses double-precision floating-point instructions.  This should
+   only be set for macros.  For instructions, FP_D in pinfo carries the
+   same information.  */
+#define INSN2_M_FP_D		    0x00000004
+/* Is an unconditional branch insn. */
+#define INSN2_UNCOND_BRANCH	    0x00000008
+/* Is a conditional branch insn. */
+#define INSN2_COND_BRANCH	    0x00000010
+/* This indicates delayed branch converted to compact branch.  */
+#define INSN2_CONVERTED_TO_COMPACT  0x00000020
+/* Marks the LI macro expansion as special, temporary.  */
+#define INSN2_MACRO		    0x00000040
+/* Marks the legacy/downgraded MTTGPR format, temporary.  */
+#define INSN2_MTTGPR_RC1	    0x00000080
+
+/* Masks used to mark instructions to indicate which MIPS ISA level
+   they were introduced in.  INSN_ISA_MASK masks an enumeration that
+   specifies the base ISA level(s).  The remainder of a 32-bit
+   word constructed using these macros is a bitmask of the remaining
+   INSN_* values below.  */
+
+#define INSN_ISA_MASK		  0x00000003ul
+
+/* We cannot start at zero due to ISA_UNKNOWN below.  */
+#define INSN_ISAN32R6   1
+#define INSN_ISAN64R6	2
+
+#define ISA_UNKNOWN	0               /* Gas internal use.  */
+
+#define ISA_NANOMIPS32R6	INSN_ISAN32R6
+#define ISA_NANOMIPS64R6	INSN_ISAN64R6
+
+/* CPU defines, use instead of hardcoding processor number. Keep this
+   in sync with bfd/archures.c in order for machine selection to work.  */
+#define CPU_UNKNOWN	0               /* Gas internal use.  */
+
+#define CPU_NANOMIPS32R6 32
+#define CPU_NANOMIPS64R6 64
+
+#define ISAF(X) (1 << (INSN_ISA##X - 1))
+
+/* The same information in table form: bit INSN_ISA<X> - 1 of index
+   INSN_UPTO<Y> - 1 is set if ISA Y includes ISA X.  */
+static const unsigned int nanomips_isa_table[] = {
+  ISAF(N32R6),
+  ISAF(N32R6) | ISAF(N64R6)
+};
+#undef ISAF
+
+/* DSP ASE */
+#define ASE_DSP			0x00000001
+#define ASE_DSP64		0x00000002
+/* Enhanced VA Scheme */
+#define ASE_EVA			0x00000004
+/* MCU (MicroController) ASE */
+#define ASE_MCU			0x00000008
+/* MT ASE */
+#define ASE_MT			0x00000010
+/* Virtualization ASE */
+#define ASE_VIRT		0x00000020
+#define ASE_VIRT64		0x00000040
+/* MSA Extension  */
+#define ASE_MSA			0x00000080
+#define ASE_MSA64		0x00000100
+/* Cyclic redundancy check (CRC) ASE */
+#define ASE_CRC			0x00000200
+#define ASE_CRC64		0x00000400
+/* Global INValidate Extension. */
+#define ASE_GINV		0x00000800
+/* The Virtualization ASE has Global INValidate extension instructions
+   which are only valid when both ASEs are enabled. */
+#define ASE_GINV_VIRT		0x00001000
+/* Excluded for low power instruction subset for nanoMIPS.  */
+#define ASE_xNMS		0x00002000
+/* TLB control ASE.  */
+#define ASE_TLB			0x00004000
+
+static inline bool
+nanomips_cpu_is_member (int cpu, unsigned int mask)
+{
+  switch (cpu)
+    {
+    case CPU_NANOMIPS32R6:
+      return (mask & INSN_ISA_MASK) == INSN_ISAN32R6;
+
+    case CPU_NANOMIPS64R6:
+      return ((mask & INSN_ISA_MASK) == INSN_ISAN32R6)
+	     || ((mask & INSN_ISA_MASK) == INSN_ISAN64R6);
+
+    default:
+      return false;
+    }
+}
+
+/* Test for membership in an ISA including chip specific ISAs.  INSN
+   is pointer to an element of the opcode table; ISA is the specified
+   ISA/ASE bitmask to test against; and CPU is the CPU specific ISA to
+   test, or zero if no CPU specific ISA test is desired.  Return true
+   if instruction INSN is available to the given ISA and CPU. */
+static inline bool
+nanomips_opcode_is_member (const struct nanomips_opcode *insn,
+			   int isa, int ase, int cpu)
+{
+  /* Test for ISA level compatibility.  */
+  if ((isa & INSN_ISA_MASK) != 0
+      && (insn->membership & INSN_ISA_MASK) != 0
+      && ((nanomips_isa_table[(isa & INSN_ISA_MASK) - 1]
+	   >> ((insn->membership & INSN_ISA_MASK) - 1)) & 1) != 0)
+    return true;
+
+  /* Test for ASE compatibility.  */
+  if (insn->ase != 0 && (ase & insn->ase) == insn->ase)
+    return true;
+
+  /* Test for processor-specific extensions.  */
+  if (nanomips_cpu_is_member (cpu, insn->membership))
+    return true;
+
+  return false;
+}
+
+/* This is a list of macro expanded instructions.
+
+   _I appended means immediate
+   _A appended means target address of a jump
+   _AB appended means address with (possibly zero) base register
+   _AC appended means either symbolic address with no base register
+   or constant offset with base register.
+   _D appended means 64 bit floating point constant
+   _S appended means 32 bit floating point constant.  */
+
+enum
+{
+  M_ABS,
+  M_ACLR_AC,
+  M_ADD_I,
+  M_ADDU_I,
+  M_AND_I,
+  M_ASET_AC,
+  M_BEQ,
+  M_BEQ_I,
+  M_BGE,
+  M_BGE_I,
+  M_BGEU,
+  M_BGEU_I,
+  M_BGEZ,
+  M_BGT,
+  M_BGT_I,
+  M_BGTU,
+  M_BGTU_I,
+  M_BGTZ,
+  M_BLE,
+  M_BLE_I,
+  M_BLEU,
+  M_BLEU_I,
+  M_BLEZ,
+  M_BLT,
+  M_BLT_I,
+  M_BLTU,
+  M_BLTU_I,
+  M_BLTZ,
+  M_BNE,
+  M_BNE_I,
+  M_CACHE_AC,
+  M_CACHEE_AC,
+  M_DABS,
+  M_DADD_I,
+  M_DADDU_I,
+  M_DLA_AB,
+  M_DLI,
+  M_DMUL,
+  M_DMUL_I,
+  M_DSUB_I,
+  M_DSUBU_I,
+  M_J_A,
+  M_JAL_A,
+  M_JRADDIUSP,
+  M_LA_AB,
+  M_LB_AC,
+  M_LBE_AC,
+  M_LBU_AC,
+  M_LBUE_AC,
+  M_LBX_AB,
+  M_LBUX_AB,
+  M_LD_AC,
+  M_LDC1_AC,
+  M_LDC1X_AB,
+  M_LDC2_AC,
+  M_LDM_AC,
+  M_LDX_AB,
+  M_LH_AC,
+  M_LHE_AC,
+  M_LHU_AC,
+  M_LHUE_AC,
+  M_LHUX_AB,
+  M_LHX_AB,
+  M_LI,
+  M_LI_D,
+  M_LI_DD,
+  M_LI_S,
+  M_LI_SS,
+  M_LL_AC,
+  M_LLD_AC,
+  M_LLE_AC,
+  M_LLDP_AC,
+  M_LLWP_AC,
+  M_LW_AC,
+  M_LWC1_AC,
+  M_LWC1X_AB,
+  M_LWC2_AC,
+  M_LWE_AC,
+  M_LWM_AC,
+  M_LWU_AC,
+  M_LWUX_AB,
+  M_LWX_AB,
+  M_MUL,
+  M_MUL_I,
+  M_NOR_I,
+  M_OR_I,
+  M_PREF_AC,
+  M_PREFE_AC,
+  M_REM_3I,
+  M_DROL,
+  M_ROL,
+  M_DROL_I,
+  M_ROL_I,
+  M_ROR_I,
+  M_SC_AC,
+  M_SCD_AC,
+  M_SCE_AC,
+  M_SCDP_AC,
+  M_SCWP_AC,
+  M_SD_AC,
+  M_SDC1_AC,
+  M_SDC1X_AB,
+  M_SDC2_AC,
+  M_SDM_AC,
+  M_SDX_AB,
+  M_SEQ,
+  M_SEQ_I,
+  M_SGE,
+  M_SGE_I,
+  M_SGEU,
+  M_SGEU_I,
+  M_SGT,
+  M_SGT_I,
+  M_SGTU,
+  M_SGTU_I,
+  M_SLE,
+  M_SLE_I,
+  M_SLEU,
+  M_SLEU_I,
+  M_SLT_I,
+  M_SLTU_I,
+  M_SNE,
+  M_SNE_I,
+  M_SB_AC,
+  M_SBE_AC,
+  M_SBX_AB,
+  M_SH_AC,
+  M_SHE_AC,
+  M_SHX_AB,
+  M_SW_AC,
+  M_SWE_AC,
+  M_SWX_AB,
+  M_SWC1_AC,
+  M_SWC1X_AB,
+  M_SWC2_AC,
+  M_SWM_AC,
+  M_SUB_I,
+  M_SUBU_I,
+  M_TEQ_I,
+  M_TNE_I,
+  M_ULD_AC,
+  M_ULH_AC,
+  M_ULW_AC,
+  M_USH_AC,
+  M_USW_AC,
+  M_USD_AC,
+  M_XOR_I,
+  M_BGEZAL,
+  M_BLTZAL,
+  M_EXT,
+  M_INS,
+  M_MOD_I,
+  M_MODU_I,
+  M_DMOD_I,
+  M_DMODU_I,
+  M_DIV_I,
+  M_DIVU_I,
+  M_DDIV_I,
+  M_DDIVU_I,
+  M_NANOMIPS_NUM_MACROS
+};
+
+/* These are the bit masks and shift counts used for the different fields
+   in the nanoMIPS instruction formats.  No masks are provided for the
+   fixed portions of an instruction, since they are not needed.  */
+
+#define NANOMIPSOP_MASK_RS		0x1f
+#define NANOMIPSOP_SH_RS		16
+#define NANOMIPSOP_MASK_RT		0x1f
+#define NANOMIPSOP_SH_RT		21
+#define NANOMIPSOP_MASK_RD		0x1f
+#define NANOMIPSOP_SH_RD		11
+#define NANOMIPSOP_SH_ME		1
+#define NANOMIPSOP_SH_MC		4
+#define NANOMIPSOP_SH_MD		7
+#define NANOMIPSOP_SH_MP		5
+#define NANOMIPSOP_SH_MM		7
+
+#define NANOMIPSOP_SH_CP0SEL		5
+#define NANOMIPSOP_MASK_CP0SEL		0x1f
+#define NANOMIPSOP_SH_HWRSEL		5
+#define NANOMIPSOP_MASK_HWRSEL		0x1f
+
+/* Describes a COP0 named register with a fixed select.  */
+struct nanomips_cp0_name
+{
+  const char *name;
+  unsigned int num;
+  unsigned int sel;
+};
+
+/* The reference list of COP0 named register with fixed selects.  */
+static const struct nanomips_cp0_name nanomips_cp0_3264r6[] = {
+    {"$index",		 0, 0},
+    {"$mvpcontrol",	 0, 1},
+    {"$mvpconf0",	 0, 2},
+    {"$mvpconf1",	 0, 3},
+    {"$vpcontrol",	 0, 4},
+    {"$random", 	 1, 0},
+    {"$vpecontrol",	 1, 1},
+    {"$vpeconf0",	 1, 2},
+    {"$vpeconf1",	 1, 3},
+    {"$yqmask", 	 1, 4},
+    {"$vpeschedule",	 1, 5},
+    {"$vpeschefback",	 1, 6},
+    {"$vpeopt", 	 1, 7},
+    {"$entrylo0",	 2, 0},
+    {"$tcstatus",	 2, 1},
+    {"$tcbind", 	 2, 2},
+    {"$tcrestart",	 2, 3},
+    {"$tchalt", 	 2, 4},
+    {"$tccontext",	 2, 5},
+    {"$tcschedule",	 2, 6},
+    {"$tcschefback",	 2, 7},
+    {"$entrylo1",	 3, 0},
+    {"$globalnumber",	 3, 1},
+    {"$tcopt",		 3, 7},
+    {"$context",	 4, 0},
+    {"$contextconfig",	 4, 1},
+    {"$userlocal",	 4, 2},
+    {"$xcontextconfig",  4, 3},
+    {"$debugcontextid",  4, 4},
+    {"$memorymapid",	 4, 5},
+    {"$pagemask",	 5, 0},
+    {"$pagegrain",	 5, 1},
+    {"$segctl0",	 5, 2},
+    {"$segctl1",	 5, 3},
+    {"$segctl2",	 5, 4},
+    {"$pwbase", 	 5, 5},
+    {"$pwfield",	 5, 6},
+    {"$pwsize", 	 5, 7},
+    {"$wired",		 6, 0},
+    {"$srsconf0",	 6, 1},
+    {"$srsconf1",	 6, 2},
+    {"$srsconf2",	 6, 3},
+    {"$srsconf3",	 6, 4},
+    {"$srsconf4",	 6, 5},
+    {"$pwctl",		 6, 6},
+    {"$hwrena", 	 7, 0},
+    {"$badvaddr",	 8, 0},
+    {"$badinst",	 8, 1},
+    {"$badinstrp",	 8, 2},
+    {"$badinstrx",	 8, 3},
+    {"$count",		 9, 0},
+    {"$entryhi",	10, 0},
+    {"$guestctl1",	10, 4},
+    {"$guestctl2",	10, 5},
+    {"$guestctl3",	10, 6},
+    {"$compare",	11, 0},
+    {"$guestctl0ext",	11, 4},
+    {"$status", 	12, 0},
+    {"$intctl", 	12, 1},
+    {"$srsctl", 	12, 2},
+    {"$srsmap", 	12, 3},
+    {"$view_ipl",	12, 4},
+    {"$srsmap2",	12, 5},
+    {"$guestctl0",	12, 6},
+    {"$gtoffset",	12, 7},
+    {"$cause",		13, 0},
+    {"$view_ripl",	13, 4},
+    {"$nestedexc",	13, 5},
+    {"$epc",		14, 0},
+    {"$nestedepc",	14, 2},
+    {"$prid",		15, 0},
+    {"$ebase",		15, 1},
+    {"$cdmmbase",	15, 2},
+    {"$cmgcrbase",	15, 3},
+    {"$bevva",		15, 4},
+    {"$config", 	16, 0},
+    {"$config1",	16, 1},
+    {"$config2",	16, 2},
+    {"$config3",	16, 3},
+    {"$config4",	16, 4},
+    {"$config5",	16, 5},
+    {"$lladdr", 	17, 0},
+    {"$maar", 		17, 1},
+    {"$maari",		17, 2},
+    {"$watchlo0",	18, 0},
+    {"$watchlo1",	18, 1},
+    {"$watchlo2",	18, 2},
+    {"$watchlo3",	18, 3},
+    {"$watchlo4",	18, 4},
+    {"$watchlo5",	18, 5},
+    {"$watchlo6",	18, 6},
+    {"$watchlo7",	18, 7},
+    {"$watchlo8",	18, 8},
+    {"$watchlo9",	18, 9},
+    {"$watchlo10",	18, 10},
+    {"$watchlo11",	18, 11},
+    {"$watchlo12",	18, 12},
+    {"$watchlo13",	18, 13},
+    {"$watchlo14",	18, 14},
+    {"$watchlo15",	18, 15},
+    {"$watchhi0",	19, 0},
+    {"$watchhi1",	19, 1},
+    {"$watchhi2",	19, 2},
+    {"$watchhi3",	19, 3},
+    {"$watchhi4",	19, 4},
+    {"$watchhi5",	19, 5},
+    {"$watchhi6",	19, 6},
+    {"$watchhi7",	19, 7},
+    {"$watchhi8",	19, 8},
+    {"$watchhi9",	19, 9},
+    {"$watchhi10",	19, 10},
+    {"$watchhi11",	19, 11},
+    {"$watchhi12",	19, 12},
+    {"$watchhi13",	19, 13},
+    {"$watchhi14",	19, 14},
+    {"$watchhi15",	19, 15},
+    {"$xcontext",	20, 0},
+    {"$debug",		23, 0},
+    {"$tracecontrol",	23, 1},
+    {"$tracecontrol2",	23, 2},
+    {"$usertracedata1", 23, 3},
+    {"$traceibpc",	23, 4},
+    {"$tracedbpc",	23, 5},
+    {"$debug2", 	23, 6},
+    {"$depc",		24, 0},
+    {"$tracecontrol3",	24, 2},
+    {"$usertracedata2", 24, 3},
+    {"$perfctl0",	25, 0},
+    {"$perfcnt0",	25, 1},
+    {"$perfctl1",	25, 2},
+    {"$perfcnt1",	25, 3},
+    {"$perfctl2",	25, 4},
+    {"$perfcnt2",	25, 5},
+    {"$perfctl3",	25, 6},
+    {"$perfcnt3",	25, 7},
+    {"$perfctl4",	25, 8},
+    {"$perfcnt4",	25, 9},
+    {"$perfctl5",	25, 10},
+    {"$perfcnt5",	25, 11},
+    {"$perfctl6",	25, 12},
+    {"$perfcnt6",	25, 13},
+    {"$perfctl7",	25, 14},
+    {"$perfcnt7",	25, 15},
+    {"$errctl", 	26, 0},
+    {"$cacheerr",	27, 0},
+    {"$itaglo", 	28, 0},
+    {"$idatalo", 	28, 1},
+    {"$dtaglo", 	28, 2},
+    {"$ddatalo", 	28, 3},
+    {"$itaghi", 	29, 0},
+    {"$idatahi", 	29, 1},
+    {"$dtaghi", 	29, 2},
+    {"$ddatahi", 	29, 3},
+    {"$errorepc",	30, 0},
+    {"$desave", 	31, 0},
+    {"$kscratch1",	31, 2},
+    {"$kscratch2",	31, 3},
+    {"$kscratch3",	31, 4},
+    {"$kscratch4",	31, 5},
+    {"$kscratch5",	31, 6},
+    {"$kscratch6",	31, 7},
+    {NULL, 0, 0}
+};
+
+/* Describes a CP0 named register which permits various select values.  */
+  struct nanomips_cp0_select
+{
+  const char *name;
+  unsigned int num;
+  unsigned int selmask;
+};
+
+/* Currently recognized CP0 select patterns.  */
+
+#define NANOMIPS_CP0SEL_MASK_EVEN	0x55555555
+#define NANOMIPS_CP0SEL_MASK_ODD	0xaaaaaaaa
+#define NANOMIPS_CP0SEL_MASK_ANY	0xffffffff
+#define NANOMIPS_CP0SEL_MASK_EVEN16	0x5555
+#define NANOMIPS_CP0SEL_MASK_ODD16	0xaaaa
+#define NANOMIPS_CP0SEL_MASK_ANY16	0xffff
+
+/* The reference list of CP0 named register with variable selects.  */
+static const struct nanomips_cp0_select nanomips_cp0sel_3264r6[] = {
+    {"$watchlo",	18, NANOMIPS_CP0SEL_MASK_ANY16},
+    {"$watchhi",	19, NANOMIPS_CP0SEL_MASK_ANY16},
+    {"$perfctl",	25, NANOMIPS_CP0SEL_MASK_EVEN16},
+    {"$perfcnt",	25, NANOMIPS_CP0SEL_MASK_ANY16},
+    {"$taglo",		28, NANOMIPS_CP0SEL_MASK_EVEN},
+    {"$datalo", 	28, NANOMIPS_CP0SEL_MASK_ODD},
+    {"$taghi",		29, NANOMIPS_CP0SEL_MASK_EVEN},
+    {"$datahi", 	29, NANOMIPS_CP0SEL_MASK_ODD},
+    {NULL, 0, 0}
+};
+
+
+/* Describes a HWR named register with a fixed select.  If the HWR name
+   is remapped from an existing CP0 register name, its cp0_num and cp0_sel
+   fields will provide the mapping, else they will both be invalid.  */
+
+struct nanomips_hwr_name
+{
+  const char *name;
+  unsigned int num;
+  unsigned int sel;
+  unsigned int cp0_num;
+  unsigned int cp0_sel;
+};
+
+#define INV_RNUM 0xffffffff
+#define INV_SEL 0xffffffff
+
+ /* The reference list of named hardware register with fixed selects.  */
+static const struct nanomips_hwr_name nanomips_hwr_names_3264r6[] = {
+    {"$cpunum",		0,	0,	INV_RNUM,	INV_SEL},
+    {"$synci_step",	1,	0,	INV_RNUM,	INV_SEL},
+    {"$cc",		2,	0,	9,		0},
+    {"$count",		2,	0,	9,		0},
+    {"$ccres",		3,	0,	INV_RNUM, 	INV_SEL},
+    {"$perfctl0",	4,	0,	25,		0},
+    {"$perfcnt0",	4,	1,	25,		1},
+    {"$perfctl1",	4,	2,	25,		2},
+    {"$perfcnt1",	4,	3,	25,		3},
+    {"$perfctl2",	4,	4,	25,		4},
+    {"$perfcnt2",	4,	5,	25,		5},
+    {"$perfctl3",	4,	6,	25,		6},
+    {"$perfcnt3",	4,	7,	25,		7},
+    {"$perfctl4",	4,	8,	25,		8},
+    {"$perfcnt4",	4,	9,	25,		9},
+    {"$perfctl5",	4,	10,	25,		10},
+    {"$perfcnt5",	4,	11,	25,		11},
+    {"$perfctl6",	4,	12,	25,		12},
+    {"$perfcnt6",	4,	13,	25,		13},
+    {"$perfctl7",	4,	14,	25,		14},
+    {"$perfcnt7",	4,	15,	25,		15},
+    {"$perfctl",	4,	0,	25,		0},
+    {"$perfcnt",	4,	1,	25,		1},
+    {"$xnp",		5,	0,	INV_RNUM,	INV_SEL},
+    {"$userlocal",	29,	0,	4,		2},
+    {NULL, 		0,	0,	INV_RNUM,	INV_SEL}
+};
+
+#define NANOMIPS_CP0SEL_PERFCNT 25
+#define NANOMIPS_HWRSEL_PERFCNT 4
+
+/* Don't care stubs in operand formats need special handling.  */
+#define NANOMIPS_MIN_DONTCARE_FMT 'A'
+#define NANOMIPS_MAX_DONTCARE_FMT 'Q'
+
+#define IS_NANOMIPS_DONTCARE_FMT(x) ((x)[0] == '-'			\
+				     && (x)[1] >= NANOMIPS_MIN_DONTCARE_FMT \
+				     && (x)[1] <= NANOMIPS_MAX_DONTCARE_FMT)
+
+/* These are the characters which may appears in the args field of a nanoMIPS
+   instruction.  They appear in the order in which the fields appear when the
+   instruction is used.  Commas and parentheses in the args string are ignored
+   when assembling, and written into the output when disassembling.
+
+   Operands for 16-bit nanoMIPS instructions.
+
+   "ma" must be $28
+   "mb" 5-bit non-zero GP register at bit 5
+   "mc" 3-bit nanoMIPS registers 4-7, 16-19 bit 4
+        The same register used as both source and target.
+   "md" 3-bit nanoMIPS registers 4-7, 16-19 at bit 7
+   "me" 3-bit nanoMIPS registers 4-7, 16-19 at bit 1
+   "mf" 3-bit nanoMIPS register 4-7, 16-19 at bit 7.
+        Must be larger than the last seen register.
+   "mg" 3-bit nanoMIPS register 4-7, 16-19 at bit 4.
+	Must be smaller than the last seen register.
+   "mh" 3-bit nanoMIPS register 4-7, 16-19 at bit 7.
+        Must be at least as large as the last seen register.
+   "mi" 3-bit nanoMIPS register 4-7, 16-19 at bit 4.
+	May be at most as large as the last seen register.
+
+   "mj" 5-bit nanoMIPS registers at bit 0
+   "mk" must be the same as the destination register
+   "ml" 3-bit nanoMIPS registers 4-7, 16-19 at bit 4
+   "mm" 3-bit nanoMIPS registers 0, 4-7, 17-19 at bit 7
+   "mn"	5-bit encoding of a save/restore register list
+   "mp" 5-bit nanoMIPS registers at bit 5
+   "mq" 2-bit pair at bits [8,3] maps to ($a0,$a1), ($a1,$a2), ($a2,$a3)
+        or ($a3,$a4)
+   "mr" 2-bit pair at bits [8,3] maps to ($a1,$a0), ($a2,$a1), ($a3,$a2)
+        or ($a4,$a3)
+   "ms" must be $29
+   "mt" must be the same as the previous register
+   "mu"	4-bit encoding of nanoMIPS destination register at bit 5
+   "mv"	4-bit encoding of nanoMIPS destination register at bit 0
+   "mw"	4-bit encoding of nanoMIPS source register at bit 5
+   "mx"	4-bit encoding of nanoMIPS source register at bit 0
+   "my" must be $31
+   "mz" must be literal 0
+
+   "mA" 7-bit relocatable GP offset (0 .. 127) << 2
+   "mB" 3-bit immediate at bit 0 (0, 4, 8, 12, 16, 20, 24, 28)
+   "mC" 4-bit immediate at bit 0 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+        65535, 14, 15)
+   "mD" 10-bit signed branch address, split & scaled at bit 0 [S9:1,S10]
+   "mE" 7-bit signed branch address, split & scaled at bit 0 [S6:1,S7]
+   "mF" 4-bit unsigned branch address, scaled at bit 0 [U4:U1]
+   "mG" 4-bit scaled immediate at bit 4, (0 .. 15) << 4
+   "mH" 2-bit scaled immediate at bit 1, (0 .. 3) << 1
+   "mI" 7-bit immediate at bit 0, (-1 .. 126)
+   "mJ" 4-bit scaled immediate at bit 0, (0 .. 15) << 2
+   "mK" 3-bit BREAK/SDBBP code at bit 0
+   "mL" 2-bit immediate at bit 0, (0 .. 3)
+   "mM" 3-bit immediate at bit 0, (1 .. 8)
+   "mN" 2-bit split scaled immediate at bits 8 & 3 (0 .. 3) << 2
+   "mO" 7-bit immediate GP offset at bit 0, (0 .. 127) << 2
+   "mP"	2-bit SYSCALL/HYPCALL code at bit 0
+   "mQ"	4-bit immediate signed offset, (s3,s2:s0)
+   "mR" 5-bit immediate at bit 0, (0 .. 31) << 2
+   "mS" 6-bit immediate at bit 0, (0 .. 63) << 2
+   "mZ" must be zero
+
+   Operands for 32-bit nanoMIPS instructions.
+
+   "+1"	18-bit unsigned GP-relative offset, (u17:u0)
+   "+2"	18-bit scaled GP-relative offset, (u18:u2) << 2
+   "+3"	21-bit scaled GP-relative offset, (u18:u1) << 1
+   "+4" 18-bit GP-relative offset, (0 .. 2^18-1) << 3
+   "+5"	4-bit encoding of nanoMIPS source register at bit 21
+   "+6" 5-bit mask encoding, corresponding to (1 << X) - 1
+   "+7" 1-bit register at bit 24, (0,1) => ($a0,$a1)
+   "+8" 23-bit un-spec'ed value at bit 3 for UDIs.
+   "+9" 7-bit immediate at bit 11, (0 .. 127)
+
+   "+A" 5-bit INS/EXT/DINS/DEXT/DINSM/DEXTM position, which becomes
+        LSB.
+   "+B" 5-bit INS/DINS size, which becomes MSB
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 0 < (pos+size) <= 32.
+   "+C" 5-bit EXT/DEXT size, which becomes MSBD.
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 0 < (pos+size) <= 32.
+   "+D"	4-bit encoding of a floating point save/restore register list
+   "+E" 5-bit DINSU/DEXTU position, which becomes LSB-32.
+   "+F" 5-bit DINSM/DINSU size, which becomes MSB-32.
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 32 < (pos+size) <= 64.
+   "+G" 5-bit DEXTM size, which becomes MSBD-32.
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 32 < (pos+size) <= 64.
+   "+H" 5-bit DEXTU size, which becomes MSBD.
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 32 < (pos+size) <= 64.
+   "+I" 5-bit EXTW/EXTD/PREPEND position, which becomes LSB.
+   "+J" 19-bit BREAK/SDBBP function code at bit 0
+   "+K"	Tri-part upper 20-bits of immediate value.
+   "+L" 10-bit WAIT code at bit 16
+   "+M"	18-bit SYSCALL/HYPCALL code at bit 0
+   "+N" 9-bit immediate at bit 3, (0 .. 511) << 3
+
+   "+i"	5-bit SYNC code type at bit 16, (0..31)
+   "+j"	9-bit signed offset (s7:s0,s8), (-256 .. 255)
+   "+k" 5-bit nanoMIPS registers at bit 3
+   "+p"	9-bit scaled signed offset, (s7:s2) << 2 for LL/SC*
+   "+q" 9-bit scaled signed offset, (s7:s3) << 3 for LLD/SCD*
+   "+r"	21-bit PC-relative branch offset (s19:s1,s20) << 1
+   "+s"	21-bit immediate offset for PC-relative operation ((s19:s1,s20) + 2) << 1
+   "+t" 5-bit non-zero GP register at bit 21
+   "+u"	25-bit PC-relative branch offset (s24:s1,s25) << 1
+   "+v"	5-bit mapping of R6 ALIGN byte-wise shift to EXTW bit-wise shift.
+   "+w"	2-bit shift for scaled address calculation at bit 9, (0..3)
+   "+*"	4-bit ROTX shift at bit 7, (0 .. 15) << 1
+   "+|"	1-bit ROTX stripe at bit 6, (0 .. 1)
+
+   "."	21-bit scaled GP-relative offset, (u21:u2) << 2
+   "<"	5-bit immediate shift value for bit operations, (0..31)
+   "|"	3-bit Element count for load/store multiple, (1..8)
+   "~"	11-bit branch offset, (s9:s1,s10) << 1
+   "^"	5-bit trap code at bit 11, (0..31)
+   "b"	5-bit base register at bit 16 for label or symbolic offsets
+   "c"	5-bit base register at bit 16, either used with immediate offset
+	or skipped with symbolic offset.
+   "d"	5-bit destination register specifier at bit 11
+   "g"	12-bit unsigned immediate at bit 0, (0..4095)
+   "h"	12-bit negative immediate at bit 0, (-4095..0)
+   "i"	12-bit unsigned immediate at bit 0, (0..4095)
+   "j"	16-bit unsigned immediate at bit 0, (0..65535)
+   "k"	5-bit cache operation code at bit 21, (0..31)
+   "n"	11-bit encoding of save/restore register list
+   "o"	12-bit offset at bit 0, (0..4095)
+   "p"	14-bit PC-relative branch offset (s13:s1,s14) << 1
+   "r"	5-bit same register at bit 16, used as both source and target
+   "s"	5-bit source register specifier at bit 16
+   "t"	5-bit target register specifier at bit 21
+   "u" 	Tri-part upper 20 bits of address
+   "x" 	Tri-part upper 20 bits of address, scaled by 12 bits
+   "v"	5-bit same register used as both source and destination at bit 15
+   "w"	5-bit same register used as both target and destination at bit 21
+   "z"	must be zero register
+
+   Used in special matching contexts:
+   "-A"	5 don't care bits at bit 16
+   "-B"	1 don't care bit at bit 10
+   "-C"	12 don't care bits at bit 0
+   "-D"	1 don't care bit at bit 17
+   "-E"	3 don't care bits at bit 13
+   "-F"	10 don't care bits at bit 16
+   "-G"	8 split don't care bits, 3 at bit 9 and 5 at bit 7
+   "-H"	9 don't care bits at bit 17
+   "-I"	5 don't care bits at bit 21
+   "-J"	3 don't care bits at bit 23
+   "-K"	2 split don't care bits, 1 at bit 2 and 1 at bit 15
+   "-L"	3 don't care bits at bit 6
+   "-M"	3 don't care bits at bit 9
+   "-N"	6 don't care bits at bit 10
+   "-O"	1 don't care bit at bit 12
+   "-P"	8 split don't care bits, 4 at bit 10 and 4 at bit 22
+   "-Q"	1 don't care bit at bit 11
+
+   "-i" Ignored register operand, internally used for macro expansions.
+   "-m" Place-holder to copy 5 bits from bit 11 to bit 21
+   "-n" Place-holder to copy 5 bits from bit 11 to bit 16
+
+   Exclusively for 48-bit nanoMIPS instructions:
+
+   "+O" Signed GP-relative 32-bit offset in instruction byte order
+   "+P" Immediate signed 32-bit value in instruction byte order
+   "+Q"	Unsigned 32-bit value or address in instruction byte order
+   "+R" Signed 32-bit value in instruction byte order
+   "+S" Signed PC-relative 32-bit offset in instruction byte order
+
+   DSP instructions:
+   "0"	5-bit shift value for DSP accumulator at bit 16, (0..63)
+   "1"	5-bit position for DSP bit operations at bit 11
+   "2" 5-bit size for DSP bit operations at bit 16
+   "3" 3-bit byte vector shift at bit 13, (0..7)
+   "4" 4-bit hword vector shift at bit 12, (0..15)
+   "5" 8-bit unsigned immediate at bit 13, (0..255)
+   "7" 2-bit DSP accumulator register at bit 14, (0..3)
+   "8" 7-bit DSP control mask at bit 14, (0x3f)
+   "@" 10-bit signed immediate at bit 11, (0..1023)
+
+   Coprocessor instructions:
+   "E" 5-bit target register
+   "G" 5-bit source register
+   "H" 5-bit sel field for (D)MTC* and (D)MFC*
+   "J" 5-bit select code at bit 11 for named COP1 registers, (0..31)
+   "K"	10-bit register+select encoding at bit 11 for named h/w register
+   "O"	10-bit register+select encoding at bit 11 for named COP1 register
+   "P"	5-bit named COP1 register at bit 16
+   "Q"	5-bit select code at bit 11
+   "U"	5-bit named HW register at bit 16
+
+   MT instructions:
+   "!"	1-bit u-mode for move to/from thread registers at bit 10, (0,1)
+   "$"	1-bit high-mode for move to/from thread registers at bit 3, (0,1)
+   "*"	2-bit accumulator register at bit 18, (0..3)
+
+   GINV instructions
+   "+;"	2-bit global invalidate operation type at bit 21, (0..3)
+
+   Floating point instructions:
+   "D" 5-bit destination register
+   "R" 5-bit fr destination register
+   "S" 5-bit fs source 1 register
+   "T" 5-bit ft source 2 register
+   "V" 5-bit same register used as floating source and destination or target
+
+   Macro instructions:
+   "A" general 32 bit expression
+   "I" 32-bit immediate (value placed in imm_expr).
+   "F" 64-bit floating point constant in memory
+   "L" 64-bit floating point constant in memory
+   "f" 32-bit floating point constant in memory
+   "l" 32-bit floating point constant in memory
+
+   CP2 instructions:
+   "C" 23-bit coprocessor function code at bit 3
+
+   MCU instructions:
+   "\"	3-bit position for atomic set/clear operations, (0..7)
+
+
+   Other:
+   "()" parens surrounding optional value
+   ","  separates operands
+   "+"  start of extension sequence
+
+   Characters used so far, for quick reference when adding more:
+   "12345 78 0"
+   ".<\|~@^!$*"
+   "A CDEFGHIJKL  OP RSTUV    "
+   " bcde ghijk  nop rstuvwx z"
+
+   Extension character sequences used so far ("+" followed by the
+   following), for quick reference when adding more:
+   "123456789
+   "*|;"
+   "ABCDEFGHIJKLMNOPQRS       "
+   "        ij     pqrstuvw   "
+
+   Extension character sequences used so far ("m" followed by the
+   following), for quick reference when adding more:
+   ""
+   ""
+   "ABCDEFGHIJKLMNOPQRS      Z"
+   "abcdefghijklmn pqrstuvwxyz"
+
+   Extension character sequences used so far ("-" followed by the
+   following), for quick reference when adding more:
+   ""
+   ""
+   "ABCDEFGHIJKLMNOPQ         "
+   "        i   mn            "
+*/
+
+extern const struct nanomips_operand *decode_nanomips_operand (const char *);
+extern const struct nanomips_opcode nanomips_opcodes[];
+extern const int bfd_nanomips_num_opcodes;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NANOMIPS_H_ */
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 3d9f4a14532..d28f3f37730 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,3 +1,20 @@
+2022-04-20  Jaydeep Patil <jaydeep.patil@imgtec.com>
+            Faraz Shahbazker <faraz.shahbazker@mips.com>
+            Maciej W. Rozycki <macro@mips.com>
+            Dragan Mladjenovic <dragan.mladjenovic@syrmia.com>
+            Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
+
+    * Makefile.am: Add nanoMIPS objects.
+    * Makefile.in: Regenerate.
+    * configure: Regenerate.
+    * configure.ac: Add nanoMIPS support.
+    * dis-buf.c (generic_predict_insn_length): New function.
+    * dis-init.c (init_disassemble_info): Use generic_predict_insn_length().
+    * disassemble.c (disassemble_init_for_target): Initialization for nanoMIPS.
+    * nanomips-dis.c: New file.
+    * nanomips-formats.h: New file.
+    * nanomips-opc.c: New file.
+
 2022-04-07  Andreas Krebbel  <krebbel@linux.ibm.com>
 
 	* s390-mkopc.c (main): Enable z16 as CPU string in the opcode
diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am
index afd19fa7785..cf6a2994626 100644
--- a/opcodes/Makefile.am
+++ b/opcodes/Makefile.am
@@ -207,6 +207,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 \
@@ -216,6 +222,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 3ab8bfb0548..9eba41fae6c 100644
--- a/opcodes/Makefile.in
+++ b/opcodes/Makefile.in
@@ -599,6 +599,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 \
@@ -608,6 +614,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 \
@@ -1020,6 +1028,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 792c863b895..cbc80d60944 100755
--- a/opcodes/configure
+++ b/opcodes/configure
@@ -12540,6 +12540,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 006a95d8704..657d1914229 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 3bd078f54dc..20e4917b6e5 100644
--- a/opcodes/dis-buf.c
+++ b/opcodes/dis-buf.c
@@ -104,3 +104,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 59039ef8b11..fc03a2ef99a 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 bd1b90b3956..3726a5b4fde 100644
--- a/opcodes/disassemble.c
+++ b/opcodes/disassemble.c
@@ -360,6 +360,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)
@@ -582,6 +587,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
@@ -729,6 +737,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..3d17d813943
--- /dev/null
+++ b/opcodes/nanomips-dis.c
@@ -0,0 +1,1505 @@
+/* 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
+\f
+
+/* FIXME: These should be shared with gdb somehow.  */
+
+static const char * const nanomips_gpr_names_numeric[32] = {
+  "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
+  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
+  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
+  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
+};
+
+static const char * const nanomips_gpr_names_symbolic[32] = {
+  "zero", "at",   "t4",   "t5",   "a0",   "a1",   "a2",   "a3",
+  "a4",   "a5",   "a6",   "a7",   "t0",   "t1",   "t2",   "t3",
+  "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
+  "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "fp",   "ra"
+};
+
+static const char * const nanomips_fpr_names_numeric[32] = {
+  "$f0",  "$f1",  "$f2",  "$f3",  "$f4",  "$f5",  "$f6",  "$f7",
+  "$f8",  "$f9",  "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
+  "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
+  "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
+};
+
+static const char * const nanomips_fpr_names_64[32] = {
+  "fv0",  "ft12", "fv1",  "ft13", "ft0",  "ft1",  "ft2",  "ft3",
+  "ft4",  "ft5",  "ft6",  "ft7",  "fa0",  "fa1",  "fa2",  "fa3",
+  "fa4",  "fa5",  "fa6",  "fa7",  "ft8",  "ft9",  "ft10", "ft11",
+  "fs0",  "fs1",  "fs2",  "fs3",  "fs4",  "fs5",  "fs6",  "fs7"
+};
+
+static const char * const nanomips_cp1_names_numeric[32] = {
+  "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
+  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
+  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
+  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
+};
+
+static const char * const nanomips_cp1_names_3264r6[32] = {
+  "c1_fir",       "c1_ufr",       "$2",           "$3",
+  "c1_unfr",      "$5",           "$6",           "$7",
+  "$8",           "$9",           "$10",          "$11",
+  "$12",          "$13",          "$14",          "$15",
+  "$16",          "$17",          "$18",          "$19",
+  "$20",          "$21",          "$22",          "$23",
+  "$24",          "c1_fccr",      "c1_fexr",      "$27",
+  "c1_fenr",      "$29",          "$30",          "c1_fcsr"
+};
+
+static const char * const msa_control_names[32] = {
+  "msa_ir",	"msa_csr",	"msa_access",	"msa_save",
+  "msa_modify",	"msa_request",	"msa_map",	"msa_unmap",
+  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
+  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
+  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
+};
+
+/* The empty-list of CP0 registers serves as an indicator to fall-back to
+   numeric register names.  */
+static const struct nanomips_cp0_name nanomips_cp0_numeric[] = {
+  {NULL, 0, 0}
+};
+static const struct nanomips_cp0_select nanomips_cp0sel_numeric[] = {
+  {NULL, 0, 0}
+};
+
+/* The empty-list of HWR registers serves as an indicator to fall-back to
+   numeric register names.  */
+static const struct nanomips_hwr_name nanomips_hwr_names_numeric[] = {
+  {NULL, 0, 0, 0, 0}
+};
+
+struct nanomips_abi_choice
+{
+  const char *name;
+  const char *const *gpr_names;
+  const char *const *fpr_names;
+};
+
+struct nanomips_abi_choice nanomips_abi_choices[] = {
+  {"numeric", nanomips_gpr_names_numeric, nanomips_fpr_names_numeric},
+  {"p32", nanomips_gpr_names_symbolic, nanomips_fpr_names_64},
+  {"p64", nanomips_gpr_names_symbolic, nanomips_fpr_names_64},
+};
+
+struct nanomips_arch_choice
+{
+  const char *name;
+  int bfd_mach_valid;
+  unsigned long bfd_mach;
+  int processor;
+  int isa;
+  int ase;
+  const struct nanomips_cp0_name *cp0_names;
+  const struct nanomips_cp0_select *cp0sel_names;
+  const char *const *cp1_names;
+  const struct nanomips_hwr_name *hwr_names;
+};
+
+const struct nanomips_arch_choice nanomips_arch_choices[] = {
+  {"numeric", 0, 0, 0, 0, 0,
+   nanomips_cp0_numeric, nanomips_cp0sel_numeric, nanomips_cp1_names_numeric,
+   nanomips_hwr_names_numeric},
+
+  {"32r6", 1, bfd_mach_nanomipsisa32r6, CPU_NANOMIPS32R6, ISA_NANOMIPS32R6,
+   (ASE_EVA | ASE_MSA | ASE_VIRT | ASE_MCU | ASE_MT | ASE_DSP | ASE_xNMS
+    | ASE_TLB | ASE_GINV | ASE_CRC),
+   nanomips_cp0_3264r6, nanomips_cp0sel_3264r6, nanomips_cp1_names_3264r6,
+   nanomips_hwr_names_3264r6},
+
+  {"32r6s", 1, bfd_mach_nanomipsisa32r6, CPU_NANOMIPS32R6, ISA_NANOMIPS32R6,
+   (ASE_EVA | ASE_MSA | ASE_VIRT | ASE_MCU | ASE_MT | ASE_DSP | ASE_TLB
+    | ASE_GINV | ASE_CRC),
+   nanomips_cp0_3264r6, nanomips_cp0sel_3264r6, nanomips_cp1_names_3264r6,
+   nanomips_hwr_names_3264r6},
+
+  {"64r6", 1, bfd_mach_nanomipsisa64r6, CPU_NANOMIPS64R6, ISA_NANOMIPS64R6,
+   (ASE_EVA | ASE_MSA | ASE_MSA64 | ASE_VIRT | ASE_MCU | ASE_MT | ASE_DSP
+    | ASE_DSP64 | ASE_xNMS | ASE_TLB | ASE_GINV | ASE_CRC | ASE_CRC64),
+   nanomips_cp0_3264r6, nanomips_cp0sel_3264r6, nanomips_cp1_names_3264r6,
+   nanomips_hwr_names_3264r6},
+};
+
+/* ISA and processor type to disassemble for, and register names to use.
+   set_default_nanomips_dis_options and parse_nanomips_dis_options fill in
+   these values.  */
+
+static int nanomips_processor;
+static int nanomips_ase;
+static int nanomips_isa;
+static const char *const *nanomips_gpr_names;
+static const char *const *nanomips_fpr_names;
+static const struct nanomips_cp0_name *nanomips_cp0_names;
+static const struct nanomips_cp0_select *nanomips_cp0sel_names;
+static const char *const *nanomips_cp1_names;
+static const struct nanomips_hwr_name *nanomips_hwr_names;
+
+/* Other options */
+static int no_aliases;	/* If set, disassemble as most general inst.  */
+static bool show_arch_insn; 	/* Mnemonics with suffix.  */
+static bool show_mttgpr_rc1 = false; /* RC1 style MTTGPR format.  */
+\f
+
+/* 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;
+    }
+}
+\f
+/* 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 *),
+		 bfd_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;
+	}
+    }
+}
+\f
+
+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];
+  bfd_uint64_t higher = 0;
+  unsigned int length;
+  int status;
+  bfd_uint64_t insn;
+
+  bfd_vma memaddr = memaddr_base;
+
+  info->bytes_per_chunk = 2;
+  info->display_endian = info->endian;
+  info->insn_info_valid = 1;
+  info->branch_delay_insns = 0;
+  info->data_size = 0;
+  info->insn_type = dis_nonbranch;
+  info->target = 0;
+  info->target2 = 0;
+
+  status = (*info->read_memory_func) (memaddr, buffer, 2, info);
+  if (status != 0)
+    {
+      (*info->memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+
+  length = 2;
+
+  if (info->endian == BFD_ENDIAN_BIG)
+    insn = bfd_getb16 (buffer);
+  else
+    insn = bfd_getl16 (buffer);
+
+  if ((insn & 0xfc00) == 0x6000)
+    {
+      unsigned imm;
+      /* This is a 48-bit nanoMIPS instruction. */
+      status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
+      if (status != 0)
+	{
+	  infprintf (is, "0x%x (expected 48 bits, got only 16): ",
+		     (unsigned) insn);
+	  (*info->memory_error_func) (status, memaddr + 2, info);
+	  return -1;
+	}
+      if (info->endian == BFD_ENDIAN_BIG)
+	imm = bfd_getb16 (buffer);
+      else
+	imm = bfd_getl16 (buffer);
+      higher = (imm << 16);
+
+      status = (*info->read_memory_func) (memaddr + 4, buffer, 2, info);
+      if (status != 0)
+	{
+	  infprintf (is, "0x%x (expected 48 bits, got only 32): ",
+		     (unsigned) insn);
+	  (*info->memory_error_func) (status, memaddr + 4, info);
+	  return -1;
+	}
+
+      if (info->endian == BFD_ENDIAN_BIG)
+	imm = bfd_getb16 (buffer);
+      else
+	imm = bfd_getl16 (buffer);
+      higher = higher | imm;
+
+      length += 4;
+    }
+  else if ((insn & 0x1000) == 0x0)
+    {
+      /* This is a 32-bit nanoMIPS instruction.  */
+      higher = insn;
+
+      status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
+      if (status != 0)
+	{
+	  infprintf (is, "0x%x (expected 32 bits, got only 16): ",
+		     (unsigned) higher);
+	  (*info->memory_error_func) (status, memaddr + 2, info);
+	  return -1;
+	}
+
+      if (info->endian == BFD_ENDIAN_BIG)
+	insn = bfd_getb16 (buffer);
+      else
+	insn = bfd_getl16 (buffer);
+
+      insn = insn | (higher << 16);
+
+      length += 2;
+    }
+
+  /* FIXME: Should probably use a hash table on the major opcode here.  */
+  const struct nanomips_opcode *opcodes;
+  int num_opcodes;
+  struct nanomips_operand const *(*decode) (const char *);
+
+  opcodes = nanomips_opcodes;
+  num_opcodes = bfd_nanomips_num_opcodes;
+  decode = decode_nanomips_operand;
+
+  opend = opcodes + num_opcodes;
+  for (op = opcodes; op < opend; op++)
+    {
+      if (op->pinfo != INSN_MACRO
+	  && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
+	  && (show_mttgpr_rc1 || (op->pinfo2 & INSN2_MTTGPR_RC1) == 0)
+	  && (insn & op->mask) == op->match
+	  && ((length == 2 && (op->mask & 0xffff0000) == 0)
+	      || (length == 6
+		  && (op->mask & 0xffff0000) == 0)
+	      || (length == 4 && (op->mask & 0xffff0000) != 0)))
+	{
+	  if (!nanomips_opcode_is_member (op, nanomips_isa, nanomips_ase,
+					  nanomips_processor)
+	      || (op->pinfo2 & INSN2_CONVERTED_TO_COMPACT))
+	    continue;
+
+	  if (!validate_insn_args (op, decode, insn, info))
+	    continue;
+
+	  infprintf (is, "%s%s", op->name,
+		     (show_arch_insn ? op->suffix : ""));
+
+	  if (length == 6)
+	    insn |= (higher << 32);
+
+	  if (op->args[0])
+	    print_insn_args (info, op, decode, insn, memaddr, length);
+
+	  /* Figure out instruction type and branch delay information.  */
+	  if ((op->pinfo2 & INSN2_UNCOND_BRANCH) != 0)
+	    {
+	      if ((op->pinfo & (INSN_WRITE_GPR_31 | INSN_WRITE_1)) != 0)
+		info->insn_type = dis_jsr;
+	      else
+		info->insn_type = dis_branch;
+	    }
+	  else if ((op->pinfo2 & INSN2_COND_BRANCH) != 0)
+	    {
+	      if ((op->pinfo & INSN_WRITE_GPR_31) != 0)
+		info->insn_type = dis_condjsr;
+	      else
+		info->insn_type = dis_condbranch;
+	    }
+	  else if ((op->pinfo & (INSN_STORE_MEMORY | INSN_LOAD_MEMORY)) != 0)
+	    info->insn_type = dis_dref;
+
+	  return length;
+	}
+    }
+
+  infprintf (is, "0x%x", (unsigned) insn);
+  info->insn_type = dis_noninsn;
+
+  return length;
+}
+
+/* Set up the options and disassemble.  */
+
+int
+print_insn_nanomips (bfd_vma memaddr, struct disassemble_info *info)
+{
+  set_default_nanomips_dis_options (info);
+  parse_nanomips_dis_options (info->disassembler_options);
+
+  return _print_insn_nanomips (memaddr, info);
+}
+\f
+/* 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"));
+}
+\f
+/* nanoMIPS hook to predict instruction length from opcode bits.  */
+
+int
+nanomips_predict_insn_length (bfd_vma memaddr_base,
+			      int previous_octect ATTRIBUTE_UNUSED,
+			      struct disassemble_info *info)
+{
+  bfd_byte buffer[2];
+  unsigned int length;
+  bfd_uint64_t insn;
+  bfd_vma memaddr = memaddr_base;
+  int status;
+
+  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)
+    length += 4;
+  else if ((insn & 0x1000) == 0x0)
+    length += 2;
+
+  return length;
+}
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] 13+ messages in thread

* [PATCH 2/3] sim: Add nanoMIPS port
       [not found] <20220429155813.388328-1-aleksandar.rikalo@syrmia.com>
  2022-04-29 15:58 ` [PATCH 1/3] bfd: Add support for nanoMIPS architecture Aleksandar Rikalo
@ 2022-04-29 15:58 ` Aleksandar Rikalo
  2022-05-04 12:45   ` Mike Frysinger
  2022-11-21 11:06   ` [PATCH v3 1/2] " Aleksandar Rikalo
  2022-04-29 15:58 ` [PATCH 3/3] gdb: " Aleksandar Rikalo
  2 siblings, 2 replies; 13+ messages in thread
From: Aleksandar Rikalo @ 2022-04-29 15:58 UTC (permalink / raw)
  To: gdb-patches

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>
---
 sim/common/sim-bits.h     |    4 +
 sim/configure             |    8 +
 sim/mips/Makefile.in      |   42 +
 sim/mips/configure        |   71 +
 sim/mips/configure.ac     |   28 +
 sim/mips/interp.c         |   75 +-
 sim/mips/micromips.igen   |   22 +-
 sim/mips/micromips16.dc   |    3 +
 sim/mips/mips.igen        |  441 +++--
 sim/mips/nanomipsdsp.igen | 1116 +++++++++++++
 sim/mips/nanomipsr6.igen  | 3283 +++++++++++++++++++++++++++++++++++++
 sim/mips/nanomipsrun.c    |  109 ++
 sim/mips/nms.c            |   44 +
 sim/mips/sim-main.c       |   87 +-
 sim/mips/sim-main.h       |  154 +-
 15 files changed, 5321 insertions(+), 166 deletions(-)
 create mode 100644 sim/mips/nanomipsdsp.igen
 create mode 100644 sim/mips/nanomipsr6.igen
 create mode 100644 sim/mips/nanomipsrun.c
 create mode 100644 sim/mips/nms.c

diff --git a/sim/common/sim-bits.h b/sim/common/sim-bits.h
index fab1dab478c..8799916de26 100644
--- a/sim/common/sim-bits.h
+++ b/sim/common/sim-bits.h
@@ -499,15 +499,19 @@ INLINE_SIM_BITS(unsigned_word) MSINSERTED (unsigned_word val, int start, int sto
 #define EXTEND4(X)  (LSSEXT ((X), 3))
 #define EXTEND5(X)  (LSSEXT ((X), 4))
 #define EXTEND6(X)  (LSSEXT ((X), 5))
+#define EXTEND7(X)  (LSSEXT ((X), 6))
 #define EXTEND8(X)  ((signed_word)(int8_t)(X))
 #define EXTEND9(X)  (LSSEXT ((X), 8))
+#define EXTEND10(X)  (LSSEXT ((X), 9))
 #define EXTEND11(X)  (LSSEXT ((X), 10))
 #define EXTEND12(X)  (LSSEXT ((X), 11))
+#define EXTEND14(X)  (LSSEXT ((X), 13))
 #define EXTEND15(X)  (LSSEXT ((X), 14))
 #define EXTEND16(X) ((signed_word)(int16_t)(X))
 #define EXTEND18(X)  (LSSEXT ((X), 17))
 #define EXTEND19(X)  (LSSEXT ((X), 18))
 #define EXTEND21(X)  (LSSEXT ((X), 20))
+#define EXTEND22(X)  (LSSEXT ((X), 21))
 #define EXTEND24(X)  (LSSEXT ((X), 23))
 #define EXTEND25(X)  (LSSEXT ((X), 24))
 #define EXTEND26(X)  (LSSEXT ((X), 25))
diff --git a/sim/configure b/sim/configure
index b31c2f5d8f3..cc2d957192f 100755
--- a/sim/configure
+++ b/sim/configure
@@ -15298,6 +15298,14 @@ fi
       sim_enable_arch_mips=true
       sim_igen=yes
       ;;
+    nanomips*-*-*)
+
+      sim_arch=mips
+      subdirs="$subdirs mips"
+
+      sim_igen=yes
+        ;;
+
   esac
 
 
diff --git a/sim/mips/Makefile.in b/sim/mips/Makefile.in
index 75438be5a18..6bf2d14bdef 100644
--- a/sim/mips/Makefile.in
+++ b/sim/mips/Makefile.in
@@ -61,6 +61,7 @@ SIM_OBJS = \
 	cp1.o \
 	mdmx.o \
 	dsp.o \
+	nms.o \
 	sim-main.o \
 	sim-resume.o \
 
@@ -79,6 +80,20 @@ SIM_EXTRA_DEPS = itable.h
 
 ## COMMON_POST_CONFIG_FRAG
 
+interp.o: $(srcdir)/interp.c sim-main.h itable.h
+
+m16run.o: sim-main.h m16_idecode.h m32_idecode.h m16run.c $(SIM_EXTRA_DEPS)
+
+micromipsrun.o: sim-main.h micromips16_idecode.h micromips32_idecode.h \
+		micromips_m32_idecode.h micromipsrun.c $(SIM_EXTRA_DEPS)
+
+nms.o: $(srcdir)/nms.c $(srcdir)/sim-main.h
+
+multi-run.o: multi-include.h tmp-mach-multi
+
+../igen/igen:
+	cd ../igen && $(MAKE)
+
 IGEN_TRACE= # -G omit-line-numbers # -G trace-rule-selection -G trace-rule-rejection -G trace-entries # -G trace-all
 IGEN_INSN=$(srcdir)/mips.igen
 IGEN_DC=$(srcdir)/mips.dc
@@ -99,6 +114,8 @@ IGEN_INCLUDE=\
 	$(srcdir)/dsp2.igen \
 	$(srcdir)/mips3264r2.igen \
 	$(srcdir)/mips3264r6.igen \
+	$(srcdir)/nanomipsdsp.igen \
+	$(srcdir)/nanomipsr6.igen
 
 # NB:	Since these can be built by a number of generators, care
 #	must be taken to ensure that they are only dependant on
@@ -463,8 +480,11 @@ tmp-mach-multi: $(IGEN_INSN) $(IGEN_DC) $(IGEN) $(IGEN_INCLUDE)
 	  f=`echo $${t} | sed -e 's/.*://'` ; \
 	  case $${p} in \
 	    micromips16*) e="-B 16 -H 15 -o $(MICROMIPS16_DC) -F 16" ;; \
+	    nanomips16*) e="-B 16 -H 15 -o $(MICROMIPS16_DC) -F 16" ;; \
 	    micromips32* | micromips64*) \
 		e="-B 32 -H 31 -o $(MICROMIPS32_DC) -F $${f}" ;; \
+	    nanomips32* | nanomips64*) \
+		e="-B 32 -H 31 -o $(MICROMIPS32_DC) -F $${f}" ;; \
 	    micromips_m32*) \
 		e="-B 32 -H 31 -o $(IGEN_DC) -F $${f}"; \
 		m="mips32r2,mips3d,mdmx,dsp,dsp2,smartmips" ;; \
@@ -579,6 +599,28 @@ tmp-run-multi: $(srcdir)/m16run.c $(srcdir)/micromipsrun.c
 	      $(SHELL) $(srcdir)/../../move-if-change tmp-run \
 						      micromips$${m}_run.c ; \
              ;;\
+	    nanomips32*) \
+	      m=`echo $${t} | sed -e 's/^nanomips32//' -e 's/:.*//'`; \
+	      sed <  $(srcdir)/nanomipsrun.c > tmp-run \
+		    -e "s/^sim_/nanomips32$${m}_/" \
+		    -e "s/nanomips_instruction_decode/nanomips32$${m}_instruction_decode/g" \
+		    -e "s/nanomips16_/nanomips16$${m}_/" \
+		    -e "s/nanomips32_/nanomips32$${m}_/" \
+		    -e "s/m32_/m32$${m}_/" ; \
+	      $(SHELL) $(srcdir)/../../move-if-change tmp-run \
+						      nanomips$${m}_run.c ; \
+             ;;\
+	    nanomips64*) \
+	      m=`echo $${t} | sed -e 's/^nanomips64//' -e 's/:.*//'`; \
+	      sed <  $(srcdir)/nanomipsrun.c > tmp-run \
+		    -e "s/^sim_/nanomips64$${m}_/" \
+		    -e "s/nanomips_instruction_decode/nanomips64$${m}_instruction_decode/g" \
+		    -e "s/nanomips16_/nanomips16$${m}_/" \
+		    -e "s/nanomips32_/nanomips64$${m}_/" \
+		    -e "s/m32_/m64$${m}_/" ; \
+	      $(SHELL) $(srcdir)/../../move-if-change tmp-run \
+						      nanomips$${m}_run.c ; \
+             ;;\
 	  esac \
 	done
 	$(SILENCE) touch $@
diff --git a/sim/mips/configure b/sim/mips/configure
index 2f635a50e10..1438951b5d1 100755
--- a/sim/mips/configure
+++ b/sim/mips/configure
@@ -1874,6 +1874,12 @@ case "${target}" in
 			  mipsisa64r6:mips64r6:32,64,f:mipsisa32r6,mipsisa64r6"
 			sim_multi_default=mipsisa64r2
 			;;
+  nanomips*-elf*)
+			sim_gen=MULTI
+			sim_multi_configs="\
+			  nanor6sim:nanomips64r6,nanomipsdsp:32,64,f:nanomipsisa64r6,nanomipsisa32r6"
+			sim_multi_default=nanomipsisa32r6
+			;;
   mips64*-*-*)		sim_igen_filter="32,64,f"
 			sim_gen=IGEN
 			;;
@@ -2072,6 +2078,17 @@ __EOF__
 	sim_multi_obj="${sim_multi_obj} micromips${name}_run.o"
 	sim_multi_flags="${sim_multi_flags} -F 16,32"
 	;;
+      *:*nanomips32*)
+	# Run igen twice, once for nanomips32 and once for nanomips16.
+	ws="nanomips16 nanomips32"
+
+	# The top-level function for the micromips simulator is
+	# in a file micromips${name}_run.c, generated by the
+	# tmp-run-multi Makefile rule.
+	sim_multi_src="${sim_multi_src} nanomips${name}_run.c"
+	sim_multi_obj="${sim_multi_obj} nanomips${name}_run.o"
+	sim_multi_flags="${sim_multi_flags} -F 16,32"
+	;;
       *:*micromips64*:*)
 	# Run igen thrice, once for micromips64, once for micromips16,
 	# and once for m64.
@@ -2084,6 +2101,17 @@ __EOF__
 	sim_multi_obj="${sim_multi_obj} micromips${name}_run.o"
 	sim_multi_flags="${sim_multi_flags} -F 16,32,64"
 	;;
+      *:*nanomips64*)
+	# Run igen twice, once for nanomips64 and once for nanomips16.
+	ws="nanomips16 nanomips64"
+
+	# The top-level function for the micromips simulator is
+	# in a file micromips${name}_run.c, generated by the
+	# tmp-run-multi Makefile rule.
+	sim_multi_src="${sim_multi_src} nanomips${name}_run.c"
+	sim_multi_obj="${sim_multi_obj} nanomips${name}_run.o"
+	sim_multi_flags="${sim_multi_flags} -F 16,32,64"
+	;;
       *)
 	ws=m32
 	;;
@@ -2126,6 +2154,8 @@ __EOF__
     }
 }
 
+int
+mips_mach_multi (SIM_DESC sd);
 int
 mips_mach_multi (SIM_DESC sd)
 {
@@ -2155,6 +2185,47 @@ __EOF__
       return bfd_mach_${sim_multi_default};
     }
 }
+
+address_word
+micromips_instruction_decode_multi (SIM_DESC sd,
+            sim_cpu* cpu,
+            address_word cia,
+            int instruction_size)
+{
+  unsigned long bfdmach;
+  if (STATE_ARCHITECTURE(SD) == NULL)
+    bfdmach = bfd_mach_${sim_multi_default};
+  else
+    bfdmach = STATE_ARCHITECTURE(SD)->mach;
+
+  switch (bfdmach)
+    {
+__EOF__
+
+  # Add a case statement for each micromips-enabled engine
+  for fc in ${micromips_configs}; do
+    machine=`echo ${fc} | sed 's/.*:\(.*\):.*:.*:.*:.*/\1/'`
+    name=`echo ${fc} | sed 's/:.*//'`
+    bfdmachs=`echo ${fc} | sed 's/.*:.*:.*:.*:\(.*\):.*/\1/'`
+    case ${machine} in
+      micromips*)
+  for bfdmach in `echo ${bfdmachs} | sed 's/,/ /g'`; do
+    echo "      case bfd_mach_${bfdmach}:" >> multi-run.c
+  done
+  echo "  return ${name}_instruction_decode (sd, cpu, cia, instruction_size);" >> multi-run.c
+  ;;
+      *)
+  ;;
+    esac
+  done
+
+  cat << __EOF__ >> multi-run.c
+      default:
+  fprintf(stderr, "no valid micromips instruction decoder for this micromips engine\n");
+  abort();
+  break;
+    }
+}
 __EOF__
 
   SIM_SUBTARGET="$SIM_SUBTARGET -DMIPS_MACH_MULTI"
diff --git a/sim/mips/configure.ac b/sim/mips/configure.ac
index 96806424958..0d48b9630d9 100644
--- a/sim/mips/configure.ac
+++ b/sim/mips/configure.ac
@@ -106,6 +106,12 @@ case "${target}" in
 			  mipsisa64r6:mips64r6:32,64,f:mipsisa32r6,mipsisa64r6"
 			sim_multi_default=mipsisa64r2
 			;;
+  nanomips*-*-elf*)
+			sim_gen=MULTI
+			sim_multi_configs="\
+			  nanor6sim:nanomips64r6,nanomipsdsp:32,64,f:nanomipsisa64r6,nanomipsisa32r6"
+			sim_multi_default=nanomipsisa64r6
+			;;
   mips64*-*-*)		sim_igen_filter="32,64,f"
 			sim_gen=IGEN
 			;;
@@ -304,6 +310,17 @@ __EOF__
 	sim_multi_obj="${sim_multi_obj} micromips${name}_run.o"
 	sim_multi_flags="${sim_multi_flags} -F 16,32"
 	;;
+      *:*nanomips32*)
+	# Run igen twice, once for nanomips32 and once for nanomips16.
+	ws="nanomips16 nanomips32"
+
+	# The top-level function for the micromips simulator is
+	# in a file micromips${name}_run.c, generated by the
+	# tmp-run-multi Makefile rule.
+	sim_multi_src="${sim_multi_src} nanomips${name}_run.c"
+	sim_multi_obj="${sim_multi_obj} nanomips${name}_run.o"
+	sim_multi_flags="${sim_multi_flags} -F 16,32"
+	;;
       *:*micromips64*:*)
 	# Run igen thrice, once for micromips64, once for micromips16,
 	# and once for m64.
@@ -316,6 +333,17 @@ __EOF__
 	sim_multi_obj="${sim_multi_obj} micromips${name}_run.o"
 	sim_multi_flags="${sim_multi_flags} -F 16,32,64"
 	;;
+      *:*nanomips64*)
+	# Run igen twice, once for nanomips64 and once for nanomips16.
+	ws="nanomips16 nanomips64"
+
+	# The top-level function for the micromips simulator is
+	# in a file micromips${name}_run.c, generated by the
+	# tmp-run-multi Makefile rule.
+	sim_multi_src="${sim_multi_src} nanomips${name}_run.c"
+	sim_multi_obj="${sim_multi_obj} nanomips${name}_run.o"
+	sim_multi_flags="${sim_multi_flags} -F 16,32,64"
+	;;
       *)
 	ws=m32
 	;;
diff --git a/sim/mips/interp.c b/sim/mips/interp.c
index c5d0901428b..eba56df0a3e 100644
--- a/sim/mips/interp.c
+++ b/sim/mips/interp.c
@@ -140,6 +140,7 @@ static SIM_ADDR lsipmon_monitor_base = 0xBFC00200;
 
 static SIM_RC sim_firmware_command (SIM_DESC sd, char* arg);
 
+int is_nanomips = 0;
 #define MEM_SIZE (8 << 20)	/* 8 MBytes */
 
 
@@ -672,10 +673,13 @@ sim_open (SIM_OPEN_KIND kind, host_callback *cb,
 	  cpu->register_widths[rn] = WITH_TARGET_FLOATING_POINT_BITSIZE;
 	else if ((rn >= 33) && (rn <= 37))
 	  cpu->register_widths[rn] = WITH_TARGET_WORD_BITSIZE;
+	else if ((rn >= 70) && (rn <= 78))
+	  cpu->register_widths[rn] = WITH_TARGET_WORD_BITSIZE;
 	else if ((rn == SRIDX)
 		 || (rn == FCR0IDX)
 		 || (rn == FCR31IDX)
-		 || ((rn >= 72) && (rn <= 89)))
+		 || (rn == DSPCRIDX)
+		 || ((rn >= 80) && (rn <= 89)))
 	  cpu->register_widths[rn] = 32;
 	else
 	  cpu->register_widths[rn] = 0;
@@ -1200,7 +1204,7 @@ sim_monitor (SIM_DESC sd,
     case 6: /* int open(char *path,int flags) */
       {
 	char *path = fetch_str (sd, A0);
-	V0 = sim_io_open (sd, path, (int)A1);
+	SET_RV0 (sim_io_open (sd, path, (int)A1));
 	free (path);
 	break;
       }
@@ -1210,7 +1214,7 @@ sim_monitor (SIM_DESC sd,
 	int fd = A0;
 	int nr = A2;
 	char *buf = zalloc (nr);
-	V0 = sim_io_read (sd, fd, buf, nr);
+	SET_RV0 (sim_io_read (sd, fd, buf, nr));
 	sim_write (sd, A1, (unsigned char *)buf, nr);
 	free (buf);
       }
@@ -1222,7 +1226,7 @@ sim_monitor (SIM_DESC sd,
 	int nr = A2;
 	char *buf = zalloc (nr);
 	sim_read (sd, A1, (unsigned char *)buf, nr);
-	V0 = sim_io_write (sd, fd, buf, nr);
+	SET_RV0 (sim_io_write (sd, fd, buf, nr));
 	if (fd == 1)
 	    sim_io_flush_stdout (sd);
 	else if (fd == 2)
@@ -1233,14 +1237,14 @@ sim_monitor (SIM_DESC sd,
 
     case 10: /* int close(int file) */
       {
-	V0 = sim_io_close (sd, (int)A0);
+	SET_RV0 (sim_io_close (sd, (int)A0));
 	break;
       }
 
     case 2:  /* Densan monitor: char inbyte(int waitflag) */
       {
 	if (A0 == 0)	/* waitflag == NOWAIT */
-	  V0 = (unsigned_word)-1;
+	    SET_RV0 ((unsigned_word)-1);
       }
      /* Drop through to case 11 */
 
@@ -1252,10 +1256,10 @@ sim_monitor (SIM_DESC sd,
         if (sim_io_read_stdin (sd, &tmp, sizeof(char)) != sizeof(char))
 	  {
 	    sim_io_error(sd,"Invalid return from character read");
-	    V0 = (unsigned_word)-1;
+	    SET_RV0 ((unsigned_word)-1);
 	  }
         else
-	  V0 = (unsigned_word)tmp;
+	    SET_RV0 ((unsigned_word)tmp);
 	break;
       }
 
@@ -1531,21 +1535,26 @@ store_word (SIM_DESC sd,
 	    uword64 vaddr,
 	    signed_word val)
 {
-  address_word paddr = vaddr;
+  address_word paddr;
+  int uncached;
 
   if ((vaddr & 3) != 0)
     SignalExceptionAddressStore ();
   else
     {
-      const uword64 mask = 7;
-      uword64 memval;
-      unsigned int byte;
-
-      paddr = (paddr & ~mask) | ((paddr & mask) ^ (ReverseEndian << 2));
-      byte = (vaddr & mask) ^ (BigEndianCPU << 2);
-      memval = ((uword64) val) << (8 * byte);
-      StoreMemory (AccessLength_WORD, memval, 0, paddr, vaddr,
-		   isREAL);
+      if (AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached,
+			      isTARGET, isREAL))
+	{
+	  const uword64 mask = 7;
+	  uword64 memval;
+	  unsigned int byte;
+
+	  paddr = (paddr & ~mask) | ((paddr & mask) ^ (ReverseEndian << 2));
+	  byte = (vaddr & mask) ^ (BigEndianCPU << 2);
+	  memval = ((uword64) val) << (8 * byte);
+	  StoreMemory (uncached, AccessLength_WORD, memval, 0, paddr, vaddr,
+		       isREAL);
+	}
     }
 }
 
@@ -1567,18 +1576,24 @@ load_word (SIM_DESC sd,
     }
   else
     {
-      address_word paddr = vaddr;
-      const uword64 mask = 0x7;
-      const unsigned int reverse = ReverseEndian ? 1 : 0;
-      const unsigned int bigend = BigEndianCPU ? 1 : 0;
-      uword64 memval;
-      unsigned int byte;
-
-      paddr = (paddr & ~mask) | ((paddr & mask) ^ (reverse << 2));
-      LoadMemory (&memval, NULL, AccessLength_WORD, paddr, vaddr, isDATA,
-		  isREAL);
-      byte = (vaddr & mask) ^ (bigend << 2);
-      return EXTEND32 (memval >> (8 * byte));
+      address_word paddr;
+      int uncached;
+
+      if (AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached,
+			      isTARGET, isREAL))
+	{
+	  const uword64 mask = 0x7;
+	  const unsigned int reverse = ReverseEndian ? 1 : 0;
+	  const unsigned int bigend = BigEndianCPU ? 1 : 0;
+	  uword64 memval;
+	  unsigned int byte;
+
+	  paddr = (paddr & ~mask) | ((paddr & mask) ^ (reverse << 2));
+	  LoadMemory (&memval,NULL,uncached, AccessLength_WORD, paddr, vaddr,
+			       isDATA, isREAL);
+	  byte = (vaddr & mask) ^ (bigend << 2);
+	  return EXTEND32 (memval >> (8 * byte));
+	}
     }
 
   return 0;
diff --git a/sim/mips/micromips.igen b/sim/mips/micromips.igen
index bb61b3f26e6..55545403a4b 100644
--- a/sim/mips/micromips.igen
+++ b/sim/mips/micromips.igen
@@ -42,6 +42,7 @@
 *micromips32:
 *micromips64:
 *micromipsdsp:
+*nanomipsdsp:
 {
   instruction_word delay_insn;
   sim_events_slip (SD, 1);
@@ -49,7 +50,7 @@
   CIA = nia;
   STATE |= simDELAYSLOT;
   ENGINE_ISSUE_PREFIX_HOOK();
-  micromips_instruction_decode (SD, CPU, CIA, delayslot_instruction_size);
+  MICROMIPS_INSTRUCTION_DECODE (SD, CPU, CIA, delayslot_instruction_size);
   STATE &= ~simDELAYSLOT;
   return target;
 }
@@ -128,6 +129,8 @@
 :function:::FP_formats:convert_fmt_micromips:int fmt
 *micromips32:
 *micromips64:
+*nanomips32r6:
+*nanomips64r6:
 {
   switch (fmt)
     {
@@ -141,6 +144,8 @@
 :function:::FP_formats:convert_fmt_micromips_cvt_d:int fmt
 *micromips32:
 *micromips64:
+*nanomips32r6:
+*nanomips64r6:
 {
   switch (fmt)
     {
@@ -155,6 +160,8 @@
 :function:::FP_formats:convert_fmt_micromips_cvt_s:int fmt
 *micromips32:
 *micromips64:
+*nanomips32r6:
+*nanomips64r6:
 {
   switch (fmt)
     {
@@ -865,8 +872,11 @@
   address_word base = GPR[BASE];
   address_word offset = EXTEND12 (IMMEDIATE);
   address_word vaddr = loadstore_ea (SD_, base, offset);
-  address_word paddr = vaddr;
-  CacheOp (OP, vaddr, paddr, instruction_0);
+  address_word paddr;
+  int uncached;
+  if (AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached,
+			  isTARGET, isREAL))
+    CacheOp (OP, vaddr, paddr, instruction_0);
 }
 
 
@@ -2275,6 +2285,8 @@
 :%s::::FMT_MICROMIPS:int fmt
 *micromips32:
 *micromips64:
+*nanomips32r6:
+*nanomips64r6:
 {
   switch (fmt)
     {
@@ -2289,6 +2301,8 @@
 :%s::::FMT_MICROMIPS_CVT_D:int fmt
 *micromips32:
 *micromips64:
+*nanomips32r6:
+*nanomips64r6:
 {
   switch (fmt)
     {
@@ -2303,6 +2317,8 @@
 :%s::::FMT_MICROMIPS_CVT_S:int fmt
 *micromips32:
 *micromips64:
+*nanomips32r6:
+*nanomips64r6:
 {
   switch (fmt)
     {
diff --git a/sim/mips/micromips16.dc b/sim/mips/micromips16.dc
index a1cd9a0ea89..ace9bb94fad 100644
--- a/sim/mips/micromips16.dc
+++ b/sim/mips/micromips16.dc
@@ -8,4 +8,7 @@
 
   switch,combine        :  9 :    6 :    :    :    :      :      :
   switch,combine        :  9 :    5 :    :    :    :      :      :
+  switch,combine        :  3 :    0 :    :    :    :      :      :
+  switch,combine        :  2 :    0 :    :    :    :      :      :
+  switch,combine        :  5 :    3 :    :    :    :      :      :
   switch,combine        :  0 :    0 :    :    :    :      :      :
diff --git a/sim/mips/mips.igen b/sim/mips/mips.igen
index dfad4227615..8f427ce258b 100644
--- a/sim/mips/mips.igen
+++ b/sim/mips/mips.igen
@@ -79,6 +79,9 @@
 :model:::micromips32:micromips64:	// micromips.igen
 :model:::micromips64:micromips64:	// micromips.igen
 :model:::micromipsdsp:micromipsdsp:	// micromipsdsp.igen
+:model:::nanomips32r6:nanomips32r6: // nanomipsr6.igen
+:model:::nanomips64r6:nanomips64r6: // nanomipsr6.igen
+:model:::nanomipsdsp:nanomipsdsp: // nanompsdsp.igen
 
 //  Vendor Extensions
 //
@@ -98,6 +101,31 @@
 // For grep - RSVD_INSTRUCTION, RSVD_INSTRUCTION_MASK
 000000,5.*,5.*,5.*,5.OP,111001:SPECIAL:32::RSVD
 "rsvd <OP>"
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*mips64:
+*mips64r2:
+*vr4100:
+*vr4120:
+*vr5000:
+*vr5400:
+*vr5500:
+*r3900:
+*mips16:
+*mips16e:
+*mips3d:
+*mdmx:
+*dsp:
+*dsp2:
+*smartmips:
+*micromips32:
+*micromips64:
+*micromipsdsp:
 {
   SignalException (ReservedInstruction, instruction_0);
 }
@@ -192,6 +220,7 @@
 *vr5000:
 *r3900:
 *micromips32:
+*nanomips32r6:
 {
   return base + offset;
 }
@@ -201,6 +230,7 @@
 *mips64r2:
 *micromips64:
 *mips64r6:
+*nanomips64r6:
 {
 #if 0 /* XXX FIXME: enable this only after some additional testing.  */
   /* If in user mode and UX is not set, use 32-bit compatibility effective
@@ -237,6 +267,8 @@
 *micromips32:
 *micromips64:
 *mips64r6:
+*nanomips32r6:
+*nanomips64r6:
 {
 #if WITH_TARGET_WORD_BITSIZE == 64
   return value != (((value & 0xffffffff) ^ 0x80000000) - 0x80000000);
@@ -274,6 +306,8 @@
 *micromips32:
 *micromips64:
 *mips64r6:
+*nanomips32r6:
+*nanomips64r6:
 {
   unpredictable_action (CPU, CIA);
 }
@@ -369,6 +403,7 @@
 *r3900:
 *micromips32:
 *micromips64:
+*nanomipsdsp:
 {
   int64_t time = sim_events_time (SD);
   history->mt.timestamp = time;
@@ -399,6 +434,7 @@
 *r3900:
 *micromips32:
 *micromips64:
+*nanomipsdsp:
 {
   int64_t time = sim_events_time (SD);
   int ok = 1;
@@ -473,6 +509,7 @@
 *r3900:
 *micromips32:
 *micromips64:
+*nanomipsdsp:
 {
   /* FIXME: could record the fact that a stall occured if we want */
   int64_t time = sim_events_time (SD);
@@ -570,6 +607,8 @@
 *micromips64:
 *micromips32:
 *mips64r6:
+*nanomips32r6:
+*nanomips64r6:
 {
 #if 0 /* XXX FIXME: enable this only after some additional testing.  */
   if (UserMode && (SR & (status_UX|status_PX)) == 0)
@@ -781,12 +820,44 @@
 }
 
 :function:::void:do_lb:int rt, int offset, int base
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*mips32r6:
+*mips64:
+*mips64r2:
+*mips64r6:
+*vr4100:
+*vr5000:
+*r3900:
+*micromips32:
+*micromips64:
 {
   GPR[rt] = EXTEND8 (do_load (SD_, AccessLength_BYTE, GPR[base],
 			      EXTEND16 (offset)));
 }
 
 :function:::void:do_lh:int rt, int offset, int base
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*mips32r6:
+*mips64:
+*mips64r2:
+*mips64r6:
+*vr4100:
+*vr5000:
+*r3900:
+*micromips32:
+*micromips64:
 {
   GPR[rt] = EXTEND16 (do_load (SD_, AccessLength_HALFWORD, GPR[base],
 			       EXTEND16 (offset)));
@@ -811,6 +882,22 @@
 }
 
 :function:::void:do_lw:int rt, int offset, int base
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*mips32r6:
+*mips64:
+*mips64r2:
+*mips64r6:
+*vr4100:
+*vr5000:
+*r3900:
+*micromips32:
+*micromips64:
 {
   GPR[rt] = EXTEND32 (do_load (SD_, AccessLength_WORD, GPR[base],
 			       EXTEND16 (offset)));
@@ -823,6 +910,22 @@
 }
 
 :function:::void:do_lhu:int rt, int offset, int base
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*mips32r6:
+*mips64:
+*mips64r2:
+*mips64r6:
+*vr4100:
+*vr5000:
+*r3900:
+*micromips32:
+*micromips64:
 {
   GPR[rt] = do_load (SD_, AccessLength_HALFWORD, GPR[base], EXTEND16 (offset));
 }
@@ -844,7 +947,8 @@
   address_word offset = EXTEND16 (insn_offset);
     {
       address_word vaddr = loadstore_ea (SD_, base, offset);
-      address_word paddr = vaddr;
+      address_word paddr;
+      int uncached;
       if ((vaddr & 3) != 0)
 	{
 	  SIM_CORE_SIGNAL (SD, CPU, cia, read_map, 4, vaddr, read_transfer,
@@ -852,19 +956,23 @@
 	}
       else
 	{
-	  uint64_t memval = 0;
-	  uint64_t memval1 = 0;
-	  uint64_t mask = (WITH_TARGET_WORD_BITSIZE == 64 ? 0x7 : 0x3);
-	  unsigned int shift = 2;
-	  unsigned int reverse = (ReverseEndian ? (mask >> shift) : 0);
-	  unsigned int bigend = (BigEndianCPU ? (mask >> shift) : 0);
-	  unsigned int byte;
-	  paddr = ((paddr & ~mask) | ((paddr & mask) ^ (reverse << shift)));
-	  LoadMemory (&memval, &memval1, AccessLength_WORD, paddr, vaddr,
-		      isDATA, isREAL);
-	  byte = ((vaddr & mask) ^ (bigend << shift));
-	  GPR[rt] = EXTEND32 (memval >> (8 * byte));
-	  LLBIT = 1;
+	  if (AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached,
+				  isTARGET, isREAL))
+	    {
+	      uint64_t memval = 0;
+	      uint64_t memval1 = 0;
+	      uint64_t mask = (WITH_TARGET_WORD_BITSIZE == 64 ? 0x7 : 0x3);
+	      unsigned int shift = 2;
+	      unsigned int reverse = (ReverseEndian ? (mask >> shift) : 0);
+	      unsigned int bigend = (BigEndianCPU ? (mask >> shift) : 0);
+	      unsigned int byte;
+	      paddr = ((paddr & ~mask) | ((paddr & mask) ^ (reverse << shift)));
+	      LoadMemory (&memval, &memval1, uncached, AccessLength_WORD, paddr,
+			 vaddr, isDATA, isREAL);
+	      byte = ((vaddr & mask) ^ (bigend << shift));
+	      GPR[rt] = EXTEND32 (memval >> (8 * byte));
+	      LLBIT = 1;
+	    }
 	}
     }
 }
@@ -875,8 +983,8 @@
   address_word offset = EXTEND16 (roffset);
   {
     address_word vaddr = loadstore_ea (SD_, base, offset);
-    address_word paddr = vaddr;
-
+    address_word paddr;
+    int uncached;
     if ((vaddr & 7) != 0)
       {
 	SIM_CORE_SIGNAL (SD, CPU, cia, read_map, 8, vaddr, read_transfer,
@@ -884,12 +992,16 @@
       }
     else
       {
-	uint64_t memval = 0;
-	uint64_t memval1 = 0;
-	LoadMemory (&memval, &memval1, AccessLength_DOUBLEWORD, paddr, vaddr,
-		    isDATA, isREAL);
-	GPR[rt] = memval;
-	LLBIT = 1;
+        if (AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached,
+                                isTARGET, isREAL))
+          {
+            uint64_t memval = 0;
+            uint64_t memval1 = 0;
+            LoadMemory (&memval, &memval1, uncached, AccessLength_DOUBLEWORD,
+                        paddr, vaddr, isDATA, isREAL);
+            GPR[rt] = memval;
+            LLBIT = 1;
+          }
       }
   }
 }
@@ -1137,8 +1249,13 @@
   address_word offset = EXTEND16 (insn_offset);
   {
     address_word vaddr = loadstore_ea (SD_, base, offset);
-    address_word paddr = vaddr;
-    /* Prefetch (paddr, vaddr, isDATA, hint); */
+    address_word paddr;
+    int uncached;
+    {
+      if (AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached,
+			      isTARGET, isREAL))
+	Prefetch (uncached, paddr, vaddr, isDATA, hint);
+    }
   }
 }
 
@@ -1149,8 +1266,8 @@
   address_word offset = EXTEND16 (offsetarg);
   {
     address_word vaddr = loadstore_ea (SD_, base, offset);
-    address_word paddr = vaddr;
-
+    address_word paddr;
+    int uncached;
     if ((vaddr & 3) != 0)
       {
 	SIM_CORE_SIGNAL (SD, CPU, cia, read_map, 4, vaddr, write_transfer,
@@ -1158,23 +1275,27 @@
       }
     else
       {
-	uint64_t memval = 0;
-	uint64_t memval1 = 0;
-	uint64_t mask = (WITH_TARGET_WORD_BITSIZE == 64 ? 0x7 : 0x3);
-	address_word reverseendian =
-	  (ReverseEndian ? (mask ^ AccessLength_WORD) : 0);
-	address_word bigendiancpu =
-	  (BigEndianCPU ? (mask ^ AccessLength_WORD) : 0);
-	unsigned int byte;
-	paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
-	byte = ((vaddr & mask) ^ bigendiancpu);
-	memval = ((uint64_t) GPR[rt] << (8 * byte));
-	if (LLBIT)
-	  StoreMemory (AccessLength_WORD, memval, memval1, paddr, vaddr,
-		        isREAL);
-	if (store_ll_bit)
-	  GPR[rt] = LLBIT;
-      }
+  if (AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached,
+              isTARGET, isREAL))
+    {
+    uint64_t memval = 0;
+    uint64_t memval1 = 0;
+    uint64_t mask = (WITH_TARGET_WORD_BITSIZE == 64 ? 0x7 : 0x3);
+    address_word reverseendian =
+      (ReverseEndian ? (mask ^ AccessLength_WORD) : 0);
+    address_word bigendiancpu =
+      (BigEndianCPU ? (mask ^ AccessLength_WORD) : 0);
+    unsigned int byte;
+    paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
+    byte = ((vaddr & mask) ^ bigendiancpu);
+    memval = ((uint64_t) GPR[rt] << (8 * byte));
+    if (LLBIT)
+        StoreMemory (uncached, AccessLength_WORD, memval, memval1, paddr, vaddr,
+                     isREAL);
+    if (store_ll_bit)
+      GPR[rt] = LLBIT;
+    }
+  }
   }
 }
 
@@ -1184,8 +1305,8 @@
   address_word offset = EXTEND16 (roffset);
   {
     address_word vaddr = loadstore_ea (SD_, base, offset);
-    address_word paddr = vaddr;
-
+    address_word paddr;
+    int uncached;
     if ((vaddr & 7) != 0)
       {
 	SIM_CORE_SIGNAL (SD, CPU, cia, read_map, 8, vaddr, write_transfer,
@@ -1193,15 +1314,19 @@
       }
     else
       {
+        if (AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached,
+                    isTARGET, isREAL))
+          {
 	uint64_t memval = 0;
 	uint64_t memval1 = 0;
 	memval = GPR[rt];
 	if (LLBIT)
-	  StoreMemory (AccessLength_DOUBLEWORD, memval, memval1, paddr, vaddr,
+	  StoreMemory (uncached, AccessLength_DOUBLEWORD, memval, memval1, paddr, vaddr,
 		       isREAL);
 	if (store_ll_bit)
 	  GPR[rt] = LLBIT;
       }
+    }
   }
 }
 
@@ -1688,8 +1813,11 @@
   address_word index = GPR[rindex];
   {
     address_word vaddr = loadstore_ea (SD_, base, index);
-    address_word paddr = vaddr;
-    /* Prefetch (paddr, vaddr, isDATA, hint); */
+    address_word paddr;
+    int uncached;
+    if (AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached, isTARGET,
+			    isREAL))
+      Prefetch (uncached, paddr, vaddr, isDATA, hint);
   }
 }
 
@@ -1753,8 +1881,8 @@
   check_fpu (SD_);
   {
     address_word vaddr = loadstore_ea (SD_, base, offset);
-    address_word paddr = vaddr;
-
+    address_word paddr;
+    int uncached;
     if ((vaddr & 3) != 0)
       {
 	SIM_CORE_SIGNAL (SD, CPU, cia, read_map, AccessLength_WORD+1, vaddr,
@@ -1762,18 +1890,23 @@
       }
     else
       {
-	uword64 memval = 0;
-	uword64 memval1 = 0;
-	uword64 mask = (WITH_TARGET_WORD_BITSIZE == 64 ? 0x7 : 0x3);
-	address_word reverseendian =
-	  (ReverseEndian ? (mask ^ AccessLength_WORD) : 0);
-	address_word bigendiancpu =
-	  (BigEndianCPU ? (mask ^ AccessLength_WORD) : 0);
-	unsigned int byte;
-	paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
-	byte = ((vaddr & mask) ^ bigendiancpu);
-	memval = (((uword64)COP_SW(1, ft)) << (8 * byte));
-	StoreMemory (AccessLength_WORD, memval, memval1, paddr, vaddr, isREAL);
+	if (AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached,
+			        isTARGET, isREAL))
+	  {
+	    uword64 memval = 0;
+	    uword64 memval1 = 0;
+	    uword64 mask = (WITH_TARGET_WORD_BITSIZE == 64 ? 0x7 : 0x3);
+	    address_word reverseendian =
+	      (ReverseEndian ?(mask ^ AccessLength_WORD): 0);
+	    address_word bigendiancpu =
+	      (BigEndianCPU ?(mask ^ AccessLength_WORD): 0);
+	    unsigned int byte;
+	    paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
+	    byte = ((vaddr & mask) ^ bigendiancpu);
+	    memval = (((uword64)COP_SW(1, ft)) << (8 * byte));
+	    StoreMemory (uncached, AccessLength_WORD, memval, memval1, paddr,
+			 vaddr, isREAL);
+	  }
       }
   }
 }
@@ -1786,8 +1919,8 @@
   check_u64 (SD_, instruction_0);
     {
       address_word vaddr = loadstore_ea (SD_, base, index);
-      address_word paddr = vaddr;
-
+      address_word paddr;
+      int uncached;
       if ((vaddr & 3) != 0)
 	{
 	  SIM_CORE_SIGNAL (SD, CPU, cia, read_map, 4, vaddr, write_transfer,
@@ -1795,19 +1928,23 @@
 	}
       else
 	{
-	  uint64_t memval = 0;
-	  uint64_t memval1 = 0;
-	  uint64_t mask = (WITH_TARGET_WORD_BITSIZE == 64 ? 0x7 : 0x3);
-	  address_word reverseendian =
-	    (ReverseEndian ? (mask ^ AccessLength_WORD) : 0);
-	  address_word bigendiancpu =
-	    (BigEndianCPU ? (mask ^ AccessLength_WORD) : 0);
-	  unsigned int byte;
-	  paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
-	  byte = ((vaddr & mask) ^ bigendiancpu);
-	  memval = (((uint64_t)COP_SW(1,fs)) << (8 * byte));
-	  StoreMemory (AccessLength_WORD, memval, memval1, paddr, vaddr,
-		       isREAL);
+	  if (AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached,
+				 isTARGET, isREAL))
+	    {
+	      uint64_t memval = 0;
+	      uint64_t memval1 = 0;
+	      uint64_t mask = (WITH_TARGET_WORD_BITSIZE == 64 ? 0x7 : 0x3);
+	      address_word reverseendian =
+		(ReverseEndian ? (mask ^ AccessLength_WORD) : 0);
+	      address_word bigendiancpu =
+		(BigEndianCPU ? (mask ^ AccessLength_WORD) : 0);
+	      unsigned int byte;
+	      paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
+	      byte = ((vaddr & mask) ^ bigendiancpu);
+	      memval = (((uint64_t)COP_SW(1,fs)) << (8 * byte));
+	      StoreMemory (uncached, AccessLength_WORD, memval, memval1, paddr,
+			   vaddr, isREAL);
+	    }
 	}
   }
 }
@@ -1861,7 +1998,23 @@
 
 
 
-:function:::void:do_addiu:int rs, int rt, uint16_t immediate
+:function:::void:do_addiu:int rs, int rt, int immediate
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*mips32r6:
+*mips64:
+*mips64r2:
+*mips64r6:
+*vr4100:
+*vr5000:
+*r3900:
+*micromips32:
+*micromips64:
 {
   if (NotWordValue (GPR[rs]))
     Unpredictable ();
@@ -2595,6 +2748,14 @@
 
 
 :function:::void:do_ddiv:int rs, int rt
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips64:
+*mips64r2:
+*micromips64:
+*vr4100:
+*vr5000:
 {
   check_div_hilo (SD_, HIHISTORY, LOHISTORY);
   TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]);
@@ -2641,6 +2802,14 @@
 
 
 :function:::void:do_ddivu:int rs, int rt
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips64:
+*mips64r2:
+*micromips64:
+*vr4100:
+*vr5000:
 {
   check_div_hilo (SD_, HIHISTORY, LOHISTORY);
   TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]);
@@ -2680,6 +2849,20 @@
 }
 
 :function:::void:do_div:int rs, int rt
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*micromips32:
+*mips64:
+*mips64r2:
+*micromips64:
+*vr4100:
+*vr5000:
+*r3900:
 {
   check_div_hilo (SD_, HIHISTORY, LOHISTORY);
   TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]);
@@ -2726,6 +2909,20 @@
 
 
 :function:::void:do_divu:int rs, int rt
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*micromips32:
+*mips64:
+*mips64r2:
+*micromips64:
+*vr4100:
+*vr5000:
+*r3900:
 {
   check_div_hilo (SD_, HIHISTORY, LOHISTORY);
   TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]);
@@ -3277,16 +3474,18 @@
   address_word bigendiancpu = (BigEndianCPU ? (mask ^ access) : 0);
   unsigned int byte;
   address_word paddr;
+  int uncached;
   uint64_t memval;
   address_word vaddr;
 
-  paddr = vaddr = loadstore_ea (SD_, base, offset);
+  vaddr = loadstore_ea (SD_, base, offset);
   if ((vaddr & access) != 0)
     {
       SIM_CORE_SIGNAL (SD, STATE_CPU (SD, 0), cia, read_map, access+1, vaddr, read_transfer, sim_core_unaligned_signal);
     }
+  AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached, isTARGET, isREAL);
   paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
-  LoadMemory (&memval, NULL, access, paddr, vaddr, isDATA, isREAL);
+  LoadMemory (&memval, NULL, uncached, access, paddr, vaddr, isDATA, isREAL);
   byte = ((vaddr & mask) ^ bigendiancpu);
   return (memval >> (8 * byte));
 }
@@ -3299,6 +3498,7 @@
   unsigned int byte;
   unsigned int word;
   address_word paddr;
+  int uncached;
   uint64_t memval;
   address_word vaddr;
   int nr_lhs_bits;
@@ -3306,7 +3506,8 @@
   unsigned_word lhs_mask;
   unsigned_word temp;
 
-  paddr = vaddr = loadstore_ea (SD_, base, offset);
+  vaddr = loadstore_ea (SD_, base, offset);
+  AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached, isTARGET, isREAL);
   paddr = (paddr ^ (reverseendian & mask));
   if (BigEndianMem == 0)
     paddr = paddr & ~access;
@@ -3323,7 +3524,7 @@
 	   (long) ((uint64_t) paddr >> 32), (long) paddr,
 	   word, byte, nr_lhs_bits, nr_rhs_bits); */
 
-  LoadMemory (&memval, NULL, byte, paddr, vaddr, isDATA, isREAL);
+  LoadMemory (&memval, NULL, uncached, byte, paddr, vaddr, isDATA, isREAL);
   if (word == 0)
     {
       /* GPR{31..32-NR_LHS_BITS} = memval{NR_LHS_BITS-1..0} */
@@ -3352,17 +3553,19 @@
   address_word bigendiancpu = (BigEndianCPU ? -1 : 0);
   unsigned int byte;
   address_word paddr;
+  int uncached;
   uint64_t memval;
   address_word vaddr;
 
-  paddr = vaddr = loadstore_ea (SD_, base, offset);
+  vaddr = loadstore_ea (SD_, base, offset);
+  AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached, isTARGET, isREAL);
   /* NOTE: SPEC is wrong, has `BigEndianMem == 0' not `BigEndianMem != 0' */
   paddr = (paddr ^ (reverseendian & mask));
   if (BigEndianMem != 0)
     paddr = paddr & ~access;
   byte = ((vaddr & mask) ^ (bigendiancpu & mask));
   /* NOTE: SPEC is wrong, had `byte' not `access - byte'.  See SW. */
-  LoadMemory (&memval, NULL, access - (access & byte), paddr, vaddr, isDATA, isREAL);
+  LoadMemory (&memval, NULL, uncached, access - (access & byte), paddr, vaddr, isDATA, isREAL);
   /* printf ("lr: 0x%08lx %d@0x%08lx 0x%08lx\n",
      (long) paddr, byte, (long) paddr, (long) memval); */
   {
@@ -3714,6 +3917,23 @@
 
 
 :function:::void:do_mfhi:int rd
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*vr4100:
+*vr5000:
+*r3900:
+*mips32:
+*mips64:
+*mips32r2:
+*mips64r2:
+*dsp:
+*micromips32:
+*micromips64:
+*micromipsdsp:
+*nanomipsdsp:
 {
   check_mf_hilo (SD_, HIHISTORY, LOHISTORY);
   TRACE_ALU_INPUT1 (HI);
@@ -4175,18 +4395,20 @@
   address_word bigendiancpu = (BigEndianCPU ? (mask ^ access) : 0);
   unsigned int byte;
   address_word paddr;
+  int uncached;
   uint64_t memval;
   address_word vaddr;
 
-  paddr = vaddr = loadstore_ea (SD_, base, offset);
+  vaddr = loadstore_ea (SD_, base, offset);
   if ((vaddr & access) != 0)
     {
       SIM_CORE_SIGNAL (SD, STATE_CPU(SD, 0), cia, read_map, access+1, vaddr, write_transfer, sim_core_unaligned_signal);
     }
+  AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached, isTARGET, isREAL);
   paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
   byte = ((vaddr & mask) ^ bigendiancpu);
   memval = (word << (8 * byte));
-  StoreMemory (access, memval, 0, paddr, vaddr, isREAL);
+  StoreMemory (uncached, access, memval, 0, paddr, vaddr, isREAL);
 }
 
 :function:::void:do_store_left:unsigned access, address_word base, address_word offset, unsigned_word rt
@@ -4197,12 +4419,14 @@
   unsigned int byte;
   unsigned int word;
   address_word paddr;
+  int uncached;
   uint64_t memval;
   address_word vaddr;
   int nr_lhs_bits;
   int nr_rhs_bits;
 
-  paddr = vaddr = loadstore_ea (SD_, base, offset);
+  vaddr = loadstore_ea (SD_, base, offset);
+  AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached, isTARGET, isREAL);
   paddr = (paddr ^ (reverseendian & mask));
   if (BigEndianMem == 0)
     paddr = paddr & ~access;
@@ -4229,7 +4453,7 @@
   /* fprintf (stderr, "s[wd]l: 0x%08lx%08lx -> 0x%08lx%08lx\n",
 	   (long) ((uint64_t) rt >> 32), (long) rt,
 	   (long) ((uint64_t) memval >> 32), (long) memval); */
-  StoreMemory (byte, memval, 0, paddr, vaddr, isREAL);
+  StoreMemory (uncached, byte, memval, 0, paddr, vaddr, isREAL);
 }
 
 :function:::void:do_store_right:unsigned access, address_word base, address_word offset, unsigned_word rt
@@ -4239,16 +4463,18 @@
   address_word bigendiancpu = (BigEndianCPU ? -1 : 0);
   unsigned int byte;
   address_word paddr;
+  int uncached;
   uint64_t memval;
   address_word vaddr;
 
-  paddr = vaddr = loadstore_ea (SD_, base, offset);
+  vaddr = loadstore_ea (SD_, base, offset);
+  AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached, isTARGET, isREAL);
   paddr = (paddr ^ (reverseendian & mask));
   if (BigEndianMem != 0)
     paddr &= ~access;
   byte = ((vaddr & mask) ^ (bigendiancpu & mask));
   memval = (rt << (byte * 8));
-  StoreMemory (access - (access & byte), memval, 0, paddr, vaddr, isREAL);
+  StoreMemory (uncached, access - (access & byte), memval, 0, paddr, vaddr, isREAL);
 }
 
 
@@ -5225,6 +5451,8 @@
 *vr4100:
 *vr5000:
 *r3900:
+*nanomips32r6:
+*nanomips64r6:
 {
   /* None of these ISAs support Paired Single, so just fall back to
      the single/double check.  */
@@ -5273,6 +5501,8 @@
 *r3900:
 *micromips32:
 *micromips64:
+*nanomips32r6:
+*nanomips64r6:
 {
   if (! COP_Usable (1))
     SignalExceptionCoProcessorUnusable (1);
@@ -5316,20 +5546,24 @@
   int bigendian = (BigEndianCPU ? ! ReverseEndian : ReverseEndian);
   address_word vaddr;
   address_word paddr;
+  int uncached;
   uint64_t memval;
   uint64_t v;
 
-  paddr = vaddr = loadstore_ea (SD_, base, offset);
+  vaddr = loadstore_ea (SD_, base, offset);
   if ((vaddr & AccessLength_DOUBLEWORD) != 0)
     {
       SIM_CORE_SIGNAL (SD, STATE_CPU (SD, 0), cia, read_map,
 		       AccessLength_DOUBLEWORD + 1, vaddr, read_transfer,
 		       sim_core_unaligned_signal);
     }
-  LoadMemory (&memval, NULL, AccessLength_WORD, paddr, vaddr, isDATA, isREAL);
+  AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached, isTARGET,
+		      isREAL);
+  LoadMemory (&memval, NULL, uncached, AccessLength_WORD, paddr, vaddr,
+	      isDATA, isREAL);
   v = (uint64_t)memval;
-  LoadMemory (&memval, NULL, AccessLength_WORD, paddr + 4, vaddr + 4, isDATA,
-	      isREAL);
+  LoadMemory (&memval, NULL, uncached, AccessLength_WORD, paddr + 4, vaddr + 4,
+	      isDATA, isREAL);
   return (bigendian ? ((v << 32) | memval) : (v | (memval << 32)));
 }
 
@@ -5351,19 +5585,24 @@
   int bigendian = (BigEndianCPU ? ! ReverseEndian : ReverseEndian);
   address_word vaddr;
   address_word paddr;
+  int uncached;
   uint64_t memval;
 
-  paddr = vaddr = loadstore_ea (SD_, base, offset);
+  vaddr = loadstore_ea (SD_, base, offset);
   if ((vaddr & AccessLength_DOUBLEWORD) != 0)
     {
       SIM_CORE_SIGNAL (SD, STATE_CPU(SD, 0), cia, read_map,
 		       AccessLength_DOUBLEWORD + 1, vaddr, write_transfer,
 		       sim_core_unaligned_signal);
     }
+  AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached, isTARGET,
+		      isREAL);
   memval = (bigendian ? (v >> 32) : (v & 0xFFFFFFFF));
-  StoreMemory (AccessLength_WORD, memval, 0, paddr, vaddr, isREAL);
+  StoreMemory (uncached, AccessLength_WORD, memval, 0, paddr, vaddr,
+	       isREAL);
   memval = (bigendian ? (v & 0xFFFFFFFF) : (v >> 32));
-  StoreMemory (AccessLength_WORD, memval, 0, paddr + 4, vaddr + 4, isREAL);
+  StoreMemory (uncached, AccessLength_WORD, memval, 0, paddr + 4, vaddr + 4,
+	       isREAL);
 }
 
 
@@ -6628,7 +6867,10 @@
   {
     address_word vaddr = loadstore_ea (SD_, base, offset);
     address_word paddr = vaddr;
-    CacheOp(op, vaddr, paddr, instruction_0);
+
+    int uncached;
+    if (AddressTranslation(vaddr,isDATA,isLOAD,&paddr,&uncached,isTARGET,isREAL))
+      CacheOp(op, vaddr, paddr, instruction_0);
   }
 }
 
@@ -6867,4 +7109,5 @@
 :include:::smartmips.igen
 :include:::micromips.igen
 :include:::micromipsdsp.igen
-
+:include:::nanomipsr6.igen
+:include:::nanomipsdsp.igen
diff --git a/sim/mips/nanomipsdsp.igen b/sim/mips/nanomipsdsp.igen
new file mode 100644
index 00000000000..65d0282f325
--- /dev/null
+++ b/sim/mips/nanomipsdsp.igen
@@ -0,0 +1,1116 @@
+// Simulator definition for the micromips ASE.
+// Copyright (C) 2018-2022 Free Software Foundation, Inc.
+// Contributed by Imagination Technologies, Ltd.
+// Written by Ali Lown <ali.lown@imgtec.com>
+//
+// This file is part of GDB, the GNU debugger.
+//
+// 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, see <http://www.gnu.org/licenses/>.
+
+001000,5.RT,5.RS,0001000100111111:POOL32A:32::ABSQ_S.PH
+"absq_s.ph r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_ph_s_absq (SD_, RT, RS);
+}
+
+001000,5.RT,5.RS,0000000100111111:POOL32A:32::ABSQ_S.QB
+"absq_s.qb r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_s_absq (SD_, RT, RS);
+}
+
+001000,5.RT,5.RS,0010000100111111:POOL32A:32::ABSQ_S.W
+"absq_s.w r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_w_s_absq (SD_, RT, RS);
+}
+
+001000,5.RT,5.RS,5.RD,00000001101:POOL32A:32::ADDQ.PH
+"addq.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_op (SD_, RD, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10000001101:POOL32A:32::ADDQ_S.PH
+"addq_s.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_op (SD_, RD, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1100000101:POOL32A:32::ADDQ_S.W
+"addq_s.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_op (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,00001001101:POOL32A:32::ADDQH.PH
+"addqh.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_ph_op (SD_, RD, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10001001101:POOL32A:32::ADDQH_R.PH
+"addqh_r.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_ph_op (SD_, RD, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,5.RD,00010001101:POOL32A:32::ADDQH.W
+"addqh.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_w_op (SD_, RD, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10010001101:POOL32A:32::ADDQH_R.W
+"addqh_r.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_w_op (SD_, RD, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1110000101:POOL32A:32::ADDSC
+"addsc r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_addsc (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,00100001101:POOL32A:32::ADDU.PH
+"addu.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_u_ph_op (SD_, RD, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10100001101:POOL32A:32::ADDU_S.PH
+"addu_s.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_u_ph_op (SD_, RD, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,5.RD,00011001101:POOL32A:32::ADDU.QB
+"addu.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_op (SD_, RD, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10011001101:POOL32A:32::ADDU_S.QB
+"addu_s.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_op (SD_, RD, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1111000101:POOL32A:32::ADDWC
+"addwc r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_addwc (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,00101001101:POOL32A:32::ADDUH.QB
+"adduh.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_uh_qb_op (SD_, RD, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10101001101:POOL32A:32::ADDUH_R.QB
+"adduh_r.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_uh_qb_op (SD_, RD, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,5.SA,1.X,1000010101:POOL32A:32::APPEND
+"append r<RT>, r<RS>, <SA>"
+*nanomipsdsp:
+{
+  do_append (SD_, RT, RS, SA);
+}
+
+001000,5.RT,5.RS,2.BP,00100010111111:POOL32A:32::BALIGN
+"balign r<RT>, r<RS>, <BP>"
+*nanomipsdsp:
+{
+  do_balign (SD_, RT, RS, BP);
+}
+
+001000,5.RT,5.RS,0011000100111111:POOL32A:32::BITREV
+"bitrev r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_bitrev (SD_, RT, RS);
+}
+
+100010,5.X,0010001,14.IMMEDIATE:POOL32I:32::BPOSGE32C
+"bposge32c <IMMEDIATE>"
+*nanomipsdsp:
+{
+  uint32_t pos = (DSPCR >> DSPCR_POS_SHIFT) & DSPCR_POS_MASK;
+  if (pos >= 32)
+    NIA = delayslot_micromips (SD_, NIA + (EXTEND12 (IMMEDIATE) << 1), NIA,
+			       MICROMIPS_DELAYSLOT_SIZE_ANY);
+}
+
+001000,5.RT,5.RS,6.X,0000000101:POOL32A:32::CMP.EQ.PH
+"cmp.eq.ph r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_cmpu (SD_, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,0000000001,000101:POOL32A:32::CMP.LT.PH
+"cmp.lt.ph r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_cmpu (SD_, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,0000000010,000101:POOL32A:32::CMP.LE.PH
+"cmp.le.ph r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_cmpu (SD_, RS, RT, 2);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0110000101:POOL32A:32::CMPGDU.EQ.QB
+"cmpgdu.eq.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpgdu (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0111000101:POOL32A:32::CMPGDU.LT.QB
+"cmpgdu.lt.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpgdu (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1000000101:POOL32A:32::CMPGDU.LE.QB
+"cmpgdu.le.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpgdu (SD_, RD, RS, RT, 2);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0011000101:POOL32A:32::CMPGU.EQ.QB
+"cmpgu.eq.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpgu (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0100000101:POOL32A:32::CMPGU.LT.QB
+"cmpgu.lt.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpgu (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0101000101:POOL32A:32::CMPGU.LE.QB
+"cmpgu.le.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpgu (SD_, RD, RS, RT, 2);
+}
+
+001000,5.RT,5.RS,5.X1,1.X2,1001000101:POOL32A:32::CMPU.EQ.QB
+"cmpu.eq.qb r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpu (SD_, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.X1,1.X2,1010000101:POOL32A:32::CMPU.LT.QB
+"cmpu.lt.qb r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpu (SD_, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.X1,1.X2,1011000101:POOL32A:32::CMPU.LE.QB
+"cmpu.le.qb r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpu (SD_, RS, RT, 2);
+}
+
+001000,5.RT,5.RS,2.AC,00000010111111:POOL32A:32::DPA.W.PH
+"dpa.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_ph_dot_product (SD_, AC, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,2.AC,00001010111111:POOL32A:32::DPAQ_S.W.PH
+"dpaq_s.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_dot_product (SD_, AC, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,2.AC,01001010111111:POOL32A:32::DPAQ_SA.L.W
+"dpaq_sa.l.w ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_dot_product (SD_, AC, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,2.AC,10001010111111:POOL32A:32::DPAQX_S.W.PH
+"dpaqx_s.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qx_w_ph_dot_product (SD_, AC, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,2.AC,11001010111111:POOL32A:32::DPAQX_SA.W.PH
+"dpaqx_sa.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qx_w_ph_dot_product (SD_, AC, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,2.AC,10000010111111:POOL32A:32::DPAU.H.QBL
+"dpau.h.qbl ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_dot_product (SD_, AC, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,2.AC,11000010111111:POOL32A:32::DPAU.H.QBR
+"dpau.h.qbr ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_dot_product (SD_, AC, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,2.AC,01000010111111:POOL32A:32::DPAX.W.PH
+"dpax.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_x_w_ph_dot_product (SD_, AC, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,2.AC,00010010111111:POOL32A:32::DPS.W.PH
+"dps.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_ph_dot_product (SD_, AC, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,2.AC,00011010111111:POOL32A:32::DPSQ_S.W.PH
+"dpsq_s.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_dot_product (SD_, AC, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,2.AC,01011010111111:POOL32A:32::DPSQ_SA.L.W
+"dpsq_sa.l.w ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_dot_product (SD_, AC, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,2.AC,10011010111111:POOL32A:32::DPSQX_S.W.PH
+"dpsqx_s.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qx_w_ph_dot_product (SD_, AC, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,2.AC,11011010111111:POOL32A:32::DPSQX_SA.W.PH
+"dpsqx_sa.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qx_w_ph_dot_product (SD_, AC, RS, RT, 1, 1);
+}
+
+001000,5.RT,5.RS,2.AC,10010010111111:POOL32A:32::DPSU.H.QBL
+"dpsu.h.qbl ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_dot_product (SD_, AC, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,2.AC,11010010111111:POOL32A:32::DPSU.H.QBR
+"dpsu.h.qbr ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_dot_product (SD_, AC, RS, RT, 1, 1);
+}
+
+001000,5.RT,5.RS,2.AC,01010010111111:POOL32A:32::DPSX.W.PH
+"dpsx.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_x_w_ph_dot_product (SD_, AC, RS, RT, 1);
+}
+
+001000,5.RT,5.SIZE,2.AC,10011001111111:POOL32A:32::EXTP
+"extp r<RT>, ac<AC>, <SIZE>"
+*nanomipsdsp:
+{
+  do_extp (SD_, RT, AC, SIZE, 0);
+}
+
+001000,5.RT,5.SIZE,2.AC,11011001111111:POOL32A:32::EXTPDP
+"extpdp r<RT>, ac<AC>, <SIZE>"
+*nanomipsdsp:
+{
+  do_extp (SD_, RT, AC, SIZE, 1);
+}
+
+001000,5.RT,5.RS,2.AC,11100010111111:POOL32A:32::EXTPDPV
+"extpdpv r<RT>, ac<AC>, r<RS>"
+*nanomipsdsp:
+{
+  do_extpv (SD_, RT, AC, RS, 1);
+}
+
+001000,5.RT,5.RS,2.AC,10100010111111:POOL32A:32::EXTPV
+"extpv r<RT>, ac<AC>, r<RS>"
+*nanomipsdsp:
+{
+  do_extpv (SD_, RT, AC, RS, 0);
+}
+
+001000,5.RT,5.SHIFT,2.AC,00111001111111:POOL32A:32::EXTR.W
+"extr.w r<RT>, ac<AC>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_w_extr (SD_, RT, AC, SHIFT, 0);
+}
+
+001000,5.RT,5.SHIFT,2.AC,01111001111111:POOL32A:32::EXTR_R.W
+"extr_r.w r<RT>, ac<AC>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_w_extr (SD_, RT, AC, SHIFT, 1);
+}
+
+001000,5.RT,5.SHIFT,2.AC,10111001111111:POOL32A:32::EXTR_RS.W
+"extr_rs.w r<RT>, ac<AC>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_w_extr (SD_, RT, AC, SHIFT, 2);
+}
+
+001000,5.RT,5.SHIFT,2.AC,11111001111111:POOL32A:32::EXTR_S.H
+"extr_s.h r<RT>, ac<AC>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_h_extr (SD_, RT, AC, SHIFT);
+}
+
+001000,5.RT,5.RS,2.AC,00111010111111:POOL32A:32::EXTRV.W
+"extrv.w r<RT>, ac<AC>, r<RS>"
+*nanomipsdsp:
+{
+  do_extrv (SD_, RT, AC, RS, 0);
+}
+
+001000,5.RT,5.RS,2.AC,01111010111111:POOL32A:32::EXTRV_R.W
+"extrv_r.w r<RT>, ac<AC>, r<RS>"
+*nanomipsdsp:
+{
+  do_extrv (SD_, RT, AC, RS, 1);
+}
+
+001000,5.RT,5.RS,2.AC,10111010111111:POOL32A:32::EXTRV_RS.W
+"extrv_rs.w r<RT>, ac<AC>, r<RS>"
+*nanomipsdsp:
+{
+  do_extrv (SD_, RT, AC, RS, 2);
+}
+
+001000,5.RT,5.RS,2.AC,11111010111111:POOL32A:32::EXTRV_S.H
+"extrv_s.h r<RT>, ac<AC>, r<RS>"
+*nanomipsdsp:
+{
+  do_extrv_s_h (SD_, RT, AC, RS);
+}
+
+001000,5.RT,5.RS,0100000100111111:POOL32A:32::INSV
+"insv r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_insv (SD_, RT, RS);
+}
+
+001000,5.RT,5.RS,2.AC,00101010111111:POOL32A:32::MADD_DSP
+"madd ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_dsp_madd (SD_, AC, RS, RT);
+}
+
+001000,5.RT,5.RS,2.AC,01101010111111:POOL32A:32::MADDU_DSP
+"maddu ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_dsp_maddu (SD_, AC, RS, RT);
+}
+
+001000,5.RT,5.RS,2.AC,01101001111111:POOL32A:32::MAQ_S.W.PHL
+"maq_s.w.phl ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_maq (SD_, AC, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,2.AC,11101001111111:POOL32A:32::MAQ_SA.W.PHL
+"maq_sa.w.phl ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_maq (SD_, AC, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,2.AC,00101001111111:POOL32A:32::MAQ_S.W.PHR
+"maq_s.w.phr ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_maq (SD_, AC, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,2.AC,10101001111111:POOL32A:32::MAQ_SA.W.PHR
+"maq_sa.w.phr ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_maq (SD_, AC, RS, RT, 1, 1);
+}
+
+001000,5.RS,5.X,2.AC,00000001111111:POOL32A:32::MFHI_DSP
+"mfhi r<RS>, ac<AC>"
+*nanomipsdsp:
+{
+  do_dsp_mfhi (SD_, AC, RS);
+}
+
+001000,5.RS,5.X,2.AC,01000001111111:POOL32A:32::MFLO_DSP
+"mflo r<RS>, ac<AC>"
+*nanomipsdsp:
+{
+  do_dsp_mflo (SD_, AC, RS);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1010010101:POOL32A:32::MODSUB
+"modsub r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_modsub (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,2.AC,10101010111111:POOL32A:32::MSUB_DSP
+"msub ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_dsp_msub (SD_, AC, RS, RT);
+}
+
+001000,5.RT,5.RS,2.AC,11101010111111:POOL32A:32::MSUBU_DSP
+"msubu ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_dsp_msubu (SD_, AC, RS, RT);
+}
+
+001000,00000,5.RS,2.AC,10000001111111:POOL32A:32::MTHI_DSP
+"mthi r<RS>, ac<AC>"
+*nanomipsdsp:
+{
+  do_dsp_mthi (SD_, AC, RS);
+}
+
+001000,00000,5.RS,2.AC,00001001111111:POOL32A:32::MTHLIP
+"mthlip r<RS>, ac<AC>"
+*nanomipsdsp:
+{
+  do_mthlip (SD_, RS, AC);
+}
+
+001000,00000,5.RS,2.AC,11000001111111:POOL32A:32::MTLO_DSP
+"mtlo r<RS>, ac<AC>"
+*nanomipsdsp:
+{
+  do_dsp_mtlo (SD_, AC, RS);
+}
+
+001000,5.RT,5.RS,5.RD,00000101101:POOL32A:32::MUL.PH
+"mul.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_op (SD_, RD, RS, RT, 2, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10000101101:POOL32A:32::MUL_S.PH
+"mul_s.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_op (SD_, RD, RS, RT, 2, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0000100101:POOL32A:32::MULEQ_S.W.PHL
+"muleq_s.w.phl r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_muleq (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0001100101:POOL32A:32::MULEQ_S.W.PHR
+"muleq_s.w.phr r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_muleq (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0010010101:POOL32A:32::MULEU_S.PH.QBL
+"muleu_s.ph.qbl r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_muleu (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0011010101:POOL32A:32::MULEU_S.PH.QBR
+"muleu_s.ph.qbr r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_muleu (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0100010101:POOL32A:32::MULQ_RS.PH
+"mulq_rs.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_mulq (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0110010101:POOL32A:32::MULQ_RS.W
+"mulq_rs.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_mulq (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0101010101:POOL32A:32::MULQ_S.PH
+"mulq_s.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_mulq (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0111010101:POOL32A:32::MULQ_S.W
+"mulq_s.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_mulq (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,2.AC,10110010111111:POOL32A:32::MULSA.W.PH
+"mulsa.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_w_mulsa (SD_, AC, RS, RT);
+}
+
+001000,5.RT,5.RS,2.AC,11110010111111:POOL32A:32::MULSAQ_S.W.PH
+"mulsaq_s.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_mulsaq_s_w_ph (SD_, AC, RS, RT);
+}
+
+001000,5.RT,5.RS,2.AC,00110010111111:POOL32A:32::MULT_DSP
+"mult ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_dsp_mult (SD_, AC, RS, RT);
+}
+
+001000,5.RT,5.RS,2.AC,01110010111111:POOL32A:32::MULTU_DSP
+"multu ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_dsp_multu (SD_, AC, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0110101101:POOL32A:32::PACKRL.PH
+"packrl.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_packrl (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1000101101:POOL32A:32::PICK.PH
+"pick.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_pick (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0111101101:POOL32A:32::PICK.QB
+"pick.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_pick (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,0101000100111111:POOL32A:32::PRECEQ.W.PHL
+"preceq.w.phl r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_w_preceq (SD_, RT, RS, 0);
+}
+
+001000,5.RT,5.RS,0110000100111111:POOL32A:32::PRECEQ.W.PHR
+"preceq.w.phr r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_w_preceq (SD_, RT, RS, 1);
+}
+
+001000,5.RT,5.RS,0111000100111111:POOL32A:32::PRECEQU.PH.QBL
+"precequ.ph.qbl r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_precequ (SD_, RT, RS, 2);
+}
+
+001000,5.RT,5.RS,0111001100111111:POOL32A:32::PRECEQU.PH.QBLA
+"precequ.ph.qbla r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_precequ (SD_, RT, RS, 3);
+}
+
+001000,5.RT,5.RS,1001000100111111:POOL32A:32::PRECEQU.PH.QBR
+"precequ.ph.qbr r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_precequ (SD_, RT, RS, 0);
+}
+
+001000,5.RT,5.RS,1001001100111111:POOL32A:32::PRECEQU.PH.QBRA
+"precequ.ph.qbra r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_precequ (SD_, RT, RS, 1);
+}
+
+001000,5.RT,5.RS,1011000100111111:POOL32A:32::PRECEU.PH.QBL
+"preceu.ph.qbl r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_preceu (SD_, RT, RS, 2);
+}
+
+001000,5.RT,5.RS,1011001100111111:POOL32A:32::PRECEU.PH.QBLA
+"preceu.ph.qbla r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_preceu (SD_, RT, RS, 3);
+}
+
+001000,5.RT,5.RS,1101000100111111:POOL32A:32::PRECEU.PH.QBR
+"preceu.ph.qbr r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_preceu (SD_, RT, RS, 0);
+}
+
+001000,5.RT,5.RS,1101001100111111:POOL32A:32::PRECEU.PH.QBRA
+"preceu.ph.qbra r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_preceu (SD_, RT, RS, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0001101101:POOL32A:32::PRECR.QB.PH
+"precr.qb.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_qb_precr (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.SA,01111001101:POOL32A:32::PRECR_SRA.PH.W
+"precr_sra.ph.w r<RT>, r<RS>, <SA>"
+*nanomipsdsp:
+{
+  do_precr_sra (SD_, RT, RS, SA, 0);
+}
+
+001000,5.RT,5.RS,5.SA,11111001101:POOL32A:32::PRECR_SRA_R.PH.W
+"precr_sra_r.ph.w r<RT>, r<RS>, <SA>"
+*nanomipsdsp:
+{
+  do_precr_sra (SD_, RT, RS, SA, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0011101101:POOL32A:32::PRECRQ.PH.W
+"precrq.ph.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_ph_precrq (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0010101101:POOL32A:32::PRECRQ.QB.PH
+"precrq.qb.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_qb_precrq (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0101101101:POOL32A:32::PRECRQU_S.QB.PH
+"precrqu_s.qb.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_qb_precrq (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0100101101:POOL32A:32::PRECRQ_RS.PH.W
+"precrq_rs.ph.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_ph_rs_precrq (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.SA,1.X,1001010101:POOL32A:32::PREPEND
+"prepend r<RT>, r<RS>, <SA>"
+*nanomipsdsp:
+{
+  do_prepend (SD_, RT, RS, SA);
+}
+
+001000,5.RT,5.RS,1111000100111111:POOL32A:32::RADDU.W.QB
+"raddu.w.qb r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_w_raddu (SD_, RT, RS);
+}
+
+001000,5.RT,7.CONTROL_MASK,00011001111111:POOL32A:32::RDDSP
+"rddsp r<RT>":CONTROL_MASK == 1111111111
+"rddsp r<RT>, <CONTROL_MASK>"
+*nanomipsdsp:
+{
+  do_rddsp (SD_, RT, CONTROL_MASK);
+}
+
+001000,5.RT,10.IMMEDIATE,1.X,0000111101:POOL32A:32::REPL.PH
+"repl.ph r<RT>, <IMMEDIATE>"
+*nanomipsdsp:
+{
+  do_repl (SD_, RT, IMMEDIATE, 2);
+}
+
+001000,5.RT,8.IMMEDIATE,1.X,010111111111:POOL32A:32::REPL.QB
+"repl.qb r<RT>, <IMMEDIATE>"
+*nanomipsdsp:
+{
+  do_repl (SD_, RT, IMMEDIATE, 0);
+}
+
+001000,5.RT,5.RS,0000001100111111:POOL32A:32::REPLV.PH
+"replv.ph r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_repl (SD_, RT, RS, 3);
+}
+
+001000,5.RT,5.RS,0001001100111111:POOL32A:32::REPLV.QB
+"replv.qb r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_repl (SD_, RT, RS, 1);
+}
+
+001000,0000,6.IMMEDIATE,2.AC,00000000011101:POOL32A:32::SHILO
+"shilo ac<AC>, <IMMEDIATE>"
+*nanomipsdsp:
+{
+  do_shilo (SD_, AC, IMMEDIATE);
+}
+
+001000,00000,5.RS,2.AC,01001001111111:POOL32A:32::SHILOV
+"shilov ac<AC>, r<RS>"
+*nanomipsdsp:
+{
+  do_shilov (SD_, AC, RS);
+}
+
+001000,5.RT,5.RS,4.SHIFT,001110110101:POOL32A:32::SHLL.PH
+"shll.ph r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_ph_shift (SD_, RT, RS, SHIFT, 0, 0);
+}
+
+001000,5.RT,5.RS,4.SHIFT,101110110101:POOL32A:32::SHLL_S.PH
+"shll_s.ph r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_ph_shift (SD_, RT, RS, SHIFT, 0, 1);
+}
+
+001000,5.RT,5.RS,3.SHIFT,0100001111111:POOL32A:32::SHLL.QB
+"shll.qb r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_qb_shift (SD_, RT, RS, SHIFT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,01110001101:POOL32A:32::SHLLV.PH
+"shllv.ph r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_ph_shl (SD_, RD, RT, RS, 0, 0);
+}
+
+001000,5.RT,5.RS,5.RD,11110001101:POOL32A:32::SHLLV_S.PH
+"shllv_s.ph r<RD>, r<RD>, r<RS>"
+*nanomipsdsp:
+{
+  do_ph_shl (SD_, RD, RT, RS, 0, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1110010101:POOL32A:32::SHLLV.QB
+"shllv.qb r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_shl (SD_, RD, RT, RS, 0);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1111010101:POOL32A:32::SHLLV_S.W
+"shllv_s.w r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_w_s_shllv (SD_, RD, RT, RS);
+}
+
+001000,5.RT,5.RS,5.SHIFT,1.X,1111110101:POOL32A:32::SHLL_S.W
+"shll_s.w r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_w_shll (SD_, RT, RS, SHIFT);
+}
+
+001000,5.RT,5.RS,3.SHIFT,0000111111111:POOL32A:32::SHRA.QB
+"shra.qb r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_qb_shra (SD_, RT, RS, SHIFT, 0);
+}
+
+001000,5.RT,5.RS,3.SHIFT,1000111111111:POOL32A:32::SHRA_R.QB
+"shra_r.qb r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_qb_shra (SD_, RT, RS, SHIFT, 1);
+}
+
+001000,5.RT,5.RS,4.SHIFT,1.X,01100110101:POOL32A:32::SHRA.PH
+"shra.ph r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_ph_shift (SD_, RT, RS, SHIFT, 1, 0);
+}
+
+001000,5.RT,5.RS,4.SHIFT,1.X,11100110101:POOL32A:32::SHRA_R.PH
+"shra_r.ph r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_ph_shift (SD_, RT, RS, SHIFT, 1, 1);
+}
+
+001000,5.RT,5.RS,5.RD,00110001101:POOL32A:32::SHRAV.PH
+"shrav.ph r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_ph_shl (SD_, RD, RT, RS, 1, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10110001101:POOL32A:32::SHRAV_R.PH
+"shrav_r.ph r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_ph_shl (SD_, RD, RT, RS, 1, 1);
+}
+
+001000,5.RT,5.RS,5.RD,00111001101:POOL32A:32::SHRAV.QB
+"shrav.qb r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_shrav (SD_, RD, RT, RS, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10111001101:POOL32A:32::SHRAV_R.QB
+"shrav_r.qb r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_shrav (SD_, RD, RT, RS, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1011010101:POOL32A:32::SHRAV_R.W
+"shrav_r.w r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_w_r_shrav (SD_, RD, RT, RS);
+}
+
+001000,5.RT,5.RS,5.SHIFT,1.X,1011110101:POOL32A:32::SHRA_R.W
+"shra_r.w r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_w_shra (SD_, RT, RS, SHIFT);
+}
+
+001000,5.RT,5.RS,4.SHIFT,001111111111:POOL32A:32::SHRL.PH
+"shrl.ph r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_ph_shrl (SD_, RT, RS, SHIFT);
+}
+
+001000,5.RT,5.RS,3.SHIFT,1100001111111:POOL32A:32::SHRL.QB
+"shrl.qb r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_qb_shift (SD_, RT, RS, SHIFT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1100010101:POOL32A:32::SHRLV.PH
+"shrlv.ph r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_ph_shrlv (SD_, RD, RT, RS);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1101010101:POOL32A:32::SHRLV.QB
+"shrlv.qb r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_shl (SD_, RD, RT, RS, 1);
+}
+
+001000,5.RT,5.RS,5.RD,01000001101:POOL32A:32::SUBQ.PH
+"subq.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_op (SD_, RD, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,5.RD,11000001101:POOL32A:32::SUBQ_S.PH
+"subq_s.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_op (SD_, RD, RS, RT, 1, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1101000101:POOL32A:32::SUBQ_S.W
+"subq_s.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_op (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,01001001101:POOL32A:32::SUBQH.PH
+"subqh.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_ph_op (SD_, RD, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,5.RD,11001001101:POOL32A:32::SUBQH_R.PH
+"subqh_r.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_ph_op (SD_, RD, RS, RT, 1, 1);
+}
+
+001000,5.RT,5.RS,5.RD,01010001101:POOL32A:32::SUBQH.W
+"subqh.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_w_op (SD_, RD, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,5.RD,11010001101:POOL32A:32::SUBQH_R.W
+"subqh_r.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_w_op (SD_, RD, RS, RT, 1, 1);
+}
+
+001000,5.RT,5.RS,5.RD,01100001101:POOL32A:32::SUBU.PH
+"subu.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_u_ph_op (SD_, RD, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,5.RD,11100001101:POOL32A:32::SUBU_S.PH
+"subu_s.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_u_ph_op (SD_, RD, RS, RT, 1, 1);
+}
+
+001000,5.RT,5.RS,5.RD,01011001101:POOL32A:32::SUBU.QB
+"subu.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_op (SD_, RD, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,5.RD,11011001101:POOL32A:32::SUBU_S.QB
+"subu_s.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_op (SD_, RD, RS, RT, 1, 1);
+}
+
+001000,5.RT,5.RS,5.RD,01101001101:POOL32A:32::SUBUH.QB
+"subuh.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_uh_qb_op (SD_, RD, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,5.RD,11101001101:POOL32A:32::SUBUH_R.QB
+"subuh_r.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_uh_qb_op (SD_, RD, RS, RT, 1, 1);
+}
+
+001000,5.RT,7.CONTROL_MASK,01011001111111:POOL32A:32::WRDSP
+"wrdsp r<RT>":CONTROL_MASK == 1111111111
+"wrdsp r<RT>, <CONTROL_MASK>"
+*nanomipsdsp:
+{
+  do_wrdsp (SD_, RT, CONTROL_MASK);
+}
diff --git a/sim/mips/nanomipsr6.igen b/sim/mips/nanomipsr6.igen
new file mode 100644
index 00000000000..109fa1510f9
--- /dev/null
+++ b/sim/mips/nanomipsr6.igen
@@ -0,0 +1,3283 @@
+// Simulator definition for the nanoMIPS.
+// Copyright (C) 2018-2022 Free Software Foundation, Inc.
+// Contributed by Imagination Technologies, Ltd.
+// Written by Ali Lown <ali.lown@imgtec.com>
+//
+// This file is part of GDB, the GNU debugger.
+//
+// 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, see <http://www.gnu.org/licenses/>.
+
+:compute:::int:U_SHIFT_1BIT:U:(U << 1)
+:compute:::int:U_SHIFT_2BIT:U:(U << 2)
+:compute:::int:U_SHIFT_3BIT:U:(U << 3)
+:compute:::int:U_SHIFT_4BIT:U:(U << 4)
+:compute:::int:EU_127:EU:((EU == 127) ? -1 \: EU)
+:compute:::int:U_LW4X4:U2,U3:((U3 << 3) | (U2 << 2))
+:compute:::int:AXUIPC_S_LO:S1,S2,S3:((EXTEND32((S3 << 31) | (S2 << 21) | (S1 << 12))) & 0x0000ffff)
+:compute:::int:AXUIPC_S_HI:S1,S2,S3:((EXTEND32((S3 << 31) | (S2 << 21) | (S1 << 12))) & 0xffff0000)
+:compute:::int:AXUIPC_S:S1,S2,S3:(EXTEND32((S3 << 31) | (S2 << 21) | (S1 << 12)))
+:compute:::int:TRD2:RD20,RD21:(compute_gpr2_dest1_reg (SD_, (RD21 << 1 | RD20)))
+:compute:::int:TRE2:RD20,RD21:(compute_gpr2_dest2_reg (SD_, (RD21 << 1 | RD20)))
+:compute:::int:TRS2:RS4,RS2_0:(compute_gpr4_zero (SD_, (RS4 << 3 | RS2_0)))
+:compute:::int:TRT2:RT4,RT2_0:(compute_gpr4_zero (SD_, (RT4 << 3 | RT2_0)))
+:compute:::int:TRD2_REV:RD4,RD2_0:(compute_gpr4 (SD_, (RD4 << 3) | RD2_0))
+:compute:::int:TRE2_REV:RE4,RE2_0:(compute_gpr4 (SD_, (RE4 << 3) | RE2_0))
+:compute:::int:TRS2_REV:RS20,RS21:(compute_gpr2_dest1_reg (SD_, (RS21 << 1 | RS20)))
+:compute:::int:TRT2_REV:RS20,RS21:(compute_gpr2_dest2_reg (SD_, (RS21 << 1 | RS20)))
+:compute:::address_word:ADDRESS8:S1,S2:(nia + EXTEND8((S2 << 7) | (S1 << 1)))
+:compute:::address_word:ADDRESS11:S1,S2:(nia + EXTEND11((S2 << 10) | (S1 << 1)))
+:compute:::address_word:ADDRESS15:S1,S2:(nia + EXTEND15((S2 << 14) | (S1 << 1)))
+:compute:::address_word:ADDRESS21:S1,S2:(nia + EXTEND21((S2 << 20) | (S1 << 1)))
+:compute:::address_word:ADDRESS22:S1,S2:(nia + EXTEND22((S2 << 21) | (S1 << 1)))
+:compute:::address_word:ADDRESS26:S1,S2:(nia + EXTEND26((S2 << 25) | (S1 << 1)))
+:compute:::int:INS_POS:LSB:(LSB)
+:compute:::int:INS_SIZE:LSB,MSBD:(1 + MSBD - LSB)
+:compute:::address_word:ADDRESS12:S1,S2:(nia + EXTEND12(S2 << 11 | S1 << 1))
+:compute:::int:S_14_BIT:S1,S2:(EXTEND14 ((S1 << 13) | S2))
+:compute:::int:S_4_BIT:S1,S2:(EXTEND4((S1 << 3) | S2))
+:compute:::int:S_9_BIT:S1,S2:(EXTEND9((S1 << 8) | S2))
+:compute:::int:S_9_BIT_LLSC:S1,S2:(EXTEND9((S1 << 8) | (S2 << 2)))
+:compute:::int:RD1:RD:(compute_gpr1_dest_reg (SD_, RD))
+:compute:::int:RT_5_BIT_NM_Z:RT1,RT2:(compute_gpr4_zero (SD_, (RT1 << 3) | RT2))
+:compute:::int:RT_5_BIT_NM:RT1,RT2:(compute_gpr4 (SD_, (RT1 << 3) | RT2))
+:compute:::int:RS_5_BIT_NM:RS1,RS2:(compute_gpr4 (SD_, (RS1 << 3) | RS2))
+:compute:::int:TRTZ:RTZ:((RTZ >= 1 && RTZ <= 3) ? (16 + RTZ) \: RTZ)
+:compute:::int:EU_12_13:EU:((EU == 12) ? 255 \: ((EU == 13) ? 65535 \: EU))
+:compute:::int:RS_MOVE:RS1,RS_CODE_1,RS_CODE_2:((RS1 << 3) | (RS_CODE_1 << 2) | RS_CODE_2)
+:compute:::int:CODE_BREAK:RS_CODE_1,RS_CODE_2:((RS_CODE_1 << 2) | RS_CODE_2)
+:compute:::int:TRD_NM:RD:((RD < 4) ? (16 + RD) \: RD)
+:compute:::int:TRS_NM:RS:((RS < 4) ? (16 + RS) \: RS)
+:compute:::int:TRT_NM:RT:((RT < 4) ? (16 + RT) \: RT)
+:compute:::int:COUNT:COUNT3:(COUNT3 == 0 ? 8 \: COUNT3)
+:compute:::int:SHIFTX_1BIT:SHIFTX:(SHIFTX << 1)
+
+:function:::void:do_msubf:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT3 (FGR[fd], FGR[fs], FGR[ft]);
+  StoreFPR (fd, fmt, FusedMultiplySub (ValueFPR (fs, fmt),
+               ValueFPR (ft, fmt),
+               ValueFPR (fd, fmt), fmt));
+  TRACE_ALU_RESULT (FGR[fd]);
+}
+
+:function:::void:do_maddf:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT3 (FGR[fd], FGR[fs], FGR[ft]);
+  StoreFPR (fd, fmt, FusedMultiplyAdd (ValueFPR (fs, fmt),
+               ValueFPR (ft, fmt),
+               ValueFPR (fd, fmt), fmt));
+  TRACE_ALU_RESULT (FGR[fd]);
+}
+
+:function:::void:do_rint:int fd, int fs, int fmt, instruction_word instruction_0
+{
+  uint64_t result = 0;
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT1 (FGR[fs]);
+  RoundToIntegralExact (ValueFPR (fs, fmt), &result, fmt);
+  StoreFPR (fd, fmt, result);
+  TRACE_ALU_RESULT (FGR[fd]);
+}
+
+:function:::void:do_class:int fd, int fs, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  StoreFPR (fd, fmt, Classify (ValueFPR (fs, fmt), fmt));
+}
+
+:function:::void:do_seleqzf:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT2 (ValueFPR(fs, fmt), FGR[ft]);
+  if ((FGR[ft] & 0x01) == 0)
+    StoreFPR (fd, fmt, ValueFPR (fs, fmt));
+  else
+    StoreFPR (fd, fmt, 0);
+  TRACE_ALU_RESULT (ValueFPR(fd, fmt));
+}
+
+:function:::void:do_selnezf:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT2 (ValueFPR(fs, fmt), FGR[ft]);
+  if ((FGR[ft] & 0x01) == 0x1)
+    StoreFPR (fd, fmt, ValueFPR (fs, fmt));
+  else
+    StoreFPR (fd, fmt, 0);
+  TRACE_ALU_RESULT (ValueFPR(fd, fmt));
+}
+
+:function:::void:do_self:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT3 (FGR[fd], ValueFPR(fs, fmt), ValueFPR(ft, fmt));
+  if ((FGR[fd] & 0x01) != 0)
+    StoreFPR (fd, fmt, ValueFPR (ft, fmt));
+  else
+    StoreFPR (fd, fmt, ValueFPR (fs, fmt));
+  TRACE_ALU_RESULT (ValueFPR(fd, fmt));
+}
+
+:function:::void:do_mina:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT2 (FGR[fs], FGR[ft]);
+  StoreFPR (fd, fmt, MinA (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt));
+  TRACE_ALU_RESULT (FGR[fd]);
+}
+
+:function:::void:do_maxa:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT2 (FGR[fs], FGR[ft]);
+  StoreFPR (fd, fmt, MaxA (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt));
+  TRACE_ALU_RESULT (FGR[fd]);
+}
+
+:function:::void:do_max:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT2 (FGR[fs], FGR[ft]);
+  StoreFPR (fd, fmt, Max (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt));
+  TRACE_ALU_RESULT (FGR[fd]);
+}
+
+:function:::void:do_min:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT2 (FGR[fs], FGR[ft]);
+  StoreFPR (fd, fmt, Min (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt));
+  TRACE_ALU_RESULT (FGR[fd]);
+}
+
+:function:::void:do_cmp:int fd, int fs, int ft, int fmt, int condition
+{
+  uint64_t result;
+  check_fpu (SD_);
+  TRACE_ALU_INPUT2 (ValueFPR (fs, fmt), ValueFPR (ft, fmt));
+  result = R6Compare (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt, condition);
+  StoreFPR (fd, fmt, result);
+  TRACE_ALU_RESULT (result);
+}
+
+:function:::void:do_modu:int rd, int rs, int rt
+{
+  uint32_t n = GPR[rs];
+  uint32_t d = GPR[rt];
+  TRACE_ALU_INPUT2 (n,d);
+  if (d == 0)
+    GPR[rd] = EXTEND32 (0);
+  else
+    GPR[rd] = EXTEND32 (n % d);
+
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_mod:int rd, int rs, int rt
+{
+  int32_t n = GPR[rs];
+  int32_t d = GPR[rt];
+  TRACE_ALU_INPUT2 (n,d);
+  if (d == 0 || (n == SIGNED32 (0x80000000) && d == -1))
+    GPR[rd] = EXTEND32 (0);
+  else
+    GPR[rd] = EXTEND32 (n % d);
+
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_muhu:int rd, int rs, int rt
+{
+  uint64_t prod;
+  if (NotWordValue (GPR[rs]) || NotWordValue (GPR[rt]))
+    Unpredictable ();
+  TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]);
+  prod = ((uint64_t)(uint32_t) GPR[rs])
+    * ((uint64_t)(uint32_t) GPR[rt]);
+  GPR[rd] = EXTEND32 (VH4_8 (prod));
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_mulu:int rd, int rs, int rt
+{
+  uint64_t prod;
+  if (NotWordValue (GPR[rs]) || NotWordValue (GPR[rt]))
+    Unpredictable ();
+  TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]);
+  prod = ((uint64_t)(uint32_t) GPR[rs])
+    * ((uint64_t)(uint32_t) GPR[rt]);
+  GPR[rd] = EXTEND32 (VL4_8 (prod));
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_muh:int rd, int rs, int rt
+{
+  int64_t prod;
+  if (NotWordValue (GPR[rs]) || NotWordValue (GPR[rt]))
+    Unpredictable ();
+  TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]);
+  prod = ((int64_t)(int32_t) GPR[rs])
+    * ((int64_t)(int32_t) GPR[rt]);
+  GPR[rd] = EXTEND32 (VH4_8 (prod));
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_lsa:int rd, int rs, int rt, unsigned immediate
+{
+  uint32_t t = GPR[rs] << immediate;
+  GPR[rd] = EXTEND32(GPR[rt] + t);
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_divu:int rd, int rs, int rt
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint32_t n = GPR[rs];
+  uint32_t d = GPR[rt];
+  TRACE_ALU_INPUT2 (n,d);
+  if (d == 0)
+    GPR[rd] = EXTEND32 (0x80000000);
+  else
+    GPR[rd] = EXTEND32 (n / d);
+
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_div:int rd, int rs, int rt
+*nanomips32r6:
+*nanomips64r6:
+{
+  int32_t n = GPR[rs];
+  int32_t d = GPR[rt];
+  TRACE_ALU_INPUT2 (n,d);
+  if (d == 0)
+    GPR[rd] = EXTEND32 (0x80000000);
+  else if (n == SIGNED32 (0x80000000) && d == -1)
+    GPR[rd] = EXTEND32 (0x80000000);
+  else
+    GPR[rd] = EXTEND32 (n / d);
+
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_llwp:int rt, int ru, int roffset, int rbase
+{
+  address_word base = GPR[rbase];
+  address_word offset = EXTEND16 (roffset);
+  {
+    address_word vaddr = loadstore_ea (SD_, base, offset);
+    address_word paddr;
+    int uncached;
+    if ((vaddr & 7) != 0)
+      {
+  SIM_CORE_SIGNAL (SD, CPU, cia, read_map, 8, vaddr, read_transfer,
+    sim_core_unaligned_signal);
+      }
+    else
+      {
+  if (AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached,
+             isTARGET, isREAL))
+    {
+      uint64_t memval = 0;
+      uint64_t memval1 = 0;
+      uint64_t data = memval;
+
+      LoadMemory (&memval, &memval1, uncached, AccessLength_DOUBLEWORD,
+            paddr, vaddr, isDATA, isREAL);
+
+      GPR[rt] = EXTEND32 (data & 0xFFFFFFFF);
+      GPR[ru] = EXTEND32 (data >> 32);
+
+      LLBIT = 1;
+      COP0_COUNT++;
+    }
+      }
+  }
+}
+
+:function:::void:do_rotx:int rt, int rs, int shift, int shiftx, int stripe
+{
+  int i;
+  uint64_t tmp0 = ((uint64_t)GPR[rs] << 32) | (GPR[rs] & 0xFFFFFFFF);
+  uint64_t tmp1, tmp2, tmp3, tmp4, tmp5;
+
+  tmp1 = tmp0;
+  for (i = 0; i <=46; i++) {
+    int s;
+
+    if (i & 0x8)
+      s = shift;
+    else
+      s = shiftx;
+
+    if (stripe != 0 && !(i & 0x4))
+      s = ~s;
+
+    if (s & 0x10) {
+      if (tmp0 & (1LL << (i + 16)))
+        tmp1 |= 1LL << i;
+      else
+        tmp1 &= ~(1LL << i);
+    }
+  }
+
+  tmp2 = tmp1;
+  for (i = 0; i <=38; i++) {
+    int s;
+
+    if (i & 0x4)
+      s = shift;
+    else
+      s = shiftx;
+
+    if (s & 0x8) {
+      if (tmp1 & (1LL << (i + 8)))
+        tmp2 |= 1LL << i;
+      else
+        tmp2 &= ~(1LL << i);
+    }
+  }
+
+  tmp3 = tmp2;
+  for (i = 0; i <=34; i++) {
+    int s;
+
+    if (i & 0x2)
+      s = shift;
+    else
+      s = shiftx;
+
+    if (s & 0x4) {
+      if (tmp2 & (1LL << (i + 4)))
+        tmp3 |= 1LL << i;
+      else
+        tmp3 &= ~(1LL << i);
+    }
+  }
+
+  tmp4 = tmp3;
+  for (i = 0; i <=32; i++) {
+    int s;
+
+    if (i & 0x1)
+      s = shift;
+    else
+      s = shiftx;
+
+    if (s & 0x2) {
+      if (tmp3 & (1LL << (i + 2)))
+        tmp4 |= 1LL << i;
+      else
+        tmp4 &= ~(1LL << i);
+    }
+  }
+
+  tmp5 = tmp4;
+  for (i = 0; i <=31; i++) {
+    int s;
+
+    s = shift;
+
+    if (s & 0x1) {
+      if (tmp4 & (1LL << (i + 1)))
+        tmp5 |= 1LL << i;
+      else
+        tmp5 &= ~(1LL << i);
+    }
+  }
+
+  GPR[rt] = EXTEND32 (tmp5);
+}
+
+:function:::void:do_lwc1xs:int ft, int rbase, int roffset
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_fpu (SD_);
+  COP_LW (1, ft, do_load (SD_, AccessLength_WORD, GPR[rbase] << 2,
+        GPR[roffset]));
+}
+
+:function:::void:do_lwpc_nanomips:int rt, uint32_t offset, address_word nia
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_fpu (SD_);
+  GPR[rt] = EXTEND32 (do_load (SD_, AccessLength_WORD, nia, offset));
+}
+
+:function:::void:check_nms_flag:
+*nanomips32r6:
+*nanomips64r6:
+{
+  if(nms_flag == 0)
+    sim_engine_abort (SD, CPU, CIA, "Error: NMS instruction generated\
+  (nanoMIPS Subset is disabled - use -march=32r6s option)\n");
+}
+
+:function:::void:do_swc1xs:int ft, int rbase, int roffset, address_word instruction_0
+*nanomips32r6:
+*nanomips64r6:
+{
+  address_word base = GPR[rbase] << 2;
+  address_word offset = GPR[roffset];
+  check_fpu (SD_);
+  {
+    address_word vaddr = loadstore_ea (SD_, base, offset);
+    address_word paddr;
+    int uncached;
+    if ((vaddr & 3) != 0)
+      {
+  SIM_CORE_SIGNAL (SD, CPU, cia, read_map, AccessLength_WORD+1, vaddr,
+       write_transfer, sim_core_unaligned_signal);
+      }
+    else
+      {
+  if (AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached,
+              isTARGET, isREAL))
+    {
+      uword64 memval = 0;
+      uword64 memval1 = 0;
+      uword64 mask = (WITH_TARGET_WORD_BITSIZE == 64 ? 0x7 : 0x3);
+      address_word reverseendian =
+        (ReverseEndian ?(mask ^ AccessLength_WORD): 0);
+      address_word bigendiancpu =
+        (BigEndianCPU ?(mask ^ AccessLength_WORD): 0);
+      unsigned int byte;
+      paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
+      byte = ((vaddr & mask) ^ bigendiancpu);
+      memval = (((uword64)COP_SW(1, ft)) << (8 * byte));
+      StoreMemory (uncached, AccessLength_WORD, memval, memval1, paddr,
+       vaddr, isREAL);
+    }
+      }
+  }
+}
+
+:function:::uint32_t:compute_gpr2_dest1_reg:int reg
+*nanomips32r6:
+*nanomips64r6:
+{
+  switch(reg)
+    {
+    case 0: return 4;
+    case 1: return 5;
+    case 2: return 6;
+    case 3: return 7;
+    default: return 4;
+    }
+}
+
+:function:::uint32_t:compute_gpr4_zero:int reg
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (reg == 3) return 0;
+  else if (reg >=4 && reg <= 7) return reg;
+  else return reg + 8;
+}
+
+:function:::uint32_t:compute_gpr4:int reg
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (reg >=4 && reg <= 7) return reg;
+  else return reg + 8;
+}
+
+:function:::uint32_t:compute_gpr2_dest2_reg:int reg
+*nanomips32r6:
+*nanomips64r6:
+{
+  switch(reg)
+    {
+    case 0: return 5;
+    case 1: return 6;
+    case 2: return 7;
+    case 3: return 8;
+    default: return 5;
+    }
+}
+
+:function:::uint32_t:compute_gpr1_dest_reg:int reg
+*nanomips32r6:
+*nanomips64r6:
+{
+  switch(reg)
+    {
+    case 0: return 4;
+    case 1: return 5;
+    default: return 4;
+    }
+}
+
+:function:::unsigned:zero_extend:signed_word value, uint32_t from_nbits
+{
+  uint32_t low_bits_mask = (1 << from_nbits) - 1;
+  return value & low_bits_mask;
+}
+
+:function:::void:do_save_gprs_to_stack_and_adjust_sp: int first_gpr, int count, int gp, int u
+*nanomips32r6:
+*nanomips64r6:
+{
+  int counter = 0;
+
+  while (counter != count) {
+    int gpr = (first_gpr & 0x10) | ((first_gpr + counter) & 0x1F);
+    int offset = - ( (counter + 1) << 2 );
+
+    if ( gp && (counter == count - 1))
+      gpr = 28;
+
+    do_store (SD_, AccessLength_WORD, GPR[SPIDX], offset, GPR[gpr]);
+
+    counter++;
+    COP0_COUNT++;
+  }
+
+  GPR[SPIDX] -= u;
+}
+
+:function:::void:do_restore_gprs_from_stack_and_adjust_sp: int first_gpr, int count, int gp, int u
+*nanomips32r6:
+*nanomips64r6:
+{
+  int counter = 0;
+
+  while (counter != count) {
+    int gpr = (first_gpr & 0x10) | ((first_gpr + counter) & 0x1F);
+    int offset;
+
+    if (gpr == 29)
+      Unpredictable();
+
+    offset = u - ((counter + 1) << 2);
+
+    if ( gp && (counter == count - 1))
+      gpr = 28;
+
+    GPR[gpr] = EXTEND32 (do_load(SD_, AccessLength_WORD, GPR[SPIDX], offset));
+
+    counter++;
+    COP0_COUNT++;
+  }
+
+  GPR[SPIDX] += u;
+}
+
+:function:::address_word:do_eret:int nc, address_word nia
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (SR & status_ERL)
+    {
+      /* Oops, not yet available */
+      sim_io_printf (SD, "Warning: ERET when SR[ERL] set not supported");
+      nia = EPC;
+      SR &= ~status_ERL;
+    }
+  else
+    {
+      nia = EPC;
+      SR &= ~status_EXL;
+      //if ( SRSCtl.HSS > 0 && Status.BEV == 0)
+      //  SRSCtl.CSS = SRSCtl.PSS
+  }
+
+  if (!nc)
+    LLBIT = 0;
+
+  //TODO: ClearHazards()
+  return nia;
+}
+
+:%s::::GPR_LIST_SAVE:int count
+*nanomips32r6:
+*nanomips64r6:
+{
+  int i;
+  static char gpr_list[100];
+
+  gpr_list[0] = '\0';
+
+  i = 0;
+
+  while (i<count)
+    {
+      char str1[32];
+      if (i == 0 || i==count-1) {
+        sprintf(str1, "%d", i);
+        strcat (gpr_list,"s");
+        strcat (gpr_list,str1);
+        if(i==0 && count > 1)
+          strcat (gpr_list,"-");
+      }
+      i++;
+    }
+  return (gpr_list);
+}
+
+:function:::void:do_break_nanomips:address_word instruction_0
+{
+  /* Check for some break instruction which are reserved for use by the
+     simulator.  */
+  unsigned int break_code = instruction_0 & HALT_INSTRUCTION_MASK_NANOMIPS;
+  if (break_code == (HALT_INSTRUCTION_NANOMIPS & HALT_INSTRUCTION_MASK_NANOMIPS))
+    {
+      sim_engine_halt (SD, CPU, NULL, cia,
+           sim_exited, (unsigned int)(A0 & 0xFFFFFFFF));
+    }
+  else if (break_code == (BREAKPOINT_INSTRUCTION_NANOMIPS & HALT_INSTRUCTION_MASK_NANOMIPS))
+    {
+      PC = cia;
+      SignalException (BreakPoint, instruction_0);
+    }
+
+  else
+    {
+    /* If we get this far, we're not an instruction reserved by the sim. Raise
+       the exception. */
+      SignalException (BreakPoint, instruction_0);
+    }
+}
+
+:function:::FP_formats:convert_fmt_micromips_mul:int fmt
+*nanomips32r6:
+*nanomips64r6:
+{
+  switch (fmt)
+    {
+    case 1: return fmt_single;
+    case 3: return fmt_double;
+    default: return fmt_unknown;
+    }
+}
+
+:%s::::GP_SAVE:int gp
+*nanomips32r6:
+*nanomips64r6:
+{
+  return (gp > 0) ? "gp" : "";
+}
+
+:%s::::FP_SAVE:int fp
+*nanomips32r6:
+*nanomips64r6:
+{
+  return (fp > 0) ? "fp" : "";
+}
+
+11111111111111111111111111111111:R6DUMMY:32,f::DUMMY0.fmt
+"dummy 0"
+*nanomips32r6:
+*nanomips64r6:
+{
+  /* Just needed so GNUSIM builds */
+}
+
+011100,3.RT,1,6.U:R6P16A1:16::ADDIUR1SP
+"addiu r<TRT_NM>, SP, <U_SHIFT_2BIT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addiu (SD_, SPIDX, TRT_NM, U_SHIFT_2BIT);
+}
+
+100100,3.RT,3.RS,0,3.U:R6P16A2:16::ADDIUR2
+"addiu r<TRT_NM>, r<TRS_NM>, <U_SHIFT_2BIT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addiu (SD_, TRS_NM, TRT_NM, U_SHIFT_2BIT);
+}
+
+100100,5.RT,1.S1,1,3.S2:R6P16ADDIURS5:16::ADDIURS5
+"nop":RT==0
+"addiu r<RT>, <S_4_BIT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (RT != 0)
+    do_addiu (SD_, RT, RT, S_4_BIT);
+}
+
+000001,5.RT,20.S1,1.S2:R6P32:32::ADDIUPC
+"addiu r<RT>, <ADDRESS22>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  GPR[RT] = ADDRESS22;
+}
+
+011000,5.RT,00011,16.IMM48:R6POOL48I:32::ADDIUPC48
+"addiu r<RT>, <IMM48>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint16_t U2;
+  uint32_t total;
+  check_nms_flag (SD_);
+  U2 = do_load (SD_, AccessLength_HALFWORD, CIA + 4, 0);
+  total = U2 << 16 | IMM48;
+  TRACE_ALU_INPUT2(GPR[RT], total);
+  GPR[RT] = CIA + 6 + EXTEND32(total);
+  TRACE_ALU_RESULT(GPR[RT]);
+  NIA = CIA + 6;
+}
+
+101100,3.RT,3.RS,3.RD,0:R6P16ADDU:16::ADDU16
+"addu r<TRD_NM>, r<TRS_NM>, r<TRT_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addu (SD_, TRS_NM, TRT_NM, TRD_NM);
+}
+
+001111,1.RT1,0,3.RT2,1.RS1,0,3.RS2:R6P164X4:16::ADDU4X4
+"addu r<RT_5_BIT_NM>, r<RS_5_BIT_NM>, r<RT_5_BIT_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_addu (SD_, RS_5_BIT_NM, RT_5_BIT_NM, RT_5_BIT_NM);
+}
+
+010100,3.RT,3.RS,10,0,0:R6POOL16C00:16::AND16
+"and r<TRT_NM>, r<TRS_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_and (SD_, TRS_NM, TRT_NM, TRT_NM);
+}
+
+111100,3.RT,3.RS,4.EU:R6P16:16::ANDI16
+"andi r<TRT_NM>, r<TRS_NM>, <EU_12_13>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_andi (SD_, TRS_NM, TRT_NM, EU_12_13);
+}
+
+001110,9.S1,1.S2:R6P16:16::BALC16
+"balc <ADDRESS11>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT1(RA);
+  RA = NIA;
+  NIA = ADDRESS11;
+  TRACE_ALU_RESULT(RA);
+
+  // For cycle counting
+  COP0_COUNT++;
+}
+
+000110,9.S1,1.S2:R6P16:16::BC16
+"bc <ADDRESS11>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  NIA = ADDRESS11;
+}
+
+110110,3.RT,3.RS,4.U!0:R6P16BR1:16::BxxC16
+"beqc r<TRS_NM>, r<TRT_NM>, <U_SHIFT_1BIT>":RS<RT
+"bnec r<TRS_NM>, r<TRT_NM>, <U_SHIFT_1BIT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  TRACE_ALU_INPUT2(GPR[TRS_NM], GPR[TRT_NM]);
+  if (RS < RT && GPR[TRS_NM] == GPR[TRT_NM])
+    NIA = NIA + U_SHIFT_1BIT; //BEQC
+  else if (RS >= RT && GPR[TRS_NM] != GPR[TRT_NM])
+    NIA = NIA + U_SHIFT_1BIT; //BNEC
+}
+
+100110,3.RT,6.S1,1.S2:R6P16:16::BEQZC16
+"beqzc r<TRT_NM>, <ADDRESS8>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT1(GPR[TRT_NM]);
+  if(GPR[TRT_NM] == 0)
+    NIA = ADDRESS8;
+}
+
+101110,3.RT,6.S1,1.S2:R6P16:16::BNEZC16
+"bnezc r<TRT_NM>, <ADDRESS8>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT1(GPR[TRT_NM]);
+  if(GPR[TRT_NM] != 0)
+    NIA = ADDRESS8;
+}
+
+110110,5.RT,1,0000:R6P16JRC:16::JALRC16
+"jalrc r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], RA);
+  RA = NIA;
+  NIA = GPR[RT];
+  TRACE_ALU_RESULT(RA);
+
+  // For cycle counting
+  COP0_COUNT++;
+}
+
+110110,5.RT,0,0000:R6P16JRC:16::JRC16
+"jrc r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT1(GPR[RT]);
+  NIA = GPR[RT];
+}
+
+010111,3.RT,3.RS,00,2.U:R6P16LB:16::LB16
+"lb r<TRT_NM>, <U>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lb (SD_, TRT_NM, U, TRS_NM);
+}
+
+010111,3.RT,3.RS,10,2.U:R6P16LB:16::LBU16
+"lbu r<TRT_NM>, <U>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2 (U, GPR[TRS_NM]);
+  do_lbu (SD_, TRT_NM, U, TRS_NM);
+  TRACE_ALU_RESULT (GPR[TRT_NM]);
+}
+
+011111,3.RT,3.RS,0,2.U,0:R6P16LH:16::LH16
+"lh r<TRT_NM>, <U_SHIFT_1BIT>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lh (SD_, TRT_NM, U_SHIFT_1BIT, TRS_NM);
+}
+
+011111,3.RT,3.RS,1,2.U,0:R6P16LH:16::LHU16
+"lhu r<TRT_NM>, <U_SHIFT_1BIT>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lhu (SD_, TRT_NM, U_SHIFT_1BIT, TRS_NM);
+}
+
+110100,3.RT,7.EU:R6P16:16::LI16
+"li r<TRT_NM>, <EU_127>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT1(GPR[TRT_NM]);
+  GPR[TRT_NM] = EU_127;
+  TRACE_ALU_RESULT(GPR[TRT_NM]);
+}
+
+011101,1.RT1,1.U2,3.RT2,1.RS1,1.U3,3.RS2:R6P16:16::LW4X4
+"lw r<RT_5_BIT_NM>, <U_LW4X4>(r<RS_5_BIT_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_lw (SD_, RT_5_BIT_NM, U_LW4X4, RS_5_BIT_NM);
+}
+
+000101,3.RT,3.RS,4.U:R6P16:16::LW16
+"lw r<TRT_NM>, <U_SHIFT_2BIT>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lw (SD_, TRT_NM, U_SHIFT_2BIT, TRS_NM);
+}
+
+010101,3.RT,7.U:R6P16:16::LWGP16
+"lw r<TRT_NM>, <U_SHIFT_2BIT>(gp)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lw (SD_, TRT_NM, U_SHIFT_2BIT, GPIDX);
+}
+
+001101,5.RT,5.U:R6P16:16::LWSP
+"lw r<RT>, <U_SHIFT_2BIT>(sp)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lw (SD_, RT, U_SHIFT_2BIT, SPIDX);
+}
+
+010100,3.RT,3.RS,3.RD,1:R6P16C:16::LWXS16
+"lwxs r<TRD_NM>, r<TRS_NM>(r<TRT_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lw (SD_, TRD_NM, GPR[TRS_NM] << 2, TRT_NM);
+}
+
+// These four instructions are grouped together because of a bug in GNUSIM
+// pattern recognition
+000100,5.RT,2.RS1,1.RS_CODE_1,2.RS_CODE_2:R6P16MOVE:16::P16MOVE_P16RI
+"move r<RT>, r<RS_MOVE>": RT != 0
+"syscall <RS_CODE_2>": RS1 == 1
+"sdbbp <CODE_BREAK>": RS1 == 3
+"break <CODE_BREAK>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (RT == 0) {
+    if (RS1 == 1)
+      SignalException (SystemCall, instruction_0);
+    else if (RS1 == 3)
+      SignalException (DebugBreakPoint, instruction_0);
+    else
+      do_break_nanomips (SD_, instruction_0);
+  }
+  else {
+    TRACE_ALU_INPUT2 (GPR[RT], GPR[RS_MOVE]);
+    GPR[RT] = GPR[RS_MOVE];
+    TRACE_ALU_RESULT2 (GPR[RT], GPR[RS_MOVE]);
+  }
+}
+
+101111,1.RT4,1.RD20,3.RT2_0,1.RS4,1.RD21,3.RS2_0:R6P16:16::MOVEP
+"movep r<TRD2>, r<TRE2>, r<TRS2>, r<TRT2>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  TRACE_ALU_INPUT4 (GPR[TRD2], GPR[TRE2], GPR[TRS2], GPR[TRT2]);
+  GPR[TRD2] = GPR[TRS2];
+  GPR[TRE2] = GPR[TRT2];
+  TRACE_ALU_RESULT2 (GPR[TRD2], GPR[TRE2]);
+
+  // For cycle counting
+  COP0_COUNT++;
+}
+
+111111,1.RE4,1.RS20,3.RE2_0,1.RD4,1.RS21,3.RD2_0:R6P16:16::MOVEPREV
+"movep r<TRD2_REV>, r<TRE2_REV>, r<TRS2_REV>, r<TRT2_REV>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  TRACE_ALU_INPUT4 (GPR[TRD2_REV], GPR[TRE2_REV], GPR[TRS2_REV], GPR[TRT2_REV]);
+  GPR[TRD2_REV] = GPR[TRS2_REV];
+  GPR[TRE2_REV] = GPR[TRT2_REV];
+  TRACE_ALU_RESULT2 (GPR[TRD2_REV], GPR[TRE2_REV]);
+
+  // For cycle counting
+  COP0_COUNT++;
+}
+
+010100,3.RT,3.RS,00,0,0:R6POOL16C00:16::NOT16
+"not r<TRT_NM>, r<TRS_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_nor (SD_, 0, TRS_NM, TRT_NM);
+}
+
+010100,3.RT,3.RS,11,0,0:R6POOL16C00:16::OR16
+"or r<TRT_NM>, r<TRS_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_or (SD_, TRS_NM, TRT_NM, TRT_NM);
+}
+
+000111,1.RT1,1,4.U,4.GPR_LIST_SAVE:R6P16SR:16::RESTORE.JRC16
+"restore.jrc <U_SHIFT_4BIT>":GPR_LIST_SAVE==15
+"restore.jrc <U_SHIFT_4BIT>, ra, %s<GPR_LIST_SAVE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (RT1 == 0)
+    do_restore_gprs_from_stack_and_adjust_sp(SD_, 30, GPR_LIST_SAVE, 0,
+                                             U_SHIFT_4BIT);
+  else
+    do_restore_gprs_from_stack_and_adjust_sp(SD_, 31, GPR_LIST_SAVE, 0,
+                                             U_SHIFT_4BIT);
+  NIA = RA;
+}
+
+000111,1.RT1,0,4.U,4.GPR_LIST_SAVE:R6P16SR:16::SAVE16
+"save <U_SHIFT_4BIT>, ra": GPR_LIST_SAVE == 0
+"save <U_SHIFT_4BIT>, ra, %s<GPR_LIST_SAVE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (RT1 == 0)
+    do_save_gprs_to_stack_and_adjust_sp(SD_, 30, GPR_LIST_SAVE, 0, U_SHIFT_4BIT);
+  else
+    do_save_gprs_to_stack_and_adjust_sp(SD_, 31, GPR_LIST_SAVE, 0, U_SHIFT_4BIT);
+
+}
+
+010111,3.RTZ,3.RS,01,2.U:R6P16LB:16::SB16
+"sb r<TRTZ>, <U>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_BYTE, GPR[TRS_NM], U, GPR[TRTZ]);
+}
+
+011111,3.RTZ,3.RS,0,2.U,1:R6P16LH:16::SH16
+"sh r<TRTZ>, <U_SHIFT_1BIT>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_HALFWORD, GPR[TRS_NM], U_SHIFT_1BIT, GPR[TRTZ]);
+}
+
+001100,3.RT,3.RS,0,3.SHIFT:R6P16SHIFT:16::SLL16
+"sll r<TRT_NM>, r<TRS_NM>, <SHIFT_DEC>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_sll (SD_, TRS_NM, TRT_NM, SHIFT_DEC);
+}
+
+001100,3.RT,3.RS,1,3.SHIFT:R6P16SHIFT:16::SRL16
+"srl r<TRT_NM>, r<TRS_NM>, <SHIFT_DEC>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_srl (SD_, TRS_NM, TRT_NM, SHIFT_DEC);
+}
+
+101100,3.RT,3.RS,3.RD,1:R6P16ADDU:16::SUBU16
+"subu r<TRD_NM>, r<TRS_NM>, r<TRT_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_subu (SD_, TRS_NM, TRT_NM, TRD_NM);
+}
+
+100101,3.RTZ,3.RS,4.U:R6P16:16::SW16
+"sw r<TRTZ>, <U_SHIFT_2BIT>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_WORD, GPR[TRS_NM], U_SHIFT_2BIT, GPR[TRTZ]);
+}
+
+101101,5.RT,5.U:R6P16:16::SWSP
+"sw r<RT>, <U_SHIFT_2BIT>(sp)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_WORD, SP, U_SHIFT_2BIT, GPR[RT]);
+}
+
+010100,3.RT,3.RS,01,0,0:R6POOL16C00:16::XOR16
+"xor r<TRT_NM>, r<TRS_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_xor (SD_, TRT_NM, TRS_NM, TRT_NM);
+}
+
+// 32-bit instructions
+
+001000,5.RT,5.RS,5.RD,1.X,0100010,000:R6POOL32A0:32::ADD
+"add r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_add (SD_, RS, RT, RD);
+}
+
+000000,5.RT!0,5.RS,16.U:R6PPADDIU:32::ADDIU
+"addiu r<RT>, r<RS>, <U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addiu (SD_, RS, RT, U);
+}
+
+010001,5.RT,011,18.U:R6PGPBH:32::ADDIUGPB
+"addiu r<RT>, GP, <U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addiu (SD_, GPIDX, RT, U);
+}
+
+010000,5.RT,19.U,00:R6PGPW:32::ADDIUGPW
+"addiu r<RT>, GP, <U_SHIFT_2BIT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addiu (SD_, GPIDX, RT, U_SHIFT_2BIT);
+}
+
+111000,5.RT,9.S1,10.S2,1,1.S3:R6PLUI:32::ALUIPC
+"aluipc r<RT>, <AXUIPC_S_HI>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  address_word address = NIA + AXUIPC_S;
+
+  TRACE_ALU_INPUT2(GPR[RT], address);
+  GPR[RT] = address & ~0xfff;
+  TRACE_ALU_RESULT(GPR[RT]);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0101010,000:R6POOL32A0:32::ADDU
+"addu r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addu (SD_, RS, RT, RD);
+}
+
+001000,5.RT,5.RS,5.RD,5.IMMEDIATE,011,111:R6POOL32A0:32::EXTW
+"prepend r<RT>, r<RS>, <IMMEDIATE>": RD == RS
+"align r<RD>, r<RS>, r<RT>, <IMMEDIATE>": IMMEDIATE != 0
+"extw r<RD>, r<RS>, r<RT>, <IMMEDIATE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (IMMEDIATE != 0) {
+    uint64_t tmp = ((uint64_t)GPR[RT] << 32) | (0xffffffff & GPR[RS]);
+    TRACE_ALU_INPUT4 (GPR[RD], GPR[RS], GPR[RT], tmp);
+    GPR[RD] = EXTEND32 (tmp >> IMMEDIATE);
+    TRACE_ALU_RESULT (GPR[RD]);
+  } else {
+    TRACE_ALU_INPUT2 (GPR[RD], GPR[RT]);
+    GPR[RD] = GPR[RT];
+    TRACE_ALU_RESULT (GPR[RD]);
+  }
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1001010,000:R6POOL32A0:32::AND
+"and r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_and (SD_, RS, RT, RD);
+}
+
+100000,5.RT,5.RS,0010,12.U:R6PU12:32::ANDI
+"andi r<RT>, r<RS>, <U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_andi (SD_, RS, RT, U);
+}
+
+001010,1,24.S1,1.S2:R6PBAL:32::BALC
+"balc <ADDRESS26>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT1(RA);
+  RA = NIA;
+  NIA = ADDRESS26;
+  TRACE_ALU_RESULT(RA);
+
+  // For cycle counting
+  COP0_COUNT++;
+}
+
+001010,0,24.S1,1.S2:R6PBAL:32::BC
+"bc <ADDRESS26>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  NIA = ADDRESS26;
+}
+
+100010,5.RT,5.RS,00,13.S1,1.S2:R6PBR1:32::BEQC
+"beqc r<RS>, r<RT>, <ADDRESS15>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RS], GPR[RT]);
+  if (GPR[RS] == GPR[RT])
+    NIA = ADDRESS15;
+}
+
+110010,5.RT,000,7.U,10.S1,1.S2:P7PBRI:32::BEQIC
+"beqic r<RT>, <U>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], U);
+  if (GPR[RT] == U) {
+    NIA = ADDRESS12;
+  }
+}
+
+100010,5.RT,5.RS,10,13.S1,1.S2:P7PBR1:32::BGEC
+"bgec r<RS>, r<RT>, <ADDRESS15>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RS], GPR[RT]);
+  if ((signed_word) GPR[RS] >= (signed_word) GPR[RT])
+    NIA = ADDRESS15;
+}
+
+110010,5.RT,010,7.U,10.S1,1.S2:P7PBRI:32::BGEIC
+"bgeic r<RT>, <U>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], U);
+  if ((signed_word) GPR[RT] >= U) {
+    NIA = ADDRESS12;
+  }
+}
+
+100010,5.RT,5.RS,11,13.S1,1.S2:P7PBR2:32::BGEUC
+"bgeuc r<RS>, r<RT>, <ADDRESS15>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RS], GPR[RT]);
+  if ((unsigned_word) (GPR[RS]) >= (unsigned_word)(GPR[RT])) {
+    NIA = ADDRESS15;
+  }
+}
+
+110010,5.RT,011,7.U,10.S1,1.S2:P7PBRI:32::BGEUIC
+"bgeuic r<RT>, <U>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], U);
+  if ((unsigned_word) GPR[RT] >= U) {
+    NIA = ADDRESS12;
+  }
+}
+
+101010,5.RT,5.RS,10,13.S1,1.S2:P7PBR2:32::BLTC
+"bltc r<RS>, r<RT>, <ADDRESS15>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RS], GPR[RT]);
+  if ((signed_word) GPR[RS] < (signed_word) GPR[RT])
+    NIA = ADDRESS15;
+}
+
+110010,5.RT,110,7.U,10.S1,1.S2:P7PBRI:32::BLTIC
+"bltic r<RT>, <U>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], U);
+  if ((signed_word) GPR[RT] < U) {
+    NIA = ADDRESS12;
+  }
+}
+
+101010,5.RT,5.RS,11,13.S1,1.S2:P7PBR2:32::BLTUC
+"bltuc r<RS>, r<RT>, <ADDRESS15>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RS], GPR[RT]);
+  if ((unsigned_word) GPR[RS] < (unsigned_word) GPR[RT]) {
+    NIA = ADDRESS15;
+  }
+}
+
+110010,5.RT,111,7.U,10.S1,1.S2:P7PBRI:32::BLTIUC
+"bltiuc <RT>, <U>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], U);
+  if ((unsigned_word) GPR[RT] < U) {
+    NIA = ADDRESS12;
+  }
+}
+
+101010,5.RT,5.RS,00,13.S1,1.S2:R6PBR2:32::BNEC
+"bnec r<RS>, r<RT>, <ADDRESS15>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RS], GPR[RT]);
+  if (GPR[RS] != GPR[RT])
+    NIA = ADDRESS15;
+}
+
+110010,5.RT,100,7.U,10.S1,1.S2:R6PBRI:32::BNEIC
+"bneic r<RT>, <U>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], U);
+  if (GPR[RT] != U) {
+    NIA = ADDRESS12;
+  }
+}
+
+000000,00000,10,19.CODE:R6PRI:32::BREAK
+"break %#lx<CODE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_break_nanomips (SD_, instruction_0);
+}
+
+101001,5.OP,5.RS,1.S1,0111,0,01,8.S2:R6PLSS1:32::CACHE
+"cache <OP>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_cache (SD_, OP, RS, S_9_BIT, instruction_0);
+}
+
+001000,5.RT,5.RS,0100101,100,111,111:R6POOL32AXF4:32::CLO
+"clo r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_clo (SD_, RT, RS);
+}
+
+001000,5.RT,5.RS,0101101,100,111,111:R6POOL32AXF4:32::CLZ
+"clz r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_clz (SD_, RT, RS);
+}
+
+001000,5.RT,5.X,01,00011,101,111,111:R6POOL32AXF5GROUP1:32::DI
+"di":RT == 0
+"di r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_di (SD_, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0100011,000:R6POOL32A0:32::DIV
+"div r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_div (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0110011,000:R6POOL32A0:32::DIVU
+"divu r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_divu (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.X,01,01011,101,111,111:R6POOL32AXF5GROUP1:32::EI
+"ei":RT == 0
+"ei r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_ei (SD_, RT);
+}
+
+001000,9.X,0,11,11001,101,111,111:R6ERETX:32::ERET
+"eret"
+*nanomips32r6:
+*nanomips64r6:
+{
+  NIA = do_eret(SD_, 0, NIA);
+}
+
+001000,9.X,1,11,11001,101,111,111:R6ERETX:32::ERETNC
+"eretnc"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  SignalException (ReservedInstruction, instruction_0);
+  NIA = do_eret(SD_, 1, NIA);
+}
+
+100000,5.RT,5.RS,1111,0,5.MSBD,0,5.LSB:R6PEXT:32::EXT
+"ext r<RT>, r<RS>, <LSB>, <MSBD+1>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  if (LSB + MSBD + 1 > 32)
+    Unpredictable ();
+
+  do_ext (SD_, RT, RS, LSB, MSBD);
+}
+
+100000,5.RT,5.RS,1110,0,5.MSBD,0,5.LSB:R6PINS:32::INS
+"ins r<RT>, r<RS>, <INS_POS>, <INS_SIZE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  if ((1 + MSBD - LSB) < 1)
+    Unpredictable ();
+  do_ins (SD_, RT, RS, LSB, MSBD);
+}
+
+100000,5.RT,5.RS,1101,0,4.SHIFTX,1.STRIPE,0,5.SHIFT:R6PROTX:32::ROTX
+"bitrev r<RT>, r<RS>": SHIFT == 31 && SHIFTX_1BIT == 0
+"bitswap r<RT>, r<RS>": SHIFT == 7 && SHIFTX_1BIT == 8 && STRIPE == 1
+"bitswap.h r<RT>, r<RS>": SHIFT == 15 && SHIFTX_1BIT == 16
+"byteswap r<RT>, r<RS>": SHIFT == 24 && SHIFTX_1BIT == 8
+"wsbh r<RT>, r<RS>": SHIFT == 8 && SHIFTX_1BIT == 24
+"rotx r<RT>, r<RS>, <SHIFT>, <SHIFTX_1BIT>": STRIPE == 0
+"rotx r<RT>, r<RS>, <SHIFT>, <SHIFTX_1BIT>, <STRIPE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+
+  TRACE_ALU_INPUT4 (GPR[RT], GPR[RS], SHIFT, SHIFTX_1BIT);
+  do_rotx (SD_, RT, RS, SHIFT, SHIFTX_1BIT, STRIPE);
+  TRACE_ALU_RESULT (GPR[RT]);
+}
+
+010010,5.RT,5.RS,0000,12.X:R6PJ:32::JALRC
+"jalrc r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  unsigned_word address;
+  TRACE_ALU_INPUT3(GPR[RT], GPR[RS], RA);
+  GPR[RT] = NIA;
+  address = GPR[RS];
+  NIA = address;
+
+  // For cycle counting
+  COP0_COUNT++;
+  TRACE_ALU_RESULT(NIA);
+
+}
+
+010010,5.RT,5.RS,0001,12.X:R6PJ:32::JALRC.HB
+"jalrc.hb r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  unsigned_word address;
+  GPR[RT] = NIA;
+  address = GPR[RS];
+  NIA = address;
+
+  // For cycle counting
+  COP0_COUNT++;
+}
+
+100001,5.RT,5.RS,0000,12.U:R6PLSU12:32::LB
+"lb r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lb (SD_, RT, U, RS);
+}
+
+010001,5.RT,000,18.U:R6PLSGP:32::LBGP
+"lb r<RT>, <U>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lb (SD_, RT, U, GPIDX);
+}
+
+101001,5.RT,5.RS,1.S1,0000,0,00,8.S2:R6PLSS0:32::LBS9
+"lb r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lb (SD_, RT, S_9_BIT, RS);
+}
+
+100001,5.RT,5.RS,0010,12.U:R6PLSU12:32::LBU
+"lbu r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lbu (SD_, RT, U, RS);
+}
+
+010001,5.RT,010,18.U:R6GPBH:32::LBUGP
+"lbu r<RT>, <U>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2 (U, GP);
+  do_lbu (SD_, RT, U, GPIDX);
+  TRACE_ALU_RESULT (GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.S1,0010,0,00,8.S2:R6PLSS0:32::LBUS9
+"lbu r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lbu (SD_, RT, S_9_BIT, RS);
+}
+
+001000,5.RT,5.RS,5.RD,0010,0,000,111:R6PPLSX:32::LBUX
+"lbux r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lbu (SD_, RD, GPR[RS], RT);
+}
+
+001000,5.RT,5.RS,5.RD,0000,0,000,111:R6PPLSX:32::LBX
+"lbx r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lb (SD_, RD, GPR[RS], RT);
+}
+
+100001,5.RT,5.RS,0100,12.U:R6PLSU12:32::LH
+"lh r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lh (SD_, RT, U, RS);
+}
+
+010001,5.RT,100,17.U,0:R6PGPLH:32::LHGP
+"lh r<RT>, <U_SHIFT_1BIT>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lh (SD_, RT, U_SHIFT_1BIT, GPIDX);
+}
+
+101001,5.RT,5.RS,1.S1,0100,0,00,8.S2:R6PLSS0:32::LHS9
+"lh r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lh (SD_, RT, S_9_BIT, RS);
+}
+
+100001,5.RT,5.RS,0110,12.U:R6PLSU12:32::LHU
+"lhu r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lhu (SD_, RT, U, RS);
+}
+
+010001,5.RT,100,17.U,1:R6PLSGP:32::LHUGP
+"lhu r<RT>, <U_SHIFT_1BIT>(gp)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lhu (SD_, RT, U_SHIFT_1BIT, GPIDX);
+}
+
+101001,5.RT,5.RS,1.S1,0110,0,00,8.S2:R6PLSS0:32::LHUS9
+"lhu r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lhu (SD_, RT, S_9_BIT, RS);
+}
+
+001000,5.RT,5.RS,5.RD,0110,0,000,111:R6PPLSX:32::LHUX
+"lhux r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lhu (SD_, RD, GPR[RS], RT);
+}
+
+001000,5.RT,5.RS,5.RD,0110,1,000,111:R6PPLSXS:32::LHUXS
+"lhux r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lhu (SD_, RD, GPR[RS] << 1, RT);
+}
+
+001000,5.RT,5.RS,5.RD,0100,0,000,111:R6PPLSX:32::LHX
+"lhx r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lh (SD_, RD, GPR[RS], RT);
+}
+
+001000,5.RT,5.RS,5.RD,0100,1,000,111:R6PPLSXS:32::LHXS
+"lhxs r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lh (SD_, RD, GPR[RS] << 1, RT);
+}
+
+101001,5.RT,5.RS,1.S1,1010,0,01,6.S2,00:R6PLL:32::LL
+"ll r<RT>, <S_9_BIT_LLSC>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3(GPR[RT], S_9_BIT_LLSC, GPR[RS]);
+  do_ll (SD_, RT, S_9_BIT_LLSC, RS);
+  TRACE_ALU_RESULT(GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.X1,1010,0,01,5.RU,1.X2,01:R6PLL:32::LLWP
+"llwp r<RT>, r<RU>, (r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_llwp (SD_, RT, RU, 0, RS);
+}
+
+001000,5.RT,5.RS,5.RD,2.U,3.X,001,111:R6POOL32A7:32::LSA
+"lsa r<RD>, r<RS>, r<RT>, <U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lsa (SD_, RD, RS, RT, U);
+}
+
+111000,5.RT,9.S1,10.S2,0,1.S3:R6PLUI:32::LUI
+"lui r<RT>, <AXUIPC_S_HI>, <AXUIPC_S_LO>":AXUIPC_S_LO != 0
+"lui r<RT>, <AXUIPC_S_HI>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2 (GPR[RT], AXUIPC_S);
+  GPR[RT] = AXUIPC_S;
+  TRACE_ALU_RESULT (GPR[RT]);
+}
+
+100001,5.RT,5.RS,1000,12.U:R6PLSU12:32::LW
+"lw r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3 (GPR[RT], U, GPR[RS]);
+  do_lw (SD_, RT, U, RS);
+  TRACE_ALU_RESULT (GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.S1,1000000,8.S2:R6PLSS0:32::LWS9
+"lw r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lw (SD_, RT, S_9_BIT, RS);
+}
+
+101001,5.RT,5.RS,1.S1,3.COUNT3,0,1,00,8.S2:R6PLSWM:32::LWM
+"lwm r<RT>, <S_9_BIT>(r<RS>), <COUNT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  int counter = 0;
+  int dest;
+  int this_offset;
+
+  check_nms_flag (SD_);
+
+  while (counter != COUNT)
+  {
+    dest = (RT & 0x10) | ((RT + counter) & 0x1F);
+
+    if ((dest == RS) && (counter != (COUNT - 1)))
+      Unpredictable ();
+
+    this_offset = S_9_BIT + (counter << 2);
+
+    do_lw (SD_, dest, this_offset, RS);
+
+    counter++;
+    if (counter != 0)
+      COP0_COUNT++;
+  }
+}
+
+010000,5.RT,19.U,10:R6PGPW:32::LWGP
+"lw r<RT>, <U_SHIFT_2BIT>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], GPR[RT]);
+  do_lw (SD_, RT, U_SHIFT_2BIT, GPIDX);
+  TRACE_ALU_RESULT(GPR[RT]);
+}
+
+011000,5.RT,01011,16.IMM48:R6POOL48I:32::LWPC48
+"lwpc r<RT>, <IMM48>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint16_t S2;
+  uint32_t total;
+  check_nms_flag (SD_);
+  S2 = do_load(SD_, AccessLength_HALFWORD, CIA + 4, 0);
+  total = S2 << 16 | IMM48;
+
+  do_lwpc_nanomips (SD_, RT, total, CIA + 6);
+  NIA = CIA + 6;
+}
+
+001000,5.RT,5.RS,5.RD,1000,0,000,111:R6PPLSX:32::LWX
+"lwx r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lw (SD_, RD, GPR[RS], RT);
+}
+
+001000,5.RT,5.RS,5.RD,1000,1,000,111:R6PPLSXS:32::LWXS
+"lwxs r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lw (SD_, RD, GPR[RS] << 2, RT);
+}
+
+001000,5.RT,5.C0S,5.SEL,1.X,0000110,000:R6POOL32A0:32::MFC0
+"mfc0 r<RT>, r<C0S>, <SEL>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  DecodeCoproc (instruction_0, 0, cp0_mfc0, RT, C0S, SEL);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0101011,000:R6POOL32A0:32::MOD
+"mod r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_mod (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0111011,000:R6POOL32A0:32::MODU
+"modu r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_modu (SD_, RD, RS, RT);
+}
+
+000010,1.RT1,1.RD,3.RT2,20.S1,1.S2:R6MOVEBALC:32::MOVE.BALC
+"move.balc r<RD1>, r<RT_5_BIT_NM_Z>, <ADDRESS22>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  TRACE_ALU_INPUT2(GPR[RD1], GPR[RT_5_BIT_NM_Z]);
+  GPR[RD1] = GPR[RT_5_BIT_NM_Z];
+  RA = NIA;
+  NIA = ADDRESS22;
+  TRACE_ALU_RESULT(GPR[RD1]);
+
+  // For cycle counting
+  COP0_COUNT += 2;
+}
+
+001000,5.RT,5.RS,5.RD,1,1000010,000:R6PCMOVE:32::MOVN
+"movn r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RS], GPR[RT]);
+  do_movn (SD_, RD, RS, RT);
+  TRACE_ALU_RESULT(GPR[RD]);
+}
+
+001000,5.RT,5.RS,5.RD,0,1000010,000:R6PCMOVE:32::MOVZ
+"movz r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_movz (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.C0S,5.SEL,1.X,0001110,000:R6POOL32A0:32::MTC0
+"mtc0 r<RT>, r<C0S>, <SEL>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  DecodeCoproc (instruction_0, 0, cp0_mtc0, RT, C0S, SEL);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0001011,000:R6POOL32A0:32::MUH
+"muh r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_muh (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0011011,000:R6POOL32A0:32::MUHU
+"muhu r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_muhu (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0000011,000:R6POOL32A0:32::MUL32
+"mul r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_mul (SD_, RD, RS, RT);
+}
+
+001111,1.RT1,0,3.RT2,1.RS1,1,3.RS2:R6P164X4:16::MUL4X4
+"mul r<RT_5_BIT_NM>, r<RS_5_BIT_NM>, r<RT_5_BIT_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_mul (SD_, RT_5_BIT_NM, RS_5_BIT_NM, RT_5_BIT_NM);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0010011,000:R6POOL32A0:32::MULU
+"mulu r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_mulu (SD_, RD, RS, RT);
+}
+
+100000,00000,5.X1,1100,3.X2,0000,00000:R6PSLL:32::NOP32
+"nop"
+*nanomips32r6:
+*nanomips64r6:
+{
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1011010,000:R6POOL32A0:32::NOR
+"nor r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_nor (SD_, RS, RT, RD);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1010010,000:R6POOL32A0:32::OR32
+"or r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_or (SD_, RS, RT, RD);
+}
+
+100000,5.RT,5.RS,0000,12.U:R6PU12:32::ORI
+"ori r<RT>, r<RS>, <U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_ori (SD_, RS, RT, U);
+}
+
+100000,00000,5.X1,1100,3.X2,0000,00101:R6PSLL:32::PAUSE
+"pause"
+*nanomips32r6:
+*nanomips64r6:
+{
+  sim_io_printf (SD, "Not implemented");
+}
+
+101001,5.HINT!31,5.RS,1.S1,0011,0,00,8.S2:R6PPREFS9:32::PREFS9
+"pref <HINT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_pref (SD_, HINT, S_9_BIT, RS);
+}
+
+100001,5.HINT,5.RS,0011,12.U:R6PLSU12:32::PREFU12
+"pref <HINT>, <U>(r<RS>)": HINT != 31
+"synci <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (HINT != 31)
+   do_pref (SD_, HINT, U, RS);
+  else
+  {
+    // synci - nothing to do currently
+    sim_io_printf (SD, "Not implemented");
+  }
+}
+
+100000,5.RT,0,4.GPR_LIST_SAVE,0011,9.U,1.GP_SAVE,10:R6PPSR:32::RESTORE
+"restore <U_SHIFT_3BIT>, r<RT>": GPR_LIST_SAVE == 0
+"restore <U_SHIFT_3BIT>, r<RT>, %s<GPR_LIST_SAVE>": !GP_SAVE && GPR_LIST_SAVE != 0
+"restore <U_SHIFT_3BIT>, r<RT>": !GP_SAVE && GPR_LIST_SAVE < 2
+"restore <U_SHIFT_3BIT>, r<RT>, %s<GPR_LIST_SAVE>" : !GP_SAVE && GPR_LIST_SAVE >=2
+"restore <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>": GP_SAVE && GPR_LIST_SAVE < 2
+"restore <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>, %s<GPR_LIST_SAVE>" : GP_SAVE && GPR_LIST_SAVE >=2
+"restore <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>": GP_SAVE && GPR_LIST_SAVE < 3
+"restore <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>, %s<GPR_LIST_SAVE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_restore_gprs_from_stack_and_adjust_sp(SD_, RT, GPR_LIST_SAVE,
+                                           GP_SAVE, U_SHIFT_3BIT);
+}
+
+100000,5.RT,0,4.GPR_LIST_SAVE,0011,9.U,1.GP_SAVE,11:R6PPSR:32::RESTORE.JRC
+"restore.jrc <U_SHIFT_3BIT>, r<RT>": GPR_LIST_SAVE == 0
+"restore.jrc <U_SHIFT_3BIT>, r<RT>, %s<GPR_LIST_SAVE>": !GP_SAVE && GPR_LIST_SAVE != 0
+"restore.jrc <U_SHIFT_3BIT>, r<RT>": !GP_SAVE && GPR_LIST_SAVE < 2
+"restore.jrc <U_SHIFT_3BIT>, r<RT>, %s<GPR_LIST_SAVE>" : !GP_SAVE && GPR_LIST_SAVE >=2
+"restore.jrc <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>": GP_SAVE && GPR_LIST_SAVE < 2
+"restore.jrc <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>, %s<GPR_LIST_SAVE>" : GP_SAVE && GPR_LIST_SAVE >=2
+"restore.jrc <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>": GP_SAVE && GPR_LIST_SAVE < 3
+"restore.jrc <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>, %s<GPR_LIST_SAVE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_restore_gprs_from_stack_and_adjust_sp(SD_, RT, GPR_LIST_SAVE,
+                                           GP_SAVE, U_SHIFT_3BIT);
+
+  NIA = GPR[RAIDX];
+}
+
+100000,5.RT,5.RS,1100,3.X,0110,5.SHIFT:R6PSHIFT:32::ROTR
+"rotr r<RT>, r<RS>, <SHIFT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  GPR[RT] = do_ror (SD_, GPR[RS], SHIFT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0011010,000:R6POOL32A0:32::ROTRV
+"rotrv r<RD>, r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint32_t shift = GPR[RT] & 0x1f;
+  GPR[RD] = do_ror (SD_, GPR[RS], shift);
+}
+
+001000,5.RT,5.RS,5.RD,0,1100010,000:R6POOL32A0:32::XOR
+"xor r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_xor (SD_, RS, RT, RD);
+}
+
+100000,5.RT,5.RS,0001,12.U:R6PU12:32::XORI
+"xori r<RT>, r<RS>, <U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_xori (SD_, RS, RT, U);
+}
+
+100000,5.RT,0,4.GPR_LIST_SAVE,0011,9.U,1.GP_SAVE,00:R6PPSR:32::SAVE
+"save <U_SHIFT_3BIT>, r<RT>": GPR_LIST_SAVE == 0
+"save <U_SHIFT_3BIT>, r<RT>, %s<GPR_LIST_SAVE>":  !GP_SAVE && GPR_LIST_SAVE != 0
+"save <U_SHIFT_3BIT>, r<RT>": !GP_SAVE && GPR_LIST_SAVE < 2
+"save <U_SHIFT_3BIT>, r<RT> %s<GPR_LIST_SAVE>" : !GP_SAVE && GPR_LIST_SAVE >=2
+"save <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>": GP_SAVE && GPR_LIST_SAVE < 2
+"save <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>, %s<GPR_LIST_SAVE>" : GP_SAVE && GPR_LIST_SAVE >=2
+"save <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>": GP_SAVE && GPR_LIST_SAVE < 3
+"save <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>, %s<GPR_LIST_SAVE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_save_gprs_to_stack_and_adjust_sp(SD_, RT, GPR_LIST_SAVE,
+                                      GP_SAVE, U_SHIFT_3BIT);
+}
+
+100001,5.RT,5.RS,0001,12.U:R6PLSU12:32::SBU12
+"sb r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_BYTE, GPR[RS], U, GPR[RT]);
+}
+
+010001,5.RT,001,18.U:R6PGPBH:32::SBGP
+"sb r<RT>, <U>(gp)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_BYTE, GP, U, GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.S1,0001,0,00,8.S2:R6PLSS0:32::SBS9
+"sb r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_BYTE, GPR[RS], S_9_BIT, GPR[RT]);
+}
+
+001000,5.RT,5.RS,5.RD,0001,0,000,111:R6PPLSX:32::SBX
+"sbx r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_store (SD_, AccessLength_BYTE, GPR[RT], GPR[RS], GPR[RD]);
+}
+
+101001,5.RT,5.RS,1.S1,1011,0,01,6.S2,00:R6PSC:32::SC
+"sc r<RT>, <S_9_BIT_LLSC>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_sc (SD_, RT, S_9_BIT_LLSC, RS, instruction_0, 1);
+}
+
+101001,5.RT,5.RS,1.X1,1011,0,01,5.RU,1.X,01:R6PSC:32::SCWP
+"scwp r<RT>, r<RU>, (r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  int offset = BigEndianCPU ? 0 : 4;
+
+  do_sc (SD_, RU, offset, RS, instruction_0, 0);
+  do_sc (SD_, RT, offset ^ 4, RS, instruction_0, 1);
+}
+
+001000,5.RT,5.RS,6.X,0000001,000:R6POOL32A0:32::SEB
+"seb r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_seb (SD_, RT, RS);
+}
+
+001000,5.RT,5.RS,6.X,0001001,000:R6POOL32A0:32::SEH
+"seh r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_seh (SD_, RT, RS);
+}
+
+100000,5.RT,5.RS,0110,12.IMMEDIATE:R6PU12:32::SEQI
+"seqi r<RT>, r<RS>, <IMMEDIATE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3(GPR[RT], GPR[RS], IMMEDIATE);
+  GPR[RT] = (GPR[RS] == IMMEDIATE) ? 1 : 0;
+  TRACE_ALU_RESULT(GPR[RT]);
+}
+
+100001,5.RT,5.RS,0101,12.U:R6PLSU12:32::SHU12
+"sh r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_HALFWORD, GPR[RS], U, GPR[RT]);
+}
+
+010001,5.RT,101,17.U,0:R6PGPSH:32::SHGP
+"sh r<RT>, <U_SHIFT_1BIT>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_HALFWORD, GP, U_SHIFT_1BIT, GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.S1,0101,0,00,8.S2:R6PLSS0:32::SHS9
+"sh r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_HALFWORD, GPR[RS], S_9_BIT, GPR[RT]);
+}
+
+001000,5.RT,5.RS,5.RD,0101,0,000,111:R6PPLSX:32::SHX
+"shx r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_store (SD_, AccessLength_HALFWORD, GPR[RT], GPR[RS], GPR[RD]);
+}
+
+001000,5.RT,5.RS,5.RD,0101,1,000,111:R6PPLSXS:32::SHXS
+"shxs r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_store (SD_, AccessLength_HALFWORD, GPR[RT], GPR[RS] << 1, GPR[RD]);
+}
+
+000000,00000,00,19.CODE:R6PRI:32::SIGRIE
+"sigrie %#lx<CODE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  SignalException (ReservedInstruction, instruction_0);
+}
+
+100000,5.RT!0,5.RS,1100,3.X,0000,5.SHIFT:R6PSLL:32::SLL32
+"sll r<RT>, r<RS>, <SHIFT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_sll (SD_, RS, RT, SHIFT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0000010,000:R6POOL32A0:32::SLLV
+"sllv r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_sllv (SD_, RT, RS, RD);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1101010,000:R6POOL32A0:32::SLT
+"slt r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_slt (SD_, RS, RT, RD);
+}
+
+100000,5.RT,5.RS,0100,12.IMMEDIATE:R6PU12:32::SLTI
+"slti r<RT>, r<RS>, <IMMEDIATE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_slti (SD_, RS, RT, EXTEND12(IMMEDIATE));
+}
+
+100000,5.RT,5.RS,0101,12.U:R6PU12:32::SLTIU
+"sltiu r<RT>, r<RS>, <U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_sltiu (SD_, RS, RT, EXTEND12(U));
+}
+
+001000,5.RT,5.RS,5.RD!0,1.X,1110010,000:R6PSLTU:32::SLTU
+"sltu r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_sltu (SD_, RS, RT, RD);
+}
+
+100000,5.RT,5.RS,1100,3.X,0100,5.SHIFT:R6PSHIFT:32::SRA
+"sra r<RT>, r<RS>, <SHIFT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_sra (SD_, RS, RT, SHIFT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0010010,000:R6POOL32A0:32::SRAV
+"srav r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_srav (SD_, RT, RS, RD);
+}
+
+100000,5.RT,5.RS,1100,3.X,0010,5.SHIFT:R6PSHIFT:32::SRL32
+"srl r<RT>, r<RS>, <SHIFT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_srl (SD_, RS, RT, SHIFT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0001010,000:R6POOL32A0:32::SRLV
+"srlv r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_srlv (SD_, RT, RS, RD);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0110010,000:R6POOL32A0:32::SUB
+"sub r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_sub (SD_, RS, RT, RD);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0111010,000:R6POOL32A0:32::SUBU32
+"subu r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_subu (SD_, RS, RT, RD);
+}
+
+100001,5.RT,5.RS,1001,12.U:R6PLSU12:32::SWU12
+"sw r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_WORD, GPR[RS], U, GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.S1,1001,0,00,8.S2:R6PLS0:32::SWS9
+"sw r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_WORD, GPR[RS], S_9_BIT, GPR[RT]);
+}
+
+010000,5.RT,19.U,11:R6PGPW:32::SWGP
+"sw r<RT>, <U_SHIFT_2BIT>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_WORD, GP, U_SHIFT_2BIT, GPR[RT]);
+}
+
+011000,5.RT,01111,16.IMM48:R6POOL48I:32::SWPC48
+"swpc r<RT>, <IMM48>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint16_t U2;
+  uint32_t total;
+  check_nms_flag (SD_);
+  U2 = do_load (SD_, AccessLength_HALFWORD, CIA + 4, 0);
+  total = U2 << 16 | IMM48;
+  TRACE_ALU_INPUT2(GPR[RT], total);
+  do_store(SD_, AccessLength_WORD, CIA + 6, total, GPR[RT]);
+  TRACE_ALU_RESULT(GPR[RT]);
+  NIA = CIA + 6;
+}
+
+
+110101,3.RTZ,7.U:R6P16:16::SWGP16
+"sw r<TRTZ>, <U_SHIFT_2BIT>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_WORD, GP, U_SHIFT_2BIT, GPR[TRTZ]);
+}
+
+001000,5.RT,5.RS,5.RD,1001,0,000,111:R6PPLSX:32::SWX
+"swx r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_store (SD_, AccessLength_WORD, GPR[RT], GPR[RS], GPR[RD]);
+}
+
+001000,5.RT,5.RS,5.RD,1001,1,000,111:R6PPLSXS:32::SWXS
+"swxs r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_store (SD_, AccessLength_WORD, GPR[RT], GPR[RS] << 2, GPR[RD]);
+}
+
+111101,1.RT1,1.U2,3.RT2,1.RS1,1.U3,3.RS2:R6P16:16::SW4X4
+"sw r<RT_5_BIT_NM_Z>, <U_LW4X4>(r<RS_5_BIT_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_store (SD_, AccessLength_WORD, GPR[RS_5_BIT_NM], U_LW4X4, GPR[RT_5_BIT_NM_Z]);
+}
+
+101001,5.RT,5.RS,1.S1,3.COUNT3,1,1,00,8.S2:R6PLSWM:32::SWM
+"swm r<RT>, <S_9_BIT>(r<RS>), <COUNT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  int counter = 0;
+  int source;
+  int offsetm;
+
+  check_nms_flag (SD_);
+
+  while (counter != COUNT)
+  {
+    if (RT == 0)
+      source = 0;
+    else
+      source = (RT & 0x10) | ((RT + counter) & 0x1F);
+
+    offsetm = S_9_BIT + (counter << 2);
+
+    do_sw (SD_, source, offsetm, RS);
+
+    counter++;
+
+    if (counter != 0)
+      COP0_COUNT++;
+  }
+}
+
+100000,00000,5.STYPE,1100,3.X,0000,00110:R6PHB:32::SYNC
+"sync":STYPE==0
+"sync <STYPE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  SyncOperation (STYPE);
+}
+
+101001,11111,5.RS,1.S1,0011,0,00,8.S2:R6PPREFS:32::SYNCI
+"synci <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // sync i-cache - nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+000000,00000,11,19.CODE:R6PRI:32::SDBBP32
+"sdbbp %#lx<CODE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  SignalException (DebugBreakPoint, instruction_0);
+}
+
+001000,10.X,00,00001,101,111,111:R6POOL32AXF5GROUP0:32::TLBP
+"tlbp"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,10.X,00,10001,101,111,111:R6POOL32AXF5GROUP0:32::TLBWI
+"tlbwi"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,10.X,00,11001,101,111,111:R6POOL32AXF5GROUP0:32::TLBWR
+"tlbwr"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+
+001000,0000000000,01,00001,101,111,111:R6POOL32AXF5GROUP1:32::TLBINV
+"tlbinv"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // invalidate a set of TLB entries based on ASID and Index match - nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,0000000000,01,01001,101,111,111:R6POOL32AXF5GROUP1:32::TLBINVF
+"tlbinvf"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // invalidate a set of TLB entries based on Index match - nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,10.CODE,10,00101,101,111,111:R6PSYSCALL:32::SYSCALL
+"syscall %#lx<CODE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  SignalException (SystemCall, instruction_0);
+}
+
+100000,00000,5.X1,1100,3.X2,0000,00011:R6PHB:32::EHB
+"ehb"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // Do nothing, there are no hazards to clear
+}
+
+001000,5.RT,5.RS,5.X,0,0000000,000:R6PTRAP:32::TEQ
+"teq r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+
+  if (GPR[RS] == GPR[RT])
+    SignalException(Trap, instruction_0);
+}
+
+001000,5.RT,5.RS,5.X,1,0000000,000:R6PTRAP:32::TNE
+"tne r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+
+  if (GPR[RS] != GPR[RT])
+    SignalException(Trap, instruction_0);
+}
+
+101001,5.RT,5.RS,1.S1,0100,0,01,8.S2:R6PLSS1:32::UALH
+"ualh r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+
+  TRACE_ALU_INPUT3(GPR[RT], S_9_BIT, GPR[RS]);
+  do_lh (SD_, RT, S_9_BIT, RS);
+  TRACE_ALU_RESULT(GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.S1,3.COUNT3,0,1,01,8.S2:R6PLSUAWM:32::UALWM
+"ualwm r<RT>, <S_9_BIT>(r<RS>), <COUNT>":COUNT != 1
+"ualw r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  int i;
+  int dest;
+  int this_offset;
+
+  address_word base = GPR[RS];
+  for(i = 0; i< COUNT; i++)
+  {
+    dest = (RT & 0x10) | ((RT + i) & 0x1F);
+
+    if (dest == RS && i != COUNT - 1)
+      Unpredictable ();
+
+    this_offset = S_9_BIT + (i << 2);
+
+    if(BigEndianCPU) {
+      GPR[dest] = EXTEND32 (do_load_left (SD_, AccessLength_WORD, base,
+         EXTEND16 (this_offset), GPR[dest]));
+      GPR[dest] = EXTEND32 (do_load_right (SD_, AccessLength_WORD, base,
+         EXTEND16 (this_offset + AccessLength_WORD), GPR[dest]));
+    } else {
+      GPR[dest] = EXTEND32 (do_load_right (SD_, AccessLength_WORD, base,
+         EXTEND16 (this_offset), GPR[dest]));
+      GPR[dest] = EXTEND32 (do_load_left (SD_, AccessLength_WORD, base,
+         EXTEND16 (this_offset + AccessLength_WORD), GPR[dest]));
+    }
+
+    if (i != 0)
+      COP0_COUNT++;
+  }
+}
+
+101001,5.RT,5.RS,1.S1,0101,0,01,8.S2:R6PLSS1:32::UASH
+"uash r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+
+  do_store (SD_, AccessLength_HALFWORD, GPR[RS], S_9_BIT, GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.S1,3.COUNT3,1,1,01,8.S2:R6PLSUAWM:32::UASWM
+"uaswm r<RT>, <S_9_BIT>(r<RS>), <COUNT>":COUNT != 1
+"uasw r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+
+  int i;
+  int source;
+  int offsetm;
+
+  for(i = 0; i< COUNT; i++)
+   {
+    if (RT == 0)
+      source = 0;
+    else
+      source = (RT & 0x10) | ((RT + i) & 0x1F);
+
+    offsetm = S_9_BIT + (i << 2);
+
+    if(BigEndianCPU) {
+      do_store_left (SD_, AccessLength_WORD, GPR[RS], EXTEND16 (offsetm), GPR[source]);
+      do_store_right (SD_, AccessLength_WORD, GPR[RS],
+                          EXTEND16 (offsetm + AccessLength_WORD), GPR[source]);
+    } else {
+      do_store_right (SD_, AccessLength_WORD, GPR[RS], EXTEND16 (offsetm), GPR[source]);
+      do_store_left (SD_, AccessLength_WORD, GPR[RS],
+                          EXTEND16 (offsetm + AccessLength_WORD), GPR[source]);
+    }
+
+    if (i != 0)
+      COP0_COUNT++;
+  }
+}
+
+001000,5.RT,5.X,00000,0,1110010,000:R6PDVP:32::DVP
+"dvp r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+
+001000,5.RT,5.HS,2.X1,3.SEL,1.X2,0111000,000:R6POOL32A0:32::RDHWR
+"rdhwr r<HS>, r<RT>, <SEL>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_rdhwr (SD_, RT, HS);
+}
+
+001000,5.RT,5.RS,11,10000,101,111,111:R6POOL32AXF5GROUP3:32::RDPGPR
+"rdpgpr r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,5.RT,5.RS,11,11000,101,111,111:R6POOL32AXF5GROUP3:32::WRPGPR
+"wrpgpr r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // TODO: implement as given in the specification
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1111010,000:R6POOL32A0:32::SOV
+"SOV r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (NotWordValue (GPR[RS]) || NotWordValue (GPR[RT]))
+    Unpredictable ();
+  TRACE_ALU_INPUT2 (GPR[RS], GPR[RT]);
+  {
+    ALU32_BEGIN (GPR[RS]);
+    ALU32_ADD (GPR[RT]);
+    if (ALU32_HAD_OVERFLOW)
+      GPR[RD] = 1;
+    else
+      GPR[RD] = 0;
+  }
+  TRACE_ALU_RESULT (GPR[RD]);
+}
+
+001000,10.X,11,10001,101,111,111:R6POOL32A0:32::DERET
+"deret"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,5.RT,5.X,00000,1,1110010,000:R6PDVP:32::EVP
+"evp r<RT>" : RT!=0
+"evp"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,10.CODE,110000110,1111111:R6POOL32AXF5GROUP2:32::WAIT
+"wait"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+011000,5.RT,00000,16.IMM48:R6POOL48I:32::LI48
+"li r<RT>, <IMM48>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint16_t U2;
+  uint32_t total;
+  check_nms_flag (SD_);
+  U2 = do_load (SD_, AccessLength_HALFWORD, CIA + 4, 0);
+  total = U2 << 16 | IMM48;
+  TRACE_ALU_INPUT2(GPR[RT], total);
+  GPR[RT] = EXTEND32(total);
+  TRACE_ALU_RESULT(GPR[RT]);
+  NIA = CIA + 6;
+}
+
+011000,5.RT,00001,16.IMM48:R6POOL48I:32::ADDIU48
+"addiu r<RT>, <IMM48>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint16_t S2;
+  uint32_t total;
+  check_nms_flag (SD_);
+  S2 = do_load(SD_, AccessLength_HALFWORD, CIA + 4, 0);
+  total = S2 << 16 | IMM48;
+  do_addiu(SD_, RT, RT, total);
+  NIA = CIA + 6;
+}
+
+100000,5.RT,5.RS,1000,12.U:R6PU12:32::ADDIUNEG
+"addiu r<RT>, r<RS>, -<U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addiu (SD_, RS, RT, -U);
+}
+
+011000,5.RT,00010,16.IMM48:R6POOL48I:32::ADDIUGP48
+"addiu r<RT>, GP, <IMM48>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint16_t S2;
+  uint32_t total;
+  check_nms_flag (SD_);
+  S2 = do_load(SD_, AccessLength_HALFWORD, CIA + 4, 0);
+  total = S2 << 16 | IMM48;
+  do_addiu (SD_, GPIDX, RT, total);
+  NIA = CIA + 6;
+}
+
+010010,00000,5.RS,1000,12.X:R6BALRSC:32::BRSC
+"brsc r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  unsigned_word address = NIA + (GPR[RS] << 1);
+  NIA = address;
+}
+
+010010,5.RT!0,5.RS,1000,12.X:R6PBALRSC:32::BALRSC
+"balrsc r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  unsigned_word address = NIA + (GPR[RS] << 1);
+
+  GPR[RT] = NIA;
+  NIA = address;
+
+  // For cycle counting
+  COP0_COUNT++;
+}
+
+110010,5.RT,001,1.X,6.BIT,10.S1,1.S2:R6PBRI:32::BBEQZC
+"bbeqzc r<RT>, <BIT>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  int testbit = (GPR[RT] >> BIT) & 1;
+
+  check_nms_flag (SD_);
+
+  if (testbit == 0)
+      NIA = ADDRESS12;
+}
+
+110010,5.RT,101,1.X,6.BIT,10.S1,1.S2:R6PBRI:32::BBNEZC
+"bbnezc r<RT>, <BIT>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  int testbit = (GPR[RT] >> BIT) & 1;
+
+  check_nms_flag (SD_);
+
+  if (testbit == 1)
+      NIA = ADDRESS12;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Not yet in the specification.
+//////////////////////////////////////////////////////////////////////
+
+100001,5.FT,5.RS,1111,12.U:R6PLSU12:32::SDC1
+"sdc1 f<FT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_fpu (SD_);
+  TRACE_ALU_INPUT3(FGR[FT], U, GPR[RS]);
+  do_store (SD_, AccessLength_DOUBLEWORD, GPR[RS], EXTEND16 (U), COP_SD (1, FT));
+}
+
+100001,5.FT,5.RS,1110,12.OFFSET:R6PLSU12:32::LDC1
+"ldc1 f<FT>, <OFFSET>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_fpu (SD_);
+  TRACE_ALU_INPUT3(FGR[FT], OFFSET, GPR[RS]);
+  COP_LD (1, FT, do_load (SD_, AccessLength_DOUBLEWORD, GPR[RS], EXTEND16 (OFFSET)));
+  TRACE_ALU_RESULT(FGR[FT]);
+}
+
+100001,5.FT,5.BASE,1010,12.OFFSET:R6PLSU12:32::LWC1
+"lwc1 f<FT>, <OFFSET>(r<BASE>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lwc1 (SD_, FT, OFFSET, BASE);
+}
+
+100001,5.FT,5.BASE,1011,12.OFFSET:R6PLSU12:32::SWC1
+"swc1 f<FT>, <OFFSET>(fp)": BASE == 30
+"swc1 f<FT>, <OFFSET>(r<BASE>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if(BASE == 30)
+    do_swc1 (SD_, FT, OFFSET, 30, instruction_0);
+  else
+    do_swc1 (SD_, FT, OFFSET, BASE, instruction_0);
+}
+
+001000,10.X,00,01001,101,111,111:R6POOL32AXF5GROUP0:32::TLBR
+"tlbr"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+101000,5.RT,5.FS,2.X,101000,00,111,011:R6POOL32FXF0:32,f::MTC1
+"mtc1 r<RT>, f<FS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], FGR[FS]);
+  do_mtc1b (SD_, RT, FS);
+  TRACE_ALU_RESULT(FGR[FS]);
+}
+
+101000,5.RT,5.FS,2.X,111000,00,111,011:R6POOL32FXF0:32,f::MTHC1
+"mthc1 r<RT>, f<FS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+TRACE_ALU_INPUT2(GPR[RT],FGR[FS]);
+  do_mthc1 (SD_, RT, FS);
+  TRACE_ALU_RESULT(FGR[FS]);
+}
+
+101000,5.FT,5.FS,5.FD,1.X,0,1.FMT_MICROMIPS,00110,000:R6POOLADDFMT1:32,f::ADD.fmt1
+"add.%s<FMT_MICROMIPS> f<FD>, f<FS>, f<FT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(FGR[FT], FGR[FS]);
+  do_add_fmt (SD_, convert_fmt_micromips (SD_, FMT_MICROMIPS), FD, FS, FT,
+        instruction_0);
+  TRACE_ALU_RESULT(FGR[FD]);
+}
+
+101000,5.FT,5.FS,5.FD,5.R6COND,0,1.FMT,0101:R6POOL32F5:32,f::CMP.cond.fmt
+"cmp.%s<R6COND>.%s<FMT> f<FD>, f<FS>, f<FT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_cmp (SD_, FD, FS, FT, FMT, R6COND);
+}
+
+101000,5.FT,5.FS,1.X,0,1.FMT_MICROMIPS,00000,01,111,011:R6POOLMOVFMT:32,f::MOV.fmt
+"mov.%s<FMT_MICROMIPS> f<FT>, f<FS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(FGR[FT], FGR[FS]);
+  do_mov_fmt (SD_, convert_fmt_micromips (SD_, FMT_MICROMIPS), FT, FS,
+        instruction_0);
+  TRACE_ALU_RESULT(FGR[FT]);
+}
+
+010001,5.FT,110,16.U,00:R6PLSGPCP1:32::LWC1GP
+"lwc1 f<FT>, <U_SHIFT_2BIT>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lwc1 (SD_, FT, U_SHIFT_2BIT, GPIDX);
+}
+
+010001,5.FT,110,16.U,01:R6PLSGPCP1:32::SWC1GP
+"swc1 f<FT>, <U_SHIFT_2BIT>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_swc1 (SD_, FT, U_SHIFT_2BIT, GPIDX, instruction_0);
+}
+
+101001,5.FT,5.RS,1.S1,1011000,8.S2:R6PLSGPCP1:32::SWC1S9
+"swc1 f<FT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_swc1 (SD_, FT, S_9_BIT, RS, instruction_0);
+}
+
+010001,5.FT,110,16.U,10:R6PLSGPCP1:32::LDC1GP
+"ldc1 f<FT>, <U_SHIFT_2BIT>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3(FGR[FT], U_SHIFT_2BIT, GP);
+  COP_LD (1, FT, do_load (SD_, AccessLength_DOUBLEWORD, GP, U_SHIFT_2BIT));
+  TRACE_ALU_RESULT(FGR[FT]);
+}
+
+100010,5.FT,00001,01,13.S2,1.S1:R6POOLPBR3A:32,f::BC1NEZC
+"bc1nezc f<FT>, <S_14_BIT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_fpu (SD_);
+  TRACE_ALU_INPUT2(NIA, S_14_BIT);
+  if ((FGR[FT] & 0x01) != 0)
+      NIA = NIA + (S_14_BIT << 1);
+  TRACE_ALU_RESULT(NIA);
+}
+
+100010,5.FT,00000,01,13.S2,1.S1:R6POOLPBR3A:32,f::BC1EQZC
+"bc1eqzc f<FT>, <S_14_BIT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_fpu (SD_);
+  TRACE_ALU_INPUT2(NIA, S_14_BIT);
+  if ((FGR[FT] & 0x01) == 0)
+      NIA = NIA + (S_14_BIT << 1);
+  TRACE_ALU_RESULT(NIA);
+}
+
+101000,5.RT,5.FS,2.X,100000,00,111,011:R6POOL32FXF0:32,f::MFC1
+"mfc1 r<RT>, f<FS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], FGR[FS]);
+  do_mfc1b (SD_, RT, FS);
+  TRACE_ALU_RESULT(GPR[RT]);
+}
+
+101000,5.RT,5.FS,2.X,110000,00,111,011:R6POOL32FXF0:32,f::MFHC1
+"mfhc1 r<RT>, f<FS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], FGR[FS]);
+  do_mfhc1 (SD_, RT, FS);
+  TRACE_ALU_RESULT(GPR[RT]);
+}
+
+101000,5.FT,5.FS,1.X,2.FMT_MICROMIPS_CVT_D!3,10011,01,111,011:R6CVTDFMT:32,f::CVT.D.fmt
+"cvt.d.%s<FMT_MICROMIPS_CVT_D> f<FT>, f<FS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_cvt_d_fmt (SD_, convert_fmt_micromips_cvt_d (SD_, FMT_MICROMIPS_CVT_D),
+    FT, FS, instruction_0);
+}
+
+:%s::::FMT_MICROMIPS_MUL:int fmt
+{
+  switch (fmt)
+    {
+    case 1: return "s";
+    case 3: return "d";
+    default: return "?";
+    }
+}
+
+101000,5.FT,5.FS,5.FD,1.X,0,2.FMT_MICROMIPS_MUL!2!0,0110,000:R6MULFMT1:32,f::MUL.fmt
+"mul.%s<FMT_MICROMIPS_MUL> f<FD>, f<FS>, f<FT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(FGR[FS], FGR[FT]);
+  do_mul_fmt (SD_, convert_fmt_micromips_mul (SD_, FMT_MICROMIPS_MUL), FD, FS, FT,
+        instruction_0);
+  TRACE_ALU_RESULT(FGR[FD]);
+}
+
+
+101000,5.FT,5.FS,5.FD,1.X,0,2.FMT_MICROMIPS_MUL!2!0,1110,000:R6DIVFMT1:32,f::DIV.fmt
+"div.%s<FMT_MICROMIPS_MUL> f<FD>, f<FS>, f<FT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(FGR[FS], FGR[FT]);
+  if (FMT_MICROMIPS_MUL == 1)
+    do_div_fmt (SD_, 0, FD, FS, FT, instruction_0);
+  else
+    do_div_fmt (SD_, 1, FD, FS, FT, instruction_0);
+  TRACE_ALU_RESULT(FGR[FD]);
+}
+
+101000,5.FT,5.FS,1.X,1.FMT_MICROMIPS,101011,00,111,011:R6POOL32FXF0:32,f::TRUNC.W.fmt
+"trunc.w.%s<FMT_MICROMIPS> f<FT>, f<FS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_trunc_fmt (SD_, fmt_word, FMT_MICROMIPS, FT, FS);
+}
+
+101000,5.FT,5.FS,1.X,2.FMT_MICROMIPS_CVT_S!3,11011,01,111,011:R6CVTSFMT:32,f::CVT.S.dsw
+"cvt.s.%s<FMT_MICROMIPS_CVT_S> f<FT>, f<FS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_cvt_s_fmt (SD_, convert_fmt_micromips_cvt_s (SD_, FMT_MICROMIPS_CVT_S),
+    FT, FS, instruction_0);
+}
+
+010001,5.FT,110,16.U,11:R6PLSU12:32::SDC1GP
+"sdc1 f<FT>, <U_SHIFT_2BIT>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3(FGR[FT], U_SHIFT_2BIT, GP);
+  do_store (SD_, AccessLength_DOUBLEWORD, GP, U_SHIFT_2BIT, COP_SD (1, FT));
+}
+
+101000,5.FT,5.FS,5.FD,1.X,0,1.FMT_MICROMIPS,01110,000:R6SUBFMT1:32,f::SUB.fmt
+"sub.%s<FMT_MICROMIPS> f<FD>, f<FS>, f<FT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(FGR[FS], FGR[FT]);
+  do_sub_fmt (SD_, convert_fmt_micromips (SD_, FMT_MICROMIPS), FD, FS, FT,
+        instruction_0);
+  TRACE_ALU_RESULT(FGR[FD]);
+}
+
+101000,5.FT,5.FS,1.X,2.FMT_MICROMIPS!3!2,00011,01,111,011:R6POOL32FXF1:32,f::::ABS.fmt
+"abs.%s<FMT_MICROMIPS> f<FT>, f<FS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_abs_fmt (SD_, convert_fmt_micromips (SD_, FMT_MICROMIPS), FT, FS,
+        instruction_0);
+}
+
+101000,5.FT,5.FS,5.FD,1.X,1.FMT_MICROMIPS,110111,000:R6POOL32F0:32,f::MADDF.fmt
+"maddf.%s<FMT_MICROMIPS> f<FD>, f<FS>, f<FT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(FGR[FS], FGR[FT]);
+  do_maddf (SD_, FD, FS, FT, convert_fmt_micromips (SD_, FMT_MICROMIPS), instruction_0);
+  TRACE_ALU_RESULT(FGR[FD]);
+}
+
+101000,5.FT,5.FS,1.X,2.FMT_MICROMIPS!3!2,01011,01,111,011:R6POOL32FXF1:32,f::NEG.fmt
+"neg.%s<FMT_MICROMIPS> f<FT>, f<FS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_neg_fmt (SD_, convert_fmt_micromips (SD_, FMT_MICROMIPS), FT, FS,
+        instruction_0);
+}
+
+101000,5.FT,5.FS,1.X,1.FMT_MICROMIPS,100011,00,111,011:R6POOL32FXF0:32,f::TRUNC.L.fmt
+"trunc.l.%s<FMT_MICROMIPS> f<FT>, f<FS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_trunc_fmt (SD_, fmt_long, FMT_MICROMIPS, FT, FS);
+}
+
+001000,5.RT,5.RS,5.FT,1011,1,000,111:R6POOLPPLSXS:32,f::SWC1XS
+"swc1xs f<FT>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_swc1xs(SD_, FT, RS, RT, instruction_0);
+}
+
+001000,5.RT,5.RS,5.FT,1111,0,000,111:R6POOLPPLSX:32,f::SDC1X
+"sdc1x f<FT>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_fpu (SD_);
+  TRACE_ALU_INPUT3(FGR[FT], GPR[RS], GPR[RT]);
+  do_store (SD_, AccessLength_DOUBLEWORD, GPR[RS], GPR[RT], COP_SD (1, FT));
+}
+
+001000,5.RT,5.RS,5.FT,1111,1,000,111:R6POOLPPLSXS:32,f::SDC1XS
+"sdc1xs f<FT>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_fpu (SD_);
+  TRACE_ALU_INPUT3(FGR[FT], GPR[RS], GPR[RT]);
+  do_store (SD_, AccessLength_DOUBLEWORD, GPR[RS] << 3, GPR[RT], COP_SD (1, FT));
+}
+
+001000,5.RT,5.RS,5.FT,1110,0,000,111:R6POOLPPLSXS:32::LDC1X
+"ldc1x f<FT>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3(FGR[FT], GPR[RS], GPR[RT]);
+  COP_LD (1, FT, do_load (SD_, AccessLength_DOUBLEWORD, GPR[RS], GPR[RT]));
+  TRACE_ALU_RESULT(FGR[FT]);
+}
+
+001000,5.RT,5.RS,5.FT,1110,1,000,111:R6POOLPPLSXS:32::LDC1XS
+"ldc1xs f<FT>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3(FGR[FT], GPR[RS], GPR[RT]);
+  COP_LD (1, FT, do_load (SD_, AccessLength_DOUBLEWORD, GPR[RS] << 3, GPR[RT]));
+  TRACE_ALU_RESULT(FGR[FT]);
+}
+
+001000,5.RT,5.RS,5.FT,1010,1,000,111:R6POOLPPLSXS:32::LWC1XS
+"lwc1xs f<FT>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3(FGR[FT], GPR[RS], GPR[RT]);
+  do_lwc1xs (SD_, FT, RS, RT);
+  TRACE_ALU_RESULT(FGR[FT]);
+}
+
+001000,5.RT,5.RS,5.FT,1010,0,000,111:R6PPLSX:32,f::LWC1X
+"lwc1x f<FT>, r<RT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3(FGR[FT], GPR[RS], GPR[RT]);
+  do_lwxc1 (SD_, FT, RT, RS, instruction_0);
+  TRACE_ALU_RESULT(FGR[FT]);
+}
+
+001000,5.RT,5.RS,5.FT,1011,0,000,111:R6PPLSX:32,f::SWC1X
+"swc1x f<FT>, r<RT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_swxc1 (SD_, FT, RT, RS, instruction_0);
+}
+
+101001,5.FT,5.RS,1.S1,1110,0,00,8.S2:R6PLSS0:32,f::LDC1S9
+"ldc1 r<FT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3(GPR[FT], S_9_BIT, GPR[RS]);
+  COP_LD (1, FT, do_load (SD_, AccessLength_DOUBLEWORD, GPR[RS], S_9_BIT));
+  TRACE_ALU_RESULT(GPR[FT]);
+}
+
+101001,5.FT,5.RS,1.S1,1111,0,00,8.S2:R6PLSS0:32,f::SDC1S9
+"sdc1 r<FT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3(GPR[FT], S_9_BIT, GPR[RS]);
+  do_store (SD_, AccessLength_DOUBLEWORD, GPR[RS], S_9_BIT, COP_SD (1, FT));
+}
+
+101001,5.FT,5.RS,1.S1,1010,0,00,8.S2:R6PLSS0:32::LWC1S9
+"lwc1 f<FT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3(GPR[FT], S_9_BIT, GPR[RS]);
+  do_lwc1 (SD_, FT, S_9_BIT, RS);
+  TRACE_ALU_RESULT(GPR[FT]);
+}
+
+101000,5.FT,5.FS,5.FD,2.FMT,000000011:R6POOL32F3:32,f::MIN.fmt
+"min.%s<FMT> f<FD>, f<FS>, f<FT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_min (SD_, FD, FS, FT, FMT, instruction_0);
+}
+
+101000,5.FT,5.FS,5.FD,2.FMT,000001,011:R6POOL32F3:32,f::MAX.fmt
+"max.%s<FMT> f<FD>, f<FS>, f<FT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_max (SD_, FD, FS, FT, FMT, instruction_0);
+}
+
+101000,5.FT,5.FS,5.FD,2.FMT,000100,011:R6POOL32F3:32,f::MINA.fmt
+"mina.%s<FMT> f<FD>, f<FS>, f<FT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_mina (SD_, FD, FS, FT, FMT, instruction_0);
+}
+
+101000,5.FT,5.FS,5.FD,2.FMT,000101,011:R6POOL32F3:32,f::MAXA.fmt
+"maxa.%s<FMT> f<FD>, f<FS>, f<FT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_maxa (SD_, FD, FS, FT, FMT, instruction_0);
+}
+
+101000,5.FT,5.FS,5.FD,2.FMT,111111,000:R6POOL32F0:32,f::MSUBF.fmt
+"msubf.%s<FMT> f<FD>, f<FS>, f<FT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_msubf (SD_, FD, FS, FT, FMT, instruction_0);
+}
+
+101000,5.FS,5.FD,00000,2.FMT,000100,000:R6POOL32F0:32,f::RINT.fmt
+"rint.%s<FMT> f<FD>, f<FS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_rint (SD_, FD, FS, FMT, instruction_0);
+}
+
+101000,5.FS,5.FD,00000,2.FMT,001100,000:R6POOL32F0:32,f::CLASS.fmt
+"class.%s<FMT> f<FD>, f<FS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_class (SD_, FD, FS, FMT, instruction_0);
+}
+
+101000,5.FT,5.FS,5.FD,2.FMT,010111,000:R6POOL32F0:32,f::SEL.fmt
+"sel.%s<FMT> f<FD>, f<FS>, f<FT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_self (SD_, FD, FS, FT, FMT, instruction_0);
+}
+
+101000,5.FT,5.FS,5.FD,2.FMT,000111,000:R6POOL32F0:32,f::SELEQZ.fmt
+"seleqz.%s<FMT> f<FD>, f<FS>, f<FT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_seleqzf (SD_, FD, FS, FT, FMT, instruction_0);
+}
+
+101000,5.FT,5.FS,5.FD,2.FMT,001111,000:R6POOL32F0:32,f::SELNEZ.fmt
+"selnez.%s<FMT> f<FD>, f<FS>, f<FT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_selnezf (SD_, FD, FS, FT, FMT, instruction_0);
+}
+
+:function:::void:do_lb:int rt, int offset, int base
+*nanomips32r6:
+*nanomips64r6:
+{
+  GPR[rt] = EXTEND8 (do_load (SD_, AccessLength_BYTE, GPR[base], offset));
+}
+
+:function:::void:do_lh:int rt, int offset, int base
+*nanomips32r6:
+*nanomips64r6:
+{
+  GPR[rt] = EXTEND16 (do_load (SD_, AccessLength_HALFWORD, GPR[base], offset));
+}
+
+:function:::void:do_lw:int rt, int offset, int base
+*nanomips32r6:
+*nanomips64r6:
+{
+  GPR[rt] = EXTEND32 (do_load (SD_, AccessLength_WORD, GPR[base], offset));
+}
+
+:function:::void:do_lhu:int rt, int offset, int base
+*nanomips32r6:
+*nanomips64r6:
+{
+  GPR[rt] = do_load (SD_, AccessLength_HALFWORD, GPR[base], offset);
+}
+
+:function:::void:do_addiu:int rs, int rt, int immediate
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (NotWordValue (GPR[rs]))
+    Unpredictable ();
+  TRACE_ALU_INPUT2 (GPR[rs], immediate);
+  GPR[rt] = EXTEND32 (GPR[rs] + immediate);
+  TRACE_ALU_RESULT (GPR[rt]);
+}
diff --git a/sim/mips/nanomipsrun.c b/sim/mips/nanomipsrun.c
new file mode 100644
index 00000000000..6321fd441ec
--- /dev/null
+++ b/sim/mips/nanomipsrun.c
@@ -0,0 +1,109 @@
+/*  Run function for the nanomips simulator
+
+    Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+    Written by Andrew Bennett <andrew.bennett@imgtec.com>.
+
+    This file is part of GDB, the GNU debugger.
+
+    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, see <http://www.gnu.org/licenses/>.  */
+
+#include "sim-main.h"
+#include "nanomips16_idecode.h"
+#include "nanomips32_idecode.h"
+#include "bfd.h"
+
+
+#define SD sd
+#define CPU cpu
+#define SIM_MONITOR_ADDRESS 0xBFC00000
+
+void
+sim_engine_run (SIM_DESC sd, int next_cpu_nr, int nr_cpus, int signal);
+
+address_word
+nanomips_instruction_decode (SIM_DESC sd, sim_cpu * cpu,
+            address_word cia,
+            int instruction_size);
+
+address_word
+nanomips_instruction_decode (SIM_DESC sd, sim_cpu * cpu,
+			      address_word cia,
+			      int instruction_size)
+{
+
+  nanomips16_instruction_word instruction_0 = IMEM16_NANOMIPS (cia);
+
+  if((cia & 0xFFF00000) == SIM_MONITOR_ADDRESS) {
+    nanomips32_instruction_word instruction_0 = IMEM32 (cia);
+    return nanomips32_idecode_issue (sd, instruction_0, cia);
+  } else if ((STATE_ARCHITECTURE (sd)->mach == bfd_mach_nanomipsisa32r6
+	  || STATE_ARCHITECTURE (sd)->mach == bfd_mach_nanomipsisa64r6)
+	     && (NANOMIPS_MAJOR_OPCODE_3_5 (instruction_0) & 0x4) == 4)
+	return nanomips16_idecode_issue (sd, instruction_0, cia);
+      else
+	{
+	  nanomips32_instruction_word instruction_0 = IMEM32_NANOMIPS (cia);
+	  return nanomips32_idecode_issue (sd, instruction_0, cia);
+	}
+}
+
+void
+sim_engine_run (SIM_DESC sd, int next_cpu_nr, int nr_cpus,
+		int signal)
+{
+  nanomips32_instruction_word instruction_0;
+  sim_cpu *cpu = STATE_CPU (sd, next_cpu_nr);
+  nanomips32_instruction_address cia = CIA_GET (cpu);
+  unsigned long bfdmach;
+  is_nanomips = 1;
+
+  bfdmach = STATE_ARCHITECTURE(SD)->mach;
+
+  if (is_nms_flag_set == 0 && (bfdmach == bfd_mach_nanomipsisa64r6
+      || bfdmach == bfd_mach_nanomipsisa32r6))
+    set_nms_flag (sd);
+
+  while (1)
+    {
+      nanomips32_instruction_address nia;
+
+	    cia = cia & ~0x1;
+
+#if defined (ENGINE_ISSUE_PREFIX_HOOK)
+      ENGINE_ISSUE_PREFIX_HOOK ();
+#endif
+
+    nia =
+      nanomips_instruction_decode (sd, cpu, cia,
+            MICROMIPS_DELAYSLOT_SIZE_ANY);
+
+#if defined (ENGINE_ISSUE_POSTFIX_HOOK)
+      ENGINE_ISSUE_POSTFIX_HOOK ();
+#endif
+      // Cycle counting
+      COP0_COUNT++;
+
+      /* Update the instruction address */
+      cia = nia;
+
+      /* process any events */
+      if (sim_events_tick (sd))
+	{
+	  CIA_SET (CPU, cia);
+	  sim_events_process (sd);
+	  cia = CIA_GET (CPU);
+	}
+    }
+}
diff --git a/sim/mips/nms.c b/sim/mips/nms.c
new file mode 100644
index 00000000000..fd957d69e8b
--- /dev/null
+++ b/sim/mips/nms.c
@@ -0,0 +1,44 @@
+/*  Run function for the nanomips simulator
+
+    Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+    Written by Andrew Bennett <andrew.bennett@imgtec.com>.
+
+    This file is part of GDB, the GNU debugger.
+
+    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, see <http://www.gnu.org/licenses/>.  */
+
+#include "sim-main.h"
+#include "elf/mips-common.h"
+#include "elf/nanomips.h"
+
+/* NMS Flag */
+int nms_flag = -1;
+
+int is_nms_flag_set = 0;
+
+void
+set_nms_flag (SIM_DESC sd)
+{
+  Elf_Internal_ABIFlags_v0 *abiflags;
+  abiflags = bfd_nanomips_elf_get_abiflags (STATE_PROG_BFD(sd));
+
+  nms_flag = 0;
+
+  if (abiflags != NULL
+      && ((abiflags->ases & NANOMIPS_ASE_xNMS) != 0))
+    nms_flag = 1;
+
+  is_nms_flag_set = 1;
+}
diff --git a/sim/mips/sim-main.c b/sim/mips/sim-main.c
index 250310eceb3..183082ab7c7 100644
--- a/sim/mips/sim-main.c
+++ b/sim/mips/sim-main.c
@@ -32,6 +32,81 @@
 /*---------------------------------------------------------------------------*/
 
 
+/* Description from page A-22 of the "MIPS IV Instruction Set" manual
+   (revision 3.1) */
+/* Translate a virtual address to a physical address and cache
+   coherence algorithm describing the mechanism used to resolve the
+   memory reference. Given the virtual address vAddr, and whether the
+   reference is to Instructions ot Data (IorD), find the corresponding
+   physical address (pAddr) and the cache coherence algorithm (CCA)
+   used to resolve the reference. If the virtual address is in one of
+   the unmapped address spaces the physical address and the CCA are
+   determined directly by the virtual address. If the virtual address
+   is in one of the mapped address spaces then the TLB is used to
+   determine the physical address and access type; if the required
+   translation is not present in the TLB or the desired access is not
+   permitted the function fails and an exception is taken.
+
+   NOTE: Normally (RAW == 0), when address translation fails, this
+   function raises an exception and does not return. */
+
+INLINE_SIM_MAIN
+(int)
+address_translation (SIM_DESC sd,
+		     sim_cpu * cpu,
+		     address_word cia,
+		     address_word vAddr,
+		     int IorD,
+		     int LorS,
+		     address_word * pAddr,
+		     int *CCA,
+		     int raw)
+{
+  int res = -1;			/* TRUE : Assume good return */
+
+#ifdef DEBUG
+  sim_io_printf (sd, "AddressTranslation(0x%s,%s,%s,...);\n", pr_addr (vAddr), (IorD ? "isDATA" : "isINSTRUCTION"), (LorS ? "iSTORE" : "isLOAD"));
+#endif
+
+  /* Check that the address is valid for this memory model */
+
+  /* For a simple (flat) memory model, we simply pass virtual
+     addressess through (mostly) unchanged. */
+  vAddr &= 0xFFFFFFFF;
+
+  *pAddr = vAddr;		/* default for isTARGET */
+  *CCA = Uncached;		/* not used for isHOST */
+
+  return (res);
+}
+
+
+
+/* Description from page A-23 of the "MIPS IV Instruction Set" manual
+   (revision 3.1) */
+/* Prefetch data from memory. Prefetch is an advisory instruction for
+   which an implementation specific action is taken. The action taken
+   may increase performance, but must not change the meaning of the
+   program, or alter architecturally-visible state. */
+
+INLINE_SIM_MAIN (void)
+prefetch (SIM_DESC sd,
+	  sim_cpu *cpu,
+	  address_word cia,
+	  int CCA,
+	  address_word pAddr,
+	  address_word vAddr,
+	  int DATA,
+	  int hint)
+{
+#ifdef DEBUG
+  sim_io_printf(sd,"Prefetch(%d,0x%s,0x%s,%d,%d);\n",CCA,pr_addr(pAddr),pr_addr(vAddr),DATA,hint);
+#endif /* DEBUG */
+
+  /* For our simple memory model we do nothing */
+  return;
+}
+
 /* Description from page A-22 of the "MIPS IV Instruction Set" manual
    (revision 3.1) */
 /* Load a value from memory. Use the cache and main memory as
@@ -266,13 +341,15 @@ ifetch32 (SIM_DESC SD,
   address_word reverseendian = (ReverseEndian ? (mask ^ access) : 0);
   address_word bigendiancpu = (BigEndianCPU ? (mask ^ access) : 0);
   unsigned int byte;
-  address_word paddr = vaddr;
+  address_word paddr;
+  int uncached;
   uint64_t memval;
 
   if ((vaddr & access) != 0)
     SignalExceptionInstructionFetch ();
+  AddressTranslation (vaddr, isINSTRUCTION, isLOAD, &paddr, &uncached, isTARGET, isREAL);
   paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
-  LoadMemory (&memval, NULL, access, paddr, vaddr, isINSTRUCTION, isREAL);
+  LoadMemory (&memval, NULL, uncached, access, paddr, vaddr, isINSTRUCTION, isREAL);
   byte = ((vaddr & mask) ^ bigendiancpu);
   return (memval >> (8 * byte));
 }
@@ -290,13 +367,15 @@ ifetch16 (SIM_DESC SD,
   address_word reverseendian = (ReverseEndian ? (mask ^ access) : 0);
   address_word bigendiancpu = (BigEndianCPU ? (mask ^ access) : 0);
   unsigned int byte;
-  address_word paddr = vaddr;
+  address_word paddr;
+  int uncached;
   uint64_t memval;
 
   if ((vaddr & access) != 0)
     SignalExceptionInstructionFetch ();
+  AddressTranslation (vaddr, isINSTRUCTION, isLOAD, &paddr, &uncached, isTARGET, isREAL);
   paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
-  LoadMemory (&memval, NULL, access, paddr, vaddr, isINSTRUCTION, isREAL);
+  LoadMemory (&memval, NULL, uncached, access, paddr, vaddr, isINSTRUCTION, isREAL);
   byte = ((vaddr & mask) ^ bigendiancpu);
   return (memval >> (8 * byte));
 }
diff --git a/sim/mips/sim-main.h b/sim/mips/sim-main.h
index 418c6599118..1397202c787 100644
--- a/sim/mips/sim-main.h
+++ b/sim/mips/sim-main.h
@@ -262,6 +262,8 @@ struct _sim_cpu {
 
 
   /* The following are internal simulator state variables: */
+#define CIA_GET(CPU) ((CPU)->registers[PCIDX] + 0)
+#define CIA_SET(CPU,CIA) ((CPU)->registers[PCIDX] = (CIA))
   address_word dspc;  /* delay-slot PC */
 #define DSPC ((CPU)->dspc)
 
@@ -318,9 +320,9 @@ struct _sim_cpu {
 #define LAST_EMBED_REGNUM (96)
 #define NUM_REGS (LAST_EMBED_REGNUM + 1)
 
-#define FP0_REGNUM 38           /* Floating point register 0 (single float) */
-#define FCRCS_REGNUM 70         /* FP control/status */
-#define FCRIR_REGNUM 71         /* FP implementation/revision */
+#define FP0_REGNUM 36           /* Floating point register 0 (single float) */
+#define FCRCS_REGNUM 68         /* FP control/status */
+#define FCRIR_REGNUM 69         /* FP implementation/revision */
 #endif
 
 
@@ -336,16 +338,16 @@ struct _sim_cpu {
 #define GPR     (&REGISTERS[0])
 #define GPR_SET(N,VAL) (REGISTERS[(N)] = (VAL))
 
-#define LO      (REGISTERS[33])
-#define HI      (REGISTERS[34])
-#define PCIDX	37
+#define HI      (REGISTERS[70])
+#define LO      (REGISTERS[71])
+#define PCIDX	(is_nanomips?32:35)
 #define PC      (REGISTERS[PCIDX])
-#define CAUSE   (REGISTERS[36])
+#define CAUSE   (REGISTERS[34])
 #define SRIDX   (32)
 #define SR      (REGISTERS[SRIDX])      /* CPU status register */
-#define FCR0IDX  (71)
+#define FCR0IDX  (69)
 #define FCR0    (REGISTERS[FCR0IDX])    /* really a 32bit register */
-#define FCR31IDX (70)
+#define FCR31IDX (68)
 #define FCR31   (REGISTERS[FCR31IDX])   /* really a 32bit register */
 #define FCSR    (FCR31)
 #define Debug	(REGISTERS[86])
@@ -353,19 +355,19 @@ struct _sim_cpu {
 #define EPC	(REGISTERS[88])
 #define ACX	(REGISTERS[89])
 
-#define AC0LOIDX	(33)	/* Must be the same register as LO */
-#define AC0HIIDX	(34)	/* Must be the same register as HI */
-#define AC1LOIDX	(90)
-#define AC1HIIDX	(91)
-#define AC2LOIDX	(92)
-#define AC2HIIDX	(93)
-#define AC3LOIDX	(94)
-#define AC3HIIDX	(95)
+#define AC0HIIDX	(70)	/* Must be the same register as HI */
+#define AC0LOIDX	(71)	/* Must be the same register as LO */
+#define AC1HIIDX	(72)
+#define AC1LOIDX	(73)
+#define AC2HIIDX	(74)
+#define AC2LOIDX	(75)
+#define AC3HIIDX	(76)
+#define AC3LOIDX	(77)
 
 #define DSPLO(N)	(REGISTERS[DSPLO_REGNUM[N]])
 #define DSPHI(N)	(REGISTERS[DSPHI_REGNUM[N]])
 
-#define DSPCRIDX	(96)	/* DSP control register */
+#define DSPCRIDX	(79)	/* DSP control register */
 #define DSPCR		(REGISTERS[DSPCRIDX])
 
 #define DSPCR_POS_SHIFT		(0)
@@ -420,6 +422,8 @@ struct _sim_cpu {
 #define A3      (REGISTERS[7])
 #define T8IDX   24
 #define T8	(REGISTERS[T8IDX])
+#define GPIDX   28
+#define GP      (REGISTERS[GPIDX])
 #define SPIDX   29
 #define SP      (REGISTERS[SPIDX])
 #define RAIDX   31
@@ -433,6 +437,7 @@ struct _sim_cpu {
   unsigned_word cop0_gpr[NR_COP0_GPR];
 #define COP0_GPR	((CPU)->cop0_gpr)
 #define COP0_BADVADDR	(COP0_GPR[8])
+#define COP0_COUNT (COP0_GPR[9])
 
   /* While space is allocated for the floating point registers in the
      main registers array, they are stored separatly.  This is because
@@ -476,6 +481,17 @@ struct _sim_cpu {
   sim_cpu_base base;
 };
 
+extern int is_nanomips;
+
+#define SET_RV0(VAL)             \
+  do {                 \
+    if (is_nanomips)             \
+      A0 = VAL;                \
+    else               \
+      V0 = VAL;                \
+  } while (0)
+
+
 extern void mips_sim_close (SIM_DESC sd, int quitting);
 #define SIM_CLOSE_HOOK(...) mips_sim_close (__VA_ARGS__)
 
@@ -643,13 +659,16 @@ enum ExceptionCause {
    is used by gdb for break-points.  NOTE: Care must be taken, since
    this value may be used in later revisions of the MIPS ISA. */
 #define HALT_INSTRUCTION_MASK   (0x03FFFFC0)
+#define HALT_INSTRUCTION_MASK_NANOMIPS (0x0007FFFF)
 
 #define HALT_INSTRUCTION        (0x03ff000d)
 #define HALT_INSTRUCTION2       (0x0000ffcd)
+#define HALT_INSTRUCTION_NANOMIPS      (0x001003FF)
 
 
 #define BREAKPOINT_INSTRUCTION  (0x0005000d)
 #define BREAKPOINT_INSTRUCTION2 (0x0000014d)
+#define BREAKPOINT_INSTRUCTION_NANOMIPS  (0x00101400)
 
 
 
@@ -728,6 +747,44 @@ void store_fcr (SIM_STATE, int fcr, unsigned_word value);
 void test_fcsr (SIM_STATE);
 #define TestFCSR() test_fcsr (SIM_ARGS)
 
+/* FPU operations.  */
+/* Non-signalling */
+#define FP_R6CMP_AF  0x0
+#define FP_R6CMP_EQ  0x2
+#define FP_R6CMP_LE  0x6
+#define FP_R6CMP_LT  0x4
+#define FP_R6CMP_NE  0x13
+#define FP_R6CMP_OR  0x11
+#define FP_R6CMP_UEQ 0x3
+#define FP_R6CMP_ULE 0x7
+#define FP_R6CMP_ULT 0x5
+#define FP_R6CMP_UN  0x1
+#define FP_R6CMP_UNE 0x12
+
+/* Signalling */
+#define FP_R6CMP_SAF  0x8
+#define FP_R6CMP_SEQ  0xa
+#define FP_R6CMP_SLE  0xe
+#define FP_R6CMP_SLT  0xc
+#define FP_R6CMP_SNE  0x1b
+#define FP_R6CMP_SOR  0x19
+#define FP_R6CMP_SUEQ 0xb
+#define FP_R6CMP_SULE 0xf
+#define FP_R6CMP_SULT 0xd
+#define FP_R6CMP_SUN  0x9
+#define FP_R6CMP_SUNE 0x1a
+
+/* FPU Class */
+#define FP_R6CLASS_SNAN    (1<<0)
+#define FP_R6CLASS_QNAN    (1<<1)
+#define FP_R6CLASS_NEGINF  (1<<2)
+#define FP_R6CLASS_NEGNORM (1<<3)
+#define FP_R6CLASS_NEGSUB  (1<<4)
+#define FP_R6CLASS_NEGZERO (1<<5)
+#define FP_R6CLASS_POSINF  (1<<6)
+#define FP_R6CLASS_POSNORM (1<<7)
+#define FP_R6CLASS_POSSUB  (1<<8)
+#define FP_R6CLASS_POSZERO (1<<9)
 
 /* FPU operations.  */
 /* Non-signalling */
@@ -812,21 +869,21 @@ uint64_t fp_fmadd (SIM_STATE, uint64_t op1, uint64_t op2,
 		     uint64_t op3, FP_formats fmt);
 #define FusedMultiplySub(op1,op2,op3,fmt) fp_fmsub(SIM_ARGS, op1, op2, op3, fmt)
 uint64_t fp_fmsub (SIM_STATE, uint64_t op1, uint64_t op2,
-		     uint64_t op3, FP_formats fmt);
+         uint64_t op3, FP_formats fmt);
 #define MultiplyAdd(op1,op2,op3,fmt) fp_madd(SIM_ARGS, op1, op2, op3, fmt)
 uint64_t fp_msub (SIM_STATE, uint64_t op1, uint64_t op2,
-		    uint64_t op3, FP_formats fmt);
+         uint64_t op3, FP_formats fmt);
 #define MultiplySub(op1,op2,op3,fmt) fp_msub(SIM_ARGS, op1, op2, op3, fmt)
 uint64_t fp_nmadd (SIM_STATE, uint64_t op1, uint64_t op2,
-		     uint64_t op3, FP_formats fmt);
+         uint64_t op3, FP_formats fmt);
 #define NegMultiplyAdd(op1,op2,op3,fmt) fp_nmadd(SIM_ARGS, op1, op2, op3, fmt)
 uint64_t fp_nmsub (SIM_STATE, uint64_t op1, uint64_t op2,
-		     uint64_t op3, FP_formats fmt);
+         uint64_t op3, FP_formats fmt);
 #define NegMultiplySub(op1,op2,op3,fmt) fp_nmsub(SIM_ARGS, op1, op2, op3, fmt)
 uint64_t convert (SIM_STATE, int rm, uint64_t op, FP_formats from, FP_formats to);
 #define Convert(rm,op,from,to) convert (SIM_ARGS, rm, op, from, to)
 uint64_t convert_ps (SIM_STATE, int rm, uint64_t op, FP_formats from,
-		       FP_formats to);
+           FP_formats to);
 #define ConvertPS(rm,op,from,to) convert_ps (SIM_ARGS, rm, op, from, to)
 
 
@@ -959,6 +1016,12 @@ uint64_t mdmx_shuffle (SIM_STATE, int, uint64_t, uint64_t);
 /* The following are generic to all versions of the MIPS architecture
    to date: */
 
+/* Memory Access Types (for CCA): */
+#define Uncached                (0)
+#define CachedNoncoherent       (1)
+#define CachedCoherent          (2)
+#define Cached                  (3)
+
 #define isINSTRUCTION   (1 == 0) /* FALSE */
 #define isDATA          (1 == 1) /* TRUE */
 #define isLOAD          (1 == 0) /* FALSE */
@@ -985,13 +1048,17 @@ uint64_t mdmx_shuffle (SIM_STATE, int, uint64_t, uint64_t);
 		    ? AccessLength_DOUBLEWORD /*7*/ \
 		    : AccessLength_WORD /*3*/)
 
+INLINE_SIM_MAIN (int) address_translation (SIM_DESC sd, sim_cpu *, address_word cia, address_word vAddr, int IorD, int LorS, address_word *pAddr, int *CCA, int raw);
+#define AddressTranslation(vAddr,IorD,LorS,pAddr,CCA,host,raw) \
+address_translation (SD, CPU, cia, vAddr, IorD, LorS, pAddr, CCA, raw)
+
 INLINE_SIM_MAIN (void) load_memory (SIM_DESC sd, sim_cpu *cpu, address_word cia, uword64* memvalp, uword64* memval1p, int CCA, unsigned int AccessLength, address_word pAddr, address_word vAddr, int IorD);
-#define LoadMemory(memvalp,memval1p,AccessLength,pAddr,vAddr,IorD,raw) \
-load_memory (SD, CPU, cia, memvalp, memval1p, 0, AccessLength, pAddr, vAddr, IorD)
+#define LoadMemory(memvalp,memval1p,CCA,AccessLength,pAddr,vAddr,IorD,raw) \
+load_memory (SD, CPU, cia, memvalp, memval1p, CCA, AccessLength, pAddr, vAddr, IorD)
 
 INLINE_SIM_MAIN (void) store_memory (SIM_DESC sd, sim_cpu *cpu, address_word cia, int CCA, unsigned int AccessLength, uword64 MemElem, uword64 MemElem1, address_word pAddr, address_word vAddr);
-#define StoreMemory(AccessLength,MemElem,MemElem1,pAddr,vAddr,raw) \
-store_memory (SD, CPU, cia, 0, AccessLength, MemElem, MemElem1, pAddr, vAddr)
+#define StoreMemory(CCA,AccessLength,MemElem,MemElem1,pAddr,vAddr,raw) \
+store_memory (SD, CPU, cia, CCA, AccessLength, MemElem, MemElem1, pAddr, vAddr)
 
 INLINE_SIM_MAIN (void) cache_op (SIM_DESC sd, sim_cpu *cpu, address_word cia, int op, address_word pAddr, address_word vAddr, unsigned int instruction);
 #define CacheOp(op,pAddr,vAddr,instruction) \
@@ -1001,6 +1068,10 @@ INLINE_SIM_MAIN (void) sync_operation (SIM_DESC sd, sim_cpu *cpu, address_word c
 #define SyncOperation(stype) \
 sync_operation (SD, CPU, cia, (stype))
 
+INLINE_SIM_MAIN (void) prefetch (SIM_DESC sd, sim_cpu *cpu, address_word cia, int CCA, address_word pAddr, address_word vAddr, int DATA, int hint);
+#define Prefetch(CCA,pAddr,vAddr,DATA,hint) \
+prefetch (SD, CPU, cia, CCA, pAddr, vAddr, DATA, hint)
+
 void unpredictable_action (sim_cpu *cpu, address_word cia);
 #define NotWordValue(val)	not_word_value (SD_, (val))
 #define Unpredictable()		unpredictable (SD_)
@@ -1022,6 +1093,16 @@ INLINE_SIM_MAIN (uint16_t) ifetch16 (SIM_DESC sd, sim_cpu *cpu, address_word cia
 #define MICROMIPS_DELAYSLOT_SIZE_16 2
 #define MICROMIPS_DELAYSLOT_SIZE_32 4
 
+#define IMEM32_NANOMIPS(CIA) \
+  (ifetch16 (SD, CPU, (CIA), (CIA)) << 16 | ifetch16 (SD, CPU, (CIA + 2), \
+                  (CIA + 2)))
+#define IMEM16_NANOMIPS(CIA) ifetch16 (SD, CPU, (CIA), ((CIA)))
+
+
+#define NANOMIPS_MAJOR_OPCODE_3_5(INSN) ((INSN & 0x1c00) >> 10)
+
+#define NANOMIPS_DELAYSLOT_SIZE_ANY 0
+
 extern int isa_mode;
 
 #define ISA_MODE_MIPS32 0
@@ -1041,6 +1122,13 @@ extern FILE *tracefh;
 extern int DSPLO_REGNUM[4];
 extern int DSPHI_REGNUM[4];
 
+/* NMS Flag */
+extern int nms_flag;
+extern int is_nms_flag_set;
+
+void
+set_nms_flag (SIM_DESC sd);
+
 INLINE_SIM_MAIN (void) pending_tick (SIM_DESC sd, sim_cpu *cpu, address_word cia);
 extern SIM_CORE_SIGNAL_FN mips_core_signal;
 
@@ -1055,10 +1143,16 @@ void mips_cpu_exception_suspend(SIM_DESC sd, sim_cpu* cpu, int exception);
 void mips_cpu_exception_resume(SIM_DESC sd, sim_cpu* cpu, int exception);
 
 #ifdef MIPS_MACH_MULTI
-extern int mips_mach_multi(SIM_DESC sd);
-#define MIPS_MACH(SD)	mips_mach_multi(SD)
+extern address_word micromips_instruction_decode_multi(SIM_DESC sd,
+                   sim_cpu* cpu,
+                   address_word cia,
+                   int instruction_size);
+#define MICROMIPS_INSTRUCTION_DECODE(SD, cpu, cia, size) \
+  micromips_instruction_decode_multi (SD, cpu, cia, size);
 #else
-#define	MIPS_MACH(SD)	MIPS_MACH_DEFAULT
+#define MIPS_MACH(SD) MIPS_MACH_DEFAULT
+#define MICROMIPS_INSTRUCTION_DECODE(SD, cpu, cia, size) \
+  micromips_instruction_decode (SD, cpu, cia, size);
 #endif
 
 /* Macros for determining whether a MIPS IV or MIPS V part is subject
-- 
2.25.1


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

* [PATCH 3/3] gdb: Add nanoMIPS port
       [not found] <20220429155813.388328-1-aleksandar.rikalo@syrmia.com>
  2022-04-29 15:58 ` [PATCH 1/3] bfd: Add support for nanoMIPS architecture Aleksandar Rikalo
  2022-04-29 15:58 ` [PATCH 2/3] sim: Add nanoMIPS port Aleksandar Rikalo
@ 2022-04-29 15:58 ` Aleksandar Rikalo
  2022-04-29 16:15   ` Eli Zaretskii
  2 siblings, 1 reply; 13+ messages in thread
From: Aleksandar Rikalo @ 2022-04-29 15:58 UTC (permalink / raw)
  To: gdb-patches

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>
---
 config.sub                                    |    1 +
 configure                                     |    3 +
 configure.ac                                  |    3 +
 gdb/Makefile.in                               |    2 +
 gdb/NEWS                                      |    1 +
 gdb/configure.host                            |    1 +
 gdb/configure.tgt                             |   11 +
 gdb/features/Makefile                         |    4 +
 gdb/features/nanomips-cp0.xml                 |   13 +
 gdb/features/nanomips-cpu.xml                 |   44 +
 gdb/features/nanomips-dsp.xml                 |   20 +
 gdb/features/nanomips-fpu.xml                 |   45 +
 gdb/features/nanomips.c                       |   54 +
 gdb/features/nanomips.xml                     |   12 +
 gdb/features/nanomips64-cp0.xml               |   13 +
 gdb/features/nanomips64-cpu.xml               |   44 +
 gdb/features/nanomips64-dsp.xml               |   20 +
 gdb/nanomips-tdep.c                           | 3421 +++++++++++++++++
 gdb/nanomips-tdep.h                           |  144 +
 gdb/testsuite/gdb.asm/asm-source.exp          |    9 +-
 gdb/testsuite/gdb.asm/nanomips.inc            |   49 +
 .../gdb.base/catch-gdb-caused-signals.c       |    3 +
 gdb/testsuite/gdb.base/float.exp              |    2 +-
 gdb/testsuite/gdb.trace/trace-common.h        |    2 +-
 gdb/testsuite/lib/gdb.exp                     |    1 +
 25 files changed, 3919 insertions(+), 3 deletions(-)
 create mode 100644 gdb/features/nanomips-cp0.xml
 create mode 100644 gdb/features/nanomips-cpu.xml
 create mode 100644 gdb/features/nanomips-dsp.xml
 create mode 100644 gdb/features/nanomips-fpu.xml
 create mode 100644 gdb/features/nanomips.c
 create mode 100644 gdb/features/nanomips.xml
 create mode 100644 gdb/features/nanomips64-cp0.xml
 create mode 100644 gdb/features/nanomips64-cpu.xml
 create mode 100644 gdb/features/nanomips64-dsp.xml
 create mode 100644 gdb/nanomips-tdep.c
 create mode 100644 gdb/nanomips-tdep.h
 create mode 100644 gdb/testsuite/gdb.asm/nanomips.inc

diff --git a/config.sub b/config.sub
index dba16e84c77..b562e37aa09 100755
--- a/config.sub
+++ b/config.sub
@@ -1243,6 +1243,7 @@ case $cpu-$vendor in
 			| moxie \
 			| mt \
 			| msp430 \
+			| nanomips | nanomipseb \
 			| nds32 | nds32le | nds32be \
 			| nfp \
 			| nios | nios2 | nios2eb | nios2el \
diff --git a/configure b/configure
index 1badcb314f8..c297043dcab 100755
--- a/configure
+++ b/configure
@@ -3908,6 +3908,9 @@ case "${target}" in
   mips*-*-*)
     noconfigdirs="$noconfigdirs gprof"
     ;;
+  nanomips*-*-elf*)
+    noconfigdirs="$noconfigdirs gas binutils ld gprof"
+    ;;
   nvptx*-*-*)
     noconfigdirs="$noconfigdirs target-libssp target-libstdc++-v3 target-libobjc"
     ;;
diff --git a/configure.ac b/configure.ac
index 5b6e2048514..f02e0357b4b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1186,6 +1186,9 @@ case "${target}" in
   mips*-*-*)
     noconfigdirs="$noconfigdirs gprof"
     ;;
+  nanomips*-*-elf*)
+    noconfigdirs="$noconfigdirs gas binutils ld gprof"
+    ;;
   nvptx*-*-*)
     noconfigdirs="$noconfigdirs target-libssp target-libstdc++-v3 target-libobjc"
     ;;
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ec0e55dd803..53f443df295 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -814,6 +814,7 @@ ALL_TARGET_OBS = \
 	mn10300-tdep.o \
 	moxie-tdep.o \
 	msp430-tdep.o \
+	nanomips-tdep.o \
 	netbsd-tdep.o \
 	nds32-tdep.o \
 	nios2-linux-tdep.o \
@@ -1384,6 +1385,7 @@ HFILES_NO_SRCDIR = \
 	mips-tdep.h \
 	mn10300-tdep.h \
 	moxie-tdep.h \
+	nanomips-tdep.h \
 	netbsd-nat.h \
 	netbsd-tdep.h \
 	nds32-tdep.h \
diff --git a/gdb/NEWS b/gdb/NEWS
index 982f4a1a18c..5ad2d316849 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -236,6 +236,7 @@ winheight
 
 * New targets
 
+GNU/ELF/nanoMIPS      nanomips*-*-*
 GNU/Linux/LoongArch		loongarch*-*-linux*
 
 * Removed targets
diff --git a/gdb/configure.host b/gdb/configure.host
index da71675b201..3a9799ee56e 100644
--- a/gdb/configure.host
+++ b/gdb/configure.host
@@ -61,6 +61,7 @@ i[34567]86*)		gdb_host_cpu=i386 ;;
 loongarch*)		gdb_host_cpu=loongarch ;;
 m68*)			gdb_host_cpu=m68k ;;
 mips*)			gdb_host_cpu=mips ;;
+nanomips*)		gdb_host_cpu=nanomips ;;
 powerpc* | rs6000)	gdb_host_cpu=powerpc ;;
 sparcv9 | sparc64)	gdb_host_cpu=sparc ;;
 s390*)			gdb_host_cpu=s390 ;;
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 0705ccf32b8..e0ff7ec7cca 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -447,6 +447,16 @@ msp430-*-elf*)
 	gdb_target_obs="msp430-tdep.o"
 	;;
 
+mt-*-*)
+	# Target: Morpho Technologies ms1 processor
+	gdb_target_obs="mt-tdep.o"
+	;;
+
+nanomips*-*-*)
+	# Target: nanomips ELF
+	gdb_target_obs="nanomips-tdep.o"
+	;;
+
 nds32*-*-elf)
 	# Target: AndesTech NDS32 core
 	gdb_target_obs="nds32-tdep.o"
@@ -765,6 +775,7 @@ m32r-*-*)		gdb_sim=m32r ;;
 m68hc11-*-*|m6811-*-*)	gdb_sim=m68hc11 ;;
 microblaze*-*-*)	gdb_sim=microblaze ;;
 mips*-*-*)		gdb_sim=mips ;;
+nanomips*-*-*)	gdb_sim=mips ;;
 mn10300*-*-*)		gdb_sim=mn10300 ;;
 moxie-*-*)		gdb_sim=moxie ;;
 msp430*-*-*)		gdb_sim=msp430 ;;
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 737d9cbd3db..023f0f8bd0a 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -46,6 +46,7 @@
 # List of .dat files to create in ../regformats/
 WHICH = mips-linux mips-dsp-linux \
 	mips64-linux mips64-dsp-linux \
+	nanomips \
 	nios2-linux \
 	or1k-linux \
 	rs6000/powerpc-32 \
@@ -73,6 +74,8 @@ mips-expedite = r29,pc
 mips-dsp-expedite = r29,pc
 mips64-expedite = r29,pc
 mips64-dsp-expedite = r29,pc
+microblaze-expedite = r1,rpc
+nanomips-expedite = r29,pc
 nios2-linux-expedite = sp,pc
 powerpc-expedite = r1,pc
 s390-linux32-expedite = r14,r15,pswa
@@ -105,6 +108,7 @@ XMLTOC = \
 	mips-linux.xml \
 	mips64-dsp-linux.xml \
 	mips64-linux.xml \
+	nanomips.xml \
 	nds32.xml \
 	nios2.xml \
 	or1k.xml \
diff --git a/gdb/features/nanomips-cp0.xml b/gdb/features/nanomips-cp0.xml
new file mode 100644
index 00000000000..7a3995f0fd7
--- /dev/null
+++ b/gdb/features/nanomips-cp0.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.nanomips.cp0">
+  <reg name="status" bitsize="32"/>
+  <reg name="badvaddr" bitsize="32"/>
+  <reg name="cause" bitsize="32"/>
+</feature>
diff --git a/gdb/features/nanomips-cpu.xml b/gdb/features/nanomips-cpu.xml
new file mode 100644
index 00000000000..bb04a24d6f6
--- /dev/null
+++ b/gdb/features/nanomips-cpu.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.nanomips.cpu">
+  <reg name="r0" bitsize="32"/>
+  <reg name="r1" bitsize="32"/>
+  <reg name="r2" bitsize="32"/>
+  <reg name="r3" bitsize="32"/>
+  <reg name="r4" bitsize="32"/>
+  <reg name="r5" bitsize="32"/>
+  <reg name="r6" bitsize="32"/>
+  <reg name="r7" bitsize="32"/>
+  <reg name="r8" bitsize="32"/>
+  <reg name="r9" bitsize="32"/>
+  <reg name="r10" bitsize="32"/>
+  <reg name="r11" bitsize="32"/>
+  <reg name="r12" bitsize="32"/>
+  <reg name="r13" bitsize="32"/>
+  <reg name="r14" bitsize="32"/>
+  <reg name="r15" bitsize="32"/>
+  <reg name="r16" bitsize="32"/>
+  <reg name="r17" bitsize="32"/>
+  <reg name="r18" bitsize="32"/>
+  <reg name="r19" bitsize="32"/>
+  <reg name="r20" bitsize="32"/>
+  <reg name="r21" bitsize="32"/>
+  <reg name="r22" bitsize="32"/>
+  <reg name="r23" bitsize="32"/>
+  <reg name="r24" bitsize="32"/>
+  <reg name="r25" bitsize="32"/>
+  <reg name="r26" bitsize="32"/>
+  <reg name="r27" bitsize="32"/>
+  <reg name="r28" bitsize="32"/>
+  <reg name="r29" bitsize="32"/>
+  <reg name="r30" bitsize="32"/>
+  <reg name="r31" bitsize="32"/>
+
+  <reg name="pc" bitsize="32"/>
+</feature>
diff --git a/gdb/features/nanomips-dsp.xml b/gdb/features/nanomips-dsp.xml
new file mode 100644
index 00000000000..659fc3850c2
--- /dev/null
+++ b/gdb/features/nanomips-dsp.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.nanomips.dsp">
+  <reg name="hi0" bitsize="32"/>
+  <reg name="lo0" bitsize="32"/>
+  <reg name="hi1" bitsize="32"/>
+  <reg name="lo1" bitsize="32"/>
+  <reg name="hi2" bitsize="32"/>
+  <reg name="lo2" bitsize="32"/>
+  <reg name="hi3" bitsize="32"/>
+  <reg name="lo3" bitsize="32"/>
+
+  <reg name="dspctl" bitsize="32"/>
+</feature>
diff --git a/gdb/features/nanomips-fpu.xml b/gdb/features/nanomips-fpu.xml
new file mode 100644
index 00000000000..cac1d51f2ac
--- /dev/null
+++ b/gdb/features/nanomips-fpu.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.nanomips.fpu">
+  <reg name="f0" bitsize="64" type="ieee_double"/>
+  <reg name="f1" bitsize="64" type="ieee_double"/>
+  <reg name="f2" bitsize="64" type="ieee_double"/>
+  <reg name="f3" bitsize="64" type="ieee_double"/>
+  <reg name="f4" bitsize="64" type="ieee_double"/>
+  <reg name="f5" bitsize="64" type="ieee_double"/>
+  <reg name="f6" bitsize="64" type="ieee_double"/>
+  <reg name="f7" bitsize="64" type="ieee_double"/>
+  <reg name="f8" bitsize="64" type="ieee_double"/>
+  <reg name="f9" bitsize="64" type="ieee_double"/>
+  <reg name="f10" bitsize="64" type="ieee_double"/>
+  <reg name="f11" bitsize="64" type="ieee_double"/>
+  <reg name="f12" bitsize="64" type="ieee_double"/>
+  <reg name="f13" bitsize="64" type="ieee_double"/>
+  <reg name="f14" bitsize="64" type="ieee_double"/>
+  <reg name="f15" bitsize="64" type="ieee_double"/>
+  <reg name="f16" bitsize="64" type="ieee_double"/>
+  <reg name="f17" bitsize="64" type="ieee_double"/>
+  <reg name="f18" bitsize="64" type="ieee_double"/>
+  <reg name="f19" bitsize="64" type="ieee_double"/>
+  <reg name="f20" bitsize="64" type="ieee_double"/>
+  <reg name="f21" bitsize="64" type="ieee_double"/>
+  <reg name="f22" bitsize="64" type="ieee_double"/>
+  <reg name="f23" bitsize="64" type="ieee_double"/>
+  <reg name="f24" bitsize="64" type="ieee_double"/>
+  <reg name="f25" bitsize="64" type="ieee_double"/>
+  <reg name="f26" bitsize="64" type="ieee_double"/>
+  <reg name="f27" bitsize="64" type="ieee_double"/>
+  <reg name="f28" bitsize="64" type="ieee_double"/>
+  <reg name="f29" bitsize="64" type="ieee_double"/>
+  <reg name="f30" bitsize="64" type="ieee_double"/>
+  <reg name="f31" bitsize="64" type="ieee_double"/>
+
+  <reg name="fcsr" bitsize="32" group="float"/>
+  <reg name="fir" bitsize="32" group="float"/>
+</feature>
diff --git a/gdb/features/nanomips.c b/gdb/features/nanomips.c
new file mode 100644
index 00000000000..43cdc8a95d5
--- /dev/null
+++ b/gdb/features/nanomips.c
@@ -0,0 +1,54 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: nanomips.xml */
+
+#include "defs.h"
+#include "osabi.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_nanomips;
+static void
+initialize_tdesc_nanomips (void)
+{
+  struct target_desc *result;
+  result = allocate_target_description ().release();
+  struct tdesc_feature *feature;
+
+  set_tdesc_architecture (result, bfd_scan_arch ("nanomips"));
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.nanomips.cpu");
+  tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r13", 13, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r14", 14, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r15", 15, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r16", 16, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r17", 17, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r18", 18, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r19", 19, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r20", 20, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r21", 21, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r22", 22, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r23", 23, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r24", 24, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r25", 25, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r26", 26, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r27", 27, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r28", 28, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r29", 29, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r30", 30, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r31", 31, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pc", 32, 1, NULL, 32, "int");
+
+  tdesc_nanomips = result;
+}
diff --git a/gdb/features/nanomips.xml b/gdb/features/nanomips.xml
new file mode 100644
index 00000000000..ae05a91e935
--- /dev/null
+++ b/gdb/features/nanomips.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>nanomips</architecture>
+  <xi:include href="nanomips-cpu.xml"/>
+</target>
diff --git a/gdb/features/nanomips64-cp0.xml b/gdb/features/nanomips64-cp0.xml
new file mode 100644
index 00000000000..6af2e2c369d
--- /dev/null
+++ b/gdb/features/nanomips64-cp0.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.nanomips.cp0">
+  <reg name="status" bitsize="32"/>
+  <reg name="badvaddr" bitsize="64"/>
+  <reg name="cause" bitsize="32"/>
+</feature>
diff --git a/gdb/features/nanomips64-cpu.xml b/gdb/features/nanomips64-cpu.xml
new file mode 100644
index 00000000000..30a237050a6
--- /dev/null
+++ b/gdb/features/nanomips64-cpu.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.nanomips.cpu">
+  <reg name="r0" bitsize="64"/>
+  <reg name="r1" bitsize="64"/>
+  <reg name="r2" bitsize="64"/>
+  <reg name="r3" bitsize="64"/>
+  <reg name="r4" bitsize="64"/>
+  <reg name="r5" bitsize="64"/>
+  <reg name="r6" bitsize="64"/>
+  <reg name="r7" bitsize="64"/>
+  <reg name="r8" bitsize="64"/>
+  <reg name="r9" bitsize="64"/>
+  <reg name="r10" bitsize="64"/>
+  <reg name="r11" bitsize="64"/>
+  <reg name="r12" bitsize="64"/>
+  <reg name="r13" bitsize="64"/>
+  <reg name="r14" bitsize="64"/>
+  <reg name="r15" bitsize="64"/>
+  <reg name="r16" bitsize="64"/>
+  <reg name="r17" bitsize="64"/>
+  <reg name="r18" bitsize="64"/>
+  <reg name="r19" bitsize="64"/>
+  <reg name="r20" bitsize="64"/>
+  <reg name="r21" bitsize="64"/>
+  <reg name="r22" bitsize="64"/>
+  <reg name="r23" bitsize="64"/>
+  <reg name="r24" bitsize="64"/>
+  <reg name="r25" bitsize="64"/>
+  <reg name="r26" bitsize="64"/>
+  <reg name="r27" bitsize="64"/>
+  <reg name="r28" bitsize="64"/>
+  <reg name="r29" bitsize="64"/>
+  <reg name="r30" bitsize="64"/>
+  <reg name="r31" bitsize="64"/>
+
+  <reg name="pc" bitsize="64"/>
+</feature>
diff --git a/gdb/features/nanomips64-dsp.xml b/gdb/features/nanomips64-dsp.xml
new file mode 100644
index 00000000000..84bf7b06cc6
--- /dev/null
+++ b/gdb/features/nanomips64-dsp.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.nanomips.dsp">
+  <reg name="hi0" bitsize="64"/>
+  <reg name="lo0" bitsize="64"/>
+  <reg name="hi1" bitsize="64"/>
+  <reg name="lo1" bitsize="64"/>
+  <reg name="hi2" bitsize="64"/>
+  <reg name="lo2" bitsize="64"/>
+  <reg name="hi3" bitsize="64"/>
+  <reg name="lo3" bitsize="64"/>
+
+  <reg name="dspctl" bitsize="32"/>
+</feature>
diff --git a/gdb/nanomips-tdep.c b/gdb/nanomips-tdep.c
new file mode 100644
index 00000000000..b7aa5f0457f
--- /dev/null
+++ b/gdb/nanomips-tdep.c
@@ -0,0 +1,3421 @@
+/* Target-dependent code for the nanoMIPS architecture, for GDB,
+   the GNU Debugger.
+
+   Copyright (C) 2017-2022 Free Software Foundation, Inc.
+   Contributed by:
+    Jaydeep Patil <jaydeep.patil@imgtec.com>
+    Matthew Fortune <matthew.fortune@imgtec.com>
+    Maciej W. Rozycki <macro@mips.com>
+    Stefan Markovic <stefan.markovic@mips.com>
+    Sara Popadic <sara.popadic@imgtec.com>
+    Dragan Mladjenovic <dragan.mladjenovic@syrmia.com>
+    Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
+
+   This file is part of GDB.
+
+   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, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "gdbcore.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "target.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "osabi.h"
+#include "nanomips-tdep.h"
+#include "block.h"
+#include "reggroups.h"
+#include "opcode/nanomips.h"
+#include "elf/mips-common.h"
+#include "elf/nanomips.h"
+#include "elf-bfd.h"
+#include "symcat.h"
+#include "sim-regno.h"
+#include "dis-asm.h"
+#include "disasm.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+#include "infcall.h"
+#include "floatformat.h"
+#include "remote.h"
+#include "target-descriptions.h"
+#include "dwarf2/frame.h"
+#include "user-regs.h"
+#include "valprint.h"
+#include "ax.h"
+#include "target-float.h"
+#include <algorithm>
+
+#include "features/nanomips.c"
+
+static const struct objfile_data *nanomips_pdr_data;
+
+/* The sizes of registers.  */
+
+enum
+{
+  NANOMIPS32_REGSIZE = 4,
+  NANOMIPS64_REGSIZE = 8
+};
+
+static const char *const nanomips_abi_strings[] = {
+  "auto",
+  "p32",
+  "p64",
+  NULL
+};
+
+/* Enum describing the different kinds of breakpoints.  */
+
+enum nanomips_breakpoint_kind
+{
+  /* 16-bit breakpoint.  */
+  NANOMIPS_BP_KIND_16 = 3,
+
+  /* 32-bit breakpoint.  */
+  NANOMIPS_BP_KIND_32 = 5,
+};
+
+/* The standard register names, and all the valid aliases for them.  */
+struct register_alias
+{
+  const char *name;
+  int regnum;
+};
+
+
+static unsigned int nanomips_debug = 0;
+
+const struct nanomips_regnum *
+nanomips_regnum (struct gdbarch *gdbarch)
+{
+  return ((struct nanomips_gdbarch_tdep*) gdbarch_tdep (gdbarch))->regnum;
+}
+
+static int
+nanomips_fp_arg_regnum (struct gdbarch *gdbarch)
+{
+  gdb_assert (nanomips_regnum (gdbarch)->fpr != -1);
+
+  return nanomips_regnum (gdbarch)->fpr + NANOMIPS_FP0_REGNUM;
+}
+
+/* Return 1 if REGNUM refers to a floating-point general register, raw
+   or cooked.  Otherwise return 0.  */
+
+static int
+nanomips_float_register_p (struct gdbarch *gdbarch, int regnum)
+{
+  int rawnum = regnum % gdbarch_num_regs (gdbarch);
+  int fprnum = nanomips_regnum (gdbarch)->fpr;
+
+  return (fprnum != -1
+	  && rawnum >= fprnum + NANOMIPS_FP0_REGNUM
+	  && rawnum < fprnum + NANOMIPS_FCSR_REGNUM);
+}
+
+/* Return 1 if REGNUM refers to a floating-point control register, raw
+   or cooked.  Otherwise return 0.  */
+
+static int
+nanomips_float_control_register_p (struct gdbarch *gdbarch, int regnum)
+{
+  int rawnum = regnum % gdbarch_num_regs (gdbarch);
+  int fprnum = nanomips_regnum (gdbarch)->fpr;
+
+  return (fprnum != -1
+	  && (rawnum == fprnum + NANOMIPS_FCSR_REGNUM
+	      || rawnum == fprnum + NANOMIPS_FIR_REGNUM));
+}
+
+/* Return 1 if REGNUM refers to a DSP accumulator register, raw or cooked.
+   Otherwise return 0.  */
+
+static int
+nanomips_dspacc_register_p (struct gdbarch *gdbarch, int regnum)
+{
+  int rawnum = regnum % gdbarch_num_regs (gdbarch);
+  int dspnum = nanomips_regnum (gdbarch)->dsp;
+
+  return (dspnum != -1
+	  && rawnum >= dspnum + NANOMIPS_DSPHI0_REGNUM
+	  && rawnum < dspnum + NANOMIPS_DSPCTL_REGNUM);
+}
+
+#define FPU_TYPE(gdbarch) (((struct nanomips_gdbarch_tdep*) gdbarch_tdep (gdbarch))->fpu_type)
+
+/* Return the nanoMIPS ABI associated with GDBARCH.  */
+enum nanomips_abi
+nanomips_abi (struct gdbarch *gdbarch)
+{
+  return ((struct nanomips_gdbarch_tdep*) gdbarch_tdep (gdbarch))->nanomips_abi;
+}
+
+int
+nanomips_isa_regsize (struct gdbarch *gdbarch)
+{
+  return ((struct nanomips_gdbarch_tdep*) gdbarch_tdep (gdbarch))->register_size;
+}
+
+/* Return the currently configured (or set) saved register size.  */
+
+unsigned int
+nanomips_abi_regsize (struct gdbarch *gdbarch)
+{
+  switch (nanomips_abi (gdbarch))
+    {
+    case NANOMIPS_ABI_P32:
+      return 4;
+    case NANOMIPS_ABI_P64:
+      return 8;
+    case NANOMIPS_ABI_UNKNOWN:
+    default:
+      internal_error (__FILE__, __LINE__, _("bad switch"));
+    }
+}
+
+static void
+nanomips_xfer_register (struct gdbarch *gdbarch, struct regcache *regcache,
+        int reg_num, int length,
+        enum bfd_endian endian, gdb_byte *in,
+        const gdb_byte *out, int buf_offset)
+{
+  int reg_offset = 0;
+
+  gdb_assert (reg_num >= gdbarch_num_regs (gdbarch));
+  /* Need to transfer the left or right part of the register, based on
+     the targets byte order.  */
+  switch (endian)
+    {
+    case BFD_ENDIAN_BIG:
+      reg_offset = register_size (gdbarch, reg_num) - length;
+      break;
+    case BFD_ENDIAN_LITTLE:
+      reg_offset = 0;
+      break;
+    case BFD_ENDIAN_UNKNOWN:  /* Indicates no alignment.  */
+      reg_offset = 0;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, _("bad switch"));
+    }
+  if (nanomips_debug)
+    gdb_printf (gdb_stderr,
+      "xfer $%d, reg offset %d, buf offset %d, length %d, ",
+      reg_num, reg_offset, buf_offset, length);
+  if (nanomips_debug && out != NULL)
+    {
+      int i;
+      gdb_printf (gdb_stdlog, "out ");
+      for (i = 0; i < length; i++)
+  gdb_printf (gdb_stdlog, "%02x", out[buf_offset + i]);
+    }
+  if (in != NULL)
+    regcache->cooked_read_part (reg_num, reg_offset, length, in + buf_offset);
+  if (out != NULL)
+    regcache->cooked_write_part (reg_num, reg_offset, length, out + buf_offset);
+  if (nanomips_debug && in != NULL)
+    {
+      int i;
+      gdb_printf (gdb_stdlog, "in ");
+      for (i = 0; i < length; i++)
+  gdb_printf (gdb_stdlog, "%02x", in[buf_offset + i]);
+    }
+  if (nanomips_debug)
+    gdb_printf (gdb_stdlog, "\n");
+}
+
+#define VM_MIN_ADDRESS (CORE_ADDR)0x400000
+
+static CORE_ADDR heuristic_proc_start (struct gdbarch *, CORE_ADDR);
+
+static void reinit_frame_cache_sfunc (const char *, int, struct cmd_list_element *);
+
+/* The list of available "set nanomips " and "show nanomips " commands.  */
+
+static struct cmd_list_element *setnanomipscmdlist = NULL;
+static struct cmd_list_element *shownanomipscmdlist = NULL;
+
+/* Return the name of the register corresponding to REGNO.  */
+
+static const char *
+nanomips_register_name (struct gdbarch *gdbarch, int regno)
+{
+  /* GPR names for p32 and p64 ABIs.  */
+  static const char *const gpr_names[]  = {
+    "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", "raw_fp", "ra"
+  };
+
+  const char *name;
+  struct nanomips_gdbarch_tdep *tdep = (struct nanomips_gdbarch_tdep*) gdbarch_tdep (gdbarch);
+
+  /* Map [gdbarch_num_regs .. 2*gdbarch_num_regs) onto the raw registers,
+     but then don't make the raw register names visible.  This (upper)
+     range of user visible register numbers are the pseudo-registers.
+
+     This approach was adopted accommodate the following scenario:
+     It is possible to debug a 64-bit device using a 32-bit
+     programming model.  In such instances, the raw registers are
+     configured to be 64-bits wide, while the pseudo registers are
+     configured to be 32-bits wide.  The registers that the user
+     sees - the pseudo registers - match the users expectations
+     given the programming model being used.  */
+  int rawnum = regno % gdbarch_num_regs (gdbarch);
+  if (regno < gdbarch_num_regs (gdbarch))
+    return "";
+
+  name = tdesc_register_name (gdbarch, rawnum);
+
+  if (rawnum >= 0 && rawnum < 32)
+    {
+      gdb_assert (name != NULL && name[0] != 0);
+      gdb_assert ((sizeof (gpr_names) / sizeof (gpr_names[0])) == 32);
+      return gpr_names[rawnum];
+    }
+
+  return name;
+}
+
+/* Return the groups that a nanoMIPS register can be categorised into.  */
+
+static int
+nanomips_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+			      const struct reggroup *reggroup)
+{
+  int vector_p;
+  int float_p;
+  int raw_p;
+  int rawnum = regnum % gdbarch_num_regs (gdbarch);
+  int pseudo = regnum / gdbarch_num_regs (gdbarch);
+  if (reggroup == all_reggroup)
+    return pseudo;
+  vector_p = (register_type (gdbarch, regnum))->is_vector ();
+  float_p = (nanomips_float_register_p (gdbarch, rawnum)
+	     || nanomips_float_control_register_p (gdbarch, rawnum));
+  /* FIXME: cagney/2003-04-13: Can't yet use gdbarch_num_regs
+     (gdbarch), as not all architectures are multi-arch.  */
+  raw_p = rawnum < gdbarch_num_regs (gdbarch);
+  if (gdbarch_register_name (gdbarch, regnum) == NULL
+      || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
+    return 0;
+  if (reggroup == float_reggroup)
+    return float_p && pseudo;
+  if (reggroup == vector_reggroup)
+    return vector_p && pseudo;
+  if (reggroup == general_reggroup)
+    return (!vector_p && !float_p) && pseudo;
+  /* Save the pseudo registers.  Need to make certain that any code
+     extracting register values from a saved register cache also uses
+     pseudo registers.  */
+  if (reggroup == save_reggroup)
+    return raw_p && pseudo;
+  /* Restore the same pseudo register.  */
+  if (reggroup == restore_reggroup)
+    return raw_p && pseudo;
+  return 0;
+}
+
+/* Return the groups that a nanoMIPS register can be categorised into.
+   This version is only used if we have a target description which
+   describes real registers (and their groups).  */
+
+static int
+nanomips_tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+				    const struct reggroup *reggroup)
+{
+  int rawnum = regnum % gdbarch_num_regs (gdbarch);
+  int pseudo = regnum / gdbarch_num_regs (gdbarch);
+  int ret;
+
+  /* Only save, restore, and display the pseudo registers.  Need to
+     make certain that any code extracting register values from a
+     saved register cache also uses pseudo registers.
+
+     Note: saving and restoring the pseudo registers is slightly
+     strange; if we have 64 bits, we should save and restore all
+     64 bits.  But this is hard and has little benefit.  */
+  if (!pseudo)
+    return 0;
+
+  ret = tdesc_register_in_reggroup_p (gdbarch, rawnum, reggroup);
+  if (ret != -1)
+    return ret;
+
+  return nanomips_register_reggroup_p (gdbarch, regnum, reggroup);
+}
+
+/* Map the symbol table registers which live in the range [1 *
+   gdbarch_num_regs .. 2 * gdbarch_num_regs) back onto the corresponding raw
+   registers.  Take care of alignment and size problems.  */
+
+static enum register_status
+nanomips_pseudo_register_read (struct gdbarch *gdbarch,
+			       struct readable_regcache *regcache,
+			       int cookednum, gdb_byte *buf)
+{
+  int rawnum = cookednum % gdbarch_num_regs (gdbarch);
+  gdb_assert (cookednum >= gdbarch_num_regs (gdbarch)
+	      && cookednum < 2 * gdbarch_num_regs (gdbarch));
+  if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum))
+    return regcache->raw_read (rawnum, buf);
+  else if (register_size (gdbarch, rawnum) >
+	   register_size (gdbarch, cookednum))
+    {
+      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+      LONGEST regval;
+      enum register_status status;
+
+      status = regcache->raw_read (rawnum, &regval);
+      if (status == REG_VALID)
+        store_signed_integer (buf, 4, byte_order, regval);
+      return status;
+    }
+  else
+    internal_error (__FILE__, __LINE__, _("bad register size"));
+}
+
+static void
+nanomips_pseudo_register_write (struct gdbarch *gdbarch,
+				struct regcache *regcache, int cookednum,
+				const gdb_byte *buf)
+{
+  int rawnum = cookednum % gdbarch_num_regs (gdbarch);
+  gdb_assert (cookednum >= gdbarch_num_regs (gdbarch)
+	      && cookednum < 2 * gdbarch_num_regs (gdbarch));
+  if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum))
+    regcache->raw_write (rawnum, buf);
+  else if (register_size (gdbarch, rawnum) >
+	   register_size (gdbarch, cookednum))
+    {
+      /* Sign extend the shortened version of the register prior
+         to placing it in the raw register.  This is required for
+         some mips64 parts in order to avoid unpredictable behavior.  */
+      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+      LONGEST regval = extract_signed_integer (buf, 4, byte_order);
+      regcache_raw_write_signed (regcache, rawnum, regval);
+    }
+  else
+    internal_error (__FILE__, __LINE__, _("bad register size"));
+}
+
+static int
+nanomips_ax_pseudo_register_collect (struct gdbarch *gdbarch,
+				     struct agent_expr *ax, int reg)
+{
+  int rawnum = reg % gdbarch_num_regs (gdbarch);
+  gdb_assert (reg >= gdbarch_num_regs (gdbarch)
+	      && reg < 2 * gdbarch_num_regs (gdbarch));
+
+  ax_reg_mask (ax, rawnum);
+
+  return 0;
+}
+
+static int
+nanomips_ax_pseudo_register_push_stack (struct gdbarch *gdbarch,
+				    struct agent_expr *ax, int reg)
+{
+  int rawnum = reg % gdbarch_num_regs (gdbarch);
+  gdb_assert (reg >= gdbarch_num_regs (gdbarch)
+	      && reg < 2 * gdbarch_num_regs (gdbarch));
+  if (register_size (gdbarch, rawnum) >= register_size (gdbarch, reg))
+    {
+      ax_reg (ax, rawnum);
+
+      if (register_size (gdbarch, rawnum) > register_size (gdbarch, reg))
+        {
+	  if (gdbarch_byte_order (gdbarch) != BFD_ENDIAN_BIG)
+	    {
+	      ax_const_l (ax, 32);
+	      ax_simple (ax, aop_lsh);
+	    }
+	  ax_const_l (ax, 32);
+	  ax_simple (ax, aop_rsh_signed);
+	}
+    }
+  else
+    internal_error (__FILE__, __LINE__, _("bad register size"));
+
+  return 0;
+}
+
+/* Table to translate nanomips 3-bit register field to
+   actual register number.  */
+static const signed char reg3_to_reg[8] = { 16, 17, 18, 19, 4, 5, 6, 7 };
+
+/* Heuristic_proc_start may hunt through the text section for a long
+   time across a 2400 baud serial line.  Allows the user to limit this
+   search.  */
+
+static int heuristic_fence_post = 0;
+
+/* Convert to/from a register and the corresponding memory value.  */
+
+/* This predicate tests for the case of a 4 byte floating point
+   value that is being transferred to or from a floating point
+   register which is 8 bytes wide.  */
+
+static int
+nanomips_convert_register_float_case_p (struct gdbarch *gdbarch, int regnum,
+					struct type *type)
+{
+  return (register_size (gdbarch, regnum) == 8
+	  && nanomips_float_register_p (gdbarch, regnum)
+	  && type->code () == TYPE_CODE_FLT && TYPE_LENGTH (type) == 4);
+}
+
+/* This predicate tests for the case of a value of less than 8
+   bytes in width that is being transfered to or from an 8 byte
+   general purpose register.  */
+static int
+nanomips_convert_register_gpreg_case_p (struct gdbarch *gdbarch, int regnum,
+					struct type *type)
+{
+  int num_regs = gdbarch_num_regs (gdbarch);
+
+  return (register_size (gdbarch, regnum) == 8
+          && regnum % num_regs > 0 && regnum % num_regs < 32
+          && TYPE_LENGTH (type) < 8);
+}
+
+static int
+nanomips_convert_register_p (struct gdbarch *gdbarch,
+			     int regnum, struct type *type)
+{
+  return (nanomips_convert_register_float_case_p (gdbarch, regnum, type)
+	  || nanomips_convert_register_gpreg_case_p (gdbarch, regnum, type));
+}
+
+static int
+nanomips_register_to_value (struct frame_info *frame, int regnum,
+			    struct type *type, gdb_byte *to,
+			    int *optimizedp, int *unavailablep)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+
+  if (nanomips_convert_register_float_case_p (gdbarch, regnum, type))
+    {
+      /* single comes from low half of 64-bit register */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	{
+	  if (!get_frame_register_bytes (frame, regnum, 4, {to + 0, 4},
+					 optimizedp, unavailablep))
+	    return 0;
+	}
+      else
+	{
+	  if (!get_frame_register_bytes (frame, regnum, 0, {to + 0, 4},
+					 optimizedp, unavailablep))
+	    return 0;
+	}
+      *optimizedp = *unavailablep = 0;
+      return 1;
+    }
+  else if (nanomips_convert_register_gpreg_case_p (gdbarch, regnum, type))
+    {
+      int len = TYPE_LENGTH (type);
+      CORE_ADDR offset;
+
+      offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 8 - len : 0;
+      if (!get_frame_register_bytes (frame, regnum, offset, {to, (size_t)len},
+				     optimizedp, unavailablep))
+	return 0;
+
+      *optimizedp = *unavailablep = 0;
+      return 1;
+    }
+  else
+    {
+      internal_error (__FILE__, __LINE__,
+                      _("nanomips_register_to_value: unrecognized case"));
+    }
+}
+
+static void
+nanomips_value_to_register (struct frame_info *frame, int regnum,
+			    struct type *type, const gdb_byte *from)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+
+  if (nanomips_convert_register_float_case_p (gdbarch, regnum, type))
+    {
+      /* single goes in low half of 64-bit register */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	put_frame_register_bytes (frame, regnum, 4, {from, 4});
+      else
+	put_frame_register_bytes (frame, regnum, 0, {from, 4});
+    }
+  else if (nanomips_convert_register_gpreg_case_p (gdbarch, regnum, type))
+    {
+      gdb_byte fill[8];
+      int len = TYPE_LENGTH (type);
+
+      /* Sign extend values, irrespective of type, that are stored to
+         a 64-bit general purpose register.  (32-bit unsigned values
+	 are stored as signed quantities within a 64-bit register.
+	 When performing an operation, in compiled code, that combines
+	 a 32-bit unsigned value with a signed 64-bit value, a type
+	 conversion is first performed that zeroes out the high 32 bits.)  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	{
+	  if (from[0] & 0x80)
+	    store_signed_integer (fill, 8, BFD_ENDIAN_BIG, -1);
+	  else
+	    store_signed_integer (fill, 8, BFD_ENDIAN_BIG, 0);
+	  put_frame_register_bytes (frame, regnum, 0, {fill, (size_t)(8 - len)});
+	  put_frame_register_bytes (frame, regnum, 8 - len, {from, (size_t)len});
+	}
+      else
+	{
+	  if (from[len-1] & 0x80)
+	    store_signed_integer (fill, 8, BFD_ENDIAN_LITTLE, -1);
+	  else
+	    store_signed_integer (fill, 8, BFD_ENDIAN_LITTLE, 0);
+	  put_frame_register_bytes (frame, regnum, 0, {from, (size_t)len});
+	  put_frame_register_bytes (frame, regnum, len, {fill, (size_t)(8 - len)});
+	}
+    }
+  else
+    {
+      internal_error (__FILE__, __LINE__,
+                      _("nanomips_value_to_register: unrecognized case"));
+    }
+}
+
+/* Return the GDB type for the pseudo register REGNUM, which is the
+   ABI-level view.  This function is only called if there is a target
+   description which includes registers, so we know precisely the
+   types of hardware registers.  */
+
+static struct type *
+nanomips_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
+{
+  const int num_regs = gdbarch_num_regs (gdbarch);
+  int rawnum = regnum % num_regs;
+  struct type *rawtype;
+
+  gdb_assert (regnum >= num_regs && regnum < 2 * num_regs);
+
+  /* Absent registers are still absent.  */
+  rawtype = gdbarch_register_type (gdbarch, rawnum);
+  if (TYPE_LENGTH (rawtype) == 0)
+    return rawtype;
+
+  /* Present the floating point registers however the hardware did;
+     do not try to convert between FPU layouts.  */
+  if (nanomips_float_register_p (gdbarch, rawnum))
+    return rawtype;
+
+  /* Floating-point control registers are always 32-bit even though for
+     backwards compatibility reasons 64-bit targets will transfer them
+     as 64-bit quantities even if using XML descriptions.  */
+  if (nanomips_float_control_register_p (gdbarch, rawnum))
+    return builtin_type (gdbarch)->builtin_int32;
+
+  /* Use pointer types for registers if we can.  For n32 we can not,
+     since we do not have a 64-bit pointer type.  */
+  if (nanomips_abi_regsize (gdbarch)
+      == TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr))
+    {
+      if (rawnum == NANOMIPS_SP_REGNUM
+	  || rawnum == nanomips_regnum (gdbarch)->badvaddr)
+	return builtin_type (gdbarch)->builtin_data_ptr;
+      else if (rawnum == NANOMIPS_PC_REGNUM)
+	return builtin_type (gdbarch)->builtin_func_ptr;
+    }
+
+  if (nanomips_abi_regsize (gdbarch) == 4 && TYPE_LENGTH (rawtype) == 8
+      && ((rawnum >= NANOMIPS_ZERO_REGNUM && rawnum <= NANOMIPS_PC_REGNUM)
+	  || rawnum == nanomips_regnum (gdbarch)->badvaddr
+	  || rawnum == nanomips_regnum (gdbarch)->status
+	  || rawnum == nanomips_regnum (gdbarch)->cause
+	  || nanomips_dspacc_register_p (gdbarch, rawnum)))
+    return builtin_type (gdbarch)->builtin_int32;
+
+  /* For all other registers, pass through the hardware type.  */
+  return rawtype;
+}
+
+/* Should the upper word of 64-bit addresses be zeroed?  */
+static enum auto_boolean mask_address_var = AUTO_BOOLEAN_AUTO;
+
+static int
+nanomips_mask_address_p (struct nanomips_gdbarch_tdep *tdep)
+{
+  switch (mask_address_var)
+    {
+    case AUTO_BOOLEAN_TRUE:
+      return 1;
+    case AUTO_BOOLEAN_FALSE:
+      return 0;
+      break;
+    case AUTO_BOOLEAN_AUTO:
+      return tdep->default_mask_address_p;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("nanomips_mask_address_p: bad switch"));
+      return -1;
+    }
+}
+
+static void
+show_mask_address (struct ui_file *file, int from_tty,
+		   struct cmd_list_element *c, const char *value)
+{
+  struct nanomips_gdbarch_tdep *tdep = (struct nanomips_gdbarch_tdep*) gdbarch_tdep (target_gdbarch ());
+
+  deprecated_show_value_hack (file, from_tty, c, value);
+  switch (mask_address_var)
+    {
+    case AUTO_BOOLEAN_TRUE:
+      gdb_printf ("The 32 bit nanomips address mask is enabled\n");
+      break;
+    case AUTO_BOOLEAN_FALSE:
+      gdb_printf ("The 32 bit nanomips address mask is disabled\n");
+      break;
+    case AUTO_BOOLEAN_AUTO:
+      gdb_printf
+	("The 32 bit address mask is set automatically.  Currently %s\n",
+	 nanomips_mask_address_p (tdep) ? "enabled" : "disabled");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, _("show_mask_address: bad switch"));
+      break;
+    }
+}
+
+/* nanoMIPS believes that the PC has a sign extended value.  Perhaps
+   all registers should be sign extended for simplicity?  */
+
+static CORE_ADDR
+nanomips_read_pc (struct readable_regcache *regcache)
+{
+  int regnum = gdbarch_pc_regnum (regcache->arch ());
+  LONGEST pc;
+
+  regcache->cooked_read (regnum, &pc);
+  return pc;
+}
+
+static CORE_ADDR
+nanomips_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_signed
+	   (next_frame, gdbarch_pc_regnum (gdbarch));
+}
+
+static CORE_ADDR
+nanomips_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_signed
+	   (next_frame, gdbarch_num_regs (gdbarch) + NANOMIPS_SP_REGNUM);
+}
+
+/* Assuming THIS_FRAME is a dummy, return the frame ID of that
+   dummy frame.  The frame ID's base needs to match the TOS value
+   saved by save_dummy_frame_tos(), and the PC match the dummy frame's
+   breakpoint.  */
+
+static struct frame_id
+nanomips_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return frame_id_build
+	   (get_frame_register_signed (this_frame,
+				       gdbarch_num_regs (gdbarch)
+				       + NANOMIPS_SP_REGNUM),
+	    get_frame_pc (this_frame));
+}
+
+/* Implement the "write_pc" gdbarch method.  */
+
+void
+nanomips_write_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+  int regnum = gdbarch_pc_regnum (regcache->arch ());
+  regcache_cooked_write_unsigned (regcache, regnum, pc);
+}
+
+/* Fetch and return 16-bit instruction from the specified location.  */
+
+static ULONGEST
+nanomips_fetch_stack_slot (struct gdbarch *gdbarch, CORE_ADDR sp, int offset)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  return read_memory_unsigned_integer (sp + offset, 4, byte_order);
+}
+
+static ULONGEST
+nanomips_fetch_instruction (struct gdbarch *gdbarch,
+			    CORE_ADDR addr, int *errp)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  gdb_byte buf[INSN16_SIZE];
+  int err;
+
+  err = target_read_memory (addr, buf, INSN16_SIZE);
+  if (errp != NULL)
+    *errp = err;
+  if (err != 0)
+    {
+      if (errp == NULL)
+	memory_error (TARGET_XFER_E_IO, addr);
+      return 0;
+    }
+  return extract_unsigned_integer (buf, INSN16_SIZE, byte_order);
+}
+
+/* MicroMIPS instruction fields.  */
+#define micromips_op(x) ((x) >> 10)
+
+/* 16-bit/32-bit-high-part instruction formats, B and S refer to the lowest
+   bit and the size respectively of the field extracted.  */
+#define b0s4_imm(x) ((x) & 0xf)
+#define b0s5_imm(x) ((x) & 0x1f)
+#define b0s5_reg(x) ((x) & 0x1f)
+#define b0s7_imm(x) ((x) & 0x7f)
+#define b0s8_imm(x) ((x) & 0xff)
+#define b0s10_imm(x) ((x) & 0x3ff)
+#define b0u13_15s1_imm(x) (((x) & 0x1fff) | (((x) & 0x8000) >> 2))
+#define b1s4_imm(x) (((x) >> 1) & 0xf)
+#define b1s9_imm(x) (((x) >> 1) & 0x1ff)
+#define b2s1_op(x) (((x) >> 2) & 0x1)
+#define b2s3_cc(x) (((x) >> 2) & 0x7)
+#define b3s2_op(x) (((x) >> 3) & 0x3)
+#define b3s9_imm(x) (((x) >> 3) & 0x1ff)
+#define b4s2_regl(x) (((x) >> 4) & 0x3)
+#define b4s3_reg(x) (((x) >> 4) & 0x7)
+#define b4s4_imm(x) (((x) >> 4) & 0xf)
+#define b5s5_op(x) (((x) >> 5) & 0x1f)
+#define b5s5_reg(x) (((x) >> 5) & 0x1f)
+#define b6s4_op(x) (((x) >> 6) & 0xf)
+#define b7s3_reg(x) (((x) >> 7) & 0x7)
+#define b8s2_regl(x) (((x) >> 8) & 0x3)
+#define b8s7_op(x) (((x) >> 8) & 0x7f)
+
+/* 32-bit instruction formats, B and S refer to the lowest bit and the size
+   respectively of the field extracted.  */
+#define b0s6_op(x) ((x) & 0x3f)
+#define b0s10_op(x) ((x) & 0x3ff)
+#define b0s11_op(x) ((x) & 0x7ff)
+#define b0s12_imm(x) ((x) & 0xfff)
+#define b0u16_imm(x) ((x) & 0xffff)
+#define b0s21_imm(x) ((x) & 0x1fffff)
+#define b0s26_imm(x) ((x) & 0x3ffffff)
+#define b6s10_ext(x) (((x) >> 6) & 0x3ff)
+#define b9s3_op(x) (((x) >> 9) & 0x7)
+#define b11s5_reg(x) (((x) >> 11) & 0x1f)
+#define b16s5_reg(x) (((x) >> 16) & 0x1f)
+#define b21s5_reg(x) (((x) >> 21) & 0x1f)
+#define b11s7_imm(x) (((x) >> 11) & 0x7f)
+#define b12s4_op(x) (((x) >> 12) & 0xf)
+#define b12s5_op(x) (((x) >> 12) & 0x1f)
+#define b14s2_op(x) (((x) >> 14) & 0x3)
+#define b16s4_imm(x) (((x) >> 16) & 0xf)
+
+/* Return the size in bytes of the instruction INSN encoded in the ISA
+   instruction set.  */
+
+static int
+nanomips_insn_size (ULONGEST insn)
+{
+  if (micromips_op (insn) == 0x18)
+    return 3 * INSN16_SIZE;
+  else if ((micromips_op (insn) & 0x4) == 0x0)
+    return 2 * INSN16_SIZE;
+  else
+    return INSN16_SIZE;
+}
+
+/* Calculate the address of the next nanoMIPS instruction to execute
+   after the instruction at the address PC.  The nanomips_next_pc
+   function supports single_step when the remote target monitor or stub
+   is not developed enough to do a single_step.  It works by decoding the
+   current instruction and predicting where a branch will go.  This isn't
+   hard because all the data is available.  */
+
+static CORE_ADDR
+nanomips_next_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ULONGEST insn;
+  CORE_ADDR offset, sp, ra;
+  int op, sreg, treg, uimm, count;
+  LONGEST val_rs, val_rt;
+
+  insn = nanomips_fetch_instruction (gdbarch, pc, NULL);
+  pc += INSN16_SIZE;
+  switch (nanomips_insn_size (insn))
+    {
+    /* 48-bit instructions.  */
+    case 3 * INSN16_SIZE:
+      /* No branch or jump instructions in this category.  */
+      pc += 2 * INSN16_SIZE;
+      break;
+
+    /* 32-bit instructions.  */
+    case 2 * INSN16_SIZE:
+      insn <<= 16;
+      insn |= nanomips_fetch_instruction (gdbarch, pc, NULL);
+      pc += INSN16_SIZE;
+      switch (micromips_op (insn >> 16))
+	{
+	case 0x0: /* P32 */
+	  op = b5s5_op (insn >> 16);
+	  switch (op)
+	    {
+	    case 0x0: /* P.RI */
+	      switch (b3s2_op (insn >> 16))
+		{
+		case 0x1: /* SYSCALL */
+		  if (b2s1_op (insn >> 16) == 0)
+		    {
+		      struct nanomips_gdbarch_tdep *tdep;
+
+		      tdep = (struct nanomips_gdbarch_tdep*) gdbarch_tdep (gdbarch);
+		      if (tdep->syscall_next_pc != NULL)
+			pc = tdep->syscall_next_pc (get_current_frame (), pc);
+		    }
+		  break;
+		}
+	      break;
+	    }
+	  break;
+
+	case 0x2: /* MOVE.BALC */
+	  offset = ((insn & 1) << 20 | ((insn >> 1) & 0xfffff)) << 1;
+	  offset = (offset ^ 0x200000) - 0x200000;
+	  pc += offset;
+	  break;
+
+	case 0xa: /* BALC, BC */
+	  offset = ((insn & 1) << 24 | ((insn >> 1) & 0xffffff)) << 1;
+	  offset = (offset ^ 0x2000000) - 0x2000000;
+	  pc += offset;
+	  break;
+
+	case 0x12: /* P.J P.BREG P.BALRC P.BALRSC */
+	  op = b12s4_op (insn);
+	  sreg = b0s5_reg (insn >> 16);
+	  treg = b5s5_reg (insn >> 16);
+	  if (op == 0x8) /* BALRSC, BRSC */
+	    {
+	      val_rs = regcache_raw_get_signed (regcache, sreg);
+	      pc += (val_rs << 1);
+	    }
+	  else if (op == 0 || op == 1) /* JALRC JALRC.HB */
+	    pc = regcache_raw_get_signed (regcache, sreg);
+	  break;
+
+	case 0x20: /* PP.SR */
+	  if ((b12s4_op (insn) == 0x3) && ((insn & 3) == 3)) /* RESTORE.JRC */
+	   {
+             sp = regcache_raw_get_signed (regcache, NANOMIPS_SP_REGNUM);
+             ra = regcache_raw_get_signed (regcache, NANOMIPS_RA_REGNUM);
+             sp += (((insn >> 3) & 0x1ff) << 3);
+             count = ((insn >> 16) & 0xf);
+             treg = b5s5_reg(insn >> 16);
+             if (count != 0 && treg <= 31 && (treg + count) > 31)
+               ra = nanomips_fetch_stack_slot (gdbarch, sp, -(31 - treg + 1) * 4);
+             pc = ra;
+           }
+	  break;
+
+	case 0x22: /* P.BR1 */
+	  op = b14s2_op (insn);
+	  sreg = b0s5_reg (insn >> 16);
+	  treg = b5s5_reg (insn >> 16);
+	  val_rs = regcache_raw_get_signed (regcache, sreg);
+	  val_rt = regcache_raw_get_signed (regcache, treg);
+	  offset = ((insn & 1) << 13 | ((insn >> 1) & 0x1fff)) << 1;
+	  offset = (offset ^ 0x4000) - 0x4000;
+	  if ((op == 0 && val_rs == val_rt) /* BEQC */
+	      || (op == 2 && val_rs >= val_rt) /* BGEC */
+	      || (op == 3
+		  && (ULONGEST) val_rs >= (ULONGEST) val_rt)) /* BGEUC */
+	    pc += offset;
+	  break;
+
+	case 0x2a: /* P.BR2 */
+	  op = b14s2_op (insn);
+	  sreg = b0s5_reg (insn >> 16);
+	  treg = b5s5_reg (insn >> 16);
+	  val_rs = regcache_raw_get_signed (regcache, sreg);
+	  val_rt = regcache_raw_get_signed (regcache, treg);
+	  offset = ((insn & 1) << 13 | ((insn >> 1) & 0x1fff)) << 1;
+	  offset = (offset ^ 0x4000) - 0x4000;
+	  if ((op == 0 && val_rs != val_rt) /* BNEC */
+	      || (op == 2 && val_rs < val_rt) /* BLTC */
+	      || (op == 3
+		  && (ULONGEST) val_rs < (ULONGEST) val_rt)) /* BLTUC */
+	    pc += offset;
+	  break;
+
+	case 0x32: /* P.BRI */
+	  op = b2s3_cc (insn >> 16);
+	  treg = b5s5_reg (insn >> 16);
+	  val_rt = regcache_raw_get_signed (regcache, treg);
+	  offset = ((insn & 1) << 10 | ((insn >> 1) & 0x3ff)) << 1;
+	  offset = (offset ^ 0x800) - 0x800;
+	  uimm = b11s7_imm (insn);
+	  if ((op == 0 && val_rt == uimm) /* BEQIC */
+              || (op == 1 && ((val_rt &  (1 << uimm)) == 0)) /* BBEQZC */
+	      || (op == 2 && val_rt >= uimm) /* BGEIC */
+	      || (op == 3 && (ULONGEST) val_rt >= uimm) /* BGEIUC */
+	      || (op == 4 && val_rt != uimm) /* BNEIC */
+              || (op == 5 && ((val_rt &  (1 << uimm)) != 0)) /* BBNEZC */
+	      || (op == 6 && val_rt < uimm) /* BLTIC */
+	      || (op == 7 && (ULONGEST) val_rt < uimm)) /* BLTIUC */
+	    pc += offset;
+	  break;
+
+	case 0x3a: /* P.BZ */
+	  op = (insn & 0x80000); /* 20th bit */
+	  treg = b5s5_reg (insn >> 16);
+	  val_rt = regcache_raw_get_signed (regcache, treg);
+	  offset = ((insn & 1) << 19 | ((insn >> 1) & 0x7ffff)) << 1;
+	  offset = (offset ^ 0x100000) - 0x100000;
+	  if ((op == 0 && val_rt == 0) /* BEQZC */
+	      || (op != 0 && val_rt != 0)) /* BNEZC */
+	    pc += offset;
+	  break;
+
+	default:
+	  break;
+	}
+
+    /* 16-bit instructions.  */
+    case INSN16_SIZE:
+      switch (micromips_op (insn))
+	{
+	case 0x4: /* P16 */
+	  op = b5s5_op (insn);
+	  switch (op)
+	    {
+	    case 0x0: /* P16.RI */
+	      switch (b3s2_op (insn))
+		{
+		case 0x1: /* SYSCALL[16] */
+		  if (b2s1_op (insn) == 0)
+		    {
+		      struct nanomips_gdbarch_tdep *tdep;
+
+		      tdep = (struct nanomips_gdbarch_tdep*) gdbarch_tdep (gdbarch);
+		      if (tdep->syscall_next_pc != NULL)
+			pc = tdep->syscall_next_pc (get_current_frame (), pc);
+		    }
+		  break;
+		}
+	      break;
+	    }
+	  break;
+
+	case 0x6: /* BC[16] */
+	case 0xe: /* BALC[16] */
+	  offset = ((insn & 1) << 9 | ((insn >> 1) & 0x1ff)) << 1;
+	  offset = (offset ^ 0x400) - 0x400;
+	  pc += offset;
+	  break;
+
+	case 0x7: /* RESTORE.JRC[16] */
+	  if ((insn & 1) == 0 && (insn & 0x20) == 0x20 && ((insn >> 8) & 1) == 1)
+          {
+            sp = regcache_raw_get_signed (regcache, NANOMIPS_SP_REGNUM);
+	    ra = regcache_raw_get_signed (regcache, NANOMIPS_RA_REGNUM);
+            sp += (((insn >> 4) & 0xf) << 4);
+            count = insn & 0xf;
+            treg = ((insn >> 9) & 0x1) ? NANOMIPS_RA_REGNUM : NANOMIPS_FP_REGNUM;
+            if (count != 0 && treg + count > 31) {
+                ra = nanomips_fetch_stack_slot (gdbarch, sp, -(31 - treg + 1) * 4);
+            }
+            pc = ra;
+          }
+	  break;
+
+	case 0x26: /* BEQZC[16] */
+	  treg = reg3_to_reg[b7s3_reg (insn)];
+	  val_rt = regcache_raw_get_signed (regcache, treg);
+	  offset = ((insn & 1) << 6 | ((insn >> 1) & 0x3f)) << 1;
+	  offset = (offset ^ 0x80) - 0x80;
+	  if (val_rt == 0)
+	    pc += offset;
+	  break;
+
+	case 0x2e: /* BNEZC[16] */
+	  treg = reg3_to_reg[b7s3_reg (insn)];
+	  val_rt = regcache_raw_get_signed (regcache, treg);
+	  offset = ((insn & 1) << 6 | ((insn >> 1) & 0x3f)) << 1;
+	  offset = (offset ^ 0x80) - 0x80;
+	  if (val_rt != 0)
+	    pc += offset;
+	  break;
+
+	case 0x36: /* P16.BR P16.JRC */
+	  sreg = b4s3_reg (insn);
+	  treg = b7s3_reg (insn);
+	  val_rs = regcache_raw_get_signed (regcache, reg3_to_reg[sreg]);
+	  val_rt = regcache_raw_get_signed (regcache, reg3_to_reg[treg]);
+	  offset = insn & 0xf;
+	  /* BEQC[16] BEQC[16] */
+	  if ((sreg < treg && offset != 0 && val_rs == val_rt)
+	      || (sreg >= treg && offset != 0 && val_rs != val_rt))
+	    pc += (offset << 1);
+	  else if (offset == 0) /* JALRC[16] JRC */
+	    pc = regcache_raw_get_signed (regcache, b5s5_reg(insn));
+	  break;
+
+	default:
+	  break;
+	}
+      break;
+
+    default:
+      break;
+    }
+  return pc;
+}
+
+struct nanomips_frame_cache
+{
+  CORE_ADDR base;
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Set a register's saved stack address in temp_saved_regs.  If an
+   address has already been set for this register, do nothing; this
+   way we will only recognize the first save of a given register in a
+   function prologue.
+
+   For simplicity, save the address in both [0 .. gdbarch_num_regs) and
+   [gdbarch_num_regs .. 2*gdbarch_num_regs).
+   Strictly speaking, only the second range is used as it is only second
+   range (the ABI instead of ISA registers) that comes into play when finding
+   saved registers in a frame.  */
+
+static void
+set_reg_offset (struct gdbarch *gdbarch, struct nanomips_frame_cache *this_cache,
+		int regnum, CORE_ADDR offset)
+{
+  if (this_cache != NULL
+      && this_cache->saved_regs[regnum].addr() == -1)
+    {
+      this_cache->saved_regs[regnum + 0 * gdbarch_num_regs (gdbarch)].set_addr(
+        offset);
+      this_cache->saved_regs[regnum + 1 * gdbarch_num_regs (gdbarch)].set_addr(
+        offset);
+    }
+}
+
+/* Analyze the function prologue from START_PC to LIMIT_PC.  Return
+   the address of the first instruction past the prologue.  */
+
+static CORE_ADDR
+nanomips_scan_prologue (struct gdbarch *gdbarch,
+			CORE_ADDR start_pc, CORE_ADDR limit_pc,
+			struct frame_info *this_frame,
+			struct nanomips_frame_cache *this_cache)
+{
+  CORE_ADDR end_prologue_addr;
+  int prev_non_prologue_insn = 0;
+  int frame_reg = NANOMIPS_SP_REGNUM;
+  int this_non_prologue_insn;
+  int non_prologue_insns = 0;
+  long frame_offset = 0;	/* Size of stack frame.  */
+  long frame_adjust = 0;	/* Offset of FP from SP.  */
+  CORE_ADDR prev_pc;
+  CORE_ADDR cur_pc;
+  ULONGEST insn;		/* current instruction */
+  CORE_ADDR sp;
+  long offset;
+  long sp_adj;
+  long v1_off = 0;		/* The assumption is LUI will replace it.  */
+  int reglist;
+  int breg;
+  int dreg;
+  int sreg;
+  int treg;
+  int loc;
+  int op;
+  int s;
+  int i;
+
+  /* Can be called when there's no process, and hence when there's no
+     THIS_FRAME.  */
+  if (this_frame != NULL)
+    sp = get_frame_register_signed (this_frame,
+				    gdbarch_num_regs (gdbarch)
+				    + NANOMIPS_SP_REGNUM);
+  else
+    sp = 0;
+
+  if (limit_pc > start_pc + 200)
+    limit_pc = start_pc + 200;
+  prev_pc = start_pc;
+
+  /* Permit at most one non-prologue non-control-transfer instruction
+     in the middle which may have been reordered by the compiler for
+     optimisation.  */
+  for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += loc)
+    {
+      this_non_prologue_insn = 0;
+      sp_adj = 0;
+      loc = 0;
+      insn = nanomips_fetch_instruction (gdbarch, cur_pc, NULL);
+      loc += INSN16_SIZE;
+      switch (nanomips_insn_size (insn))
+	{
+	/* 48-bit instructions.  */
+	case 3 * INSN16_SIZE:
+	  if (micromips_op (insn) == 0x18)
+	    {
+	      op = b0s5_imm (insn);
+	      treg = b5s5_reg (insn);
+	      offset = nanomips_fetch_instruction (gdbarch, cur_pc + 2, NULL);
+	      offset <<= 16;
+	      offset |= nanomips_fetch_instruction (gdbarch, cur_pc + 4, NULL);
+	      if (op == 0x0 && treg == 3) /* LI48 $v1, imm32 */
+		v1_off = offset;
+	      else if (op == 0x1 /* ADDIU48 $sp, imm32 */
+		       && treg == NANOMIPS_SP_REGNUM)
+		sp_adj = offset;
+	      else
+		this_non_prologue_insn = 1;
+	    }
+	      else
+		this_non_prologue_insn = 1;
+	  break;
+
+	/* 32-bit instructions.  */
+	case 2 * INSN16_SIZE:
+	  insn <<= 16;
+	  insn |= nanomips_fetch_instruction (gdbarch,
+					  cur_pc + loc, NULL);
+	  loc += INSN16_SIZE;
+
+	  switch (micromips_op (insn >> 16))
+	    {
+	    case 0x0: /* PP.ADDIU bits 000000 */
+	      sreg = b0s5_reg (insn >> 16);
+	      treg = b5s5_reg (insn >> 16);
+	      offset = b0u16_imm (insn);
+	      if (sreg == treg
+		  && treg == NANOMIPS_SP_REGNUM) /* ADDIU $sp, $sp, imm */
+		sp_adj = offset;
+	      else if (sreg == NANOMIPS_SP_REGNUM
+		       && treg == NANOMIPS_FP_REGNUM) /* ADDIU $fp, $sp, imm */
+		{
+		  frame_adjust = offset;
+		  frame_reg = NANOMIPS_FP_REGNUM;
+		}
+	      else if (sreg != NANOMIPS_GP_REGNUM
+		       || treg != NANOMIPS_GP_REGNUM)
+		this_non_prologue_insn = 1;
+	      break;
+
+	    case 0x8: /* P32A: bits 001000 */
+	      op = b0s10_op (insn);
+	      sreg = b0s5_reg (insn >> 16);
+	      treg = b5s5_reg (insn >> 16);
+	      dreg = b11s5_reg (insn);
+	      if (op == 0x1d0	/* SUBU: bits 001000 0111010000 */
+		  && dreg == NANOMIPS_SP_REGNUM && sreg == NANOMIPS_SP_REGNUM
+		  && treg == 3)	/* SUBU $sp, $v1 */
+		sp_adj = v1_off;
+	      else
+		this_non_prologue_insn = 1;
+	      break;
+
+	    case 0x20: /* P.U12 bits 100000 */
+	      /* SAVE: bits 100000 rt 0 count 0011 */
+	      if (b12s4_op (insn) == 0x3)
+		{
+		  int rt, this_rt, gp, use_gp;
+		  int counter = 0, count = b16s4_imm (insn);
+		  long this_offset;
+		  offset = b3s9_imm (insn) << 3;
+		  rt = b21s5_reg (insn);
+		  sp_adj = -offset;
+		  gp = (insn >> 2) & 1;
+		  while (counter != count)
+		    {
+		      use_gp = gp & (counter == count - 1);
+		      if (use_gp)
+			this_rt = NANOMIPS_GP_REGNUM;
+		      else
+			this_rt = (((rt >> 4) & 1) << 4) | (rt + counter);
+		      this_offset = (counter + 1) << 2;
+		      set_reg_offset (gdbarch, this_cache, this_rt,
+				      sp + offset - this_offset);
+		      counter++;
+		    }
+		}
+	      else if (b12s4_op (insn) == 8) /* ADDIU[NEG]: bits 100000 1000 */
+		{
+		  sreg = b0s5_reg (insn >> 16);
+		  treg = b5s5_reg (insn >> 16);
+		  if (sreg == treg && sreg == NANOMIPS_SP_REGNUM)
+			  /* ADDIU[NEG] $sp, $sp, imm */
+		    {
+		      offset = b0s11_op (insn);
+		      sp_adj = -offset;
+		    }
+		}
+	      else if (b12s4_op (insn) == 0) /* ORI: bits 100000 0000 */
+		{
+		  sreg = b0s5_reg (insn >> 16);
+		  treg = b5s5_reg (insn >> 16);
+		  if (sreg == treg && treg == 3) /* ORI $v1, $v1, imm */
+		    v1_off |= b0s11_op (insn);
+		  else
+		    this_non_prologue_insn = 1;
+		}
+		else
+		  this_non_prologue_insn = 1;
+	      break;
+
+	    case 0x21: /* P.LS.U12 bits 100001 */
+	      if (b12s4_op (insn) == 0x9) /* SW 100001 1001 */
+		{
+		  breg = b0s5_reg (insn >> 16);
+		  sreg = b5s5_reg (insn >> 16);
+		  offset = b0s12_imm (insn);
+		  if (breg == NANOMIPS_SP_REGNUM) /* SW reg,offset($sp) */
+		    set_reg_offset (gdbarch, this_cache, sreg, sp + offset);
+		  else
+		    this_non_prologue_insn = 1;
+		}
+	      break;
+
+	    case 0x29: /* P.LS.S9 bits 101001 */
+	      if (b8s7_op (insn) == 0x48) /* SW[S9] 101001 1001 0 00 */
+		{
+		  breg = b0s5_reg (insn >> 16);
+		  sreg = b5s5_reg (insn >> 16);
+		  offset = (((insn >> 15) & 1) << 8) | b0s8_imm (insn);
+		  offset = (offset ^ 0x100) - 0x100;
+		  if (breg == NANOMIPS_SP_REGNUM) /* SW[S9] reg,offset($sp) */
+		    set_reg_offset (gdbarch, this_cache, sreg, sp + offset);
+		  else
+		    this_non_prologue_insn = 1;
+		}
+	      break;
+
+	    case 0x38: /* P.LUI bits 111000 */
+	      treg = b5s5_reg (insn >> 16);
+	      if ((insn & 2) == 0 /* LU20I bits 111000 0 */
+		  && treg == 3) /* LU20I $v1, imm */
+		{
+		  v1_off = ((insn & 1) << 19)
+			    | (((insn >> 2) & 0x3ff) << 9)
+			    | (((insn >> 12) & 0x1ff));
+		  v1_off = v1_off << 12;
+		}
+	      else
+		this_non_prologue_insn = 1;
+	      break;
+
+	   default:
+	     this_non_prologue_insn = 1;
+	     break;
+	   }
+
+	  insn >>= 16;
+	  break;
+
+	/* 16-bit instructions.  */
+	case INSN16_SIZE:
+	  switch (micromips_op (insn))
+	    {
+	    case 0x4: /* MOVE: bits 000100 */
+	      sreg = b0s5_reg (insn);
+	      dreg = b5s5_reg (insn);
+	      if (sreg == NANOMIPS_SP_REGNUM && dreg == NANOMIPS_FP_REGNUM)
+				/* MOVE  $fp, $sp */
+		frame_reg = NANOMIPS_FP_REGNUM;
+	      else
+		this_non_prologue_insn = 1;
+	      break;
+
+	    case 0x7: /* SAVE: bits 000111 */
+	      {
+		int rt, rt1, this_rt;
+		int counter = 0, count = b0s4_imm (insn);
+		long this_offset;
+		offset = b4s4_imm (insn) << 4;
+		rt1 = (insn >> 9) & 1;
+		rt = 30 | rt1;
+		sp_adj = -offset;
+		while (counter != count)
+		  {
+		    this_rt = (((rt >> 4) & 1) << 4) | (rt + counter);
+		    this_offset = (counter + 1) << 2;
+		    set_reg_offset (gdbarch, this_cache, this_rt,
+				    sp + offset - this_offset);
+		    counter++;
+		  }
+		break;
+	      }
+
+	    case 0x35: /* SW[SP]: bits 110101 */
+	      treg = b5s5_reg (insn);
+	      offset = b0s5_imm (insn);
+	      set_reg_offset (gdbarch, this_cache, treg, sp + offset);
+	      break;
+
+	    default:
+	      this_non_prologue_insn = 1;
+	      break;
+	    }
+	  break;
+	}
+
+      if (sp_adj < 0)
+	frame_offset -= sp_adj;
+
+      non_prologue_insns += this_non_prologue_insn;
+
+      if (non_prologue_insns > 1 || sp_adj > 0)
+  break;
+
+      prev_non_prologue_insn = this_non_prologue_insn;
+      prev_pc = cur_pc;
+    }
+
+  if (this_cache != NULL)
+    {
+      this_cache->base =
+	(get_frame_register_signed (this_frame,
+				    gdbarch_num_regs (gdbarch) + frame_reg)
+	 + frame_offset - frame_adjust);
+      /* FIXME: brobecker/2004-10-10: Just as in the mips32 case, we should
+	 be able to get rid of the assignment below, evetually. But it's
+	 still needed for now.  */
+      this_cache->saved_regs[gdbarch_num_regs (gdbarch) + NANOMIPS_PC_REGNUM]
+	= this_cache->saved_regs[gdbarch_num_regs (gdbarch)
+				 + NANOMIPS_RA_REGNUM];
+    }
+
+  /* Set end_prologue_addr to the address of the instruction immediately
+     after the last one we scanned.  Unless the last one looked like a
+     non-prologue instruction (and we looked ahead), in which case use
+     its address instead.  */
+  end_prologue_addr
+    = prev_non_prologue_insn ? prev_pc : cur_pc;
+
+  return end_prologue_addr;
+}
+
+/* Heuristic unwinder for procedures using nanoMIPS instructions.
+   Procedures that use the 32-bit instruction set are handled by the
+   mips_insn32 unwinder.  Likewise MIPS16 and the mips_insn16 unwinder. */
+
+static struct nanomips_frame_cache *
+nanomips_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct nanomips_frame_cache *cache;
+
+  if ((*this_cache) != NULL)
+    return (struct nanomips_frame_cache *) (*this_cache);
+
+  cache = FRAME_OBSTACK_ZALLOC (struct nanomips_frame_cache);
+  (*this_cache) = cache;
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+  /* Analyze the function prologue.  */
+  {
+    const CORE_ADDR pc = get_frame_address_in_block (this_frame);
+    CORE_ADDR start_addr;
+
+    find_pc_partial_function (pc, NULL, &start_addr, NULL);
+    if (start_addr == 0)
+      start_addr = heuristic_proc_start (get_frame_arch (this_frame), pc);
+    /* We can't analyze the prologue if we couldn't find the begining
+       of the function.  */
+    if (start_addr == 0)
+      return cache;
+
+    nanomips_scan_prologue (gdbarch, start_addr, pc, this_frame,
+			    (struct nanomips_frame_cache *) *this_cache);
+  }
+
+  /* gdbarch_sp_regnum contains the value and not the address.  */
+  cache->saved_regs[gdbarch_num_regs (gdbarch)
+        + NANOMIPS_SP_REGNUM].set_value (cache->base);
+
+  return (struct nanomips_frame_cache *) (*this_cache);
+}
+
+static void
+nanomips_frame_this_id (struct frame_info *this_frame, void **this_cache,
+			struct frame_id *this_id)
+{
+  struct nanomips_frame_cache *info = nanomips_frame_cache (this_frame,
+							    this_cache);
+  /* This marks the outermost frame.  */
+  if (info->base == 0)
+    return;
+  (*this_id) = frame_id_build (info->base, get_frame_func (this_frame));
+}
+
+static struct value *
+nanomips_frame_prev_register (struct frame_info *this_frame,
+			      void **this_cache, int regnum)
+{
+  struct nanomips_frame_cache *info = nanomips_frame_cache (this_frame,
+							    this_cache);
+  return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
+}
+
+static int
+nanomips_frame_sniffer (const struct frame_unwind *self,
+			struct frame_info *this_frame, void **this_cache)
+{
+  return 1;
+}
+
+static const struct frame_unwind nanomips_frame_unwind =
+{
+  "nanoMIPS insn prologue",
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  nanomips_frame_this_id,
+  nanomips_frame_prev_register,
+  NULL,
+  nanomips_frame_sniffer
+};
+
+static CORE_ADDR
+nanomips_frame_base_address (struct frame_info *this_frame,
+			     void **this_cache)
+{
+  struct nanomips_frame_cache *info = nanomips_frame_cache (this_frame,
+							    this_cache);
+  return info->base;
+}
+
+static const struct frame_base nanomips_frame_base =
+{
+  &nanomips_frame_unwind,
+  nanomips_frame_base_address,
+  nanomips_frame_base_address,
+  nanomips_frame_base_address
+};
+
+static const struct frame_base *
+nanomips_frame_base_sniffer (struct frame_info *this_frame)
+{
+  return &nanomips_frame_base;
+}
+
+/* nanomips_addr_bits_remove - remove useless address bits  */
+
+static CORE_ADDR
+nanomips_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  struct nanomips_gdbarch_tdep *tdep = (struct nanomips_gdbarch_tdep*) gdbarch_tdep (gdbarch);
+
+  if (nanomips_mask_address_p (tdep)
+      && (((ULONGEST) addr) >> 32 == 0xffffffffUL))
+    /* This hack is a work-around for existing boards using PMON, the
+       simulator, and any other 64-bit targets that doesn't have true
+       64-bit addressing.  On these targets, the upper 32 bits of
+       addresses are ignored by the hardware.  Thus, the PC or SP are
+       likely to have been sign extended to all 1s by instruction
+       sequences that load 32-bit addresses.  For example, a typical
+       piece of code that loads an address is this:
+
+       lui $r2, <upper 16 bits>
+       ori $r2, <lower 16 bits>
+
+       But the lui sign-extends the value such that the upper 32 bits
+       may be all 1s.  The workaround is simply to mask off these
+       bits.  In the future, gcc may be changed to support true 64-bit
+       addressing, and this masking will have to be disabled.  */
+    return addr &= 0xffffffffUL;
+  else
+    return addr;
+}
+
+
+/* Checks for an atomic sequence of instructions beginning with a LL/LLD
+   instruction and ending with a SC/SCD instruction.  If such a sequence
+   is found, attempt to step through it.  A breakpoint is placed at the end of
+   the sequence.  */
+
+static std::vector<CORE_ADDR>
+nanomips_deal_with_atomic_sequence (struct gdbarch *gdbarch,
+				    CORE_ADDR pc)
+{
+  const int atomic_sequence_length = 16; /* Instruction sequence length.  */
+  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */
+  CORE_ADDR breaks[2] = {CORE_ADDR_MAX, CORE_ADDR_MAX};
+  CORE_ADDR branch_bp = 0; /* Breakpoint at branch instruction's
+			      destination.  */
+  CORE_ADDR loc = pc;
+  int sc_found = 0;
+  ULONGEST insn;
+  int insn_count;
+  int index;
+
+  /* Assume all atomic sequences start with a ll/lld instruction.  */
+  insn = nanomips_fetch_instruction (gdbarch, loc, NULL);
+  if (micromips_op (insn) != 0x29)	/* P.LL: bits 101001 */
+    return {};
+  loc += INSN16_SIZE;
+  insn <<= 16;
+  insn |= nanomips_fetch_instruction (gdbarch, loc, NULL);
+  if (b8s7_op (insn) != 0x51)	/* LL: bits 101001 1010 0 01 */
+    return {};
+  loc += INSN16_SIZE;
+
+  /* Assume all atomic sequences end with an sc/scd instruction.  Assume
+     that no atomic sequence is longer than "atomic_sequence_length"
+     instructions.  */
+  for (insn_count = 0;
+       !sc_found && insn_count < atomic_sequence_length;
+       ++insn_count)
+    {
+      int is_branch = 0, op;
+      CORE_ADDR offset;
+
+      insn = nanomips_fetch_instruction (gdbarch, loc, NULL);
+      loc += INSN16_SIZE;
+
+      /* Assume that there is at most one conditional branch in the
+         atomic sequence.  If a branch is found, put a breakpoint in
+         its destination address.  */
+      switch (nanomips_insn_size (insn))
+	{
+	/* 32-bit instructions.  */
+	case 2 * INSN16_SIZE:
+	  insn <<= 16;
+	  insn |= nanomips_fetch_instruction (gdbarch, loc, NULL);
+	  loc += INSN16_SIZE;
+
+	  switch (micromips_op (insn >> 16))
+	    {
+	    case 0xa: /* BALC, BC */
+	      offset = ((insn & 1) << 24 | ((insn >> 1) & 0xffffff)) << 1;
+	      offset = (offset ^ 0x2000000) - 0x2000000;
+	      branch_bp = loc + offset;
+	      is_branch = 1;
+	      break;
+
+	    case 0x12:
+	      op = b12s4_op (insn);
+	      if (op == 0x8) /* BALRC, BALRSC */
+		return {}; /* Fall back to the standard single-step code. */
+	      else if (op == 0 || op == 1) /* JALRC JALRC.HB */
+		return {}; /* Fall back to the standard single-step code. */
+	      break;
+
+	    case 0x20: /* PP.SR */
+	      if (b12s5_op (insn) == 0x13) /* RESTORE.JRC */
+		return {}; /* Fall back to the standard single-step code. */
+	      break;
+
+	    case 0x22: /* P.BR1 */
+	    case 0x2a: /* P.BR2 */
+	      op = b14s2_op (insn);
+	      offset = ((insn & 1) << 13 | ((insn >> 1) & 0x1fff)) << 1;
+	      offset = (offset ^ 0x4000) - 0x4000;
+	      if (op == 0 /* BEQC, BNEC */
+		  || op == 2 /* BGEC, BLTC */
+		  || op == 3) /* BGEUC, BLTUC */
+		{
+		  branch_bp = loc + offset;
+		  is_branch = 1;
+		}
+	      break;
+
+	    case 0x32: /* P.BRI */
+	      op = b2s3_cc (insn >> 16);
+	      offset = ((insn & 1) << 10 | ((insn >> 1) & 0x3ff)) << 1;
+	      offset = (offset ^ 0x800) - 0x800;
+	      if (op == 0 /* BEQIC */
+		  || op == 2 /* BGEIC */
+		  || op == 3 /* BGEIUC */
+		  || op == 4 /* BNEIC */
+		  || op == 6 /* BLTIC */
+		  || op == 7 ) /* BLTIUC */
+		{
+		  branch_bp = loc + offset;
+		  is_branch = 1;
+		}
+	      break;
+
+	    case 0x3a: /* P.BZ */
+	      op = (insn & 0x80000); /* 20th bit */
+	      offset = ((insn & 1) << 19 | ((insn >> 1) & 0x7ffff)) << 1;
+	      offset = (offset ^ 0x100000) - 0x100000;
+	      if (op == 0 /* BEQZC */
+	          || op != 0 ) /* BNEZC */
+		{
+		  branch_bp = loc + offset;
+		  is_branch = 1;
+		}
+	      break;
+
+	    case 0x29: /* P.SC: bits 101001 */
+	      if (b8s7_op (insn) == 0x59) /* SC: bits 101001 1011 0 01 */
+		sc_found = 1;
+	      break;
+	    }
+	  break;
+
+	/* 16-bit instructions.  */
+	case INSN16_SIZE:
+	  switch (micromips_op (insn))
+	    {
+	    case 0x6: /* BC[16] */
+	    case 0xe: /* BALC[16] */
+	      offset = ((insn & 1) << 9 | ((insn >> 1) & 0x1ff)) << 1;
+	      offset = (offset ^ 0x400) - 0x400;
+	      branch_bp = loc + offset;
+	      is_branch = 1;
+	      break;
+
+	    case 0x7: /* RESTORE.JRC[16] */
+	      if ((insn & 1) == 0 && (insn & 0x20) == 0x20)
+		return {}; /* Fall back to the standard single-step code. */
+	      break;
+
+	    case 0x26: /* BEQZC[16] */
+	    case 0x2e: /* BNEZC[16] */
+	      offset = ((insn & 1) << 6 | ((insn >> 1) & 0x3f)) << 1;
+	      offset = (offset ^ 0x80) - 0x80;
+	      branch_bp = loc + offset;
+	      is_branch = 1;
+	      break;
+
+	    case 0x36: /* P16.BR P16.JRC */
+	      offset = insn & 0xf;
+	      /* BEQC[16] BEQC[16] */
+	      if (offset != 0)
+		{
+		  branch_bp = loc + offset;
+		  is_branch = 1;
+		}
+	      else if (offset == 0) /* JALRC[16] JRC */
+		return {}; /* Fall back to the standard single-step code. */
+	      break;
+	    }
+	  break;
+	}
+
+      if (is_branch)
+	{
+	  if (last_breakpoint >= 1)
+	    return {}; /* More than one branch found, fallback to the
+			 standard single-step code.  */
+	  breaks[1] = branch_bp;
+	  last_breakpoint++;
+	}
+    }
+  if (!sc_found)
+    return {};
+
+  /* Insert a breakpoint right after the end of the atomic sequence.  */
+  breaks[0] = loc;
+
+  /* Check for duplicated breakpoints.  Check also for a breakpoint
+     placed (branch instruction's destination) in the atomic sequence */
+  if (last_breakpoint && pc <= breaks[1] && breaks[1] <= breaks[0])
+    last_breakpoint = 0;
+
+  std::vector<CORE_ADDR> next_pcs;
+
+  /* Effectively inserts the breakpoints.  */
+  for (index = 0; index <= last_breakpoint; index++)
+    next_pcs.push_back (breaks[index]);
+
+  return next_pcs;
+}
+
+/* nanomips_software_single_step() is called just before we want to resume
+   the inferior, if we want to single-step it but there is no hardware
+   or kernel single-step support (nanoMIPS on GNU/Linux for example).  We find
+   the target of the coming instruction and breakpoint it.  */
+
+std::vector<CORE_ADDR>
+nanomips_software_single_step (struct regcache *regcache)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  CORE_ADDR pc, next_pc;
+
+  pc = regcache_read_pc (regcache);
+  std::vector<CORE_ADDR> next_pcs =
+			nanomips_deal_with_atomic_sequence (gdbarch, pc);
+
+  if (!next_pcs.empty ())
+    return next_pcs;
+
+  next_pc = nanomips_next_pc (regcache, pc);
+
+  return {next_pc};
+}
+
+/* This fencepost looks highly suspicious to me.  Removing it also
+   seems suspicious as it could affect remote debugging across serial
+   lines.  */
+
+static CORE_ADDR
+heuristic_proc_start (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR start_pc;
+  CORE_ADDR fence;
+  int instlen;
+  int seen_adjsp = 0;
+  struct inferior *inf;
+
+  pc = gdbarch_addr_bits_remove (gdbarch, pc);
+  start_pc = pc;
+  fence = start_pc - heuristic_fence_post;
+  if (start_pc == 0)
+    return 0;
+
+  if (heuristic_fence_post == -1 || fence < VM_MIN_ADDRESS)
+    fence = VM_MIN_ADDRESS;
+
+  instlen = INSN16_SIZE;
+
+  inf = current_inferior ();
+
+  /* Search back for previous return.  */
+  for (start_pc -= instlen;; start_pc -= instlen)
+    if (start_pc < fence)
+      {
+	/* It's not clear to me why we reach this point when
+	   stop_soon, but with this test, at least we
+	   don't print out warnings for every child forked (eg, on
+	   decstation).  22apr93 rich@cygnus.com.  */
+	if (inf->control.stop_soon == NO_STOP_QUIETLY)
+	  {
+	    static int blurb_printed = 0;
+
+	    warning (_("GDB can't find the start of the function at %s."),
+		     paddress (gdbarch, pc));
+
+	    if (!blurb_printed)
+	      {
+		/* This actually happens frequently in embedded
+		   development, when you first connect to a board
+		   and your stack pointer and pc are nowhere in
+		   particular.  This message needs to give people
+		   in that situation enough information to
+		   determine that it's no big deal.  */
+		gdb_printf ("\n\
+    GDB is unable to find the start of the function at %s\n\
+and thus can't determine the size of that function's stack frame.\n\
+This means that GDB may be unable to access that stack frame, or\n\
+the frames below it.\n\
+    This problem is most likely caused by an invalid program counter or\n\
+stack pointer.\n\
+    However, if you think GDB should simply search farther back\n\
+from %s for code which looks like the beginning of a\n\
+function, you can increase the range of the search using the `set\n\
+heuristic-fence-post' command.\n",
+			paddress (gdbarch, pc), paddress (gdbarch, pc));
+		blurb_printed = 1;
+	      }
+	  }
+
+	return 0;
+      }
+    else
+      {
+	ULONGEST insn;
+	int size;
+
+	/* On nanomips, SAVE is likely to be the start of a function.  */
+	insn = nanomips_fetch_instruction (gdbarch, pc, NULL);
+	size = nanomips_insn_size (insn);
+	if ((size == 2 && micromips_op (insn) == 0x7) ||
+	    (size == 4 && micromips_op (insn) == 0x20))
+	    break;
+      }
+
+  return start_pc;
+}
+
+/* On p32, argument passing in GPRs depends on the alignment of the type being
+   passed.  Return 1 if this type must be aligned to a doubleword boundary.  */
+
+static int
+type_needs_double_align (struct type *type)
+{
+  enum type_code typecode = type->code ();
+
+  if ((typecode == TYPE_CODE_FLT || typecode == TYPE_CODE_INT)
+      && TYPE_LENGTH (type) == 8)
+    return 1;
+  else if (typecode == TYPE_CODE_STRUCT)
+    {
+      if (type->num_fields () > 1)
+	return 0;
+      return type_needs_double_align (type->field (0).type ());
+    }
+  else if (typecode == TYPE_CODE_UNION)
+    {
+      int i, n;
+
+      n = type->num_fields ();
+      for (i = 0; i < n; i++)
+	if (type_needs_double_align (type->field (i).type ()))
+	  return 1;
+      return 0;
+    }
+  return 0;
+}
+
+/* Adjust the address downward (direction of stack growth) so that it
+   is correctly aligned for a new stack frame.  */
+static CORE_ADDR
+nanomips_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  return align_down (addr, 16);
+}
+
+/* Implement the "push_dummy_code" gdbarch method.  */
+
+static CORE_ADDR
+nanomips_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
+			  CORE_ADDR funaddr, struct value **args,
+			  int nargs, struct type *value_type,
+			  CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+			  struct regcache *regcache)
+{
+  /* Reserve enough room on the stack for our breakpoint instruction.  */
+  sp = sp - 4;
+  *bp_addr = sp;
+
+  /* Inferior resumes at the function entry point.  */
+  *real_pc = funaddr;
+
+  return sp;
+}
+
+/* p32, p64 ABI stuff.  */
+
+#define MAX_REG_ARGS	8	/* Maximum 8 arguments in registers */
+
+/* FIXME: Complete this once we have calling conventions set for nanomips */
+static CORE_ADDR
+nanomips_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+			  struct regcache *regcache, CORE_ADDR bp_addr,
+			  int nargs, struct value **args, CORE_ADDR sp,
+			  function_call_return_method return_method, CORE_ADDR struct_addr)
+{
+  int arg_gpr = 0, arg_fpr = 0;
+  int argnum;
+  int stack_offset = 0, stack_size = 0;
+  int seen_on_stack = 0;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR func_addr = find_function_addr (function, NULL);
+  int regsize = nanomips_abi_regsize (gdbarch);
+
+  /* Set the return address register to point to the entry point of
+     the program, where a breakpoint lies in wait.  */
+  regcache_cooked_write_signed (regcache, NANOMIPS_RA_REGNUM, bp_addr);
+
+  /* First ensure that the stack and structure return address (if any)
+     are properly aligned.  The stack has to be at least 64-bit
+     aligned even on 32-bit machines, because doubles must be 64-bit
+     aligned.  */
+
+  sp = align_down (sp, 16);
+  struct_addr = align_down (struct_addr, 16);
+
+  /* Calculate space required on the stack for the args.  */
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      struct type *arg_type = check_typedef (value_type (args[argnum]));
+
+      /* Align to double-word if necessary.  */
+      if (type_needs_double_align (arg_type))
+	stack_size = align_up (stack_size, NANOMIPS32_REGSIZE * 2);
+
+      /* Allocate space on the stack.  */
+      stack_size += align_up (TYPE_LENGTH (arg_type), NANOMIPS32_REGSIZE);
+    }
+  stack_size = align_up (stack_size, 16);
+
+  if (nanomips_debug)
+    gdb_printf (gdb_stdlog, "nanomips_push_dummy_call (stack_size=%d)\n", stack_size);
+
+  /* The struct_return pointer occupies the first parameter-passing reg.  */
+  if (return_method == return_method_struct)
+    {
+      if (nanomips_debug)
+	gdb_printf (gdb_stdlog,
+			    "  struct_return reg=%d %s\n",
+			    arg_gpr + NANOMIPS_A0_REGNUM,
+			    paddress (gdbarch, struct_addr));
+
+      regcache_cooked_write_unsigned (regcache, arg_gpr + NANOMIPS_A0_REGNUM,
+				      struct_addr);
+
+      /* occupy first argument reg */
+      arg_gpr++;
+    }
+
+  /* Now load as many as possible of the first arguments into
+     registers, and push the rest onto the stack.  Loop thru args
+     from first to last.  */
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      const gdb_byte *val;
+      gdb_byte valbuf[NANOMIPS64_REGSIZE];
+      struct value *arg = args[argnum];
+      struct type *arg_type = check_typedef (value_type (arg));
+      int len = TYPE_LENGTH (arg_type);
+      enum type_code typecode = arg_type->code ();
+
+      if (typecode == TYPE_CODE_STRUCT && arg_type->num_fields () == 1)
+      {
+          if ((arg_type->field (0).type ())->code () == TYPE_CODE_TYPEDEF)
+            {
+              struct type *type = check_typedef (arg_type->field (0).type ());
+              typecode = type->code ();
+              len = TYPE_LENGTH (arg_type);
+            }
+          else if ((arg_type->field (0).type ())->code () == TYPE_CODE_FLT)
+            {
+              typecode = TYPE_CODE_FLT;
+            }
+      }
+
+      /* The P32 ABI passes structures larger than 8 bytes by reference. */
+      if ((typecode == TYPE_CODE_ARRAY || typecode == TYPE_CODE_STRUCT
+          || typecode == TYPE_CODE_UNION || typecode == TYPE_CODE_COMPLEX)
+          && len > regsize * 2)
+        {
+          store_unsigned_integer (valbuf, regsize, byte_order,
+                value_address (arg));
+          typecode = TYPE_CODE_PTR;
+          len = 4;
+          val = valbuf;
+
+          if (nanomips_debug)
+            gdb_printf (gdb_stdlog, " push");
+        }
+          else
+        val = value_contents (arg).data ();
+
+
+      while (len > 0)
+	{
+	  int partial_len = (len < NANOMIPS32_REGSIZE ? len : NANOMIPS32_REGSIZE);
+	  int base_arg_reg;
+	  LONGEST regval;
+	  int use_stack = 0;
+
+	  /* Align the argument register for double and long long types.  */
+	  if ((arg_gpr < MAX_REG_ARGS) && (arg_gpr & 1) && (len == 8)
+        && ((typecode == TYPE_CODE_FLT
+        && FPU_TYPE(gdbarch) == NANOMIPS_FPU_SOFT)
+        || typecode == TYPE_CODE_INT))
+	    {
+	      arg_gpr++;
+	      stack_offset += 4;
+	    }
+
+    if (typecode == TYPE_CODE_STRUCT && (len <= 8 && len > 4) && arg_gpr == 7)
+      arg_gpr ++;
+
+	  /* double type occupies only one register.  */
+	  if (typecode == TYPE_CODE_FLT && len == 8)
+	    partial_len = (FPU_TYPE(gdbarch) == NANOMIPS_FPU_HARD ? 8 : 4);
+
+	  regval = extract_unsigned_integer (val, partial_len, byte_order);
+
+	  /* Check if any argument register is available.  */
+	  if (typecode == TYPE_CODE_FLT && FPU_TYPE(gdbarch) == NANOMIPS_FPU_HARD)
+	    {
+        if(arg_fpr < MAX_REG_ARGS)
+          {
+            if (nanomips_debug)
+              {
+                int r_num = arg_fpr + nanomips_fp_arg_regnum (gdbarch)
+                  + gdbarch_num_regs (gdbarch);
+                const char *r = nanomips_register_name (gdbarch, r_num);
+                gdb_printf (gdb_stdlog,
+                        "  argnum=%d,reg=%s,len=%d,val=%ld\n",
+                        argnum + 1, r, partial_len, regval);
+              }
+
+           /* Update the register with specified value.  */
+           regcache_cooked_write_unsigned (regcache,
+                    arg_fpr + nanomips_fp_arg_regnum (gdbarch),
+                    regval);
+            arg_fpr++;
+          }
+        else
+          use_stack = 1;
+	    }
+	  else
+	    {
+		    if (arg_gpr < MAX_REG_ARGS)
+          {
+            if (nanomips_debug)
+              {
+                int r_num = arg_gpr + NANOMIPS_A0_REGNUM
+                  + gdbarch_num_regs (gdbarch);
+                const char *r = nanomips_register_name (gdbarch, r_num);
+                gdb_printf (gdb_stdlog,
+                        "  argnum=%d,reg=%s,len=%d,val=%ld\n",
+                        argnum + 1, r, partial_len, regval);
+              }
+
+            /* Update the register with specified value.  */
+            regcache_cooked_write_unsigned (regcache,
+                     arg_gpr + NANOMIPS_A0_REGNUM, regval);
+            arg_gpr++;
+
+	        }
+	      else
+	        use_stack = 1;
+
+	    }
+
+	  if (use_stack)
+	    {
+	      CORE_ADDR addr;
+
+	      if (nanomips_debug)
+		{
+		  int i;
+		  LONGEST regval = extract_unsigned_integer (val, len,
+							     byte_order);
+		  gdb_printf (gdb_stdlog,
+				      "  argnum=%d,off=%d,len=%d,val=%ld\n",
+				      argnum + 1, stack_offset, partial_len,
+				      regval);
+		}
+
+	      addr = (sp - stack_size) + stack_offset;
+	      write_memory (addr, val, partial_len);
+
+	      seen_on_stack = 1;
+	      stack_offset += (partial_len <= NANOMIPS32_REGSIZE)
+                            ? NANOMIPS32_REGSIZE : partial_len;
+	      use_stack = 0;
+	    } /* argument on stack */
+
+	  val += partial_len;
+	  len -= partial_len;
+	}
+    }
+
+  if (seen_on_stack)
+    sp -= stack_size;
+
+  regcache_cooked_write_signed (regcache, NANOMIPS_SP_REGNUM, sp);
+
+  /* Return adjusted stack pointer.  */
+  return sp;
+}
+
+static enum return_value_convention
+nanomips_return_value (struct gdbarch *gdbarch, struct value *function,
+           struct type *type, struct regcache *regcache,
+           gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+  if ((type->code () == TYPE_CODE_ARRAY
+      || type->code () == TYPE_CODE_STRUCT
+      || type->code () == TYPE_CODE_COMPLEX)
+      && TYPE_LENGTH (type) > 2 * NANOMIPS32_REGSIZE)
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  else if (type->code () == TYPE_CODE_COMPLEX
+     && FPU_TYPE(gdbarch) == NANOMIPS_FPU_HARD)
+    {
+      gdb_assert (nanomips_regnum (gdbarch)->fpr != -1);
+
+      nanomips_xfer_register (gdbarch, regcache,
+			      (gdbarch_num_regs (gdbarch)
+			       + nanomips_regnum (gdbarch)->fpr
+			       + NANOMIPS_FP0_REGNUM),
+			      4, gdbarch_byte_order (gdbarch),
+			      readbuf, writebuf, 0);
+      nanomips_xfer_register (gdbarch, regcache,
+			      (gdbarch_num_regs (gdbarch)
+			       + nanomips_regnum (gdbarch)->fpr
+			       + NANOMIPS_FP0_REGNUM + 1),
+			      4, gdbarch_byte_order (gdbarch),
+			      readbuf, writebuf, 4);
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  else if (type->code () == TYPE_CODE_FLT
+     && FPU_TYPE(gdbarch) == NANOMIPS_FPU_HARD)
+    {
+      gdb_assert (nanomips_regnum (gdbarch)->fpr != -1);
+
+      nanomips_xfer_register (gdbarch, regcache,
+			      (gdbarch_num_regs (gdbarch)
+			       + nanomips_regnum (gdbarch)->fpr
+			       + NANOMIPS_FP0_REGNUM),
+			      TYPE_LENGTH (type), gdbarch_byte_order (gdbarch),
+			      readbuf, writebuf, 0);
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  else
+    {
+      int offset;
+      int regnum;
+      for (offset = 0, regnum = NANOMIPS_A0_REGNUM;
+     offset < TYPE_LENGTH (type);
+     offset += NANOMIPS32_REGSIZE, regnum++)
+  {
+    int xfer = NANOMIPS32_REGSIZE;
+    if (offset + xfer > TYPE_LENGTH (type))
+      xfer = TYPE_LENGTH (type) - offset;
+    if (nanomips_debug)
+      gdb_printf (gdb_stderr, "Return scalar+%d:%d in $%d\n",
+        offset, xfer, regnum);
+    nanomips_xfer_register (gdbarch, regcache,
+            gdbarch_num_regs (gdbarch) + regnum, xfer,
+            gdbarch_byte_order (gdbarch),
+            readbuf, writebuf, offset);
+  }
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+}
+
+/* Copy a 32-bit single-precision value from the current frame
+   into rare_buffer.  */
+
+static void
+read_fp_register_single (struct frame_info *frame, int regno,
+			 gdb_byte *rare_buffer)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int raw_size = register_size (gdbarch, regno);
+  int offset;
+  gdb_byte *raw_buffer = (gdb_byte *) alloca (raw_size);
+
+  if (!deprecated_frame_register_read (frame, regno, raw_buffer))
+    error (_("can't read register %d (%s)"),
+	   regno, gdbarch_register_name (gdbarch, regno));
+
+  /* We have a 64-bit value for this register.  Find the low-order 32 bits.  */
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+    offset = 4;
+  else
+    offset = 0;
+
+  memcpy (rare_buffer, raw_buffer + offset, 4);
+}
+
+/* Copy a 64-bit double-precision value from the current frame into
+   rare_buffer.  */
+
+static void
+read_fp_register_double (struct frame_info *frame, int regno,
+			 gdb_byte *rare_buffer)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+
+  /* We have a 64-bit value for this register, use all 64 bits.  */
+  if (!deprecated_frame_register_read (frame, regno, rare_buffer))
+      error (_("can't read register %d (%s)"),
+	     regno, gdbarch_register_name (gdbarch, regno));
+}
+
+static void
+print_fp_register (struct ui_file *file, struct frame_info *frame,
+		   int regnum)
+{		/* Do values for FP (float) regs.  */
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  gdb_byte *raw_buffer;
+  std::string flt_str, dbl_str;
+  struct value_print_options opts;
+
+  const struct type *flt_type = builtin_type (gdbarch)->builtin_float;
+  const struct type *dbl_type = builtin_type (gdbarch)->builtin_double;
+
+  gdb_assert (nanomips_regnum (gdbarch)->fpr != -1);
+
+  raw_buffer
+    = ((gdb_byte *)
+       alloca (2 * register_size (gdbarch,
+				  (nanomips_regnum (gdbarch)->fpr
+				   + NANOMIPS_FP0_REGNUM))));
+
+  gdb_printf (file, "%s:", gdbarch_register_name (gdbarch, regnum));
+  gdb_printf (file, "%*s",
+		    4 - (int) strlen (gdbarch_register_name (gdbarch, regnum)),
+		    "");
+
+  /* Eight byte registers: print each one as hex, float and double.  */
+  read_fp_register_single (frame, regnum, raw_buffer);
+  flt_str = target_float_to_string (raw_buffer, flt_type, "%-17.9g");
+
+  read_fp_register_double (frame, regnum, raw_buffer);
+  dbl_str = target_float_to_string (raw_buffer, dbl_type, "%-24.17g");
+
+  get_formatted_print_options (&opts, 'x');
+  print_scalar_formatted (raw_buffer,
+			  builtin_type (gdbarch)->builtin_uint64,
+			  &opts, 'g', file);
+
+  gdb_printf (file, " flt: %s", flt_str.c_str ());
+
+  gdb_printf (file, " dbl: %s", dbl_str.c_str ());
+}
+
+static void
+nanomips_print_register (struct ui_file *file, struct frame_info *frame,
+			 int regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct value_print_options opts;
+  struct value *val;
+
+  if (nanomips_float_register_p (gdbarch, regnum))
+    {
+      print_fp_register (file, frame, regnum);
+      return;
+    }
+
+  val = get_frame_register_value (frame, regnum);
+
+  gdb_puts (gdbarch_register_name (gdbarch, regnum), file);
+
+  /* The problem with printing numeric register names (r26, etc.) is that
+     the user can't use them on input.  Probably the best solution is to
+     fix it so that either the numeric or the funky (a2, etc.) names
+     are accepted on input.  */
+  if (regnum < NUMREGS)
+    gdb_printf (file, "(r%d): ", regnum);
+  else
+    gdb_printf (file, ": ");
+
+  get_formatted_print_options (&opts, 'x');
+  value_print_scalar_formatted (val, &opts, 0, file);
+}
+
+/* Print IEEE exception condition bits in FLAGS.  */
+
+static void
+print_fpu_flags (struct ui_file *file, int flags)
+{
+  if (flags & (1 << 0))
+    gdb_puts (" inexact", file);
+  if (flags & (1 << 1))
+    gdb_puts (" uflow", file);
+  if (flags & (1 << 2))
+    gdb_puts (" oflow", file);
+  if (flags & (1 << 3))
+    gdb_puts (" div0", file);
+  if (flags & (1 << 4))
+    gdb_puts (" inval", file);
+  if (flags & (1 << 5))
+    gdb_puts (" unimp", file);
+  gdb_putc ('\n', file);
+}
+
+/* Print interesting information about the floating point processor
+   (if present) or emulator.  */
+
+static void
+nanomips_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
+			   struct frame_info *frame, const char *args)
+{
+  int fcsr = nanomips_regnum (gdbarch)->fpr + NANOMIPS_FCSR_REGNUM;
+  enum fpu_type type = FPU_TYPE (gdbarch);
+  ULONGEST fcs = 0;
+  int i;
+
+  if (nanomips_regnum (gdbarch)->fpr == -1
+      || !read_frame_register_unsigned (frame, fcsr, &fcs))
+    type = NANOMIPS_FPU_NONE;
+
+  gdb_printf (file, "fpu type: %s\n",
+		    type == NANOMIPS_FPU_HARD ? "64bit hardware floating point"
+		    : type == NANOMIPS_FPU_SOFT ? "Software floating point"
+		    : "none / unused");
+
+  if (type == NANOMIPS_FPU_NONE)
+    return;
+
+  gdb_printf (file, "reg size: %d bits\n",
+		    register_size (gdbarch,
+				   (nanomips_regnum (gdbarch)->fpr
+				    + NANOMIPS_FP0_REGNUM)) * 8);
+
+  gdb_puts ("cond    :", file);
+  if (fcs & (1 << 23))
+    gdb_puts (" 0", file);
+  for (i = 1; i <= 7; i++)
+    if (fcs & (1 << (24 + i)))
+      gdb_printf (file, " %d", i);
+  gdb_putc ('\n', file);
+
+  gdb_puts ("cause   :", file);
+  print_fpu_flags (file, (fcs >> 12) & 0x3f);
+  fputs ("mask    :", stdout);
+  print_fpu_flags (file, (fcs >> 7) & 0x1f);
+  fputs ("flags   :", stdout);
+  print_fpu_flags (file, (fcs >> 2) & 0x1f);
+
+  gdb_puts ("rounding: ", file);
+  switch (fcs & 3)
+    {
+    case 0: gdb_puts ("nearest\n", file); break;
+    case 1: gdb_puts ("zero\n", file); break;
+    case 2: gdb_puts ("+inf\n", file); break;
+    case 3: gdb_puts ("-inf\n", file); break;
+    }
+
+  gdb_puts ("flush   :", file);
+  if (fcs & (1 << 21))
+    gdb_puts (" nearest", file);
+  if (fcs & (1 << 22))
+    gdb_puts (" override", file);
+  if (fcs & (1 << 24))
+    gdb_puts (" zero", file);
+  if ((fcs & (0xb << 21)) == 0)
+    gdb_puts (" no", file);
+  gdb_putc ('\n', file);
+
+  gdb_printf (file, "nan2008 : %s\n", fcs & (1 << 18) ? "yes" : "no");
+  gdb_printf (file, "abs2008 : %s\n", fcs & (1 << 19) ? "yes" : "no");
+  gdb_putc ('\n', file);
+
+  default_print_float_info (gdbarch, file, frame, args);
+}
+
+/* Replacement for generic do_registers_info.
+   Print regs in pretty columns.  */
+
+static int
+print_fp_register_row (struct ui_file *file, struct frame_info *frame,
+		       int regnum)
+{
+  gdb_printf (file, " ");
+  print_fp_register (file, frame, regnum);
+  gdb_printf (file, "\n");
+  return regnum + 1;
+}
+
+
+/* Print a row's worth of GP (int) registers, with name labels above.  */
+
+static int
+print_gp_register_row (struct ui_file *file, struct frame_info *frame,
+		       int start_regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  /* Do values for GP (int) regs.  */
+  gdb_byte raw_buffer[NANOMIPS64_REGSIZE];
+  int ncols = (nanomips_abi_regsize (gdbarch) == 8 ? 4 : 8);    /* display cols
+							       per row.  */
+  int col, byte;
+  int regnum;
+
+  /* For GP registers, we print a separate row of names above the vals.  */
+  for (col = 0, regnum = start_regnum;
+       col < ncols && regnum < gdbarch_num_regs (gdbarch)
+			       + gdbarch_num_pseudo_regs (gdbarch);
+       regnum++)
+    {
+      if (*gdbarch_register_name (gdbarch, regnum) == '\0')
+	continue;		/* unused register */
+      if (nanomips_float_register_p (gdbarch, regnum))
+	break;			/* End the row: reached FP register.  */
+      /* Large registers are handled separately.  */
+      if (register_size (gdbarch, regnum) > nanomips_abi_regsize (gdbarch))
+	{
+	  if (col > 0)
+	    break;		/* End the row before this register.  */
+
+	  /* Print this register on a row by itself.  */
+	  nanomips_print_register (file, frame, regnum);
+	  gdb_printf (file, "\n");
+	  return regnum + 1;
+	}
+      if (col == 0)
+	gdb_printf (file, "     ");
+      gdb_printf (file,
+			nanomips_abi_regsize (gdbarch) == 8 ? "%17s" : "%9s",
+			gdbarch_register_name (gdbarch, regnum));
+      col++;
+    }
+
+  if (col == 0)
+    return regnum;
+
+  /* Print the R0 to R31 names.  */
+  if ((start_regnum % gdbarch_num_regs (gdbarch)) < NUMREGS)
+    gdb_printf (file, "\n R%-4d",
+		      start_regnum % gdbarch_num_regs (gdbarch));
+  else
+    gdb_printf (file, "\n      ");
+
+  /* Now print the values in hex, 4 or 8 to the row.  */
+  for (col = 0, regnum = start_regnum;
+       col < ncols && regnum < gdbarch_num_regs (gdbarch)
+			       + gdbarch_num_pseudo_regs (gdbarch);
+       regnum++)
+    {
+      if (*gdbarch_register_name (gdbarch, regnum) == '\0')
+	continue;		/* unused register */
+      if (nanomips_float_register_p (gdbarch, regnum))
+	break;			/* End row: reached FP register.  */
+      if (register_size (gdbarch, regnum) > nanomips_abi_regsize (gdbarch))
+	break;			/* End row: large register.  */
+
+      /* OK: get the data in raw format.  */
+      if (!deprecated_frame_register_read (frame, regnum, raw_buffer))
+	error (_("can't read register %d (%s)"),
+	       regnum, gdbarch_register_name (gdbarch, regnum));
+      /* pad small registers */
+      for (byte = 0;
+	   byte < (nanomips_abi_regsize (gdbarch)
+		   - register_size (gdbarch, regnum)); byte++)
+	gdb_printf ("  ");
+      /* Now print the register value in hex, endian order.  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	for (byte =
+	     register_size (gdbarch, regnum) - register_size (gdbarch, regnum);
+	     byte < register_size (gdbarch, regnum); byte++)
+	  gdb_printf (file, "%02x", raw_buffer[byte]);
+      else
+	for (byte = register_size (gdbarch, regnum) - 1;
+	     byte >= 0; byte--)
+	  gdb_printf (file, "%02x", raw_buffer[byte]);
+      gdb_printf (file, " ");
+      col++;
+    }
+  if (col > 0)			/* ie. if we actually printed anything...  */
+    gdb_printf (file, "\n");
+
+  return regnum;
+}
+
+/* MIPS_DO_REGISTERS_INFO(): called by "info register" command.  */
+
+static void
+nanomips_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
+			       struct frame_info *frame, int regnum, int all)
+{
+  if (regnum != -1)		/* Do one specified register.  */
+    {
+      gdb_assert (regnum >= gdbarch_num_regs (gdbarch));
+      if (*(gdbarch_register_name (gdbarch, regnum)) == '\0')
+	error (_("Not a valid register for the current processor type"));
+
+      nanomips_print_register (file, frame, regnum);
+      gdb_printf (file, "\n");
+    }
+  else
+    /* Do all (or most) registers.  */
+    {
+      regnum = gdbarch_num_regs (gdbarch);
+      while (regnum < gdbarch_num_regs (gdbarch)
+		      + gdbarch_num_pseudo_regs (gdbarch))
+	{
+	  if (nanomips_float_register_p (gdbarch, regnum))
+	    {
+	      if (all)		/* True for "INFO ALL-REGISTERS" command.  */
+		regnum = print_fp_register_row (file, frame, regnum);
+	      else
+		regnum += NUMREGS;	/* Skip floating point regs.  */
+	    }
+	  else
+	    regnum = print_gp_register_row (file, frame, regnum);
+	}
+    }
+}
+
+/* To skip prologues, I use this predicate.  Returns either PC itself
+   if the code at PC does not look like a function prologue; otherwise
+   returns an address that (if we're lucky) follows the prologue.  If
+   LENIENT, then we must skip everything which is involved in setting
+   up the frame (it's OK to skip more, just so long as we don't skip
+   anything which might clobber the registers which are being saved.
+   We must skip more in the case where part of the prologue is in the
+   delay slot of a non-prologue instruction).  */
+
+static CORE_ADDR
+nanomips_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR limit_pc;
+  CORE_ADDR func_addr;
+
+  /* See if we can determine the end of the prologue via the symbol table.
+     If so, then return either PC, or the PC after the prologue, whichever
+     is greater.  */
+  if (find_pc_partial_function (pc, NULL, &func_addr, NULL))
+    {
+      CORE_ADDR post_prologue_pc
+	= skip_prologue_using_sal (gdbarch, func_addr);
+      if (post_prologue_pc != 0)
+	return std::max (pc, post_prologue_pc);
+    }
+
+  /* Can't determine prologue from the symbol table, need to examine
+     instructions.  */
+
+  /* Find an upper limit on the function prologue using the debug
+     information.  If the debug information could not be used to provide
+     that bound, then use an arbitrary large number as the upper bound.  */
+  limit_pc = skip_prologue_using_sal (gdbarch, pc);
+  if (limit_pc == 0)
+    limit_pc = pc + 100;          /* Magic.  */
+
+  return nanomips_scan_prologue (gdbarch, pc, limit_pc, NULL, NULL);
+}
+
+/* Implement the stack_frame_destroyed_p gdbarch method (nanoMIPS version).
+   This is a helper function for mips_stack_frame_destroyed_p.  */
+
+static int
+nanomips_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR func_addr = 0;
+  CORE_ADDR func_end = 0;
+  CORE_ADDR addr;
+  ULONGEST insn;
+  long offset;
+  int dreg;
+  int sreg;
+  int treg, op;
+  int loc;
+
+  if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+    return 0;
+
+  /* The nanoMIPS epilogue is max. 12 bytes long.  */
+  addr = func_end - 12;
+
+  if (addr < func_addr + 2)
+    addr = func_addr + 2;
+  if (pc < addr)
+    return 0;
+
+  for (; pc < func_end; pc += loc)
+    {
+      loc = 0;
+      insn = nanomips_fetch_instruction (gdbarch, pc, NULL);
+      loc += INSN16_SIZE;
+      switch (nanomips_insn_size (insn))
+	{
+	/* 48-bit instructions.  */
+	case 3 * INSN16_SIZE:
+	  if (micromips_op (insn) == 0x18)
+	    {
+	      op = b0s5_imm (insn);
+	      treg = b5s5_reg (insn);
+	      if (op == 0x0) /* LI48 xx, imm32 */
+		break; /* continue scan */
+	      else if (op == 0x1 /* ADDIU48 $sp, imm32 */
+		       && treg == NANOMIPS_SP_REGNUM)
+		return 1;
+	    }
+	  return 0;
+
+	/* 32-bit instructions.  */
+	case 2 * INSN16_SIZE:
+	  insn <<= 16;
+	  insn |= nanomips_fetch_instruction (gdbarch, pc + loc, NULL);
+	  loc += INSN16_SIZE;
+
+	  switch (micromips_op (insn >> 16))
+	    {
+	    case 0x0: /* PP.ADDIU bits 000000 */
+	      treg = b5s5_reg (insn >> 16);
+	      sreg = b0s5_reg (insn >> 16);
+	      if (sreg == treg
+		  && treg == NANOMIPS_SP_REGNUM) /* ADDIU $sp, $sp, imm */
+		return 1;
+	      else if (sreg == NANOMIPS_SP_REGNUM && treg == 30)
+		break; /* continue scan */
+	      return 0;
+
+	    case 0x8: /* _POOL32A0 */
+	      if ((insn & 0x1ff) == 0x150) /* ADDU */
+		{
+		  dreg = b11s5_reg (insn);
+		  sreg = b0s5_reg (insn >> 16);
+		  if ((dreg == sreg && sreg == NANOMIPS_SP_REGNUM)
+		      /* ADDU $sp, $sp, xx */
+		      || (dreg == NANOMIPS_SP_REGNUM && sreg == 30))
+		      /* ADDU $sp, $fp, xx */
+		    break; /* continue scan */
+		}
+	      else if (((insn & 0xffff) == 0xE37F) /* DERET */
+		       || ((insn & 0x1ffff) == 0xF37F) /* ERET */
+		       || ((insn & 0x1ffff) == 0x1F37F)) /* ERETNC */
+		return 1;
+	      return 0;
+
+	    case 0x20: /* P.U12 bits 100000 */
+	      if (b12s4_op (insn) == 0) /* ORI: bits 100000 0000 */
+		{
+		  sreg = b0s5_reg (insn >> 16);
+		  treg = b5s5_reg (insn >> 16);
+		  if (sreg == treg && treg == 3) /* ORI $v1, $v1, imm */
+		    break; /* continue scan */
+		}
+	      else if (b12s5_op (insn) == 0x13) /* RESTORE, RESTORE.JRC */
+		return 1;
+	      return 0;
+
+	    case 0x38: /* P.LUI bits 111000 */
+	      treg = b5s5_reg (insn >> 16);
+	      if ((insn & 2) == 0 /* LU20I bits 111000 0 */
+		  && treg == 3) /* LU20I $v1, imm */
+		break; /* continue scan */
+	      return 0;
+
+	    default:
+	      return 0;
+	    }
+	  break;
+
+	/* 16-bit instructions.  */
+	case INSN16_SIZE:
+	  switch (micromips_op (insn))
+	    {
+	    case 0x4: /* MOVE: bits 000100 */
+	      sreg = b0s5_reg (insn);
+	      dreg = b5s5_reg (insn);
+	      if (sreg == NANOMIPS_SP_REGNUM && dreg == 30)
+			/* MOVE  $fp, $sp */
+		return 1;
+	      return 0;
+
+	    case 0x7: /* RESTORE[16], RESTORE.JRC[16] */
+	      if ((insn & 0x20) == 0x20)
+		return 1;
+	      return 0;
+
+	    case 0x36: /* JRC[16] $31 */
+	      if ((insn & 0x1f) == 0 && b5s5_reg (insn) == 31)
+		return 1;
+	      return 0;
+
+	    default:
+		return 0;
+	    }
+	  break;
+	}
+    }
+
+  return 1;
+}
+
+/* Root of all "set nanomips "/"show nanomips " commands.  This will eventually be
+   used for all nanoMIPS-specific commands.  */
+
+static void
+show_nanomips_command (const char *args, int from_tty)
+{
+  help_list (shownanomipscmdlist, "show nanomips ", all_commands, gdb_stdout);
+}
+
+static void
+set_nanomips_command (const char *args, int from_tty)
+{
+  printf_unfiltered
+    ("\"set nanomips\" must be followed by an appropriate subcommand.\n");
+  help_list (setnanomipscmdlist, "set nanomips ", all_commands, gdb_stdout);
+}
+
+/* Just like reinit_frame_cache, but with the right arguments to be
+   callable as an sfunc.  */
+
+static void
+reinit_frame_cache_sfunc (const char *args, int from_tty,
+			  struct cmd_list_element *c)
+{
+  reinit_frame_cache ();
+}
+
+static int
+gdb_print_insn_nanomips_p32 (bfd_vma memaddr, struct disassemble_info *info)
+{
+  info->mach = bfd_mach_nanomipsisa32r6;
+  info->flavour = bfd_target_elf_flavour;
+  info->disassembler_options = "gpr-names=p32";
+
+  return print_insn_nanomips (memaddr, info);
+}
+
+static int
+gdb_print_insn_nanomips_p64 (bfd_vma memaddr, struct disassemble_info *info)
+{
+  info->mach = bfd_mach_nanomipsisa64r6;
+  info->flavour = bfd_target_elf_flavour;
+  info->disassembler_options = "gpr-names=p64";
+
+  return print_insn_nanomips (memaddr, info);
+}
+
+/* Implement the breakpoint_kind_from_pc gdbarch method.  */
+
+static int
+nanomips_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
+{
+  CORE_ADDR pc = *pcptr;
+  ULONGEST insn;
+  int status;
+
+  insn = nanomips_fetch_instruction (gdbarch, pc, &status);
+  if (status || (nanomips_insn_size (insn) == 2))
+    return NANOMIPS_BP_KIND_16;
+  else
+    return NANOMIPS_BP_KIND_32;
+}
+
+/* Implement the sw_breakpoint_from_kind gdbarch method.  */
+
+static const gdb_byte *
+nanomips_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
+{
+  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+
+  switch (kind)
+    {
+    case NANOMIPS_BP_KIND_16:
+      {
+	static gdb_byte be16_break[] = { 0x10, 0x10 };
+	static gdb_byte le16_break[] = { 0x10, 0x10 };
+
+	*size = 2;
+
+	if (byte_order_for_code == BFD_ENDIAN_BIG)
+	  return be16_break;
+	else
+	  return le16_break;
+      }
+    case NANOMIPS_BP_KIND_32:
+      {
+	static gdb_byte be32_break[] = { 0, 0x10, 0, 0 };
+	static gdb_byte le32_break[] = { 0x10, 0, 0, 0 };
+
+	*size = 4;
+	if (byte_order_for_code == BFD_ENDIAN_BIG)
+	  return be32_break;
+	else
+	  return le32_break;
+      }
+    default:
+      gdb_assert_not_reached ("unexpected nanomips breakpoint kind");
+    };
+}
+
+/* Convert a dbx stab register number (from `r' declaration) to a GDB
+   [1 * gdbarch_num_regs .. 2 * gdbarch_num_regs) REGNUM.  */
+
+static int
+nanomips_stab_reg_to_regnum (struct gdbarch *gdbarch, int num)
+{
+  int regnum;
+  if (num >= 0 && num < 32)
+    regnum = num;
+  else if (nanomips_regnum (gdbarch)->fpr != -1 && num >= 36 && num < 70)
+    regnum = num + nanomips_regnum (gdbarch)->fpr + NANOMIPS_FP0_REGNUM - 36;
+  else if (nanomips_regnum (gdbarch)->dsp != -1 && num >= 70 && num < 78)
+    regnum
+      = num + nanomips_regnum (gdbarch)->dsp + NANOMIPS_DSPHI0_REGNUM - 70;
+  else
+    return -1;
+  return gdbarch_num_regs (gdbarch) + regnum;
+}
+
+
+/* Convert a dwarf, dwarf2, or ecoff register number to a GDB [1 *
+   gdbarch_num_regs .. 2 * gdbarch_num_regs) REGNUM.  */
+
+static int
+nanomips_dwarf_dwarf2_ecoff_reg_to_regnum (struct gdbarch *gdbarch, int num)
+{
+  int regnum;
+  if (num >= 0 && num < 32)
+    regnum = num;
+  else if (nanomips_regnum (gdbarch)->fpr != -1 && num >= 32 && num < 64)
+    regnum = num + nanomips_regnum (gdbarch)->fpr + NANOMIPS_FP0_REGNUM - 32;
+  else if (nanomips_regnum (gdbarch)->dsp != -1 && num >= 64 && num < 72)
+    regnum
+      = num + nanomips_regnum (gdbarch)->dsp + NANOMIPS_DSPHI0_REGNUM - 64;
+  else
+    return -1;
+  return gdbarch_num_regs (gdbarch) + regnum;
+}
+
+static int
+nanomips_register_sim_regno (struct gdbarch *gdbarch, int regnum)
+{
+  /* Only makes sense to supply raw registers.  */
+  gdb_assert (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch));
+  /* FIXME: cagney/2002-05-13: Need to look at the pseudo register to
+     decide if it is valid.  Should instead define a standard sim/gdb
+     register numbering scheme.  */
+  if (gdbarch_register_name (gdbarch,
+			     gdbarch_num_regs (gdbarch) + regnum) != NULL
+      && gdbarch_register_name (gdbarch,
+			        gdbarch_num_regs (gdbarch)
+				+ regnum)[0] != '\0')
+    return regnum;
+  else
+    return LEGACY_SIM_REGNO_IGNORE;
+}
+
+
+/* Convert an integer into an address.  Extracting the value signed
+   guarantees a correctly sign extended address.  */
+
+static CORE_ADDR
+nanomips_integer_to_address (struct gdbarch *gdbarch,
+			     struct type *type, const gdb_byte *buf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  return extract_signed_integer (buf, TYPE_LENGTH (type), byte_order);
+}
+
+/* Dummy virtual frame pointer method.  This is no more or less accurate
+   than most other architectures; we just need to be explicit about it,
+   because the pseudo-register gdbarch_sp_regnum will otherwise lead to
+   an assertion failure.  */
+
+static void
+nanomips_virtual_frame_pointer (struct gdbarch *gdbarch,
+				CORE_ADDR pc, int *reg, LONGEST *offset)
+{
+  *reg = NANOMIPS_SP_REGNUM;
+  *offset = 0;
+}
+
+static struct gdbarch *
+nanomips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  static const char *const mips_gprs[] = {
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+    "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+    "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+  };
+  static const char *const mips_fprs[] = {
+    "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 mips_dsprs[] = {
+    "hi0", "lo0", "hi1", "lo1", "hi2", "lo2", "hi3", "lo3"
+  };
+  const struct tdesc_feature *feature;
+  struct gdbarch *gdbarch;
+  struct nanomips_gdbarch_tdep *tdep;
+  int elf_flags;
+  enum nanomips_abi nanomips_abi, found_abi;
+  int i, num_regs;
+  enum fpu_type fpu_type;
+  tdesc_arch_data_up tdesc_data;
+  const struct target_desc *tdesc = info.target_desc;
+  int elf_fpu_type = Val_GNU_NANOMIPS_ABI_FP_ANY;
+  struct nanomips_regnum nanomips_regnum, *regnum;
+  int register_size;
+  int valid_p;
+
+  num_regs = 0;
+
+  nanomips_regnum.cause = -1;
+  nanomips_regnum.status = -1;
+  nanomips_regnum.badvaddr = -1;
+  nanomips_regnum.fpr = -1;
+  nanomips_regnum.dsp = -1;
+  nanomips_regnum.restart = -1;
+
+  /* If there's no target description, then use the default.  */
+  if (!tdesc_has_registers (tdesc))
+    tdesc = tdesc_nanomips;
+
+  /* The CPU feature and the registers within are mandatory.  */
+  feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.cpu");
+  if (feature == NULL)
+    return NULL;
+
+  tdesc_data = tdesc_data_alloc ();
+
+  valid_p = 1;
+  for (i = 0; i < 32; i++, num_regs++)
+    valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs,
+					mips_gprs[i]);
+  valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs++, "pc");
+  if (!valid_p)
+      return NULL;
+  register_size = tdesc_register_bitsize (feature, "r0") / 8;
+
+  /* All the remaining target description features are optional.  */
+
+  /* Check for and assign a number to the syscall restart PC register.  */
+  feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.linux");
+  if (feature != NULL)
+    {
+      if (tdesc_numbered_register (feature, tdesc_data.get (), num_regs, "restart"))
+	nanomips_regnum.restart = num_regs++;
+
+      /* Check for and assign numbers to particular CP0 registers.
+	 These are only special and need known numbers with Linux
+	 targets, due to the use in signal frames, etc.  Bare metal
+	 stubs can simply include them along with other CP0 registers.  */
+      feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.cp0");
+      if (feature != NULL)
+	{
+	  if (tdesc_numbered_register (feature, tdesc_data.get (), num_regs,
+				       "badvaddr"))
+	    nanomips_regnum.badvaddr = num_regs++;
+	  if (tdesc_numbered_register (feature, tdesc_data.get (), num_regs,
+				       "status"))
+	    nanomips_regnum.status = num_regs++;
+	  if (tdesc_numbered_register (feature, tdesc_data.get (), num_regs,
+				       "cause"))
+	    nanomips_regnum.cause = num_regs++;
+	}
+    }
+
+  /* Check for and assign numbers to FPU registers.  */
+  feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.fpu");
+  if (feature != NULL)
+    {
+      nanomips_regnum.fpr = num_regs;
+      for (i = 0; i < 32; i++, num_regs++)
+	valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs,
+					    mips_fprs[i]);
+      valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs++,
+					  "fcsr");
+      valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs++,
+					  "fir");
+      if (!valid_p)
+      return NULL;
+    }
+
+  /* Check for and assign numbers to DSP registers.  */
+  feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.dsp");
+  if (feature != NULL)
+    {
+      nanomips_regnum.dsp = num_regs;
+      for (i = 0; i < 8; i++, num_regs++)
+	valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs,
+					    mips_dsprs[i]);
+      valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs++,
+					  "dspctl");
+      if (!valid_p)
+        return NULL;
+    }
+
+  /* First of all, extract the elf_flags, if available.  */
+  if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else if (arches != NULL)
+    elf_flags = ((struct nanomips_gdbarch_tdep*) gdbarch_tdep (arches->gdbarch))->elf_flags;
+  else
+    elf_flags = 0;
+
+  if (gdbarch_debug)
+    gdb_printf (gdb_stdlog,
+			"nanomips_gdbarch_init: elf_flags = 0x%08x\n",
+			elf_flags);
+
+  /* Check ELF_FLAGS to see if it specifies the ABI being used.  */
+  switch ((elf_flags & EF_NANOMIPS_ABI))
+    {
+    case E_NANOMIPS_ABI_P32:
+      found_abi = NANOMIPS_ABI_P32;
+      break;
+    case E_NANOMIPS_ABI_P64:
+      found_abi = NANOMIPS_ABI_P64;
+      break;
+    default:
+      found_abi = NANOMIPS_ABI_UNKNOWN;
+      break;
+    }
+
+  /* If we have no useful BFD information, use the ABI from the last
+     nanoMIPS architecture (if there is one).  */
+  if (found_abi == NANOMIPS_ABI_UNKNOWN && info.abfd == NULL && arches != NULL)
+    found_abi = ((struct nanomips_gdbarch_tdep*) gdbarch_tdep (arches->gdbarch))->found_abi;
+
+  /* Try the architecture for any hint of the correct ABI.  */
+  if (found_abi == NANOMIPS_ABI_UNKNOWN
+      && info.bfd_arch_info != NULL
+      && info.bfd_arch_info->arch == bfd_arch_nanomips)
+    {
+      switch (info.bfd_arch_info->mach)
+	{
+	case bfd_mach_nanomipsisa32r6:
+	  found_abi = NANOMIPS_ABI_P32;
+	  break;
+	case bfd_mach_nanomipsisa64r6:
+	  found_abi = NANOMIPS_ABI_P64;
+	  break;
+	}
+    }
+
+  /* Default 64-bit objects to P64 instead of P32.  */
+  if (found_abi == NANOMIPS_ABI_UNKNOWN
+      && info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour
+      && elf_elfheader (info.abfd)->e_ident[EI_CLASS] == ELFCLASS64)
+    found_abi = NANOMIPS_ABI_P64;
+
+  if (gdbarch_debug)
+    gdb_printf (gdb_stdlog, "nanomips_gdbarch_init: found_abi = %d\n",
+			found_abi);
+
+  /* Now that we have found what the ABI for this binary would be,
+     check whether the user is overriding it.  */
+  if (found_abi != NANOMIPS_ABI_UNKNOWN)
+    nanomips_abi = found_abi;
+  else
+    nanomips_abi = NANOMIPS_ABI_P32;
+  if (gdbarch_debug)
+    gdb_printf (gdb_stdlog,
+			"nanomips_gdbarch_init: nanomips_abi = %d\n",
+			nanomips_abi);
+
+  /* Determine the nanoMIPS FPU type.  */
+  if (info.abfd
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    {
+      Elf_Internal_ABIFlags_v0 *abiflags;
+      abiflags = bfd_nanomips_elf_get_abiflags (info.abfd);
+      if (abiflags != NULL)
+	elf_fpu_type = abiflags->fp_abi;
+    }
+
+  if (elf_fpu_type != Val_GNU_NANOMIPS_ABI_FP_ANY)
+    {
+      switch (elf_fpu_type)
+	{
+	case Val_GNU_NANOMIPS_ABI_FP_SOFT:
+	  fpu_type = NANOMIPS_FPU_SOFT;
+	  break;
+	default:
+	  fpu_type = NANOMIPS_FPU_HARD;
+	  break;
+	}
+    }
+  else if (arches != NULL)
+    fpu_type = ((struct nanomips_gdbarch_tdep*) gdbarch_tdep (arches->gdbarch))->fpu_type;
+  else
+    fpu_type = NANOMIPS_FPU_HARD;
+
+  if (gdbarch_debug)
+    gdb_printf (gdb_stdlog,
+			"nanomips_gdbarch_init: fpu_type = %d\n", fpu_type);
+
+  /* Check for blatant incompatibilities.  */
+
+  /* If we have only 32-bit registers, then we can't debug a 64-bit ABI.  */
+  if (register_size == 4 && nanomips_abi != NANOMIPS_ABI_P32)
+    {
+      return NULL;
+    }
+
+  /* Try to find a pre-existing architecture.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      /* nanoMIPS needs to be pedantic about which ABI and the compressed
+         ISA variation the object is using.  */
+      if (((struct nanomips_gdbarch_tdep*) gdbarch_tdep (arches->gdbarch))->elf_flags != elf_flags)
+	continue;
+      if (((struct nanomips_gdbarch_tdep*) gdbarch_tdep (arches->gdbarch))->nanomips_abi != nanomips_abi)
+	continue;
+      /* Be pedantic about which FPU is selected.  */
+      if (((struct nanomips_gdbarch_tdep*) gdbarch_tdep (arches->gdbarch))->fpu_type != fpu_type)
+	continue;
+
+      return arches->gdbarch;
+    }
+
+  /* Need a new architecture.  Fill in a target specific vector.  */
+  tdep = XNEW (struct nanomips_gdbarch_tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+  tdep->elf_flags = elf_flags;
+  tdep->found_abi = found_abi;
+  tdep->nanomips_abi = nanomips_abi;
+  tdep->fpu_type = fpu_type;
+  tdep->register_size = register_size;
+
+  /* Initially set everything according to the default ABI/ISA.  */
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 32);
+  set_gdbarch_float_bit (gdbarch, 32);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_register_reggroup_p (gdbarch, nanomips_register_reggroup_p);
+  set_gdbarch_pseudo_register_read (gdbarch, nanomips_pseudo_register_read);
+  set_gdbarch_pseudo_register_write (gdbarch, nanomips_pseudo_register_write);
+  set_gdbarch_ax_pseudo_register_collect (gdbarch,
+					  nanomips_ax_pseudo_register_collect);
+  set_gdbarch_ax_pseudo_register_push_stack
+      (gdbarch, nanomips_ax_pseudo_register_push_stack);
+
+  tdep->default_mask_address_p = 0;
+
+  set_gdbarch_push_dummy_call (gdbarch, nanomips_push_dummy_call);
+  set_gdbarch_return_value (gdbarch, nanomips_return_value);
+
+  switch (nanomips_abi)
+    {
+    case NANOMIPS_ABI_P32:
+      set_gdbarch_long_bit (gdbarch, 32);
+      set_gdbarch_ptr_bit (gdbarch, 32);
+      set_gdbarch_long_long_bit (gdbarch, 64);
+      break;
+    case NANOMIPS_ABI_P64:
+      set_gdbarch_long_bit (gdbarch, 64);
+      set_gdbarch_ptr_bit (gdbarch, 64);
+      set_gdbarch_long_long_bit (gdbarch, 64);
+      set_gdbarch_long_double_bit (gdbarch, 128);
+      set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, _("unknown ABI in switch"));
+    }
+
+  set_gdbarch_read_pc (gdbarch, nanomips_read_pc);
+  set_gdbarch_write_pc (gdbarch, nanomips_write_pc);
+
+  /* Add/remove bits from an address.  The nanoMIPS needs be careful to
+     ensure that all 32 bit addresses are sign extended to 64 bits.  */
+  set_gdbarch_addr_bits_remove (gdbarch, nanomips_addr_bits_remove);
+
+  /* Unwind the frame.  */
+  set_gdbarch_unwind_pc (gdbarch, nanomips_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, nanomips_unwind_sp);
+  set_gdbarch_dummy_id (gdbarch, nanomips_dummy_id);
+
+  /* Map debug register numbers onto internal register numbers.  */
+  set_gdbarch_stab_reg_to_regnum (gdbarch, nanomips_stab_reg_to_regnum);
+  set_gdbarch_ecoff_reg_to_regnum (gdbarch,
+				   nanomips_dwarf_dwarf2_ecoff_reg_to_regnum);
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch,
+				    nanomips_dwarf_dwarf2_ecoff_reg_to_regnum);
+  set_gdbarch_register_sim_regno (gdbarch, nanomips_register_sim_regno);
+
+  /* nanoMIPS version of CALL_DUMMY.  */
+
+  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+  set_gdbarch_push_dummy_code (gdbarch, nanomips_push_dummy_code);
+  set_gdbarch_frame_align (gdbarch, nanomips_frame_align);
+
+  set_gdbarch_print_float_info (gdbarch, nanomips_print_float_info);
+
+  set_gdbarch_convert_register_p (gdbarch, nanomips_convert_register_p);
+  set_gdbarch_register_to_value (gdbarch, nanomips_register_to_value);
+  set_gdbarch_value_to_register (gdbarch, nanomips_value_to_register);
+
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_breakpoint_kind_from_pc (gdbarch,
+				       nanomips_breakpoint_kind_from_pc);
+  set_gdbarch_sw_breakpoint_from_kind (gdbarch,
+				       nanomips_sw_breakpoint_from_kind);
+
+  set_gdbarch_skip_prologue (gdbarch, nanomips_skip_prologue);
+
+  set_gdbarch_stack_frame_destroyed_p (gdbarch,
+				       nanomips_stack_frame_destroyed_p);
+
+  set_gdbarch_pointer_to_address (gdbarch, signed_pointer_to_address);
+  set_gdbarch_address_to_pointer (gdbarch, address_to_signed_pointer);
+  set_gdbarch_integer_to_address (gdbarch, nanomips_integer_to_address);
+
+  set_gdbarch_print_registers_info (gdbarch, nanomips_print_registers_info);
+
+  if (nanomips_abi == NANOMIPS_ABI_P64)
+    set_gdbarch_print_insn (gdbarch, gdb_print_insn_nanomips_p64);
+  else
+    set_gdbarch_print_insn (gdbarch, gdb_print_insn_nanomips_p32);
+
+  /* FIXME: cagney/2003-08-29: The macros target_have_steppable_watchpoint,
+     HAVE_NONSTEPPABLE_WATCHPOINT, and target_have_continuable_watchpoint
+     need to all be folded into the target vector.  Since they are
+     being used as guards for target_stopped_by_watchpoint, why not have
+     target_stopped_by_watchpoint return the type of watchpoint that the code
+     is sitting on?  */
+  set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
+
+  /* Virtual tables.  */
+  set_gdbarch_vbit_in_delta (gdbarch, 0);
+
+  /* Hook in OS ABI-specific overrides, if they have been registered.  */
+  info.target_desc = tdesc;
+  info.tdesc_data = tdesc_data.get ();
+  gdbarch_init_osabi (info, gdbarch);
+
+  /* Unwind the frame.  */
+  dwarf2_append_unwinders (gdbarch);
+  frame_unwind_append_unwinder (gdbarch, &nanomips_frame_unwind);
+  frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
+  frame_base_append_sniffer (gdbarch, nanomips_frame_base_sniffer);
+
+  regnum = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct nanomips_regnum);
+  *regnum = nanomips_regnum;
+  tdep->regnum = regnum;
+
+  set_gdbarch_num_regs (gdbarch, num_regs);
+  set_tdesc_pseudo_register_type (gdbarch, nanomips_pseudo_register_type);
+  tdesc_use_registers (gdbarch, info.target_desc, std::move (tdesc_data));
+
+  /* Override the normal target description methods to handle our
+     dual real and pseudo registers.  */
+  set_gdbarch_register_name (gdbarch, nanomips_register_name);
+  set_gdbarch_register_reggroup_p (gdbarch,
+				   nanomips_tdesc_register_reggroup_p);
+
+  /* The target description may have adjusted num_regs, fetch the final
+     value and set pc_regnum and sp_regnum now that it has been fixed.  */
+  num_regs = gdbarch_num_regs (gdbarch);
+  set_gdbarch_num_pseudo_regs (gdbarch, num_regs);
+  set_gdbarch_pc_regnum (gdbarch, NANOMIPS_PC_REGNUM + num_regs);
+  set_gdbarch_sp_regnum (gdbarch, NANOMIPS_SP_REGNUM + num_regs);
+  if (regnum->fpr != -1)
+    set_gdbarch_fp0_regnum (gdbarch, regnum->fpr + NANOMIPS_FP0_REGNUM);
+  set_gdbarch_virtual_frame_pointer (gdbarch, nanomips_virtual_frame_pointer);
+
+  return gdbarch;
+}
+
+static void
+nanomips_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
+{
+  struct nanomips_gdbarch_tdep *tdep = (struct nanomips_gdbarch_tdep*) gdbarch_tdep (gdbarch);
+  if (tdep != NULL)
+    {
+      int ef_mips_arch;
+      int ef_mips_32bitmode;
+      /* Determine the ISA.  */
+      switch (tdep->elf_flags & EF_NANOMIPS_ARCH)
+	{
+	case E_NANOMIPS_ARCH_32R6:
+	  ef_mips_arch = 1;
+	  break;
+	case E_NANOMIPS_ARCH_64R6:
+	  ef_mips_arch = 2;
+	  break;
+	default:
+	  ef_mips_arch = 0;
+	  break;
+	}
+      /* Determine the size of a pointer.  */
+      ef_mips_32bitmode = (tdep->elf_flags & EF_NANOMIPS_32BITMODE);
+      gdb_printf (file,
+			  "nanomips_dump_tdep: tdep->elf_flags = 0x%x\n",
+			  tdep->elf_flags);
+      gdb_printf (file,
+			  "nanomips_dump_tdep: ef_mips_32bitmode = %d\n",
+			  ef_mips_32bitmode);
+      gdb_printf (file,
+			  "nanomips_dump_tdep: ef_mips_arch = %d\n",
+			  ef_mips_arch);
+      gdb_printf (file,
+			  "nanomips_dump_tdep: tdep->nanomips_abi = %d (%s)\n",
+			  tdep->nanomips_abi,
+			  nanomips_abi_strings[tdep->nanomips_abi]);
+      gdb_printf (file,
+			  "nanomips_dump_tdep: "
+			  "nanomips_mask_address_p() %d (default %d)\n",
+			  nanomips_mask_address_p (tdep),
+			  tdep->default_mask_address_p);
+    }
+
+  gdb_printf (file,
+		      "nanomips_dump_tdep: FPU_TYPE = %d (%s)\n",
+		      FPU_TYPE (gdbarch),
+		      (FPU_TYPE (gdbarch) == NANOMIPS_FPU_NONE ? "unknown"
+		       : FPU_TYPE (gdbarch) == NANOMIPS_FPU_HARD ?
+						"64bit hardware floating point"
+		       : FPU_TYPE (gdbarch) == NANOMIPS_FPU_SOFT ?
+						"Software floating point"
+		       : "???"));
+}
+
+void _initialize_nanomips_tdep(); /* -Wmissing-prototypes */
+
+void
+_initialize_nanomips_tdep ()
+{
+  gdbarch_register (bfd_arch_nanomips, nanomips_gdbarch_init,
+		    nanomips_dump_tdep);
+
+  initialize_tdesc_nanomips ();
+
+  nanomips_pdr_data = register_objfile_data ();
+
+  /* Add root prefix command for all "set/show nanomips" commands.  */
+  add_prefix_cmd ("nanomips", no_class, set_nanomips_command,
+		  _("Various nanoMIPS specific commands."),
+		  &setnanomipscmdlist, 0, &setlist);
+
+  add_prefix_cmd ("nanomips", no_class, show_nanomips_command,
+		  _("Various nanoMIPS specific commands."),
+		  &shownanomipscmdlist, 0, &showlist);
+
+  /* We really would like to have both "0" and "unlimited" work, but
+     command.c doesn't deal with that.  So make it a var_zinteger
+     because the user can always use "999999" or some such for unlimited.  */
+  add_setshow_zinteger_cmd ("heuristic-fence-post", class_support,
+			    &heuristic_fence_post, _("\
+Set the distance searched for the start of a function."), _("\
+Show the distance searched for the start of a function."), _("\
+If you are debugging a stripped executable, GDB needs to search through the\n\
+program for the start of a function.  This command sets the distance of the\n\
+search.  The only need to set it is when debugging a stripped executable."),
+			    reinit_frame_cache_sfunc,
+			    NULL, /* FIXME: i18n: The distance searched for
+				     the start of a function is %s.  */
+			    &setlist, &showlist);
+
+  /* Allow the user to control whether the upper bits of 64-bit
+     addresses should be zeroed.  */
+  add_setshow_auto_boolean_cmd ("mask-address", no_class,
+				&mask_address_var, _("\
+Set zeroing of upper 32 bits of 64-bit addresses."), _("\
+Show zeroing of upper 32 bits of 64-bit addresses."), _("\
+Use \"on\" to enable the masking, \"off\" to disable it and \"auto\" to\n\
+allow GDB to determine the correct value."),
+				NULL, show_mask_address,
+				&setnanomipscmdlist, &shownanomipscmdlist);
+
+  /* Debug this files internals.  */
+  add_setshow_zuinteger_cmd ("nanomips", class_maintenance,
+			     &nanomips_debug, _("\
+Set nanomips debugging."), _("\
+Show nanomips debugging."), _("\
+When non-zero, nanomips specific debugging is enabled."),
+			     NULL,
+			     NULL, /* FIXME: i18n: Mips debugging is
+				      currently %s.  */
+			     &setdebuglist, &showdebuglist);
+}
diff --git a/gdb/nanomips-tdep.h b/gdb/nanomips-tdep.h
new file mode 100644
index 00000000000..6bced514e85
--- /dev/null
+++ b/gdb/nanomips-tdep.h
@@ -0,0 +1,144 @@
+/* Target-dependent header for the nanoMIPS architecture, for GDB,
+   the GNU Debugger.
+
+   Copyright (C) 2002-2022 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef NANOMIPS_TDEP_H
+#define NANOMIPS_TDEP_H
+
+#include "objfiles.h"
+
+struct gdbarch;
+
+/* All the possible nanoMIPS ABIs.  */
+enum nanomips_abi
+  {
+    NANOMIPS_ABI_UNKNOWN = 0,
+    NANOMIPS_ABI_P32,
+    NANOMIPS_ABI_P64,
+  };
+
+/* Return the nanoMIPS ABI associated with GDBARCH.  */
+enum nanomips_abi nanomips_abi (struct gdbarch *gdbarch);
+
+/* Return the current index for various nanoMIPS registers.  */
+struct nanomips_regnum
+{
+  int fpr;		/* Floating-point unit registers.  */
+  int badvaddr;		/* Bad vaddr for addressing exception.  */
+  int status;		/* Status register.  */
+  int cause;		/* Describes last exception.  */
+  int dsp;		/* DSP registers.  */
+  int restart;		/* Linux syscall restart flag.  */
+};
+
+extern const struct nanomips_regnum *nanomips_regnum (struct gdbarch *gdbarch);
+
+/* nanoMIPS floating-point operations.  */
+
+enum fpu_type
+{
+  NANOMIPS_FPU_NONE,	/* Unknown floating point.  */
+  NANOMIPS_FPU_HARD,	/* Double precision floating point.  */
+  NANOMIPS_FPU_SOFT	/* Software floating point.  */
+};
+
+/* nanoMIPS specific per-architecture information.  */
+struct nanomips_gdbarch_tdep : gdbarch_tdep
+{
+  /* from the elf header */
+  int elf_flags;
+
+  /* nanomips options */
+  enum nanomips_abi nanomips_abi;
+  enum nanomips_abi found_abi;
+  enum fpu_type fpu_type;
+  int mips_last_arg_regnum;
+  int default_mask_address_p;
+
+  /* Indexes for various registers determined dynamically at run time.
+     This contains the "public" fields.  Don't add any that do not need
+     to be public.  */
+  struct nanomips_regnum *regnum;
+
+  /* The size of register data available from the target.  */
+  int register_size;
+
+  /* Return the expected next PC if FRAME is stopped at a syscall
+     instruction.  */
+  CORE_ADDR (*syscall_next_pc) (struct frame_info *frame, CORE_ADDR pc);
+};
+
+/* Register numbers of various important registers from the fixed
+   GPR+PC register set that is always present.  The rest is determined
+   dynamically at run time and held in `gdbarch_tdep->regnum'.  */
+
+enum
+{
+  NANOMIPS_ZERO_REGNUM = 0,
+  NANOMIPS_AT_REGNUM = 1,
+  NANOMIPS_T4_REGNUM = 2,
+  NANOMIPS_A0_REGNUM = 4,
+  NANOMIPS_GP_REGNUM = 28,
+  NANOMIPS_SP_REGNUM = 29,
+  NANOMIPS_FP_REGNUM = 30,
+  NANOMIPS_RA_REGNUM = 31,
+  NANOMIPS_PC_REGNUM = 32
+};
+
+/* Floating-point register offsets relative to `gdbarch_tdep->regnum->fpr'.  */
+
+enum
+{
+  NANOMIPS_FP0_REGNUM = 0,
+  NANOMIPS_FCSR_REGNUM = 32,
+  NANOMIPS_FIR_REGNUM = 33
+};
+
+/* DSP register offsets, relative to `gdbarch_tdep->regnum->dsp'.  */
+
+enum
+{
+  NANOMIPS_DSPHI0_REGNUM = 0,
+  NANOMIPS_DSPLO0_REGNUM = 1,
+  NANOMIPS_DSPCTL_REGNUM = 8
+};
+
+/* Instruction sizes and other useful constants.  */
+enum
+{
+  INSN16_SIZE = 2,
+  INSN32_SIZE = 4,
+  /* The number of floating-point or integer registers.  */
+  NUMREGS = 32
+};
+
+/* Single step based on where the current instruction will take us.  */
+extern std::vector<CORE_ADDR>
+nanomips_software_single_step (struct regcache *regcache);
+
+/* Return the currently determined ISA register size.  */
+extern int nanomips_isa_regsize (struct gdbarch *gdbarch);
+
+/* Return the currently configured (or set) saved register size.  */
+extern unsigned int nanomips_abi_regsize (struct gdbarch *gdbarch);
+
+/* Make PC the address of the next instruction to execute.  */
+extern void nanomips_write_pc (struct regcache *regcache, CORE_ADDR pc);
+
+#endif /* NANOMIPS_TDEP_H */
diff --git a/gdb/testsuite/gdb.asm/asm-source.exp b/gdb/testsuite/gdb.asm/asm-source.exp
index d56a5076b44..c2ec299a81f 100644
--- a/gdb/testsuite/gdb.asm/asm-source.exp
+++ b/gdb/testsuite/gdb.asm/asm-source.exp
@@ -100,6 +100,13 @@ switch -glob -- [istarget] {
     "mips*-*" {
         set asm-arch mips
     }
+    "nanomips*-elf" {
+        set asm-arch nanomips
+	append link-flags " -Ttext 0x80020000 -Tdata 0x80030000"
+	set board [target_info name]
+	set old_ldscript [board_info $board ldscript]
+	set_board_info ldscript ""
+    }
     "powerpc64le-*" {
         set asm-arch powerpc64le
         set asm-flags "-a64 -I${srcdir}/${subdir} $obj_include"
@@ -260,7 +267,7 @@ if {[target_link [list $asm1obj $asm2obj] "${binfile}" ${link-flags}] != "" } th
 }
 
 # Restore the target board linker script for HC11/HC12.
-if { [istarget "m6811-*-*"] || [istarget "m6812-*-*"] } {
+if { [istarget "m6811-*-*"] || [istarget "m6812-*-*"] || [istarget "nanomips*-elf"] } {
     set_board_info ldscript $old_ldscript
 }
 
diff --git a/gdb/testsuite/gdb.asm/nanomips.inc b/gdb/testsuite/gdb.asm/nanomips.inc
new file mode 100644
index 00000000000..6e2ead15d2c
--- /dev/null
+++ b/gdb/testsuite/gdb.asm/nanomips.inc
@@ -0,0 +1,49 @@
+	comment "subroutine declare"
+	.purgem gdbasm_declare
+	.macro gdbasm_declare name
+	.align	1
+	.ent	\name
+	.type	\name,@function
+\name:
+	.endm
+
+	comment "subroutine prologue"
+	.macro gdbasm_enter
+	save 32, $fp, $ra
+	addiu $fp, $sp, -4080
+	.endm
+
+	comment "subroutine epilogue"
+	.macro gdbasm_leave
+	restore.jrc 32, $fp, $ra
+	.endm
+
+	comment "subroutine end"
+	.purgem gdbasm_end
+	.macro gdbasm_end name
+	.end	\name
+	.endm
+
+	.macro gdbasm_call subr
+        li     $t9, \subr
+        jalrc  $ra, $t9
+	.endm
+
+	.macro gdbasm_several_nops
+	nop
+	nop
+	nop
+	nop
+	.endm
+
+	comment "exit (0)"
+	.macro gdbasm_exit0
+	comment "Don't know how to exit, but this will certainly halt..."
+	lw 	$a3, 0($zero)
+	.endm
+
+	comment "crt0 startup"
+	.macro gdbasm_startup
+	li $sp, 0x8007fff0
+	li $fp, 0
+	.endm
diff --git a/gdb/testsuite/gdb.base/catch-gdb-caused-signals.c b/gdb/testsuite/gdb.base/catch-gdb-caused-signals.c
index e9923814b01..a2064b3bb2e 100644
--- a/gdb/testsuite/gdb.base/catch-gdb-caused-signals.c
+++ b/gdb/testsuite/gdb.base/catch-gdb-caused-signals.c
@@ -27,6 +27,9 @@ main (void)
 {
   int i = 0;
 
+  /* Ensure printf function is available.  */
+  printf ("printf available %d\n", i);
+
   gdb_unbuffer_output ();
 
   i++; /* set dprintf here */
diff --git a/gdb/testsuite/gdb.base/float.exp b/gdb/testsuite/gdb.base/float.exp
index c50193e5cd3..f09ce249408 100644
--- a/gdb/testsuite/gdb.base/float.exp
+++ b/gdb/testsuite/gdb.base/float.exp
@@ -67,7 +67,7 @@ if { [is_aarch64_target] } then {
             pass "info float (without FPU)"
 	}
     }
-} elseif [istarget "mips*-*-*"] then {
+} elseif { [istarget "mips*-*-*"] || [istarget "nanomips*-*-*"] } then {
     gdb_test_multiple "info float" "info float" {
 	-re "fpu type: none / unused\r\n$gdb_prompt $" {
 	      pass "info float (without FPU)"
diff --git a/gdb/testsuite/gdb.trace/trace-common.h b/gdb/testsuite/gdb.trace/trace-common.h
index f8cd654ba2b..6dfab081f1e 100644
--- a/gdb/testsuite/gdb.trace/trace-common.h
+++ b/gdb/testsuite/gdb.trace/trace-common.h
@@ -43,7 +43,7 @@ x86_trace_dummy ()
        "    call " SYMBOL(x86_trace_dummy) "\n" \
        )
 
-#elif (defined __aarch64__) || (defined __powerpc__)
+#elif (defined __aarch64__) || (defined __powerpc__) || (__nanomips__)
 
 #define FAST_TRACEPOINT_LABEL(name) \
   asm ("    .global " SYMBOL(name) "\n" \
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 47cb2b23676..9a9fabbed6f 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -2961,6 +2961,7 @@ gdb_caching_proc supports_memtag {
 proc can_hardware_single_step {} {
 
     if { [istarget "arm*-*-*"] || [istarget "mips*-*-*"]
+	 || [istarget "nanomips*-*-*"]
 	 || [istarget "tic6x-*-*"] || [istarget "sparc*-*-linux*"]
 	 || [istarget "nios2-*-*"] || [istarget "riscv*-*-linux*"] } {
 	return 0
-- 
2.25.1


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

* Re: [PATCH 3/3] gdb: Add nanoMIPS port
  2022-04-29 15:58 ` [PATCH 3/3] gdb: " Aleksandar Rikalo
@ 2022-04-29 16:15   ` Eli Zaretskii
  0 siblings, 0 replies; 13+ messages in thread
From: Eli Zaretskii @ 2022-04-29 16:15 UTC (permalink / raw)
  To: Aleksandar Rikalo; +Cc: gdb-patches

> From: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
> Date: Fri, 29 Apr 2022 17:58:13 +0200
> 
>  config.sub                                    |    1 +
>  configure                                     |    3 +
>  configure.ac                                  |    3 +
>  gdb/Makefile.in                               |    2 +
>  gdb/NEWS                                      |    1 +
>  gdb/configure.host                            |    1 +
>  gdb/configure.tgt                             |   11 +
>  gdb/features/Makefile                         |    4 +
>  gdb/features/nanomips-cp0.xml                 |   13 +
>  gdb/features/nanomips-cpu.xml                 |   44 +
>  gdb/features/nanomips-dsp.xml                 |   20 +
>  gdb/features/nanomips-fpu.xml                 |   45 +
>  gdb/features/nanomips.c                       |   54 +
>  gdb/features/nanomips.xml                     |   12 +
>  gdb/features/nanomips64-cp0.xml               |   13 +
>  gdb/features/nanomips64-cpu.xml               |   44 +
>  gdb/features/nanomips64-dsp.xml               |   20 +
>  gdb/nanomips-tdep.c                           | 3421 +++++++++++++++++
>  gdb/nanomips-tdep.h                           |  144 +
>  gdb/testsuite/gdb.asm/asm-source.exp          |    9 +-
>  gdb/testsuite/gdb.asm/nanomips.inc            |   49 +
>  .../gdb.base/catch-gdb-caused-signals.c       |    3 +
>  gdb/testsuite/gdb.base/float.exp              |    2 +-
>  gdb/testsuite/gdb.trace/trace-common.h        |    2 +-
>  gdb/testsuite/lib/gdb.exp                     |    1 +
>  25 files changed, 3919 insertions(+), 3 deletions(-)

The documentation part is OK, thanks.

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

* Re: [PATCH 1/3] bfd: Add support for nanoMIPS architecture
  2022-04-29 15:58 ` [PATCH 1/3] bfd: Add support for nanoMIPS architecture Aleksandar Rikalo
@ 2022-05-01 22:56   ` Maciej W. Rozycki
  0 siblings, 0 replies; 13+ messages in thread
From: Maciej W. Rozycki @ 2022-05-01 22:56 UTC (permalink / raw)
  To: Aleksandar Rikalo; +Cc: gdb-patches

Hi Aleksandar,

>  create mode 100644 bfd/cpu-nanomips.c
>  create mode 100644 bfd/elfnn-nanomips.c
>  create mode 100644 bfd/elfxx-nanomips.c
>  create mode 100644 bfd/elfxx-nanomips.h
>  create mode 100644 include/elf/mips-common.h
>  create mode 100644 include/elf/nanomips.h
>  create mode 100644 include/opcode/nanomips.h
>  create mode 100644 opcodes/nanomips-dis.c
>  create mode 100644 opcodes/nanomips-formats.h
>  create mode 100644 opcodes/nanomips-opc.c

 BFD/opcodes changes need to be sent to <binutils@sourceware.org>.  Please 
consult the MAINTAINERS file at the top level for what mailing list to use 
for individual subdirectories.

  Maciej

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

* Re: [PATCH 2/3] sim: Add nanoMIPS port
  2022-04-29 15:58 ` [PATCH 2/3] sim: Add nanoMIPS port Aleksandar Rikalo
@ 2022-05-04 12:45   ` Mike Frysinger
  2022-11-21 11:06   ` [PATCH v3 1/2] " Aleksandar Rikalo
  1 sibling, 0 replies; 13+ messages in thread
From: Mike Frysinger @ 2022-05-04 12:45 UTC (permalink / raw)
  To: Aleksandar Rikalo; +Cc: gdb-patches

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

On 29 Apr 2022 17:58, Aleksandar Rikalo wrote:
> 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>

is everyone's copyright papers in place ?

> --- a/sim/configure
> +++ b/sim/configure

you seem to be missing the change to the source of this file.
this is generated, so you shouldn't be editing this.

> --- a/sim/common/sim-bits.h
> +++ b/sim/common/sim-bits.h

looks fine

> --- a/sim/mips/Makefile.in
> +++ b/sim/mips/Makefile.in
> @@ -79,6 +80,20 @@ SIM_EXTRA_DEPS = itable.h
>  
>  ## COMMON_POST_CONFIG_FRAG
>  
> +interp.o: $(srcdir)/interp.c sim-main.h itable.h
> +
> +m16run.o: sim-main.h m16_idecode.h m32_idecode.h m16run.c $(SIM_EXTRA_DEPS)
> +
> +micromipsrun.o: sim-main.h micromips16_idecode.h micromips32_idecode.h \
> +		micromips_m32_idecode.h micromipsrun.c $(SIM_EXTRA_DEPS)
> +
> +nms.o: $(srcdir)/nms.c $(srcdir)/sim-main.h
> +
> +multi-run.o: multi-include.h tmp-mach-multi
> +
> +../igen/igen:
> +	cd ../igen && $(MAKE)

we deleted all this stuff.  don't add it back.

> --- a/sim/mips/configure.ac
> +++ b/sim/mips/configure.ac
> @@ -106,6 +106,12 @@ case "${target}" in
>  			  mipsisa64r6:mips64r6:32,64,f:mipsisa32r6,mipsisa64r6"
>  			sim_multi_default=mipsisa64r2
>  			;;
> +  nanomips*-*-elf*)
> +			sim_gen=MULTI
> +			sim_multi_configs="\
> +			  nanor6sim:nanomips64r6,nanomipsdsp:32,64,f:nanomipsisa64r6,nanomipsisa32r6"
> +			sim_multi_default=nanomipsisa64r6
> +			;;

seems odd that you're using a new "nanomips*" tuple instead of existing
"mips*" space.  but i guess if you've convinced everyone else that this
isn't wrong, then sim/ will just follow.

> --- a/sim/mips/interp.c
> +++ b/sim/mips/interp.c
>  
> +int is_nanomips = 0;

do not declare globals.  state goes in sim_cpu.

> @@ -1531,21 +1535,26 @@ store_word (SIM_DESC sd,
>  	    uword64 vaddr,
>  	    signed_word val)
>  {
> -  address_word paddr = vaddr;
> +  address_word paddr;
> +  int uncached;
>  
>    if ((vaddr & 3) != 0)
>      SignalExceptionAddressStore ();
>    else
>      {
> -      const uword64 mask = 7;
> -      uword64 memval;
> -      unsigned int byte;
> -
> -      paddr = (paddr & ~mask) | ((paddr & mask) ^ (ReverseEndian << 2));
> -      byte = (vaddr & mask) ^ (BigEndianCPU << 2);
> -      memval = ((uword64) val) << (8 * byte);
> -      StoreMemory (AccessLength_WORD, memval, 0, paddr, vaddr,
> -		   isREAL);
> +      if (AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached,
> +			      isTARGET, isREAL))
> +	{
> +	  const uword64 mask = 7;
> +	  uword64 memval;
> +	  unsigned int byte;
> +
> +	  paddr = (paddr & ~mask) | ((paddr & mask) ^ (ReverseEndian << 2));
> +	  byte = (vaddr & mask) ^ (BigEndianCPU << 2);
> +	  memval = ((uword64) val) << (8 * byte);
> +	  StoreMemory (uncached, AccessLength_WORD, memval, 0, paddr, vaddr,
> +		       isREAL);
> +	}

you seem to be reverting changes in mips/ that we made a while ago with
no explanation.  i'm giving up on reviewing at this point.  you need to
update your port to the current state of the world, not roll it back to
code from 7 years ago.
-mike

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* [PATCH v3 1/2] sim: Add nanoMIPS port
@ 2022-11-21 11:06   ` Aleksandar Rikalo
  2022-11-21 11:06     ` [PATCH v3 2/2] gdb: " Aleksandar Rikalo
  2022-11-25 12:11     ` [PATCH v3 1/2] sim: " Mike Frysinger
  0 siblings, 2 replies; 13+ messages in thread
From: Aleksandar Rikalo @ 2022-11-21 11:06 UTC (permalink / raw)
  To: gdb-patches; +Cc: aleksandar.rikalo, arikalo

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>
---
 sim/common/sim-bits.h     |    4 +
 sim/configure             |    2 +-
 sim/configure.ac          |    2 +-
 sim/mips/Makefile.in      |   28 +
 sim/mips/configure        |   28 +
 sim/mips/configure.ac     |   28 +
 sim/mips/interp.c         |   21 +-
 sim/mips/micromips16.dc   |    3 +
 sim/mips/mips.igen        |  193 ++-
 sim/mips/nanomipsdsp.igen | 1115 +++++++++++++++
 sim/mips/nanomipsr6.igen  | 2744 +++++++++++++++++++++++++++++++++++++
 sim/mips/nanomipsrun.c    |  109 ++
 sim/mips/nms.c            |   44 +
 sim/mips/sim-main.h       |   61 +-
 14 files changed, 4358 insertions(+), 24 deletions(-)
 create mode 100644 sim/mips/nanomipsdsp.igen
 create mode 100644 sim/mips/nanomipsr6.igen
 create mode 100644 sim/mips/nanomipsrun.c
 create mode 100644 sim/mips/nms.c

diff --git a/sim/common/sim-bits.h b/sim/common/sim-bits.h
index fab1dab478c..8799916de26 100644
--- a/sim/common/sim-bits.h
+++ b/sim/common/sim-bits.h
@@ -499,15 +499,19 @@ INLINE_SIM_BITS(unsigned_word) MSINSERTED (unsigned_word val, int start, int sto
 #define EXTEND4(X)  (LSSEXT ((X), 3))
 #define EXTEND5(X)  (LSSEXT ((X), 4))
 #define EXTEND6(X)  (LSSEXT ((X), 5))
+#define EXTEND7(X)  (LSSEXT ((X), 6))
 #define EXTEND8(X)  ((signed_word)(int8_t)(X))
 #define EXTEND9(X)  (LSSEXT ((X), 8))
+#define EXTEND10(X)  (LSSEXT ((X), 9))
 #define EXTEND11(X)  (LSSEXT ((X), 10))
 #define EXTEND12(X)  (LSSEXT ((X), 11))
+#define EXTEND14(X)  (LSSEXT ((X), 13))
 #define EXTEND15(X)  (LSSEXT ((X), 14))
 #define EXTEND16(X) ((signed_word)(int16_t)(X))
 #define EXTEND18(X)  (LSSEXT ((X), 17))
 #define EXTEND19(X)  (LSSEXT ((X), 18))
 #define EXTEND21(X)  (LSSEXT ((X), 20))
+#define EXTEND22(X)  (LSSEXT ((X), 21))
 #define EXTEND24(X)  (LSSEXT ((X), 23))
 #define EXTEND25(X)  (LSSEXT ((X), 24))
 #define EXTEND26(X)  (LSSEXT ((X), 25))
diff --git a/sim/configure b/sim/configure
index 57c4fcf6972..aa9e21a2923 100755
--- a/sim/configure
+++ b/sim/configure
@@ -15157,7 +15157,7 @@ fi
 
       sim_enable_arch_mips=false
   case "${targ}" in
-    all|mips*-*-*)
+    all|mips*-*-*|nanomips*-*-*)
       if test "${targ}" = "${target}"; then
         SIM_PRIMARY_TARGET=mips
       fi
diff --git a/sim/configure.ac b/sim/configure.ac
index 675fa1bb44d..3f606ac5b64 100644
--- a/sim/configure.ac
+++ b/sim/configure.ac
@@ -143,7 +143,7 @@ if test "${enable_sim}" != no; then
     SIM_TARGET([m68hc11-*-*|m6811-*-*], [m68hc11])
     SIM_TARGET([mcore-*-*], [mcore])
     SIM_TARGET([microblaze*-*-*], [microblaze])
-    SIM_TARGET([mips*-*-*], [mips], [true], [sim_igen=yes])
+    SIM_TARGET([mips*-*-*|nanomips*-*-*], [mips], [true], [sim_igen=yes])
     SIM_TARGET([mn10300*-*-*], [mn10300], [], [sim_igen=yes])
     SIM_TARGET([moxie-*-*], [moxie])
     SIM_TARGET([msp430*-*-*], [msp430])
diff --git a/sim/mips/Makefile.in b/sim/mips/Makefile.in
index 75438be5a18..8637b46b186 100644
--- a/sim/mips/Makefile.in
+++ b/sim/mips/Makefile.in
@@ -61,6 +61,7 @@ SIM_OBJS = \
 	cp1.o \
 	mdmx.o \
 	dsp.o \
+	nms.o \
 	sim-main.o \
 	sim-resume.o \
 
@@ -99,6 +100,8 @@ IGEN_INCLUDE=\
 	$(srcdir)/dsp2.igen \
 	$(srcdir)/mips3264r2.igen \
 	$(srcdir)/mips3264r6.igen \
+	$(srcdir)/nanomipsdsp.igen \
+	$(srcdir)/nanomipsr6.igen
 
 # NB:	Since these can be built by a number of generators, care
 #	must be taken to ensure that they are only dependant on
@@ -463,8 +466,11 @@ tmp-mach-multi: $(IGEN_INSN) $(IGEN_DC) $(IGEN) $(IGEN_INCLUDE)
 	  f=`echo $${t} | sed -e 's/.*://'` ; \
 	  case $${p} in \
 	    micromips16*) e="-B 16 -H 15 -o $(MICROMIPS16_DC) -F 16" ;; \
+	    nanomips16*) e="-B 16 -H 15 -o $(MICROMIPS16_DC) -F 16" ;; \
 	    micromips32* | micromips64*) \
 		e="-B 32 -H 31 -o $(MICROMIPS32_DC) -F $${f}" ;; \
+	    nanomips32* | nanomips64*) \
+		e="-B 32 -H 31 -o $(MICROMIPS32_DC) -F $${f}" ;; \
 	    micromips_m32*) \
 		e="-B 32 -H 31 -o $(IGEN_DC) -F $${f}"; \
 		m="mips32r2,mips3d,mdmx,dsp,dsp2,smartmips" ;; \
@@ -579,6 +585,28 @@ tmp-run-multi: $(srcdir)/m16run.c $(srcdir)/micromipsrun.c
 	      $(SHELL) $(srcdir)/../../move-if-change tmp-run \
 						      micromips$${m}_run.c ; \
              ;;\
+	    nanomips32*) \
+	      m=`echo $${t} | sed -e 's/^nanomips32//' -e 's/:.*//'`; \
+	      sed <  $(srcdir)/nanomipsrun.c > tmp-run \
+		    -e "s/^sim_/nanomips32$${m}_/" \
+		    -e "s/nanomips_instruction_decode/nanomips32$${m}_instruction_decode/g" \
+		    -e "s/nanomips16_/nanomips16$${m}_/" \
+		    -e "s/nanomips32_/nanomips32$${m}_/" \
+		    -e "s/m32_/m32$${m}_/" ; \
+	      $(SHELL) $(srcdir)/../../move-if-change tmp-run \
+						      nanomips$${m}_run.c ; \
+             ;;\
+	    nanomips64*) \
+	      m=`echo $${t} | sed -e 's/^nanomips64//' -e 's/:.*//'`; \
+	      sed <  $(srcdir)/nanomipsrun.c > tmp-run \
+		    -e "s/^sim_/nanomips64$${m}_/" \
+		    -e "s/nanomips_instruction_decode/nanomips64$${m}_instruction_decode/g" \
+		    -e "s/nanomips16_/nanomips16$${m}_/" \
+		    -e "s/nanomips32_/nanomips64$${m}_/" \
+		    -e "s/m32_/m64$${m}_/" ; \
+	      $(SHELL) $(srcdir)/../../move-if-change tmp-run \
+						      nanomips$${m}_run.c ; \
+             ;;\
 	  esac \
 	done
 	$(SILENCE) touch $@
diff --git a/sim/mips/configure b/sim/mips/configure
index b0ba7ba7470..493547fc97b 100755
--- a/sim/mips/configure
+++ b/sim/mips/configure
@@ -2028,6 +2028,12 @@ case "${target}" in
 			  mipsisa64r6:mips64r6:32,64,f:mipsisa32r6,mipsisa64r6"
 			sim_multi_default=mipsisa64r2
 			;;
+  nanomips*-elf*)
+			sim_gen=MULTI
+			sim_multi_configs="\
+			  nanor6sim:nanomips64r6,nanomipsdsp:32,64,f:nanomipsisa64r6,nanomipsisa32r6"
+			sim_multi_default=nanomipsisa32r6
+			;;
   mips64*-*-*)		sim_igen_filter="32,64,f"
 			sim_gen=IGEN
 			;;
@@ -2226,6 +2232,17 @@ __EOF__
 	sim_multi_obj="${sim_multi_obj} micromips${name}_run.o"
 	sim_multi_flags="${sim_multi_flags} -F 16,32"
 	;;
+      *:*nanomips32*)
+	# Run igen twice, once for nanomips32 and once for nanomips16.
+	ws="nanomips16 nanomips32"
+
+	# The top-level function for the micromips simulator is
+	# in a file micromips${name}_run.c, generated by the
+	# tmp-run-multi Makefile rule.
+	sim_multi_src="${sim_multi_src} nanomips${name}_run.c"
+	sim_multi_obj="${sim_multi_obj} nanomips${name}_run.o"
+	sim_multi_flags="${sim_multi_flags} -F 16,32"
+	;;
       *:*micromips64*:*)
 	# Run igen thrice, once for micromips64, once for micromips16,
 	# and once for m64.
@@ -2238,6 +2255,17 @@ __EOF__
 	sim_multi_obj="${sim_multi_obj} micromips${name}_run.o"
 	sim_multi_flags="${sim_multi_flags} -F 16,32,64"
 	;;
+      *:*nanomips64*)
+	# Run igen twice, once for nanomips64 and once for nanomips16.
+	ws="nanomips16 nanomips64"
+
+	# The top-level function for the micromips simulator is
+	# in a file micromips${name}_run.c, generated by the
+	# tmp-run-multi Makefile rule.
+	sim_multi_src="${sim_multi_src} nanomips${name}_run.c"
+	sim_multi_obj="${sim_multi_obj} nanomips${name}_run.o"
+	sim_multi_flags="${sim_multi_flags} -F 16,32,64"
+	;;
       *)
 	ws=m32
 	;;
diff --git a/sim/mips/configure.ac b/sim/mips/configure.ac
index f1d9f3d2410..e8153b0c5ac 100644
--- a/sim/mips/configure.ac
+++ b/sim/mips/configure.ac
@@ -106,6 +106,12 @@ case "${target}" in
 			  mipsisa64r6:mips64r6:32,64,f:mipsisa32r6,mipsisa64r6"
 			sim_multi_default=mipsisa64r2
 			;;
+  nanomips*-*-elf*)
+			sim_gen=MULTI
+			sim_multi_configs="\
+			  nanor6sim:nanomips64r6,nanomipsdsp:32,64,f:nanomipsisa64r6,nanomipsisa32r6"
+			sim_multi_default=nanomipsisa64r6
+			;;
   mips64*-*-*)		sim_igen_filter="32,64,f"
 			sim_gen=IGEN
 			;;
@@ -304,6 +310,17 @@ __EOF__
 	sim_multi_obj="${sim_multi_obj} micromips${name}_run.o"
 	sim_multi_flags="${sim_multi_flags} -F 16,32"
 	;;
+      *:*nanomips32*)
+	# Run igen twice, once for nanomips32 and once for nanomips16.
+	ws="nanomips16 nanomips32"
+
+	# The top-level function for the micromips simulator is
+	# in a file micromips${name}_run.c, generated by the
+	# tmp-run-multi Makefile rule.
+	sim_multi_src="${sim_multi_src} nanomips${name}_run.c"
+	sim_multi_obj="${sim_multi_obj} nanomips${name}_run.o"
+	sim_multi_flags="${sim_multi_flags} -F 16,32"
+	;;
       *:*micromips64*:*)
 	# Run igen thrice, once for micromips64, once for micromips16,
 	# and once for m64.
@@ -316,6 +333,17 @@ __EOF__
 	sim_multi_obj="${sim_multi_obj} micromips${name}_run.o"
 	sim_multi_flags="${sim_multi_flags} -F 16,32,64"
 	;;
+      *:*nanomips64*)
+	# Run igen twice, once for nanomips64 and once for nanomips16.
+	ws="nanomips16 nanomips64"
+
+	# The top-level function for the micromips simulator is
+	# in a file micromips${name}_run.c, generated by the
+	# tmp-run-multi Makefile rule.
+	sim_multi_src="${sim_multi_src} nanomips${name}_run.c"
+	sim_multi_obj="${sim_multi_obj} nanomips${name}_run.o"
+	sim_multi_flags="${sim_multi_flags} -F 16,32,64"
+	;;
       *)
 	ws=m32
 	;;
diff --git a/sim/mips/interp.c b/sim/mips/interp.c
index ab20f079939..3612956bb2b 100644
--- a/sim/mips/interp.c
+++ b/sim/mips/interp.c
@@ -356,6 +356,8 @@ sim_open (SIM_OPEN_KIND kind, host_callback *cb,
 
   cpu = STATE_CPU (sd, 0); /* FIXME */
 
+  IS_NANOMIPS = 0;
+
   /* FIXME: watchpoints code shouldn't need this */
   STATE_WATCHPOINTS (sd)->interrupt_handler = interrupt_event;
 
@@ -672,10 +674,13 @@ sim_open (SIM_OPEN_KIND kind, host_callback *cb,
 	  cpu->register_widths[rn] = WITH_TARGET_FLOATING_POINT_BITSIZE;
 	else if ((rn >= 33) && (rn <= 37))
 	  cpu->register_widths[rn] = WITH_TARGET_WORD_BITSIZE;
+	else if ((rn >= 70) && (rn <= 78))
+	  cpu->register_widths[rn] = WITH_TARGET_WORD_BITSIZE;
 	else if ((rn == SRIDX)
 		 || (rn == FCR0IDX)
 		 || (rn == FCR31IDX)
-		 || ((rn >= 72) && (rn <= 89)))
+		 || (rn == DSPCRIDX)
+		 || ((rn >= 80) && (rn <= 89)))
 	  cpu->register_widths[rn] = 32;
 	else
 	  cpu->register_widths[rn] = 0;
@@ -1200,7 +1205,7 @@ sim_monitor (SIM_DESC sd,
     case 6: /* int open(char *path,int flags) */
       {
 	char *path = fetch_str (sd, A0);
-	V0 = sim_io_open (sd, path, (int)A1);
+	SET_RV0 (sim_io_open (sd, path, (int)A1));
 	free (path);
 	break;
       }
@@ -1210,7 +1215,7 @@ sim_monitor (SIM_DESC sd,
 	int fd = A0;
 	int nr = A2;
 	char *buf = zalloc (nr);
-	V0 = sim_io_read (sd, fd, buf, nr);
+	SET_RV0 (sim_io_read (sd, fd, buf, nr));
 	sim_write (sd, A1, buf, nr);
 	free (buf);
       }
@@ -1222,7 +1227,7 @@ sim_monitor (SIM_DESC sd,
 	int nr = A2;
 	char *buf = zalloc (nr);
 	sim_read (sd, A1, buf, nr);
-	V0 = sim_io_write (sd, fd, buf, nr);
+	SET_RV0 (sim_io_write (sd, fd, buf, nr));
 	if (fd == 1)
 	    sim_io_flush_stdout (sd);
 	else if (fd == 2)
@@ -1233,14 +1238,14 @@ sim_monitor (SIM_DESC sd,
 
     case 10: /* int close(int file) */
       {
-	V0 = sim_io_close (sd, (int)A0);
+	SET_RV0 (sim_io_close (sd, (int)A0));
 	break;
       }
 
     case 2:  /* Densan monitor: char inbyte(int waitflag) */
       {
 	if (A0 == 0)	/* waitflag == NOWAIT */
-	  V0 = (unsigned_word)-1;
+	    SET_RV0 ((unsigned_word)-1);
       }
      /* Drop through to case 11 */
 
@@ -1252,10 +1257,10 @@ sim_monitor (SIM_DESC sd,
         if (sim_io_read_stdin (sd, &tmp, sizeof(char)) != sizeof(char))
 	  {
 	    sim_io_error(sd,"Invalid return from character read");
-	    V0 = (unsigned_word)-1;
+	    SET_RV0 ((unsigned_word)-1);
 	  }
         else
-	  V0 = (unsigned_word)tmp;
+	    SET_RV0 ((unsigned_word)tmp);
 	break;
       }
 
diff --git a/sim/mips/micromips16.dc b/sim/mips/micromips16.dc
index a1cd9a0ea89..ace9bb94fad 100644
--- a/sim/mips/micromips16.dc
+++ b/sim/mips/micromips16.dc
@@ -8,4 +8,7 @@
 
   switch,combine        :  9 :    6 :    :    :    :      :      :
   switch,combine        :  9 :    5 :    :    :    :      :      :
+  switch,combine        :  3 :    0 :    :    :    :      :      :
+  switch,combine        :  2 :    0 :    :    :    :      :      :
+  switch,combine        :  5 :    3 :    :    :    :      :      :
   switch,combine        :  0 :    0 :    :    :    :      :      :
diff --git a/sim/mips/mips.igen b/sim/mips/mips.igen
index 0746a52d5ab..e9110c44f2f 100644
--- a/sim/mips/mips.igen
+++ b/sim/mips/mips.igen
@@ -79,6 +79,9 @@
 :model:::micromips32:micromips64:	// micromips.igen
 :model:::micromips64:micromips64:	// micromips.igen
 :model:::micromipsdsp:micromipsdsp:	// micromipsdsp.igen
+:model:::nanomips32r6:nanomips32r6: // nanomipsr6.igen
+:model:::nanomips64r6:nanomips64r6: // nanomipsr6.igen
+:model:::nanomipsdsp:nanomipsdsp: // nanompsdsp.igen
 
 //  Vendor Extensions
 //
@@ -98,6 +101,33 @@
 // For grep - RSVD_INSTRUCTION, RSVD_INSTRUCTION_MASK
 000000,5.*,5.*,5.*,5.OP,111001:SPECIAL:32::RSVD
 "rsvd <OP>"
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*mips32r6:
+*mips64:
+*mips64r2:
+*mips64r6:
+*vr4100:
+*vr4120:
+*vr5000:
+*vr5400:
+*vr5500:
+*r3900:
+*mips16:
+*mips16e:
+*mips3d:
+*mdmx:
+*dsp:
+*dsp2:
+*smartmips:
+*micromips32:
+*micromips64:
+*micromipsdsp:
 {
   SignalException (ReservedInstruction, instruction_0);
 }
@@ -192,6 +222,7 @@
 *vr5000:
 *r3900:
 *micromips32:
+*nanomips32r6:
 {
   return base + offset;
 }
@@ -201,6 +232,7 @@
 *mips64r2:
 *micromips64:
 *mips64r6:
+*nanomips64r6:
 {
 #if 0 /* XXX FIXME: enable this only after some additional testing.  */
   /* If in user mode and UX is not set, use 32-bit compatibility effective
@@ -237,6 +269,8 @@
 *micromips32:
 *micromips64:
 *mips64r6:
+*nanomips32r6:
+*nanomips64r6:
 {
 #if WITH_TARGET_WORD_BITSIZE == 64
   return value != (((value & 0xffffffff) ^ 0x80000000) - 0x80000000);
@@ -274,6 +308,8 @@
 *micromips32:
 *micromips64:
 *mips64r6:
+*nanomips32r6:
+*nanomips64r6:
 {
   unpredictable_action (CPU, CIA);
 }
@@ -369,6 +405,7 @@
 *r3900:
 *micromips32:
 *micromips64:
+*nanomipsdsp:
 {
   int64_t time = sim_events_time (SD);
   history->mt.timestamp = time;
@@ -399,6 +436,7 @@
 *r3900:
 *micromips32:
 *micromips64:
+*nanomipsdsp:
 {
   int64_t time = sim_events_time (SD);
   int ok = 1;
@@ -473,6 +511,7 @@
 *r3900:
 *micromips32:
 *micromips64:
+*nanomipsdsp:
 {
   /* FIXME: could record the fact that a stall occured if we want */
   int64_t time = sim_events_time (SD);
@@ -570,6 +609,8 @@
 *micromips64:
 *micromips32:
 *mips64r6:
+*nanomips32r6:
+*nanomips64r6:
 {
 #if 0 /* XXX FIXME: enable this only after some additional testing.  */
   if (UserMode && (SR & (status_UX|status_PX)) == 0)
@@ -781,12 +822,44 @@
 }
 
 :function:::void:do_lb:int rt, int offset, int base
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*mips32r6:
+*mips64:
+*mips64r2:
+*mips64r6:
+*vr4100:
+*vr5000:
+*r3900:
+*micromips32:
+*micromips64:
 {
   GPR[rt] = EXTEND8 (do_load (SD_, AccessLength_BYTE, GPR[base],
 			      EXTEND16 (offset)));
 }
 
 :function:::void:do_lh:int rt, int offset, int base
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*mips32r6:
+*mips64:
+*mips64r2:
+*mips64r6:
+*vr4100:
+*vr5000:
+*r3900:
+*micromips32:
+*micromips64:
 {
   GPR[rt] = EXTEND16 (do_load (SD_, AccessLength_HALFWORD, GPR[base],
 			       EXTEND16 (offset)));
@@ -811,6 +884,22 @@
 }
 
 :function:::void:do_lw:int rt, int offset, int base
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*mips32r6:
+*mips64:
+*mips64r2:
+*mips64r6:
+*vr4100:
+*vr5000:
+*r3900:
+*micromips32:
+*micromips64:
 {
   GPR[rt] = EXTEND32 (do_load (SD_, AccessLength_WORD, GPR[base],
 			       EXTEND16 (offset)));
@@ -823,6 +912,22 @@
 }
 
 :function:::void:do_lhu:int rt, int offset, int base
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*mips32r6:
+*mips64:
+*mips64r2:
+*mips64r6:
+*vr4100:
+*vr5000:
+*r3900:
+*micromips32:
+*micromips64:
 {
   GPR[rt] = do_load (SD_, AccessLength_HALFWORD, GPR[base], EXTEND16 (offset));
 }
@@ -1861,7 +1966,23 @@
 
 
 
-:function:::void:do_addiu:int rs, int rt, uint16_t immediate
+:function:::void:do_addiu:int rs, int rt, int immediate
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*mips32r6:
+*mips64:
+*mips64r2:
+*mips64r6:
+*vr4100:
+*vr5000:
+*r3900:
+*micromips32:
+*micromips64:
 {
   if (NotWordValue (GPR[rs]))
     Unpredictable ();
@@ -2595,6 +2716,14 @@
 
 
 :function:::void:do_ddiv:int rs, int rt
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips64:
+*mips64r2:
+*micromips64:
+*vr4100:
+*vr5000:
 {
   check_div_hilo (SD_, HIHISTORY, LOHISTORY);
   TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]);
@@ -2641,6 +2770,14 @@
 
 
 :function:::void:do_ddivu:int rs, int rt
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips64:
+*mips64r2:
+*micromips64:
+*vr4100:
+*vr5000:
 {
   check_div_hilo (SD_, HIHISTORY, LOHISTORY);
   TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]);
@@ -2680,6 +2817,20 @@
 }
 
 :function:::void:do_div:int rs, int rt
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*micromips32:
+*mips64:
+*mips64r2:
+*micromips64:
+*vr4100:
+*vr5000:
+*r3900:
 {
   check_div_hilo (SD_, HIHISTORY, LOHISTORY);
   TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]);
@@ -2726,6 +2877,20 @@
 
 
 :function:::void:do_divu:int rs, int rt
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*mips32:
+*mips32r2:
+*micromips32:
+*mips64:
+*mips64r2:
+*micromips64:
+*vr4100:
+*vr5000:
+*r3900:
 {
   check_div_hilo (SD_, HIHISTORY, LOHISTORY);
   TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]);
@@ -3714,6 +3879,25 @@
 
 
 :function:::void:do_mfhi:int rd
+*mipsI:
+*mipsII:
+*mipsIII:
+*mipsIV:
+*mipsV:
+*vr4100:
+*vr5000:
+*r3900:
+*mips32:
+*mips64:
+*mips32r2:
+*mips32r6:
+*mips64r2:
+*mips64r6:
+*dsp:
+*micromips32:
+*micromips64:
+*micromipsdsp:
+*nanomipsdsp:
 {
   check_mf_hilo (SD_, HIHISTORY, LOHISTORY);
   TRACE_ALU_INPUT1 (HI);
@@ -5225,6 +5409,8 @@
 *vr4100:
 *vr5000:
 *r3900:
+*nanomips32r6:
+*nanomips64r6:
 {
   /* None of these ISAs support Paired Single, so just fall back to
      the single/double check.  */
@@ -5273,6 +5459,8 @@
 *r3900:
 *micromips32:
 *micromips64:
+*nanomips32r6:
+*nanomips64r6:
 {
   if (! COP_Usable (1))
     SignalExceptionCoProcessorUnusable (1);
@@ -6867,4 +7055,5 @@
 :include:::smartmips.igen
 :include:::micromips.igen
 :include:::micromipsdsp.igen
-
+:include:::nanomipsr6.igen
+:include:::nanomipsdsp.igen
diff --git a/sim/mips/nanomipsdsp.igen b/sim/mips/nanomipsdsp.igen
new file mode 100644
index 00000000000..07fd26b6ad0
--- /dev/null
+++ b/sim/mips/nanomipsdsp.igen
@@ -0,0 +1,1115 @@
+// Simulator definition for the micromips ASE.
+// Copyright (C) 2018-2022 Free Software Foundation, Inc.
+// Contributed by Imagination Technologies, Ltd.
+// Written by Ali Lown <ali.lown@imgtec.com>
+//
+// This file is part of GDB, the GNU debugger.
+//
+// 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, see <http://www.gnu.org/licenses/>.
+
+001000,5.RT,5.RS,0001000100111111:POOL32A:32::ABSQ_S.PH
+"absq_s.ph r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_ph_s_absq (SD_, RT, RS);
+}
+
+001000,5.RT,5.RS,0000000100111111:POOL32A:32::ABSQ_S.QB
+"absq_s.qb r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_s_absq (SD_, RT, RS);
+}
+
+001000,5.RT,5.RS,0010000100111111:POOL32A:32::ABSQ_S.W
+"absq_s.w r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_w_s_absq (SD_, RT, RS);
+}
+
+001000,5.RT,5.RS,5.RD,00000001101:POOL32A:32::ADDQ.PH
+"addq.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_op (SD_, RD, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10000001101:POOL32A:32::ADDQ_S.PH
+"addq_s.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_op (SD_, RD, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1100000101:POOL32A:32::ADDQ_S.W
+"addq_s.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_op (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,00001001101:POOL32A:32::ADDQH.PH
+"addqh.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_ph_op (SD_, RD, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10001001101:POOL32A:32::ADDQH_R.PH
+"addqh_r.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_ph_op (SD_, RD, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,5.RD,00010001101:POOL32A:32::ADDQH.W
+"addqh.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_w_op (SD_, RD, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10010001101:POOL32A:32::ADDQH_R.W
+"addqh_r.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_w_op (SD_, RD, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1110000101:POOL32A:32::ADDSC
+"addsc r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_addsc (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,00100001101:POOL32A:32::ADDU.PH
+"addu.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_u_ph_op (SD_, RD, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10100001101:POOL32A:32::ADDU_S.PH
+"addu_s.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_u_ph_op (SD_, RD, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,5.RD,00011001101:POOL32A:32::ADDU.QB
+"addu.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_op (SD_, RD, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10011001101:POOL32A:32::ADDU_S.QB
+"addu_s.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_op (SD_, RD, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1111000101:POOL32A:32::ADDWC
+"addwc r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_addwc (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,00101001101:POOL32A:32::ADDUH.QB
+"adduh.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_uh_qb_op (SD_, RD, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10101001101:POOL32A:32::ADDUH_R.QB
+"adduh_r.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_uh_qb_op (SD_, RD, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,5.SA,1.X,1000010101:POOL32A:32::APPEND
+"append r<RT>, r<RS>, <SA>"
+*nanomipsdsp:
+{
+  do_append (SD_, RT, RS, SA);
+}
+
+001000,5.RT,5.RS,2.BP,00100010111111:POOL32A:32::BALIGN
+"balign r<RT>, r<RS>, <BP>"
+*nanomipsdsp:
+{
+  do_balign (SD_, RT, RS, BP);
+}
+
+001000,5.RT,5.RS,0011000100111111:POOL32A:32::BITREV
+"bitrev r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_bitrev (SD_, RT, RS);
+}
+
+100010,5.X,0010001,13.S1,1.S2:POOL32I:32::BPOSGE32C
+"bposge32c <ADDRESS15>"
+*nanomipsdsp:
+{
+  uint32_t pos = (DSPCR >> DSPCR_POS_SHIFT) & DSPCR_POS_MASK;
+  if (pos >= 32)
+    NIA = ADDRESS15;
+}
+
+001000,5.RT,5.RS,6.X,0000000101:POOL32A:32::CMP.EQ.PH
+"cmp.eq.ph r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_cmpu (SD_, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,0000000001,000101:POOL32A:32::CMP.LT.PH
+"cmp.lt.ph r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_cmpu (SD_, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,0000000010,000101:POOL32A:32::CMP.LE.PH
+"cmp.le.ph r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_cmpu (SD_, RS, RT, 2);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0110000101:POOL32A:32::CMPGDU.EQ.QB
+"cmpgdu.eq.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpgdu (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0111000101:POOL32A:32::CMPGDU.LT.QB
+"cmpgdu.lt.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpgdu (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1000000101:POOL32A:32::CMPGDU.LE.QB
+"cmpgdu.le.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpgdu (SD_, RD, RS, RT, 2);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0011000101:POOL32A:32::CMPGU.EQ.QB
+"cmpgu.eq.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpgu (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0100000101:POOL32A:32::CMPGU.LT.QB
+"cmpgu.lt.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpgu (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0101000101:POOL32A:32::CMPGU.LE.QB
+"cmpgu.le.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpgu (SD_, RD, RS, RT, 2);
+}
+
+001000,5.RT,5.RS,5.X1,1.X2,1001000101:POOL32A:32::CMPU.EQ.QB
+"cmpu.eq.qb r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpu (SD_, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.X1,1.X2,1010000101:POOL32A:32::CMPU.LT.QB
+"cmpu.lt.qb r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpu (SD_, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.X1,1.X2,1011000101:POOL32A:32::CMPU.LE.QB
+"cmpu.le.qb r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_cmpu (SD_, RS, RT, 2);
+}
+
+001000,5.RT,5.RS,2.AC,00000010111111:POOL32A:32::DPA.W.PH
+"dpa.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_ph_dot_product (SD_, AC, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,2.AC,00001010111111:POOL32A:32::DPAQ_S.W.PH
+"dpaq_s.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_dot_product (SD_, AC, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,2.AC,01001010111111:POOL32A:32::DPAQ_SA.L.W
+"dpaq_sa.l.w ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_dot_product (SD_, AC, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,2.AC,10001010111111:POOL32A:32::DPAQX_S.W.PH
+"dpaqx_s.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qx_w_ph_dot_product (SD_, AC, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,2.AC,11001010111111:POOL32A:32::DPAQX_SA.W.PH
+"dpaqx_sa.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qx_w_ph_dot_product (SD_, AC, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,2.AC,10000010111111:POOL32A:32::DPAU.H.QBL
+"dpau.h.qbl ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_dot_product (SD_, AC, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,2.AC,11000010111111:POOL32A:32::DPAU.H.QBR
+"dpau.h.qbr ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_dot_product (SD_, AC, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,2.AC,01000010111111:POOL32A:32::DPAX.W.PH
+"dpax.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_x_w_ph_dot_product (SD_, AC, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,2.AC,00010010111111:POOL32A:32::DPS.W.PH
+"dps.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_ph_dot_product (SD_, AC, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,2.AC,00011010111111:POOL32A:32::DPSQ_S.W.PH
+"dpsq_s.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_dot_product (SD_, AC, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,2.AC,01011010111111:POOL32A:32::DPSQ_SA.L.W
+"dpsq_sa.l.w ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_dot_product (SD_, AC, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,2.AC,10011010111111:POOL32A:32::DPSQX_S.W.PH
+"dpsqx_s.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qx_w_ph_dot_product (SD_, AC, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,2.AC,11011010111111:POOL32A:32::DPSQX_SA.W.PH
+"dpsqx_sa.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qx_w_ph_dot_product (SD_, AC, RS, RT, 1, 1);
+}
+
+001000,5.RT,5.RS,2.AC,10010010111111:POOL32A:32::DPSU.H.QBL
+"dpsu.h.qbl ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_dot_product (SD_, AC, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,2.AC,11010010111111:POOL32A:32::DPSU.H.QBR
+"dpsu.h.qbr ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_dot_product (SD_, AC, RS, RT, 1, 1);
+}
+
+001000,5.RT,5.RS,2.AC,01010010111111:POOL32A:32::DPSX.W.PH
+"dpsx.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_x_w_ph_dot_product (SD_, AC, RS, RT, 1);
+}
+
+001000,5.RT,5.SIZE,2.AC,10011001111111:POOL32A:32::EXTP
+"extp r<RT>, ac<AC>, <SIZE>"
+*nanomipsdsp:
+{
+  do_extp (SD_, RT, AC, SIZE, 0);
+}
+
+001000,5.RT,5.SIZE,2.AC,11011001111111:POOL32A:32::EXTPDP
+"extpdp r<RT>, ac<AC>, <SIZE>"
+*nanomipsdsp:
+{
+  do_extp (SD_, RT, AC, SIZE, 1);
+}
+
+001000,5.RT,5.RS,2.AC,11100010111111:POOL32A:32::EXTPDPV
+"extpdpv r<RT>, ac<AC>, r<RS>"
+*nanomipsdsp:
+{
+  do_extpv (SD_, RT, AC, RS, 1);
+}
+
+001000,5.RT,5.RS,2.AC,10100010111111:POOL32A:32::EXTPV
+"extpv r<RT>, ac<AC>, r<RS>"
+*nanomipsdsp:
+{
+  do_extpv (SD_, RT, AC, RS, 0);
+}
+
+001000,5.RT,5.SHIFT,2.AC,00111001111111:POOL32A:32::EXTR.W
+"extr.w r<RT>, ac<AC>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_w_extr (SD_, RT, AC, SHIFT, 0);
+}
+
+001000,5.RT,5.SHIFT,2.AC,01111001111111:POOL32A:32::EXTR_R.W
+"extr_r.w r<RT>, ac<AC>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_w_extr (SD_, RT, AC, SHIFT, 1);
+}
+
+001000,5.RT,5.SHIFT,2.AC,10111001111111:POOL32A:32::EXTR_RS.W
+"extr_rs.w r<RT>, ac<AC>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_w_extr (SD_, RT, AC, SHIFT, 2);
+}
+
+001000,5.RT,5.SHIFT,2.AC,11111001111111:POOL32A:32::EXTR_S.H
+"extr_s.h r<RT>, ac<AC>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_h_extr (SD_, RT, AC, SHIFT);
+}
+
+001000,5.RT,5.RS,2.AC,00111010111111:POOL32A:32::EXTRV.W
+"extrv.w r<RT>, ac<AC>, r<RS>"
+*nanomipsdsp:
+{
+  do_extrv (SD_, RT, AC, RS, 0);
+}
+
+001000,5.RT,5.RS,2.AC,01111010111111:POOL32A:32::EXTRV_R.W
+"extrv_r.w r<RT>, ac<AC>, r<RS>"
+*nanomipsdsp:
+{
+  do_extrv (SD_, RT, AC, RS, 1);
+}
+
+001000,5.RT,5.RS,2.AC,10111010111111:POOL32A:32::EXTRV_RS.W
+"extrv_rs.w r<RT>, ac<AC>, r<RS>"
+*nanomipsdsp:
+{
+  do_extrv (SD_, RT, AC, RS, 2);
+}
+
+001000,5.RT,5.RS,2.AC,11111010111111:POOL32A:32::EXTRV_S.H
+"extrv_s.h r<RT>, ac<AC>, r<RS>"
+*nanomipsdsp:
+{
+  do_extrv_s_h (SD_, RT, AC, RS);
+}
+
+001000,5.RT,5.RS,0100000100111111:POOL32A:32::INSV
+"insv r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_insv (SD_, RT, RS);
+}
+
+001000,5.RT,5.RS,2.AC,00101010111111:POOL32A:32::MADD_DSP
+"madd ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_dsp_madd (SD_, AC, RS, RT);
+}
+
+001000,5.RT,5.RS,2.AC,01101010111111:POOL32A:32::MADDU_DSP
+"maddu ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_dsp_maddu (SD_, AC, RS, RT);
+}
+
+001000,5.RT,5.RS,2.AC,01101001111111:POOL32A:32::MAQ_S.W.PHL
+"maq_s.w.phl ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_maq (SD_, AC, RS, RT, 0, 0);
+}
+
+001000,5.RT,5.RS,2.AC,11101001111111:POOL32A:32::MAQ_SA.W.PHL
+"maq_sa.w.phl ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_maq (SD_, AC, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,2.AC,00101001111111:POOL32A:32::MAQ_S.W.PHR
+"maq_s.w.phr ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_maq (SD_, AC, RS, RT, 0, 1);
+}
+
+001000,5.RT,5.RS,2.AC,10101001111111:POOL32A:32::MAQ_SA.W.PHR
+"maq_sa.w.phr ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_maq (SD_, AC, RS, RT, 1, 1);
+}
+
+001000,5.RS,5.X,2.AC,00000001111111:POOL32A:32::MFHI_DSP
+"mfhi r<RS>, ac<AC>"
+*nanomipsdsp:
+{
+  do_dsp_mfhi (SD_, AC, RS);
+}
+
+001000,5.RS,5.X,2.AC,01000001111111:POOL32A:32::MFLO_DSP
+"mflo r<RS>, ac<AC>"
+*nanomipsdsp:
+{
+  do_dsp_mflo (SD_, AC, RS);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1010010101:POOL32A:32::MODSUB
+"modsub r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_modsub (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,2.AC,10101010111111:POOL32A:32::MSUB_DSP
+"msub ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_dsp_msub (SD_, AC, RS, RT);
+}
+
+001000,5.RT,5.RS,2.AC,11101010111111:POOL32A:32::MSUBU_DSP
+"msubu ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_dsp_msubu (SD_, AC, RS, RT);
+}
+
+001000,00000,5.RS,2.AC,10000001111111:POOL32A:32::MTHI_DSP
+"mthi r<RS>, ac<AC>"
+*nanomipsdsp:
+{
+  do_dsp_mthi (SD_, AC, RS);
+}
+
+001000,00000,5.RS,2.AC,00001001111111:POOL32A:32::MTHLIP
+"mthlip r<RS>, ac<AC>"
+*nanomipsdsp:
+{
+  do_mthlip (SD_, RS, AC);
+}
+
+001000,00000,5.RS,2.AC,11000001111111:POOL32A:32::MTLO_DSP
+"mtlo r<RS>, ac<AC>"
+*nanomipsdsp:
+{
+  do_dsp_mtlo (SD_, AC, RS);
+}
+
+001000,5.RT,5.RS,5.RD,00000101101:POOL32A:32::MUL.PH
+"mul.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_op (SD_, RD, RS, RT, 2, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10000101101:POOL32A:32::MUL_S.PH
+"mul_s.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_op (SD_, RD, RS, RT, 2, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0000100101:POOL32A:32::MULEQ_S.W.PHL
+"muleq_s.w.phl r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_muleq (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0001100101:POOL32A:32::MULEQ_S.W.PHR
+"muleq_s.w.phr r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_muleq (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0010010101:POOL32A:32::MULEU_S.PH.QBL
+"muleu_s.ph.qbl r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_muleu (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0011010101:POOL32A:32::MULEU_S.PH.QBR
+"muleu_s.ph.qbr r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_muleu (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0100010101:POOL32A:32::MULQ_RS.PH
+"mulq_rs.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_mulq (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0110010101:POOL32A:32::MULQ_RS.W
+"mulq_rs.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_mulq (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0101010101:POOL32A:32::MULQ_S.PH
+"mulq_s.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_mulq (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0111010101:POOL32A:32::MULQ_S.W
+"mulq_s.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_mulq (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,2.AC,10110010111111:POOL32A:32::MULSA.W.PH
+"mulsa.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_w_mulsa (SD_, AC, RS, RT);
+}
+
+001000,5.RT,5.RS,2.AC,11110010111111:POOL32A:32::MULSAQ_S.W.PH
+"mulsaq_s.w.ph ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_mulsaq_s_w_ph (SD_, AC, RS, RT);
+}
+
+001000,5.RT,5.RS,2.AC,00110010111111:POOL32A:32::MULT_DSP
+"mult ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_dsp_mult (SD_, AC, RS, RT);
+}
+
+001000,5.RT,5.RS,2.AC,01110010111111:POOL32A:32::MULTU_DSP
+"multu ac<AC>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_dsp_multu (SD_, AC, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0110101101:POOL32A:32::PACKRL.PH
+"packrl.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_packrl (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1000101101:POOL32A:32::PICK.PH
+"pick.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_pick (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0111101101:POOL32A:32::PICK.QB
+"pick.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_pick (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,0101000100111111:POOL32A:32::PRECEQ.W.PHL
+"preceq.w.phl r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_w_preceq (SD_, RT, RS, 0);
+}
+
+001000,5.RT,5.RS,0110000100111111:POOL32A:32::PRECEQ.W.PHR
+"preceq.w.phr r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_w_preceq (SD_, RT, RS, 1);
+}
+
+001000,5.RT,5.RS,0111000100111111:POOL32A:32::PRECEQU.PH.QBL
+"precequ.ph.qbl r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_precequ (SD_, RT, RS, 2);
+}
+
+001000,5.RT,5.RS,0111001100111111:POOL32A:32::PRECEQU.PH.QBLA
+"precequ.ph.qbla r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_precequ (SD_, RT, RS, 3);
+}
+
+001000,5.RT,5.RS,1001000100111111:POOL32A:32::PRECEQU.PH.QBR
+"precequ.ph.qbr r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_precequ (SD_, RT, RS, 0);
+}
+
+001000,5.RT,5.RS,1001001100111111:POOL32A:32::PRECEQU.PH.QBRA
+"precequ.ph.qbra r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_precequ (SD_, RT, RS, 1);
+}
+
+001000,5.RT,5.RS,1011000100111111:POOL32A:32::PRECEU.PH.QBL
+"preceu.ph.qbl r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_preceu (SD_, RT, RS, 2);
+}
+
+001000,5.RT,5.RS,1011001100111111:POOL32A:32::PRECEU.PH.QBLA
+"preceu.ph.qbla r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_preceu (SD_, RT, RS, 3);
+}
+
+001000,5.RT,5.RS,1101000100111111:POOL32A:32::PRECEU.PH.QBR
+"preceu.ph.qbr r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_preceu (SD_, RT, RS, 0);
+}
+
+001000,5.RT,5.RS,1101001100111111:POOL32A:32::PRECEU.PH.QBRA
+"preceu.ph.qbra r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_ph_preceu (SD_, RT, RS, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0001101101:POOL32A:32::PRECR.QB.PH
+"precr.qb.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_qb_precr (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.SA,01111001101:POOL32A:32::PRECR_SRA.PH.W
+"precr_sra.ph.w r<RT>, r<RS>, <SA>"
+*nanomipsdsp:
+{
+  do_precr_sra (SD_, RT, RS, SA, 0);
+}
+
+001000,5.RT,5.RS,5.SA,11111001101:POOL32A:32::PRECR_SRA_R.PH.W
+"precr_sra_r.ph.w r<RT>, r<RS>, <SA>"
+*nanomipsdsp:
+{
+  do_precr_sra (SD_, RT, RS, SA, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0011101101:POOL32A:32::PRECRQ.PH.W
+"precrq.ph.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_ph_precrq (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0010101101:POOL32A:32::PRECRQ.QB.PH
+"precrq.qb.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_qb_precrq (SD_, RD, RS, RT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0101101101:POOL32A:32::PRECRQU_S.QB.PH
+"precrqu_s.qb.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_qb_precrq (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0100101101:POOL32A:32::PRECRQ_RS.PH.W
+"precrq_rs.ph.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_ph_rs_precrq (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.SA,1.X,1001010101:POOL32A:32::PREPEND
+"prepend r<RT>, r<RS>, <SA>"
+*nanomipsdsp:
+{
+  do_prepend (SD_, RT, RS, SA);
+}
+
+001000,5.RT,5.RS,1111000100111111:POOL32A:32::RADDU.W.QB
+"raddu.w.qb r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_w_raddu (SD_, RT, RS);
+}
+
+001000,5.RT,7.CONTROL_MASK,00011001111111:POOL32A:32::RDDSP
+"rddsp r<RT>":CONTROL_MASK == 1111111111
+"rddsp r<RT>, <CONTROL_MASK>"
+*nanomipsdsp:
+{
+  do_rddsp (SD_, RT, CONTROL_MASK);
+}
+
+001000,5.RT,10.IMMEDIATE,1.X,0000111101:POOL32A:32::REPL.PH
+"repl.ph r<RT>, <IMMEDIATE>"
+*nanomipsdsp:
+{
+  do_repl (SD_, RT, IMMEDIATE, 2);
+}
+
+001000,5.RT,8.IMMEDIATE,1.X,010111111111:POOL32A:32::REPL.QB
+"repl.qb r<RT>, <IMMEDIATE>"
+*nanomipsdsp:
+{
+  do_repl (SD_, RT, IMMEDIATE, 0);
+}
+
+001000,5.RT,5.RS,0000001100111111:POOL32A:32::REPLV.PH
+"replv.ph r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_repl (SD_, RT, RS, 3);
+}
+
+001000,5.RT,5.RS,0001001100111111:POOL32A:32::REPLV.QB
+"replv.qb r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_repl (SD_, RT, RS, 1);
+}
+
+001000,0000,6.IMMEDIATE,2.AC,00000000011101:POOL32A:32::SHILO
+"shilo ac<AC>, <IMMEDIATE>"
+*nanomipsdsp:
+{
+  do_shilo (SD_, AC, IMMEDIATE);
+}
+
+001000,00000,5.RS,2.AC,01001001111111:POOL32A:32::SHILOV
+"shilov ac<AC>, r<RS>"
+*nanomipsdsp:
+{
+  do_shilov (SD_, AC, RS);
+}
+
+001000,5.RT,5.RS,4.SHIFT,001110110101:POOL32A:32::SHLL.PH
+"shll.ph r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_ph_shift (SD_, RT, RS, SHIFT, 0, 0);
+}
+
+001000,5.RT,5.RS,4.SHIFT,101110110101:POOL32A:32::SHLL_S.PH
+"shll_s.ph r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_ph_shift (SD_, RT, RS, SHIFT, 0, 1);
+}
+
+001000,5.RT,5.RS,3.SHIFT,0100001111111:POOL32A:32::SHLL.QB
+"shll.qb r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_qb_shift (SD_, RT, RS, SHIFT, 0);
+}
+
+001000,5.RT,5.RS,5.RD,01110001101:POOL32A:32::SHLLV.PH
+"shllv.ph r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_ph_shl (SD_, RD, RT, RS, 0, 0);
+}
+
+001000,5.RT,5.RS,5.RD,11110001101:POOL32A:32::SHLLV_S.PH
+"shllv_s.ph r<RD>, r<RD>, r<RS>"
+*nanomipsdsp:
+{
+  do_ph_shl (SD_, RD, RT, RS, 0, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1110010101:POOL32A:32::SHLLV.QB
+"shllv.qb r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_shl (SD_, RD, RT, RS, 0);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1111010101:POOL32A:32::SHLLV_S.W
+"shllv_s.w r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_w_s_shllv (SD_, RD, RT, RS);
+}
+
+001000,5.RT,5.RS,5.SHIFT,1.X,1111110101:POOL32A:32::SHLL_S.W
+"shll_s.w r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_w_shll (SD_, RT, RS, SHIFT);
+}
+
+001000,5.RT,5.RS,3.SHIFT,0000111111111:POOL32A:32::SHRA.QB
+"shra.qb r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_qb_shra (SD_, RT, RS, SHIFT, 0);
+}
+
+001000,5.RT,5.RS,3.SHIFT,1000111111111:POOL32A:32::SHRA_R.QB
+"shra_r.qb r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_qb_shra (SD_, RT, RS, SHIFT, 1);
+}
+
+001000,5.RT,5.RS,4.SHIFT,1.X,01100110101:POOL32A:32::SHRA.PH
+"shra.ph r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_ph_shift (SD_, RT, RS, SHIFT, 1, 0);
+}
+
+001000,5.RT,5.RS,4.SHIFT,1.X,11100110101:POOL32A:32::SHRA_R.PH
+"shra_r.ph r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_ph_shift (SD_, RT, RS, SHIFT, 1, 1);
+}
+
+001000,5.RT,5.RS,5.RD,00110001101:POOL32A:32::SHRAV.PH
+"shrav.ph r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_ph_shl (SD_, RD, RT, RS, 1, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10110001101:POOL32A:32::SHRAV_R.PH
+"shrav_r.ph r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_ph_shl (SD_, RD, RT, RS, 1, 1);
+}
+
+001000,5.RT,5.RS,5.RD,00111001101:POOL32A:32::SHRAV.QB
+"shrav.qb r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_shrav (SD_, RD, RT, RS, 0);
+}
+
+001000,5.RT,5.RS,5.RD,10111001101:POOL32A:32::SHRAV_R.QB
+"shrav_r.qb r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_shrav (SD_, RD, RT, RS, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1011010101:POOL32A:32::SHRAV_R.W
+"shrav_r.w r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_w_r_shrav (SD_, RD, RT, RS);
+}
+
+001000,5.RT,5.RS,5.SHIFT,1.X,1011110101:POOL32A:32::SHRA_R.W
+"shra_r.w r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_w_shra (SD_, RT, RS, SHIFT);
+}
+
+001000,5.RT,5.RS,4.SHIFT,001111111111:POOL32A:32::SHRL.PH
+"shrl.ph r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_ph_shrl (SD_, RT, RS, SHIFT);
+}
+
+001000,5.RT,5.RS,3.SHIFT,1100001111111:POOL32A:32::SHRL.QB
+"shrl.qb r<RT>, r<RS>, <SHIFT>"
+*nanomipsdsp:
+{
+  do_qb_shift (SD_, RT, RS, SHIFT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1100010101:POOL32A:32::SHRLV.PH
+"shrlv.ph r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_ph_shrlv (SD_, RD, RT, RS);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1101010101:POOL32A:32::SHRLV.QB
+"shrlv.qb r<RD>, r<RT>, r<RS>"
+*nanomipsdsp:
+{
+  do_qb_shl (SD_, RD, RT, RS, 1);
+}
+
+001000,5.RT,5.RS,5.RD,01000001101:POOL32A:32::SUBQ.PH
+"subq.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_op (SD_, RD, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,5.RD,11000001101:POOL32A:32::SUBQ_S.PH
+"subq_s.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_ph_op (SD_, RD, RS, RT, 1, 1);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1101000101:POOL32A:32::SUBQ_S.W
+"subq_s.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_w_op (SD_, RD, RS, RT, 1);
+}
+
+001000,5.RT,5.RS,5.RD,01001001101:POOL32A:32::SUBQH.PH
+"subqh.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_ph_op (SD_, RD, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,5.RD,11001001101:POOL32A:32::SUBQH_R.PH
+"subqh_r.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_ph_op (SD_, RD, RS, RT, 1, 1);
+}
+
+001000,5.RT,5.RS,5.RD,01010001101:POOL32A:32::SUBQH.W
+"subqh.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_w_op (SD_, RD, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,5.RD,11010001101:POOL32A:32::SUBQH_R.W
+"subqh_r.w r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qh_w_op (SD_, RD, RS, RT, 1, 1);
+}
+
+001000,5.RT,5.RS,5.RD,01100001101:POOL32A:32::SUBU.PH
+"subu.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_u_ph_op (SD_, RD, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,5.RD,11100001101:POOL32A:32::SUBU_S.PH
+"subu_s.ph r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_u_ph_op (SD_, RD, RS, RT, 1, 1);
+}
+
+001000,5.RT,5.RS,5.RD,01011001101:POOL32A:32::SUBU.QB
+"subu.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_op (SD_, RD, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,5.RD,11011001101:POOL32A:32::SUBU_S.QB
+"subu_s.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_qb_op (SD_, RD, RS, RT, 1, 1);
+}
+
+001000,5.RT,5.RS,5.RD,01101001101:POOL32A:32::SUBUH.QB
+"subuh.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_uh_qb_op (SD_, RD, RS, RT, 1, 0);
+}
+
+001000,5.RT,5.RS,5.RD,11101001101:POOL32A:32::SUBUH_R.QB
+"subuh_r.qb r<RD>, r<RS>, r<RT>"
+*nanomipsdsp:
+{
+  do_uh_qb_op (SD_, RD, RS, RT, 1, 1);
+}
+
+001000,5.RT,7.CONTROL_MASK,01011001111111:POOL32A:32::WRDSP
+"wrdsp r<RT>":CONTROL_MASK == 1111111111
+"wrdsp r<RT>, <CONTROL_MASK>"
+*nanomipsdsp:
+{
+  do_wrdsp (SD_, RT, CONTROL_MASK);
+}
diff --git a/sim/mips/nanomipsr6.igen b/sim/mips/nanomipsr6.igen
new file mode 100644
index 00000000000..bef5c04c3b3
--- /dev/null
+++ b/sim/mips/nanomipsr6.igen
@@ -0,0 +1,2744 @@
+// Simulator definition for the nanoMIPS.
+// Copyright (C) 2018-2022 Free Software Foundation, Inc.
+// Contributed by Imagination Technologies, Ltd.
+// Written by Ali Lown <ali.lown@imgtec.com>
+//
+// This file is part of GDB, the GNU debugger.
+//
+// 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, see <http://www.gnu.org/licenses/>.
+
+:compute:::int:U_SHIFT_1BIT:U:(U << 1)
+:compute:::int:U_SHIFT_2BIT:U:(U << 2)
+:compute:::int:U_SHIFT_3BIT:U:(U << 3)
+:compute:::int:U_SHIFT_4BIT:U:(U << 4)
+:compute:::int:EU_127:EU:((EU == 127) ? -1 \: EU)
+:compute:::int:U_LW4X4:U2,U3:((U3 << 3) | (U2 << 2))
+:compute:::int:AXUIPC_S_LO:S1,S2,S3:((EXTEND32((S3 << 31) | (S2 << 21) | (S1 << 12))) & 0x0000ffff)
+:compute:::int:AXUIPC_S_HI:S1,S2,S3:((EXTEND32((S3 << 31) | (S2 << 21) | (S1 << 12))) & 0xffff0000)
+:compute:::int:AXUIPC_S:S1,S2,S3:(EXTEND32((S3 << 31) | (S2 << 21) | (S1 << 12)))
+:compute:::int:TRD2:RD20,RD21:(compute_gpr2_dest1_reg (SD_, (RD21 << 1 | RD20)))
+:compute:::int:TRE2:RD20,RD21:(compute_gpr2_dest2_reg (SD_, (RD21 << 1 | RD20)))
+:compute:::int:TRS2:RS4,RS2_0:(compute_gpr4_zero (SD_, (RS4 << 3 | RS2_0)))
+:compute:::int:TRT2:RT4,RT2_0:(compute_gpr4_zero (SD_, (RT4 << 3 | RT2_0)))
+:compute:::int:TRD2_REV:RD4,RD2_0:(compute_gpr4 (SD_, (RD4 << 3) | RD2_0))
+:compute:::int:TRE2_REV:RE4,RE2_0:(compute_gpr4 (SD_, (RE4 << 3) | RE2_0))
+:compute:::int:TRS2_REV:RS20,RS21:(compute_gpr2_dest1_reg (SD_, (RS21 << 1 | RS20)))
+:compute:::int:TRT2_REV:RS20,RS21:(compute_gpr2_dest2_reg (SD_, (RS21 << 1 | RS20)))
+:compute:::address_word:ADDRESS8:S1,S2:(nia + EXTEND8((S2 << 7) | (S1 << 1)))
+:compute:::address_word:ADDRESS11:S1,S2:(nia + EXTEND11((S2 << 10) | (S1 << 1)))
+:compute:::address_word:ADDRESS15:S1,S2:(nia + EXTEND15((S2 << 14) | (S1 << 1)))
+:compute:::address_word:ADDRESS21:S1,S2:(nia + EXTEND21((S2 << 20) | (S1 << 1)))
+:compute:::address_word:ADDRESS22:S1,S2:(nia + EXTEND22((S2 << 21) | (S1 << 1)))
+:compute:::address_word:ADDRESS26:S1,S2:(nia + EXTEND26((S2 << 25) | (S1 << 1)))
+:compute:::int:INS_POS:LSB:(LSB)
+:compute:::int:INS_SIZE:LSB,MSBD:(1 + MSBD - LSB)
+:compute:::address_word:ADDRESS12:S1,S2:(nia + EXTEND12(S2 << 11 | S1 << 1))
+:compute:::int:S_14_BIT:S1,S2:(EXTEND14 ((S1 << 13) | S2))
+:compute:::int:S_4_BIT:S1,S2:(EXTEND4((S1 << 3) | S2))
+:compute:::int:S_9_BIT:S1,S2:(EXTEND9((S1 << 8) | S2))
+:compute:::int:S_9_BIT_LLSC:S1,S2:(EXTEND9((S1 << 8) | (S2 << 2)))
+:compute:::int:RD1:RD:(compute_gpr1_dest_reg (SD_, RD))
+:compute:::int:RT_5_BIT_NM_Z:RT1,RT2:(compute_gpr4_zero (SD_, (RT1 << 3) | RT2))
+:compute:::int:RT_5_BIT_NM:RT1,RT2:(compute_gpr4 (SD_, (RT1 << 3) | RT2))
+:compute:::int:RS_5_BIT_NM:RS1,RS2:(compute_gpr4 (SD_, (RS1 << 3) | RS2))
+:compute:::int:TRTZ:RTZ:((RTZ >= 1 && RTZ <= 3) ? (16 + RTZ) \: RTZ)
+:compute:::int:EU_12_13:EU:((EU == 12) ? 255 \: ((EU == 13) ? 65535 \: EU))
+:compute:::int:RS_MOVE:RS1,RS_CODE_1,RS_CODE_2:((RS1 << 3) | (RS_CODE_1 << 2) | RS_CODE_2)
+:compute:::int:CODE_BREAK:RS_CODE_1,RS_CODE_2:((RS_CODE_1 << 2) | RS_CODE_2)
+:compute:::int:TRD_NM:RD:((RD < 4) ? (16 + RD) \: RD)
+:compute:::int:TRS_NM:RS:((RS < 4) ? (16 + RS) \: RS)
+:compute:::int:TRT_NM:RT:((RT < 4) ? (16 + RT) \: RT)
+:compute:::int:COUNT:COUNT3:(COUNT3 == 0 ? 8 \: COUNT3)
+:compute:::int:SHIFTX_1BIT:SHIFTX:(SHIFTX << 1)
+
+:function:::void:do_msubf:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT3 (FGR[fd], FGR[fs], FGR[ft]);
+  StoreFPR (fd, fmt, FusedMultiplySub (ValueFPR (fs, fmt),
+               ValueFPR (ft, fmt),
+               ValueFPR (fd, fmt), fmt));
+  TRACE_ALU_RESULT (FGR[fd]);
+}
+
+:function:::void:do_maddf:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT3 (FGR[fd], FGR[fs], FGR[ft]);
+  StoreFPR (fd, fmt, FusedMultiplyAdd (ValueFPR (fs, fmt),
+               ValueFPR (ft, fmt),
+               ValueFPR (fd, fmt), fmt));
+  TRACE_ALU_RESULT (FGR[fd]);
+}
+
+:function:::void:do_rint:int fd, int fs, int fmt, instruction_word instruction_0
+{
+  uint64_t result = 0;
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT1 (FGR[fs]);
+  RoundToIntegralExact (ValueFPR (fs, fmt), &result, fmt);
+  StoreFPR (fd, fmt, result);
+  TRACE_ALU_RESULT (FGR[fd]);
+}
+
+:function:::void:do_class:int fd, int fs, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  StoreFPR (fd, fmt, Classify (ValueFPR (fs, fmt), fmt));
+}
+
+:function:::void:do_seleqzf:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT2 (ValueFPR(fs, fmt), FGR[ft]);
+  if ((FGR[ft] & 0x01) == 0)
+    StoreFPR (fd, fmt, ValueFPR (fs, fmt));
+  else
+    StoreFPR (fd, fmt, 0);
+  TRACE_ALU_RESULT (ValueFPR(fd, fmt));
+}
+
+:function:::void:do_selnezf:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT2 (ValueFPR(fs, fmt), FGR[ft]);
+  if ((FGR[ft] & 0x01) == 0x1)
+    StoreFPR (fd, fmt, ValueFPR (fs, fmt));
+  else
+    StoreFPR (fd, fmt, 0);
+  TRACE_ALU_RESULT (ValueFPR(fd, fmt));
+}
+
+:function:::void:do_self:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT3 (FGR[fd], ValueFPR(fs, fmt), ValueFPR(ft, fmt));
+  if ((FGR[fd] & 0x01) != 0)
+    StoreFPR (fd, fmt, ValueFPR (ft, fmt));
+  else
+    StoreFPR (fd, fmt, ValueFPR (fs, fmt));
+  TRACE_ALU_RESULT (ValueFPR(fd, fmt));
+}
+
+:function:::void:do_mina:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT2 (FGR[fs], FGR[ft]);
+  StoreFPR (fd, fmt, MinA (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt));
+  TRACE_ALU_RESULT (FGR[fd]);
+}
+
+:function:::void:do_maxa:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT2 (FGR[fs], FGR[ft]);
+  StoreFPR (fd, fmt, MaxA (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt));
+  TRACE_ALU_RESULT (FGR[fd]);
+}
+
+:function:::void:do_max:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT2 (FGR[fs], FGR[ft]);
+  StoreFPR (fd, fmt, Max (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt));
+  TRACE_ALU_RESULT (FGR[fd]);
+}
+
+:function:::void:do_min:int fd, int fs, int ft, int fmt, instruction_word instruction_0
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  TRACE_ALU_INPUT2 (FGR[fs], FGR[ft]);
+  StoreFPR (fd, fmt, Min (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt));
+  TRACE_ALU_RESULT (FGR[fd]);
+}
+
+:function:::void:do_cmp:int fd, int fs, int ft, int fmt, int condition
+{
+  uint64_t result;
+  check_fpu (SD_);
+  TRACE_ALU_INPUT2 (ValueFPR (fs, fmt), ValueFPR (ft, fmt));
+  result = R6Compare (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt, condition);
+  StoreFPR (fd, fmt, result);
+  TRACE_ALU_RESULT (result);
+}
+
+:function:::void:do_modu:int rd, int rs, int rt
+{
+  uint32_t n = GPR[rs];
+  uint32_t d = GPR[rt];
+  TRACE_ALU_INPUT2 (n,d);
+  if (d == 0)
+    GPR[rd] = EXTEND32 (0);
+  else
+    GPR[rd] = EXTEND32 (n % d);
+
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_mod:int rd, int rs, int rt
+{
+  int32_t n = GPR[rs];
+  int32_t d = GPR[rt];
+  TRACE_ALU_INPUT2 (n,d);
+  if (d == 0 || (n == SIGNED32 (0x80000000) && d == -1))
+    GPR[rd] = EXTEND32 (0);
+  else
+    GPR[rd] = EXTEND32 (n % d);
+
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_muhu:int rd, int rs, int rt
+{
+  uint64_t prod;
+  if (NotWordValue (GPR[rs]) || NotWordValue (GPR[rt]))
+    Unpredictable ();
+  TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]);
+  prod = ((uint64_t)(uint32_t) GPR[rs])
+    * ((uint64_t)(uint32_t) GPR[rt]);
+  GPR[rd] = EXTEND32 (VH4_8 (prod));
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_mulu:int rd, int rs, int rt
+{
+  uint64_t prod;
+  if (NotWordValue (GPR[rs]) || NotWordValue (GPR[rt]))
+    Unpredictable ();
+  TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]);
+  prod = ((uint64_t)(uint32_t) GPR[rs])
+    * ((uint64_t)(uint32_t) GPR[rt]);
+  GPR[rd] = EXTEND32 (VL4_8 (prod));
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_muh:int rd, int rs, int rt
+{
+  int64_t prod;
+  if (NotWordValue (GPR[rs]) || NotWordValue (GPR[rt]))
+    Unpredictable ();
+  TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]);
+  prod = ((int64_t)(int32_t) GPR[rs])
+    * ((int64_t)(int32_t) GPR[rt]);
+  GPR[rd] = EXTEND32 (VH4_8 (prod));
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_lsa:int rd, int rs, int rt, unsigned immediate
+{
+  uint32_t t = GPR[rs] << immediate;
+  GPR[rd] = EXTEND32(GPR[rt] + t);
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_divu:int rd, int rs, int rt
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint32_t n = GPR[rs];
+  uint32_t d = GPR[rt];
+  TRACE_ALU_INPUT2 (n,d);
+  if (d == 0)
+    GPR[rd] = EXTEND32 (0x80000000);
+  else
+    GPR[rd] = EXTEND32 (n / d);
+
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_div:int rd, int rs, int rt
+*nanomips32r6:
+*nanomips64r6:
+{
+  int32_t n = GPR[rs];
+  int32_t d = GPR[rt];
+  TRACE_ALU_INPUT2 (n,d);
+  if (d == 0)
+    GPR[rd] = EXTEND32 (0x80000000);
+  else if (n == SIGNED32 (0x80000000) && d == -1)
+    GPR[rd] = EXTEND32 (0x80000000);
+  else
+    GPR[rd] = EXTEND32 (n / d);
+
+  TRACE_ALU_RESULT (GPR[rd]);
+}
+
+:function:::void:do_llwp:int rt, int ru, int roffset, int rbase
+{
+  address_word base = GPR[rbase];
+  address_word offset = EXTEND16 (roffset);
+  {
+    address_word vaddr = loadstore_ea (SD_, base, offset);
+    address_word paddr = vaddr;
+    int uncached;
+    if ((vaddr & 7) != 0)
+      {
+  SIM_CORE_SIGNAL (SD, CPU, cia, read_map, 8, vaddr, read_transfer,
+    sim_core_unaligned_signal);
+      }
+    else
+      {
+      uint64_t memval = 0;
+      uint64_t memval1 = 0;
+      uint64_t data = memval;
+
+      LoadMemory (&memval, &memval1, AccessLength_DOUBLEWORD, paddr,
+            vaddr, isDATA, isREAL);
+
+      GPR[rt] = EXTEND32 (data & 0xFFFFFFFF);
+      GPR[ru] = EXTEND32 (data >> 32);
+
+      LLBIT = 1;
+      COP0_COUNT++;
+      }
+  }
+}
+
+:function:::void:do_rotx:int rt, int rs, int shift, int shiftx, int stripe
+{
+  int i;
+  uint64_t tmp0 = ((uint64_t)GPR[rs] << 32) | (GPR[rs] & 0xFFFFFFFF);
+  uint64_t tmp1, tmp2, tmp3, tmp4, tmp5;
+
+  tmp1 = tmp0;
+  for (i = 0; i <=46; i++) {
+    int s;
+
+    if (i & 0x8)
+      s = shift;
+    else
+      s = shiftx;
+
+    if (stripe != 0 && !(i & 0x4))
+      s = ~s;
+
+    if (s & 0x10) {
+      if (tmp0 & (1LL << (i + 16)))
+        tmp1 |= 1LL << i;
+      else
+        tmp1 &= ~(1LL << i);
+    }
+  }
+
+  tmp2 = tmp1;
+  for (i = 0; i <=38; i++) {
+    int s;
+
+    if (i & 0x4)
+      s = shift;
+    else
+      s = shiftx;
+
+    if (s & 0x8) {
+      if (tmp1 & (1LL << (i + 8)))
+        tmp2 |= 1LL << i;
+      else
+        tmp2 &= ~(1LL << i);
+    }
+  }
+
+  tmp3 = tmp2;
+  for (i = 0; i <=34; i++) {
+    int s;
+
+    if (i & 0x2)
+      s = shift;
+    else
+      s = shiftx;
+
+    if (s & 0x4) {
+      if (tmp2 & (1LL << (i + 4)))
+        tmp3 |= 1LL << i;
+      else
+        tmp3 &= ~(1LL << i);
+    }
+  }
+
+  tmp4 = tmp3;
+  for (i = 0; i <=32; i++) {
+    int s;
+
+    if (i & 0x1)
+      s = shift;
+    else
+      s = shiftx;
+
+    if (s & 0x2) {
+      if (tmp3 & (1LL << (i + 2)))
+        tmp4 |= 1LL << i;
+      else
+        tmp4 &= ~(1LL << i);
+    }
+  }
+
+  tmp5 = tmp4;
+  for (i = 0; i <=31; i++) {
+    int s;
+
+    s = shift;
+
+    if (s & 0x1) {
+      if (tmp4 & (1LL << (i + 1)))
+        tmp5 |= 1LL << i;
+      else
+        tmp5 &= ~(1LL << i);
+    }
+  }
+
+  GPR[rt] = EXTEND32 (tmp5);
+}
+
+:function:::void:do_lwc1xs:int ft, int rbase, int roffset
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_fpu (SD_);
+  COP_LW (1, ft, do_load (SD_, AccessLength_WORD, GPR[rbase] << 2,
+        GPR[roffset]));
+}
+
+:function:::void:do_lwpc_nanomips:int rt, uint32_t offset, address_word nia
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_fpu (SD_);
+  GPR[rt] = EXTEND32 (do_load (SD_, AccessLength_WORD, nia, offset));
+}
+
+:function:::void:check_nms_flag:
+*nanomips32r6:
+*nanomips64r6:
+{
+  if(nms_flag == 0)
+    sim_engine_abort (SD, CPU, CIA, "Error: NMS instruction generated\
+  (nanoMIPS Subset is disabled - use -march=32r6s option)\n");
+}
+
+:function:::uint32_t:compute_gpr2_dest1_reg:int reg
+*nanomips32r6:
+*nanomips64r6:
+{
+  switch(reg)
+    {
+    case 0: return 4;
+    case 1: return 5;
+    case 2: return 6;
+    case 3: return 7;
+    default: return 4;
+    }
+}
+
+:function:::uint32_t:compute_gpr4_zero:int reg
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (reg == 3) return 0;
+  else if (reg >=4 && reg <= 7) return reg;
+  else return reg + 8;
+}
+
+:function:::uint32_t:compute_gpr4:int reg
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (reg >=4 && reg <= 7) return reg;
+  else return reg + 8;
+}
+
+:function:::uint32_t:compute_gpr2_dest2_reg:int reg
+*nanomips32r6:
+*nanomips64r6:
+{
+  switch(reg)
+    {
+    case 0: return 5;
+    case 1: return 6;
+    case 2: return 7;
+    case 3: return 8;
+    default: return 5;
+    }
+}
+
+:function:::uint32_t:compute_gpr1_dest_reg:int reg
+*nanomips32r6:
+*nanomips64r6:
+{
+  switch(reg)
+    {
+    case 0: return 4;
+    case 1: return 5;
+    default: return 4;
+    }
+}
+
+:function:::unsigned:zero_extend:signed_word value, uint32_t from_nbits
+{
+  uint32_t low_bits_mask = (1 << from_nbits) - 1;
+  return value & low_bits_mask;
+}
+
+:function:::void:do_save_gprs_to_stack_and_adjust_sp: int first_gpr, int count, int gp, int u
+*nanomips32r6:
+*nanomips64r6:
+{
+  int counter = 0;
+
+  while (counter != count) {
+    int gpr = (first_gpr & 0x10) | ((first_gpr + counter) & 0x1F);
+    int offset = - ( (counter + 1) << 2 );
+
+    if ( gp && (counter == count - 1))
+      gpr = 28;
+
+    do_store (SD_, AccessLength_WORD, GPR[SPIDX], offset, GPR[gpr]);
+
+    counter++;
+    COP0_COUNT++;
+  }
+
+  GPR[SPIDX] -= u;
+}
+
+:function:::void:do_restore_gprs_from_stack_and_adjust_sp: int first_gpr, int count, int gp, int u
+*nanomips32r6:
+*nanomips64r6:
+{
+  int counter = 0;
+
+  while (counter != count) {
+    int gpr = (first_gpr & 0x10) | ((first_gpr + counter) & 0x1F);
+    int offset;
+
+    if (gpr == 29)
+      Unpredictable();
+
+    offset = u - ((counter + 1) << 2);
+
+    if ( gp && (counter == count - 1))
+      gpr = 28;
+
+    GPR[gpr] = EXTEND32 (do_load(SD_, AccessLength_WORD, GPR[SPIDX], offset));
+
+    counter++;
+    COP0_COUNT++;
+  }
+
+  GPR[SPIDX] += u;
+}
+
+:function:::address_word:do_eret:int nc, address_word nia
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (SR & status_ERL)
+    {
+      /* Oops, not yet available */
+      sim_io_printf (SD, "Warning: ERET when SR[ERL] set not supported");
+      nia = EPC;
+      SR &= ~status_ERL;
+    }
+  else
+    {
+      nia = EPC;
+      SR &= ~status_EXL;
+      //if ( SRSCtl.HSS > 0 && Status.BEV == 0)
+      //  SRSCtl.CSS = SRSCtl.PSS
+  }
+
+  if (!nc)
+    LLBIT = 0;
+
+  //TODO: ClearHazards()
+  return nia;
+}
+
+:%s::::GPR_LIST_SAVE:int count
+*nanomips32r6:
+*nanomips64r6:
+{
+  int i;
+  static char gpr_list[100];
+
+  gpr_list[0] = '\0';
+
+  i = 0;
+
+  while (i<count)
+    {
+      char str1[32];
+      if (i == 0 || i==count-1) {
+        sprintf(str1, "%d", i);
+        strcat (gpr_list,"s");
+        strcat (gpr_list,str1);
+        if(i==0 && count > 1)
+          strcat (gpr_list,"-");
+      }
+      i++;
+    }
+  return (gpr_list);
+}
+
+:function:::void:do_break_nanomips:address_word instruction_0
+{
+  /* Check for some break instruction which are reserved for use by the
+     simulator.  */
+  unsigned int break_code = instruction_0 & HALT_INSTRUCTION_MASK_NANOMIPS;
+  if (break_code == (HALT_INSTRUCTION_NANOMIPS & HALT_INSTRUCTION_MASK_NANOMIPS))
+    {
+      sim_engine_halt (SD, CPU, NULL, cia,
+           sim_exited, (unsigned int)(A0 & 0xFFFFFFFF));
+    }
+  else if (break_code == (BREAKPOINT_INSTRUCTION_NANOMIPS & HALT_INSTRUCTION_MASK_NANOMIPS))
+    {
+      PC = cia;
+      SignalException (BreakPoint, instruction_0);
+    }
+
+  else
+    {
+    /* If we get this far, we're not an instruction reserved by the sim. Raise
+       the exception. */
+      SignalException (BreakPoint, instruction_0);
+    }
+}
+
+:%s::::GP_SAVE:int gp
+*nanomips32r6:
+*nanomips64r6:
+{
+  return (gp > 0) ? "gp" : "";
+}
+
+:%s::::FP_SAVE:int fp
+*nanomips32r6:
+*nanomips64r6:
+{
+  return (fp > 0) ? "fp" : "";
+}
+
+11111111111111111111111111111111:R6DUMMY:32,f::DUMMY0.fmt
+"dummy 0"
+*nanomips32r6:
+*nanomips64r6:
+{
+  /* Just needed so GNUSIM builds */
+}
+
+011100,3.RT,1,6.U:R6P16A1:16::ADDIUR1SP
+"addiu r<TRT_NM>, SP, <U_SHIFT_2BIT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addiu (SD_, SPIDX, TRT_NM, U_SHIFT_2BIT);
+}
+
+100100,3.RT,3.RS,0,3.U:R6P16A2:16::ADDIUR2
+"addiu r<TRT_NM>, r<TRS_NM>, <U_SHIFT_2BIT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addiu (SD_, TRS_NM, TRT_NM, U_SHIFT_2BIT);
+}
+
+100100,5.RT,1.S1,1,3.S2:R6P16ADDIURS5:16::ADDIURS5
+"nop":RT==0
+"addiu r<RT>, <S_4_BIT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (RT != 0)
+    do_addiu (SD_, RT, RT, S_4_BIT);
+}
+
+000001,5.RT,20.S1,1.S2:R6P32:32::ADDIUPC
+"addiu r<RT>, <ADDRESS22>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  GPR[RT] = ADDRESS22;
+}
+
+011000,5.RT,00011,16.IMM48:R6POOL48I:32::ADDIUPC48
+"addiu r<RT>, <IMM48>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint16_t U2;
+  uint32_t total;
+  check_nms_flag (SD_);
+  U2 = do_load (SD_, AccessLength_HALFWORD, CIA + 4, 0);
+  total = U2 << 16 | IMM48;
+  TRACE_ALU_INPUT2(GPR[RT], total);
+  GPR[RT] = CIA + 6 + EXTEND32(total);
+  TRACE_ALU_RESULT(GPR[RT]);
+  NIA = CIA + 6;
+}
+
+101100,3.RT,3.RS,3.RD,0:R6P16ADDU:16::ADDU16
+"addu r<TRD_NM>, r<TRS_NM>, r<TRT_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addu (SD_, TRS_NM, TRT_NM, TRD_NM);
+}
+
+001111,1.RT1,0,3.RT2,1.RS1,0,3.RS2:R6P164X4:16::ADDU4X4
+"addu r<RT_5_BIT_NM>, r<RS_5_BIT_NM>, r<RT_5_BIT_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_addu (SD_, RS_5_BIT_NM, RT_5_BIT_NM, RT_5_BIT_NM);
+}
+
+010100,3.RT,3.RS,10,0,0:R6POOL16C00:16::AND16
+"and r<TRT_NM>, r<TRS_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_and (SD_, TRS_NM, TRT_NM, TRT_NM);
+}
+
+111100,3.RT,3.RS,4.EU:R6P16:16::ANDI16
+"andi r<TRT_NM>, r<TRS_NM>, <EU_12_13>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_andi (SD_, TRS_NM, TRT_NM, EU_12_13);
+}
+
+001110,9.S1,1.S2:R6P16:16::BALC16
+"balc <ADDRESS11>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT1(RA);
+  RA = NIA;
+  NIA = ADDRESS11;
+  TRACE_ALU_RESULT(RA);
+
+  // For cycle counting
+  COP0_COUNT++;
+}
+
+000110,9.S1,1.S2:R6P16:16::BC16
+"bc <ADDRESS11>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  NIA = ADDRESS11;
+}
+
+110110,3.RT,3.RS,4.U!0:R6P16BR1:16::BxxC16
+"beqc r<TRS_NM>, r<TRT_NM>, <U_SHIFT_1BIT>":RS<RT
+"bnec r<TRS_NM>, r<TRT_NM>, <U_SHIFT_1BIT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  TRACE_ALU_INPUT2(GPR[TRS_NM], GPR[TRT_NM]);
+  if (RS < RT && GPR[TRS_NM] == GPR[TRT_NM])
+    NIA = NIA + U_SHIFT_1BIT; //BEQC
+  else if (RS >= RT && GPR[TRS_NM] != GPR[TRT_NM])
+    NIA = NIA + U_SHIFT_1BIT; //BNEC
+}
+
+100110,3.RT,6.S1,1.S2:R6P16:16::BEQZC16
+"beqzc r<TRT_NM>, <ADDRESS8>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT1(GPR[TRT_NM]);
+  if(GPR[TRT_NM] == 0)
+    NIA = ADDRESS8;
+}
+
+101110,3.RT,6.S1,1.S2:R6P16:16::BNEZC16
+"bnezc r<TRT_NM>, <ADDRESS8>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT1(GPR[TRT_NM]);
+  if(GPR[TRT_NM] != 0)
+    NIA = ADDRESS8;
+}
+
+110110,5.RT,1,0000:R6P16JRC:16::JALRC16
+"jalrc r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], RA);
+  RA = NIA;
+  NIA = GPR[RT];
+  TRACE_ALU_RESULT(RA);
+
+  // For cycle counting
+  COP0_COUNT++;
+}
+
+110110,5.RT,0,0000:R6P16JRC:16::JRC16
+"jrc r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT1(GPR[RT]);
+  NIA = GPR[RT];
+}
+
+010111,3.RT,3.RS,00,2.U:R6P16LB:16::LB16
+"lb r<TRT_NM>, <U>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lb (SD_, TRT_NM, U, TRS_NM);
+}
+
+010111,3.RT,3.RS,10,2.U:R6P16LB:16::LBU16
+"lbu r<TRT_NM>, <U>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2 (U, GPR[TRS_NM]);
+  do_lbu (SD_, TRT_NM, U, TRS_NM);
+  TRACE_ALU_RESULT (GPR[TRT_NM]);
+}
+
+011111,3.RT,3.RS,0,2.U,0:R6P16LH:16::LH16
+"lh r<TRT_NM>, <U_SHIFT_1BIT>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lh (SD_, TRT_NM, U_SHIFT_1BIT, TRS_NM);
+}
+
+011111,3.RT,3.RS,1,2.U,0:R6P16LH:16::LHU16
+"lhu r<TRT_NM>, <U_SHIFT_1BIT>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lhu (SD_, TRT_NM, U_SHIFT_1BIT, TRS_NM);
+}
+
+110100,3.RT,7.EU:R6P16:16::LI16
+"li r<TRT_NM>, <EU_127>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT1(GPR[TRT_NM]);
+  GPR[TRT_NM] = EU_127;
+  TRACE_ALU_RESULT(GPR[TRT_NM]);
+}
+
+011101,1.RT1,1.U2,3.RT2,1.RS1,1.U3,3.RS2:R6P16:16::LW4X4
+"lw r<RT_5_BIT_NM>, <U_LW4X4>(r<RS_5_BIT_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_lw (SD_, RT_5_BIT_NM, U_LW4X4, RS_5_BIT_NM);
+}
+
+000101,3.RT,3.RS,4.U:R6P16:16::LW16
+"lw r<TRT_NM>, <U_SHIFT_2BIT>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lw (SD_, TRT_NM, U_SHIFT_2BIT, TRS_NM);
+}
+
+010101,3.RT,7.U:R6P16:16::LWGP16
+"lw r<TRT_NM>, <U_SHIFT_2BIT>(gp)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lw (SD_, TRT_NM, U_SHIFT_2BIT, GPIDX);
+}
+
+001101,5.RT,5.U:R6P16:16::LWSP
+"lw r<RT>, <U_SHIFT_2BIT>(sp)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lw (SD_, RT, U_SHIFT_2BIT, SPIDX);
+}
+
+010100,3.RT,3.RS,3.RD,1:R6P16C:16::LWXS16
+"lwxs r<TRD_NM>, r<TRS_NM>(r<TRT_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lw (SD_, TRD_NM, GPR[TRS_NM] << 2, TRT_NM);
+}
+
+// These four instructions are grouped together because of a bug in GNUSIM
+// pattern recognition
+000100,5.RT,2.RS1,1.RS_CODE_1,2.RS_CODE_2:R6P16MOVE:16::P16MOVE_P16RI
+"move r<RT>, r<RS_MOVE>": RT != 0
+"syscall <RS_CODE_2>": RS1 == 1
+"sdbbp <CODE_BREAK>": RS1 == 3
+"break <CODE_BREAK>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (RT == 0) {
+    if (RS1 == 1)
+      SignalException (SystemCall, instruction_0);
+    else if (RS1 == 3)
+      SignalException (DebugBreakPoint, instruction_0);
+    else
+      do_break_nanomips (SD_, instruction_0);
+  }
+  else {
+    TRACE_ALU_INPUT2 (GPR[RT], GPR[RS_MOVE]);
+    GPR[RT] = GPR[RS_MOVE];
+    TRACE_ALU_RESULT2 (GPR[RT], GPR[RS_MOVE]);
+  }
+}
+
+101111,1.RT4,1.RD20,3.RT2_0,1.RS4,1.RD21,3.RS2_0:R6P16:16::MOVEP
+"movep r<TRD2>, r<TRE2>, r<TRS2>, r<TRT2>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  TRACE_ALU_INPUT4 (GPR[TRD2], GPR[TRE2], GPR[TRS2], GPR[TRT2]);
+  GPR[TRD2] = GPR[TRS2];
+  GPR[TRE2] = GPR[TRT2];
+  TRACE_ALU_RESULT2 (GPR[TRD2], GPR[TRE2]);
+
+  // For cycle counting
+  COP0_COUNT++;
+}
+
+111111,1.RE4,1.RS20,3.RE2_0,1.RD4,1.RS21,3.RD2_0:R6P16:16::MOVEPREV
+"movep r<TRD2_REV>, r<TRE2_REV>, r<TRS2_REV>, r<TRT2_REV>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  TRACE_ALU_INPUT4 (GPR[TRD2_REV], GPR[TRE2_REV], GPR[TRS2_REV], GPR[TRT2_REV]);
+  GPR[TRD2_REV] = GPR[TRS2_REV];
+  GPR[TRE2_REV] = GPR[TRT2_REV];
+  TRACE_ALU_RESULT2 (GPR[TRD2_REV], GPR[TRE2_REV]);
+
+  // For cycle counting
+  COP0_COUNT++;
+}
+
+010100,3.RT,3.RS,00,0,0:R6POOL16C00:16::NOT16
+"not r<TRT_NM>, r<TRS_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_nor (SD_, 0, TRS_NM, TRT_NM);
+}
+
+010100,3.RT,3.RS,11,0,0:R6POOL16C00:16::OR16
+"or r<TRT_NM>, r<TRS_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_or (SD_, TRS_NM, TRT_NM, TRT_NM);
+}
+
+000111,1.RT1,1,4.U,4.GPR_LIST_SAVE:R6P16SR:16::RESTORE.JRC16
+"restore.jrc <U_SHIFT_4BIT>":GPR_LIST_SAVE==15
+"restore.jrc <U_SHIFT_4BIT>, ra, %s<GPR_LIST_SAVE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (RT1 == 0)
+    do_restore_gprs_from_stack_and_adjust_sp(SD_, 30, GPR_LIST_SAVE, 0,
+                                             U_SHIFT_4BIT);
+  else
+    do_restore_gprs_from_stack_and_adjust_sp(SD_, 31, GPR_LIST_SAVE, 0,
+                                             U_SHIFT_4BIT);
+  NIA = RA;
+}
+
+000111,1.RT1,0,4.U,4.GPR_LIST_SAVE:R6P16SR:16::SAVE16
+"save <U_SHIFT_4BIT>, ra": GPR_LIST_SAVE == 0
+"save <U_SHIFT_4BIT>, ra, %s<GPR_LIST_SAVE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (RT1 == 0)
+    do_save_gprs_to_stack_and_adjust_sp(SD_, 30, GPR_LIST_SAVE, 0, U_SHIFT_4BIT);
+  else
+    do_save_gprs_to_stack_and_adjust_sp(SD_, 31, GPR_LIST_SAVE, 0, U_SHIFT_4BIT);
+
+}
+
+010111,3.RTZ,3.RS,01,2.U:R6P16LB:16::SB16
+"sb r<TRTZ>, <U>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_BYTE, GPR[TRS_NM], U, GPR[TRTZ]);
+}
+
+011111,3.RTZ,3.RS,0,2.U,1:R6P16LH:16::SH16
+"sh r<TRTZ>, <U_SHIFT_1BIT>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_HALFWORD, GPR[TRS_NM], U_SHIFT_1BIT, GPR[TRTZ]);
+}
+
+001100,3.RT,3.RS,0,3.SHIFT:R6P16SHIFT:16::SLL16
+"sll r<TRT_NM>, r<TRS_NM>, <SHIFT_DEC>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_sll (SD_, TRS_NM, TRT_NM, SHIFT_DEC);
+}
+
+001100,3.RT,3.RS,1,3.SHIFT:R6P16SHIFT:16::SRL16
+"srl r<TRT_NM>, r<TRS_NM>, <SHIFT_DEC>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_srl (SD_, TRS_NM, TRT_NM, SHIFT_DEC);
+}
+
+101100,3.RT,3.RS,3.RD,1:R6P16ADDU:16::SUBU16
+"subu r<TRD_NM>, r<TRS_NM>, r<TRT_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_subu (SD_, TRS_NM, TRT_NM, TRD_NM);
+}
+
+100101,3.RTZ,3.RS,4.U:R6P16:16::SW16
+"sw r<TRTZ>, <U_SHIFT_2BIT>(r<TRS_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_WORD, GPR[TRS_NM], U_SHIFT_2BIT, GPR[TRTZ]);
+}
+
+101101,5.RT,5.U:R6P16:16::SWSP
+"sw r<RT>, <U_SHIFT_2BIT>(sp)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_WORD, SP, U_SHIFT_2BIT, GPR[RT]);
+}
+
+010100,3.RT,3.RS,01,0,0:R6POOL16C00:16::XOR16
+"xor r<TRT_NM>, r<TRS_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_xor (SD_, TRT_NM, TRS_NM, TRT_NM);
+}
+
+// 32-bit instructions
+
+001000,5.RT,5.RS,5.RD,1.X,0100010,000:R6POOL32A0:32::ADD
+"add r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_add (SD_, RS, RT, RD);
+}
+
+000000,5.RT!0,5.RS,16.U:R6PPADDIU:32::ADDIU
+"addiu r<RT>, r<RS>, <U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addiu (SD_, RS, RT, U);
+}
+
+010001,5.RT,011,18.U:R6PGPBH:32::ADDIUGPB
+"addiu r<RT>, GP, <U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addiu (SD_, GPIDX, RT, U);
+}
+
+010000,5.RT,19.U,00:R6PGPW:32::ADDIUGPW
+"addiu r<RT>, GP, <U_SHIFT_2BIT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addiu (SD_, GPIDX, RT, U_SHIFT_2BIT);
+}
+
+111000,5.RT,9.S1,10.S2,1,1.S3:R6PLUI:32::ALUIPC
+"aluipc r<RT>, <AXUIPC_S_HI>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  address_word address = NIA + AXUIPC_S;
+
+  TRACE_ALU_INPUT2(GPR[RT], address);
+  GPR[RT] = address & ~0xfff;
+  TRACE_ALU_RESULT(GPR[RT]);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0101010,000:R6POOL32A0:32::ADDU
+"addu r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addu (SD_, RS, RT, RD);
+}
+
+001000,5.RT,5.RS,5.RD,5.IMMEDIATE,011,111:R6POOL32A0:32::EXTW
+"prepend r<RT>, r<RS>, <IMMEDIATE>": RD == RS
+"align r<RD>, r<RS>, r<RT>, <IMMEDIATE>": IMMEDIATE != 0
+"extw r<RD>, r<RS>, r<RT>, <IMMEDIATE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (IMMEDIATE != 0) {
+    uint64_t tmp = ((uint64_t)GPR[RT] << 32) | (0xffffffff & GPR[RS]);
+    TRACE_ALU_INPUT4 (GPR[RD], GPR[RS], GPR[RT], tmp);
+    GPR[RD] = EXTEND32 (tmp >> IMMEDIATE);
+    TRACE_ALU_RESULT (GPR[RD]);
+  } else {
+    TRACE_ALU_INPUT2 (GPR[RD], GPR[RT]);
+    GPR[RD] = GPR[RT];
+    TRACE_ALU_RESULT (GPR[RD]);
+  }
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1001010,000:R6POOL32A0:32::AND
+"and r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_and (SD_, RS, RT, RD);
+}
+
+100000,5.RT,5.RS,0010,12.U:R6PU12:32::ANDI
+"andi r<RT>, r<RS>, <U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_andi (SD_, RS, RT, U);
+}
+
+001010,1,24.S1,1.S2:R6PBAL:32::BALC
+"balc <ADDRESS26>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT1(RA);
+  RA = NIA;
+  NIA = ADDRESS26;
+  TRACE_ALU_RESULT(RA);
+
+  // For cycle counting
+  COP0_COUNT++;
+}
+
+001010,0,24.S1,1.S2:R6PBAL:32::BC
+"bc <ADDRESS26>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  NIA = ADDRESS26;
+}
+
+100010,5.RT,5.RS,00,13.S1,1.S2:R6PBR1:32::BEQC
+"beqc r<RS>, r<RT>, <ADDRESS15>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RS], GPR[RT]);
+  if (GPR[RS] == GPR[RT])
+    NIA = ADDRESS15;
+}
+
+110010,5.RT,000,7.U,10.S1,1.S2:P7PBRI:32::BEQIC
+"beqic r<RT>, <U>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], U);
+  if (GPR[RT] == U) {
+    NIA = ADDRESS12;
+  }
+}
+
+100010,5.RT,5.RS,10,13.S1,1.S2:P7PBR1:32::BGEC
+"bgec r<RS>, r<RT>, <ADDRESS15>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RS], GPR[RT]);
+  if ((signed_word) GPR[RS] >= (signed_word) GPR[RT])
+    NIA = ADDRESS15;
+}
+
+110010,5.RT,010,7.U,10.S1,1.S2:P7PBRI:32::BGEIC
+"bgeic r<RT>, <U>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], U);
+  if ((signed_word) GPR[RT] >= U) {
+    NIA = ADDRESS12;
+  }
+}
+
+100010,5.RT,5.RS,11,13.S1,1.S2:P7PBR2:32::BGEUC
+"bgeuc r<RS>, r<RT>, <ADDRESS15>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RS], GPR[RT]);
+  if ((unsigned_word) (GPR[RS]) >= (unsigned_word)(GPR[RT])) {
+    NIA = ADDRESS15;
+  }
+}
+
+110010,5.RT,011,7.U,10.S1,1.S2:P7PBRI:32::BGEUIC
+"bgeuic r<RT>, <U>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], U);
+  if ((unsigned_word) GPR[RT] >= U) {
+    NIA = ADDRESS12;
+  }
+}
+
+101010,5.RT,5.RS,10,13.S1,1.S2:P7PBR2:32::BLTC
+"bltc r<RS>, r<RT>, <ADDRESS15>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RS], GPR[RT]);
+  if ((signed_word) GPR[RS] < (signed_word) GPR[RT])
+    NIA = ADDRESS15;
+}
+
+110010,5.RT,110,7.U,10.S1,1.S2:P7PBRI:32::BLTIC
+"bltic r<RT>, <U>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], U);
+  if ((signed_word) GPR[RT] < U) {
+    NIA = ADDRESS12;
+  }
+}
+
+101010,5.RT,5.RS,11,13.S1,1.S2:P7PBR2:32::BLTUC
+"bltuc r<RS>, r<RT>, <ADDRESS15>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RS], GPR[RT]);
+  if ((unsigned_word) GPR[RS] < (unsigned_word) GPR[RT]) {
+    NIA = ADDRESS15;
+  }
+}
+
+110010,5.RT,111,7.U,10.S1,1.S2:P7PBRI:32::BLTIUC
+"bltiuc <RT>, <U>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], U);
+  if ((unsigned_word) GPR[RT] < U) {
+    NIA = ADDRESS12;
+  }
+}
+
+101010,5.RT,5.RS,00,13.S1,1.S2:R6PBR2:32::BNEC
+"bnec r<RS>, r<RT>, <ADDRESS15>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RS], GPR[RT]);
+  if (GPR[RS] != GPR[RT])
+    NIA = ADDRESS15;
+}
+
+110010,5.RT,100,7.U,10.S1,1.S2:R6PBRI:32::BNEIC
+"bneic r<RT>, <U>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], U);
+  if (GPR[RT] != U) {
+    NIA = ADDRESS12;
+  }
+}
+
+000000,00000,10,19.CODE:R6PRI:32::BREAK
+"break %#lx<CODE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_break_nanomips (SD_, instruction_0);
+}
+
+101001,5.OP,5.RS,1.S1,0111,0,01,8.S2:R6PLSS1:32::CACHE
+"cache <OP>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_cache (SD_, OP, RS, S_9_BIT, instruction_0);
+}
+
+001000,5.RT,5.RS,0100101,100,111,111:R6POOL32AXF4:32::CLO
+"clo r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_clo (SD_, RT, RS);
+}
+
+001000,5.RT,5.RS,0101101,100,111,111:R6POOL32AXF4:32::CLZ
+"clz r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_clz (SD_, RT, RS);
+}
+
+001000,5.RT,5.X,01,00011,101,111,111:R6POOL32AXF5GROUP1:32::DI
+"di":RT == 0
+"di r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_di (SD_, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0100011,000:R6POOL32A0:32::DIV
+"div r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_div (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0110011,000:R6POOL32A0:32::DIVU
+"divu r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_divu (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.X,01,01011,101,111,111:R6POOL32AXF5GROUP1:32::EI
+"ei":RT == 0
+"ei r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_ei (SD_, RT);
+}
+
+001000,9.X,0,11,11001,101,111,111:R6ERETX:32::ERET
+"eret"
+*nanomips32r6:
+*nanomips64r6:
+{
+  NIA = do_eret(SD_, 0, NIA);
+}
+
+001000,9.X,1,11,11001,101,111,111:R6ERETX:32::ERETNC
+"eretnc"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  SignalException (ReservedInstruction, instruction_0);
+  NIA = do_eret(SD_, 1, NIA);
+}
+
+100000,5.RT,5.RS,1111,0,5.MSBD,0,5.LSB:R6PEXT:32::EXT
+"ext r<RT>, r<RS>, <LSB>, <MSBD+1>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  if (LSB + MSBD + 1 > 32)
+    Unpredictable ();
+
+  do_ext (SD_, RT, RS, LSB, MSBD);
+}
+
+100000,5.RT,5.RS,1110,0,5.MSBD,0,5.LSB:R6PINS:32::INS
+"ins r<RT>, r<RS>, <INS_POS>, <INS_SIZE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  if ((1 + MSBD - LSB) < 1)
+    Unpredictable ();
+  do_ins (SD_, RT, RS, LSB, MSBD);
+}
+
+100000,5.RT,5.RS,1101,0,4.SHIFTX,1.STRIPE,0,5.SHIFT:R6PROTX:32::ROTX
+"bitrev r<RT>, r<RS>": SHIFT == 31 && SHIFTX_1BIT == 0
+"bitswap r<RT>, r<RS>": SHIFT == 7 && SHIFTX_1BIT == 8 && STRIPE == 1
+"bitswap.h r<RT>, r<RS>": SHIFT == 15 && SHIFTX_1BIT == 16
+"byteswap r<RT>, r<RS>": SHIFT == 24 && SHIFTX_1BIT == 8
+"wsbh r<RT>, r<RS>": SHIFT == 8 && SHIFTX_1BIT == 24
+"rotx r<RT>, r<RS>, <SHIFT>, <SHIFTX_1BIT>": STRIPE == 0
+"rotx r<RT>, r<RS>, <SHIFT>, <SHIFTX_1BIT>, <STRIPE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+
+  TRACE_ALU_INPUT4 (GPR[RT], GPR[RS], SHIFT, SHIFTX_1BIT);
+  do_rotx (SD_, RT, RS, SHIFT, SHIFTX_1BIT, STRIPE);
+  TRACE_ALU_RESULT (GPR[RT]);
+}
+
+010010,5.RT,5.RS,0000,12.X:R6PJ:32::JALRC
+"jalrc r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  unsigned_word address;
+  TRACE_ALU_INPUT3(GPR[RT], GPR[RS], RA);
+  GPR[RT] = NIA;
+  address = GPR[RS];
+  NIA = address;
+
+  // For cycle counting
+  COP0_COUNT++;
+  TRACE_ALU_RESULT(NIA);
+
+}
+
+010010,5.RT,5.RS,0001,12.X:R6PJ:32::JALRC.HB
+"jalrc.hb r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  unsigned_word address;
+  GPR[RT] = NIA;
+  address = GPR[RS];
+  NIA = address;
+
+  // For cycle counting
+  COP0_COUNT++;
+}
+
+100001,5.RT,5.RS,0000,12.U:R6PLSU12:32::LB
+"lb r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lb (SD_, RT, U, RS);
+}
+
+010001,5.RT,000,18.U:R6PLSGP:32::LBGP
+"lb r<RT>, <U>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lb (SD_, RT, U, GPIDX);
+}
+
+101001,5.RT,5.RS,1.S1,0000,0,00,8.S2:R6PLSS0:32::LBS9
+"lb r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lb (SD_, RT, S_9_BIT, RS);
+}
+
+100001,5.RT,5.RS,0010,12.U:R6PLSU12:32::LBU
+"lbu r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lbu (SD_, RT, U, RS);
+}
+
+010001,5.RT,010,18.U:R6GPBH:32::LBUGP
+"lbu r<RT>, <U>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2 (U, GP);
+  do_lbu (SD_, RT, U, GPIDX);
+  TRACE_ALU_RESULT (GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.S1,0010,0,00,8.S2:R6PLSS0:32::LBUS9
+"lbu r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lbu (SD_, RT, S_9_BIT, RS);
+}
+
+001000,5.RT,5.RS,5.RD,0010,0,000,111:R6PPLSX:32::LBUX
+"lbux r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lbu (SD_, RD, GPR[RS], RT);
+}
+
+001000,5.RT,5.RS,5.RD,0000,0,000,111:R6PPLSX:32::LBX
+"lbx r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lb (SD_, RD, GPR[RS], RT);
+}
+
+100001,5.RT,5.RS,0100,12.U:R6PLSU12:32::LH
+"lh r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lh (SD_, RT, U, RS);
+}
+
+010001,5.RT,100,17.U,0:R6PGPLH:32::LHGP
+"lh r<RT>, <U_SHIFT_1BIT>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lh (SD_, RT, U_SHIFT_1BIT, GPIDX);
+}
+
+101001,5.RT,5.RS,1.S1,0100,0,00,8.S2:R6PLSS0:32::LHS9
+"lh r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lh (SD_, RT, S_9_BIT, RS);
+}
+
+100001,5.RT,5.RS,0110,12.U:R6PLSU12:32::LHU
+"lhu r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lhu (SD_, RT, U, RS);
+}
+
+010001,5.RT,100,17.U,1:R6PLSGP:32::LHUGP
+"lhu r<RT>, <U_SHIFT_1BIT>(gp)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lhu (SD_, RT, U_SHIFT_1BIT, GPIDX);
+}
+
+101001,5.RT,5.RS,1.S1,0110,0,00,8.S2:R6PLSS0:32::LHUS9
+"lhu r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lhu (SD_, RT, S_9_BIT, RS);
+}
+
+001000,5.RT,5.RS,5.RD,0110,0,000,111:R6PPLSX:32::LHUX
+"lhux r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lhu (SD_, RD, GPR[RS], RT);
+}
+
+001000,5.RT,5.RS,5.RD,0110,1,000,111:R6PPLSXS:32::LHUXS
+"lhux r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lhu (SD_, RD, GPR[RS] << 1, RT);
+}
+
+001000,5.RT,5.RS,5.RD,0100,0,000,111:R6PPLSX:32::LHX
+"lhx r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lh (SD_, RD, GPR[RS], RT);
+}
+
+001000,5.RT,5.RS,5.RD,0100,1,000,111:R6PPLSXS:32::LHXS
+"lhxs r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lh (SD_, RD, GPR[RS] << 1, RT);
+}
+
+101001,5.RT,5.RS,1.S1,1010,0,01,6.S2,00:R6PLL:32::LL
+"ll r<RT>, <S_9_BIT_LLSC>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3(GPR[RT], S_9_BIT_LLSC, GPR[RS]);
+  do_ll (SD_, RT, S_9_BIT_LLSC, RS);
+  TRACE_ALU_RESULT(GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.X1,1010,0,01,5.RU,1.X2,01:R6PLL:32::LLWP
+"llwp r<RT>, r<RU>, (r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_llwp (SD_, RT, RU, 0, RS);
+}
+
+001000,5.RT,5.RS,5.RD,2.U,3.X,001,111:R6POOL32A7:32::LSA
+"lsa r<RD>, r<RS>, r<RT>, <U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lsa (SD_, RD, RS, RT, U);
+}
+
+111000,5.RT,9.S1,10.S2,0,1.S3:R6PLUI:32::LUI
+"lui r<RT>, <AXUIPC_S_HI>, <AXUIPC_S_LO>":AXUIPC_S_LO != 0
+"lui r<RT>, <AXUIPC_S_HI>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2 (GPR[RT], AXUIPC_S);
+  GPR[RT] = AXUIPC_S;
+  TRACE_ALU_RESULT (GPR[RT]);
+}
+
+100001,5.RT,5.RS,1000,12.U:R6PLSU12:32::LW
+"lw r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3 (GPR[RT], U, GPR[RS]);
+  do_lw (SD_, RT, U, RS);
+  TRACE_ALU_RESULT (GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.S1,1000000,8.S2:R6PLSS0:32::LWS9
+"lw r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lw (SD_, RT, S_9_BIT, RS);
+}
+
+101001,5.RT,5.RS,1.S1,3.COUNT3,0,1,00,8.S2:R6PLSWM:32::LWM
+"lwm r<RT>, <S_9_BIT>(r<RS>), <COUNT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  int counter = 0;
+  int dest;
+  int this_offset;
+
+  check_nms_flag (SD_);
+
+  while (counter != COUNT)
+  {
+    dest = (RT & 0x10) | ((RT + counter) & 0x1F);
+
+    if ((dest == RS) && (counter != (COUNT - 1)))
+      Unpredictable ();
+
+    this_offset = S_9_BIT + (counter << 2);
+
+    do_lw (SD_, dest, this_offset, RS);
+
+    counter++;
+    if (counter != 0)
+      COP0_COUNT++;
+  }
+}
+
+010000,5.RT,19.U,10:R6PGPW:32::LWGP
+"lw r<RT>, <U_SHIFT_2BIT>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RT], GPR[RT]);
+  do_lw (SD_, RT, U_SHIFT_2BIT, GPIDX);
+  TRACE_ALU_RESULT(GPR[RT]);
+}
+
+011000,5.RT,01011,16.IMM48:R6POOL48I:32::LWPC48
+"lwpc r<RT>, <IMM48>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint16_t S2;
+  uint32_t total;
+  check_nms_flag (SD_);
+  S2 = do_load(SD_, AccessLength_HALFWORD, CIA + 4, 0);
+  total = S2 << 16 | IMM48;
+
+  do_lwpc_nanomips (SD_, RT, total, CIA + 6);
+  NIA = CIA + 6;
+}
+
+001000,5.RT,5.RS,5.RD,1000,0,000,111:R6PPLSX:32::LWX
+"lwx r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lw (SD_, RD, GPR[RS], RT);
+}
+
+001000,5.RT,5.RS,5.RD,1000,1,000,111:R6PPLSXS:32::LWXS
+"lwxs r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_lw (SD_, RD, GPR[RS] << 2, RT);
+}
+
+001000,5.RT,5.C0S,5.SEL,1.X,0000110,000:R6POOL32A0:32::MFC0
+"mfc0 r<RT>, r<C0S>, <SEL>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  DecodeCoproc (instruction_0, 0, cp0_mfc0, RT, C0S, SEL);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0101011,000:R6POOL32A0:32::MOD
+"mod r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_mod (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0111011,000:R6POOL32A0:32::MODU
+"modu r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_modu (SD_, RD, RS, RT);
+}
+
+000010,1.RT1,1.RD,3.RT2,20.S1,1.S2:R6MOVEBALC:32::MOVE.BALC
+"move.balc r<RD1>, r<RT_5_BIT_NM_Z>, <ADDRESS22>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  TRACE_ALU_INPUT2(GPR[RD1], GPR[RT_5_BIT_NM_Z]);
+  GPR[RD1] = GPR[RT_5_BIT_NM_Z];
+  RA = NIA;
+  NIA = ADDRESS22;
+  TRACE_ALU_RESULT(GPR[RD1]);
+
+  // For cycle counting
+  COP0_COUNT += 2;
+}
+
+001000,5.RT,5.RS,5.RD,1,1000010,000:R6PCMOVE:32::MOVN
+"movn r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT2(GPR[RS], GPR[RT]);
+  do_movn (SD_, RD, RS, RT);
+  TRACE_ALU_RESULT(GPR[RD]);
+}
+
+001000,5.RT,5.RS,5.RD,0,1000010,000:R6PCMOVE:32::MOVZ
+"movz r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_movz (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.C0S,5.SEL,1.X,0001110,000:R6POOL32A0:32::MTC0
+"mtc0 r<RT>, r<C0S>, <SEL>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  DecodeCoproc (instruction_0, 0, cp0_mtc0, RT, C0S, SEL);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0001011,000:R6POOL32A0:32::MUH
+"muh r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_muh (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0011011,000:R6POOL32A0:32::MUHU
+"muhu r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_muhu (SD_, RD, RS, RT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0000011,000:R6POOL32A0:32::MUL32
+"mul r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_mul (SD_, RD, RS, RT);
+}
+
+001111,1.RT1,0,3.RT2,1.RS1,1,3.RS2:R6P164X4:16::MUL4X4
+"mul r<RT_5_BIT_NM>, r<RS_5_BIT_NM>, r<RT_5_BIT_NM>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_mul (SD_, RT_5_BIT_NM, RS_5_BIT_NM, RT_5_BIT_NM);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0010011,000:R6POOL32A0:32::MULU
+"mulu r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_mulu (SD_, RD, RS, RT);
+}
+
+100000,00000,5.X1,1100,3.X2,0000,00000:R6PSLL:32::NOP32
+"nop"
+*nanomips32r6:
+*nanomips64r6:
+{
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1011010,000:R6POOL32A0:32::NOR
+"nor r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_nor (SD_, RS, RT, RD);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1010010,000:R6POOL32A0:32::OR32
+"or r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_or (SD_, RS, RT, RD);
+}
+
+100000,5.RT,5.RS,0000,12.U:R6PU12:32::ORI
+"ori r<RT>, r<RS>, <U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_ori (SD_, RS, RT, U);
+}
+
+100000,00000,5.X1,1100,3.X2,0000,00101:R6PSLL:32::PAUSE
+"pause"
+*nanomips32r6:
+*nanomips64r6:
+{
+  sim_io_printf (SD, "Not implemented");
+}
+
+101001,5.HINT!31,5.RS,1.S1,0011,0,00,8.S2:R6PPREFS9:32::PREFS9
+"pref <HINT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_pref (SD_, HINT, S_9_BIT, RS);
+}
+
+100001,5.HINT,5.RS,0011,12.U:R6PLSU12:32::PREFU12
+"pref <HINT>, <U>(r<RS>)": HINT != 31
+"synci <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (HINT != 31)
+   do_pref (SD_, HINT, U, RS);
+  else
+  {
+    // synci - nothing to do currently
+    sim_io_printf (SD, "Not implemented");
+  }
+}
+
+100000,5.RT,0,4.GPR_LIST_SAVE,0011,9.U,1.GP_SAVE,10:R6PPSR:32::RESTORE
+"restore <U_SHIFT_3BIT>, r<RT>": GPR_LIST_SAVE == 0
+"restore <U_SHIFT_3BIT>, r<RT>, %s<GPR_LIST_SAVE>": !GP_SAVE && GPR_LIST_SAVE != 0
+"restore <U_SHIFT_3BIT>, r<RT>": !GP_SAVE && GPR_LIST_SAVE < 2
+"restore <U_SHIFT_3BIT>, r<RT>, %s<GPR_LIST_SAVE>" : !GP_SAVE && GPR_LIST_SAVE >=2
+"restore <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>": GP_SAVE && GPR_LIST_SAVE < 2
+"restore <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>, %s<GPR_LIST_SAVE>" : GP_SAVE && GPR_LIST_SAVE >=2
+"restore <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>": GP_SAVE && GPR_LIST_SAVE < 3
+"restore <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>, %s<GPR_LIST_SAVE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_restore_gprs_from_stack_and_adjust_sp(SD_, RT, GPR_LIST_SAVE,
+                                           GP_SAVE, U_SHIFT_3BIT);
+}
+
+100000,5.RT,0,4.GPR_LIST_SAVE,0011,9.U,1.GP_SAVE,11:R6PPSR:32::RESTORE.JRC
+"restore.jrc <U_SHIFT_3BIT>, r<RT>": GPR_LIST_SAVE == 0
+"restore.jrc <U_SHIFT_3BIT>, r<RT>, %s<GPR_LIST_SAVE>": !GP_SAVE && GPR_LIST_SAVE != 0
+"restore.jrc <U_SHIFT_3BIT>, r<RT>": !GP_SAVE && GPR_LIST_SAVE < 2
+"restore.jrc <U_SHIFT_3BIT>, r<RT>, %s<GPR_LIST_SAVE>" : !GP_SAVE && GPR_LIST_SAVE >=2
+"restore.jrc <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>": GP_SAVE && GPR_LIST_SAVE < 2
+"restore.jrc <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>, %s<GPR_LIST_SAVE>" : GP_SAVE && GPR_LIST_SAVE >=2
+"restore.jrc <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>": GP_SAVE && GPR_LIST_SAVE < 3
+"restore.jrc <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>, %s<GPR_LIST_SAVE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_restore_gprs_from_stack_and_adjust_sp(SD_, RT, GPR_LIST_SAVE,
+                                           GP_SAVE, U_SHIFT_3BIT);
+
+  NIA = GPR[RAIDX];
+}
+
+100000,5.RT,5.RS,1100,3.X,0110,5.SHIFT:R6PSHIFT:32::ROTR
+"rotr r<RT>, r<RS>, <SHIFT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  GPR[RT] = do_ror (SD_, GPR[RS], SHIFT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0011010,000:R6POOL32A0:32::ROTRV
+"rotrv r<RD>, r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint32_t shift = GPR[RT] & 0x1f;
+  GPR[RD] = do_ror (SD_, GPR[RS], shift);
+}
+
+001000,5.RT,5.RS,5.RD,0,1100010,000:R6POOL32A0:32::XOR
+"xor r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_xor (SD_, RS, RT, RD);
+}
+
+100000,5.RT,5.RS,0001,12.U:R6PU12:32::XORI
+"xori r<RT>, r<RS>, <U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_xori (SD_, RS, RT, U);
+}
+
+100000,5.RT,0,4.GPR_LIST_SAVE,0011,9.U,1.GP_SAVE,00:R6PPSR:32::SAVE
+"save <U_SHIFT_3BIT>, r<RT>": GPR_LIST_SAVE == 0
+"save <U_SHIFT_3BIT>, r<RT>, %s<GPR_LIST_SAVE>":  !GP_SAVE && GPR_LIST_SAVE != 0
+"save <U_SHIFT_3BIT>, r<RT>": !GP_SAVE && GPR_LIST_SAVE < 2
+"save <U_SHIFT_3BIT>, r<RT> %s<GPR_LIST_SAVE>" : !GP_SAVE && GPR_LIST_SAVE >=2
+"save <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>": GP_SAVE && GPR_LIST_SAVE < 2
+"save <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>, %s<GPR_LIST_SAVE>" : GP_SAVE && GPR_LIST_SAVE >=2
+"save <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>": GP_SAVE && GPR_LIST_SAVE < 3
+"save <U_SHIFT_3BIT>, r<RT>, %s<GP_SAVE>, %s<GPR_LIST_SAVE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_save_gprs_to_stack_and_adjust_sp(SD_, RT, GPR_LIST_SAVE,
+                                      GP_SAVE, U_SHIFT_3BIT);
+}
+
+100001,5.RT,5.RS,0001,12.U:R6PLSU12:32::SBU12
+"sb r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_BYTE, GPR[RS], U, GPR[RT]);
+}
+
+010001,5.RT,001,18.U:R6PGPBH:32::SBGP
+"sb r<RT>, <U>(gp)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_BYTE, GP, U, GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.S1,0001,0,00,8.S2:R6PLSS0:32::SBS9
+"sb r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_BYTE, GPR[RS], S_9_BIT, GPR[RT]);
+}
+
+001000,5.RT,5.RS,5.RD,0001,0,000,111:R6PPLSX:32::SBX
+"sbx r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_store (SD_, AccessLength_BYTE, GPR[RT], GPR[RS], GPR[RD]);
+}
+
+101001,5.RT,5.RS,1.S1,1011,0,01,6.S2,00:R6PSC:32::SC
+"sc r<RT>, <S_9_BIT_LLSC>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_sc (SD_, RT, S_9_BIT_LLSC, RS, instruction_0, 1);
+}
+
+101001,5.RT,5.RS,1.X1,1011,0,01,5.RU,1.X,01:R6PSC:32::SCWP
+"scwp r<RT>, r<RU>, (r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  int offset = BigEndianCPU ? 0 : 4;
+
+  do_sc (SD_, RU, offset, RS, instruction_0, 0);
+  do_sc (SD_, RT, offset ^ 4, RS, instruction_0, 1);
+}
+
+001000,5.RT,5.RS,6.X,0000001,000:R6POOL32A0:32::SEB
+"seb r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_seb (SD_, RT, RS);
+}
+
+001000,5.RT,5.RS,6.X,0001001,000:R6POOL32A0:32::SEH
+"seh r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_seh (SD_, RT, RS);
+}
+
+100000,5.RT,5.RS,0110,12.IMMEDIATE:R6PU12:32::SEQI
+"seqi r<RT>, r<RS>, <IMMEDIATE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  TRACE_ALU_INPUT3(GPR[RT], GPR[RS], IMMEDIATE);
+  GPR[RT] = (GPR[RS] == IMMEDIATE) ? 1 : 0;
+  TRACE_ALU_RESULT(GPR[RT]);
+}
+
+100001,5.RT,5.RS,0101,12.U:R6PLSU12:32::SHU12
+"sh r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_HALFWORD, GPR[RS], U, GPR[RT]);
+}
+
+010001,5.RT,101,17.U,0:R6PGPSH:32::SHGP
+"sh r<RT>, <U_SHIFT_1BIT>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_HALFWORD, GP, U_SHIFT_1BIT, GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.S1,0101,0,00,8.S2:R6PLSS0:32::SHS9
+"sh r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_HALFWORD, GPR[RS], S_9_BIT, GPR[RT]);
+}
+
+001000,5.RT,5.RS,5.RD,0101,0,000,111:R6PPLSX:32::SHX
+"shx r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_store (SD_, AccessLength_HALFWORD, GPR[RT], GPR[RS], GPR[RD]);
+}
+
+001000,5.RT,5.RS,5.RD,0101,1,000,111:R6PPLSXS:32::SHXS
+"shxs r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_store (SD_, AccessLength_HALFWORD, GPR[RT], GPR[RS] << 1, GPR[RD]);
+}
+
+000000,00000,00,19.CODE:R6PRI:32::SIGRIE
+"sigrie %#lx<CODE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  SignalException (ReservedInstruction, instruction_0);
+}
+
+100000,5.RT!0,5.RS,1100,3.X,0000,5.SHIFT:R6PSLL:32::SLL32
+"sll r<RT>, r<RS>, <SHIFT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_sll (SD_, RS, RT, SHIFT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0000010,000:R6POOL32A0:32::SLLV
+"sllv r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_sllv (SD_, RT, RS, RD);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1101010,000:R6POOL32A0:32::SLT
+"slt r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_slt (SD_, RS, RT, RD);
+}
+
+100000,5.RT,5.RS,0100,12.IMMEDIATE:R6PU12:32::SLTI
+"slti r<RT>, r<RS>, <IMMEDIATE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_slti (SD_, RS, RT, EXTEND12(IMMEDIATE));
+}
+
+100000,5.RT,5.RS,0101,12.U:R6PU12:32::SLTIU
+"sltiu r<RT>, r<RS>, <U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_sltiu (SD_, RS, RT, EXTEND12(U));
+}
+
+001000,5.RT,5.RS,5.RD!0,1.X,1110010,000:R6PSLTU:32::SLTU
+"sltu r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_sltu (SD_, RS, RT, RD);
+}
+
+100000,5.RT,5.RS,1100,3.X,0100,5.SHIFT:R6PSHIFT:32::SRA
+"sra r<RT>, r<RS>, <SHIFT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_sra (SD_, RS, RT, SHIFT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0010010,000:R6POOL32A0:32::SRAV
+"srav r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_srav (SD_, RT, RS, RD);
+}
+
+100000,5.RT,5.RS,1100,3.X,0010,5.SHIFT:R6PSHIFT:32::SRL32
+"srl r<RT>, r<RS>, <SHIFT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_srl (SD_, RS, RT, SHIFT);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0001010,000:R6POOL32A0:32::SRLV
+"srlv r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_srlv (SD_, RT, RS, RD);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0110010,000:R6POOL32A0:32::SUB
+"sub r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_sub (SD_, RS, RT, RD);
+}
+
+001000,5.RT,5.RS,5.RD,1.X,0111010,000:R6POOL32A0:32::SUBU32
+"subu r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_subu (SD_, RS, RT, RD);
+}
+
+100001,5.RT,5.RS,1001,12.U:R6PLSU12:32::SWU12
+"sw r<RT>, <U>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_WORD, GPR[RS], U, GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.S1,1001,0,00,8.S2:R6PLS0:32::SWS9
+"sw r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_WORD, GPR[RS], S_9_BIT, GPR[RT]);
+}
+
+010000,5.RT,19.U,11:R6PGPW:32::SWGP
+"sw r<RT>, <U_SHIFT_2BIT>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_WORD, GP, U_SHIFT_2BIT, GPR[RT]);
+}
+
+011000,5.RT,01111,16.IMM48:R6POOL48I:32::SWPC48
+"swpc r<RT>, <IMM48>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint16_t U2;
+  uint32_t total;
+  check_nms_flag (SD_);
+  U2 = do_load (SD_, AccessLength_HALFWORD, CIA + 4, 0);
+  total = U2 << 16 | IMM48;
+  TRACE_ALU_INPUT2(GPR[RT], total);
+  do_store(SD_, AccessLength_WORD, CIA + 6, total, GPR[RT]);
+  TRACE_ALU_RESULT(GPR[RT]);
+  NIA = CIA + 6;
+}
+
+
+110101,3.RTZ,7.U:R6P16:16::SWGP16
+"sw r<TRTZ>, <U_SHIFT_2BIT>(GP)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_store (SD_, AccessLength_WORD, GP, U_SHIFT_2BIT, GPR[TRTZ]);
+}
+
+001000,5.RT,5.RS,5.RD,1001,0,000,111:R6PPLSX:32::SWX
+"swx r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_store (SD_, AccessLength_WORD, GPR[RT], GPR[RS], GPR[RD]);
+}
+
+001000,5.RT,5.RS,5.RD,1001,1,000,111:R6PPLSXS:32::SWXS
+"swxs r<RD>, r<RS>(r<RT>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_store (SD_, AccessLength_WORD, GPR[RT], GPR[RS] << 2, GPR[RD]);
+}
+
+111101,1.RT1,1.U2,3.RT2,1.RS1,1.U3,3.RS2:R6P16:16::SW4X4
+"sw r<RT_5_BIT_NM_Z>, <U_LW4X4>(r<RS_5_BIT_NM>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_store (SD_, AccessLength_WORD, GPR[RS_5_BIT_NM], U_LW4X4, GPR[RT_5_BIT_NM_Z]);
+}
+
+101001,5.RT,5.RS,1.S1,3.COUNT3,1,1,00,8.S2:R6PLSWM:32::SWM
+"swm r<RT>, <S_9_BIT>(r<RS>), <COUNT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  int counter = 0;
+  int source;
+  int offsetm;
+
+  check_nms_flag (SD_);
+
+  while (counter != COUNT)
+  {
+    if (RT == 0)
+      source = 0;
+    else
+      source = (RT & 0x10) | ((RT + counter) & 0x1F);
+
+    offsetm = S_9_BIT + (counter << 2);
+
+    do_sw (SD_, source, offsetm, RS);
+
+    counter++;
+
+    if (counter != 0)
+      COP0_COUNT++;
+  }
+}
+
+100000,00000,5.STYPE,1100,3.X,0000,00110:R6PHB:32::SYNC
+"sync":STYPE==0
+"sync <STYPE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  SyncOperation (STYPE);
+}
+
+101001,11111,5.RS,1.S1,0011,0,00,8.S2:R6PPREFS:32::SYNCI
+"synci <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // sync i-cache - nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+000000,00000,11,19.CODE:R6PRI:32::SDBBP32
+"sdbbp %#lx<CODE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  SignalException (DebugBreakPoint, instruction_0);
+}
+
+001000,10.X,00,00001,101,111,111:R6POOL32AXF5GROUP0:32::TLBP
+"tlbp"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,10.X,00,10001,101,111,111:R6POOL32AXF5GROUP0:32::TLBWI
+"tlbwi"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,10.X,00,11001,101,111,111:R6POOL32AXF5GROUP0:32::TLBWR
+"tlbwr"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+
+001000,0000000000,01,00001,101,111,111:R6POOL32AXF5GROUP1:32::TLBINV
+"tlbinv"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // invalidate a set of TLB entries based on ASID and Index match - nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,0000000000,01,01001,101,111,111:R6POOL32AXF5GROUP1:32::TLBINVF
+"tlbinvf"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // invalidate a set of TLB entries based on Index match - nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,10.CODE,10,00101,101,111,111:R6PSYSCALL:32::SYSCALL
+"syscall %#lx<CODE>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  SignalException (SystemCall, instruction_0);
+}
+
+100000,00000,5.X1,1100,3.X2,0000,00011:R6PHB:32::EHB
+"ehb"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // Do nothing, there are no hazards to clear
+}
+
+001000,5.RT,5.RS,5.X,0,0000000,000:R6PTRAP:32::TEQ
+"teq r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+
+  if (GPR[RS] == GPR[RT])
+    SignalException(Trap, instruction_0);
+}
+
+001000,5.RT,5.RS,5.X,1,0000000,000:R6PTRAP:32::TNE
+"tne r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+
+  if (GPR[RS] != GPR[RT])
+    SignalException(Trap, instruction_0);
+}
+
+101001,5.RT,5.RS,1.S1,0100,0,01,8.S2:R6PLSS1:32::UALH
+"ualh r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+
+  TRACE_ALU_INPUT3(GPR[RT], S_9_BIT, GPR[RS]);
+  do_lh (SD_, RT, S_9_BIT, RS);
+  TRACE_ALU_RESULT(GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.S1,3.COUNT3,0,1,01,8.S2:R6PLSUAWM:32::UALWM
+"ualwm r<RT>, <S_9_BIT>(r<RS>), <COUNT>":COUNT != 1
+"ualw r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  int i;
+  int dest;
+  int this_offset;
+
+  address_word base = GPR[RS];
+  for(i = 0; i< COUNT; i++)
+  {
+    dest = (RT & 0x10) | ((RT + i) & 0x1F);
+
+    if (dest == RS && i != COUNT - 1)
+      Unpredictable ();
+
+    this_offset = S_9_BIT + (i << 2);
+
+    if(BigEndianCPU) {
+      GPR[dest] = EXTEND32 (do_load_left (SD_, AccessLength_WORD, base,
+         EXTEND16 (this_offset), GPR[dest]));
+      GPR[dest] = EXTEND32 (do_load_right (SD_, AccessLength_WORD, base,
+         EXTEND16 (this_offset + AccessLength_WORD), GPR[dest]));
+    } else {
+      GPR[dest] = EXTEND32 (do_load_right (SD_, AccessLength_WORD, base,
+         EXTEND16 (this_offset), GPR[dest]));
+      GPR[dest] = EXTEND32 (do_load_left (SD_, AccessLength_WORD, base,
+         EXTEND16 (this_offset + AccessLength_WORD), GPR[dest]));
+    }
+
+    if (i != 0)
+      COP0_COUNT++;
+  }
+}
+
+101001,5.RT,5.RS,1.S1,0101,0,01,8.S2:R6PLSS1:32::UASH
+"uash r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+
+  do_store (SD_, AccessLength_HALFWORD, GPR[RS], S_9_BIT, GPR[RT]);
+}
+
+101001,5.RT,5.RS,1.S1,3.COUNT3,1,1,01,8.S2:R6PLSUAWM:32::UASWM
+"uaswm r<RT>, <S_9_BIT>(r<RS>), <COUNT>":COUNT != 1
+"uasw r<RT>, <S_9_BIT>(r<RS>)"
+*nanomips32r6:
+*nanomips64r6:
+{
+
+  int i;
+  int source;
+  int offsetm;
+
+  for(i = 0; i< COUNT; i++)
+   {
+    if (RT == 0)
+      source = 0;
+    else
+      source = (RT & 0x10) | ((RT + i) & 0x1F);
+
+    offsetm = S_9_BIT + (i << 2);
+
+    if(BigEndianCPU) {
+      do_store_left (SD_, AccessLength_WORD, GPR[RS], EXTEND16 (offsetm), GPR[source]);
+      do_store_right (SD_, AccessLength_WORD, GPR[RS],
+                          EXTEND16 (offsetm + AccessLength_WORD), GPR[source]);
+    } else {
+      do_store_right (SD_, AccessLength_WORD, GPR[RS], EXTEND16 (offsetm), GPR[source]);
+      do_store_left (SD_, AccessLength_WORD, GPR[RS],
+                          EXTEND16 (offsetm + AccessLength_WORD), GPR[source]);
+    }
+
+    if (i != 0)
+      COP0_COUNT++;
+  }
+}
+
+001000,5.RT,5.X,00000,0,1110010,000:R6PDVP:32::DVP
+"dvp r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+
+001000,5.RT,5.HS,2.X1,3.SEL,1.X2,0111000,000:R6POOL32A0:32::RDHWR
+"rdhwr r<HS>, r<RT>, <SEL>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  check_nms_flag (SD_);
+  do_rdhwr (SD_, RT, HS);
+}
+
+001000,5.RT,5.RS,11,10000,101,111,111:R6POOL32AXF5GROUP3:32::RDPGPR
+"rdpgpr r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,5.RT,5.RS,11,11000,101,111,111:R6POOL32AXF5GROUP3:32::WRPGPR
+"wrpgpr r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,5.RT,5.RS,5.RD,1.X,1111010,000:R6POOL32A0:32::SOV
+"SOV r<RD>, r<RS>, r<RT>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (NotWordValue (GPR[RS]) || NotWordValue (GPR[RT]))
+    Unpredictable ();
+  TRACE_ALU_INPUT2 (GPR[RS], GPR[RT]);
+  {
+    ALU32_BEGIN (GPR[RS]);
+    ALU32_ADD (GPR[RT]);
+    if (ALU32_HAD_OVERFLOW)
+      GPR[RD] = 1;
+    else
+      GPR[RD] = 0;
+  }
+  TRACE_ALU_RESULT (GPR[RD]);
+}
+
+001000,10.X,11,10001,101,111,111:R6POOL32A0:32::DERET
+"deret"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,5.RT,5.X,00000,1,1110010,000:R6PDVP:32::EVP
+"evp r<RT>" : RT!=0
+"evp"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+001000,10.CODE,110000110,1111111:R6POOL32AXF5GROUP2:32::WAIT
+"wait"
+*nanomips32r6:
+*nanomips64r6:
+{
+  // nothing to do currently
+  sim_io_printf (SD, "Not implemented");
+}
+
+011000,5.RT,00000,16.IMM48:R6POOL48I:32::LI48
+"li r<RT>, <IMM48>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint16_t U2;
+  uint32_t total;
+  check_nms_flag (SD_);
+  U2 = do_load (SD_, AccessLength_HALFWORD, CIA + 4, 0);
+  total = U2 << 16 | IMM48;
+  TRACE_ALU_INPUT2(GPR[RT], total);
+  GPR[RT] = EXTEND32(total);
+  TRACE_ALU_RESULT(GPR[RT]);
+  NIA = CIA + 6;
+}
+
+011000,5.RT,00001,16.IMM48:R6POOL48I:32::ADDIU48
+"addiu r<RT>, <IMM48>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint16_t S2;
+  uint32_t total;
+  check_nms_flag (SD_);
+  S2 = do_load(SD_, AccessLength_HALFWORD, CIA + 4, 0);
+  total = S2 << 16 | IMM48;
+  do_addiu(SD_, RT, RT, total);
+  NIA = CIA + 6;
+}
+
+100000,5.RT,5.RS,1000,12.U:R6PU12:32::ADDIUNEG
+"addiu r<RT>, r<RS>, -<U>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  do_addiu (SD_, RS, RT, -U);
+}
+
+011000,5.RT,00010,16.IMM48:R6POOL48I:32::ADDIUGP48
+"addiu r<RT>, GP, <IMM48>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  uint16_t S2;
+  uint32_t total;
+  check_nms_flag (SD_);
+  S2 = do_load(SD_, AccessLength_HALFWORD, CIA + 4, 0);
+  total = S2 << 16 | IMM48;
+  do_addiu (SD_, GPIDX, RT, total);
+  NIA = CIA + 6;
+}
+
+010010,00000,5.RS,1000,12.X:R6BALRSC:32::BRSC
+"brsc r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  unsigned_word address = NIA + (GPR[RS] << 1);
+  NIA = address;
+}
+
+010010,5.RT!0,5.RS,1000,12.X:R6PBALRSC:32::BALRSC
+"balrsc r<RT>, r<RS>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  unsigned_word address = NIA + (GPR[RS] << 1);
+
+  GPR[RT] = NIA;
+  NIA = address;
+
+  // For cycle counting
+  COP0_COUNT++;
+}
+
+110010,5.RT,001,1.X,6.BIT,10.S1,1.S2:R6PBRI:32::BBEQZC
+"bbeqzc r<RT>, <BIT>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  int testbit = (GPR[RT] >> BIT) & 1;
+
+  check_nms_flag (SD_);
+
+  if (testbit == 0)
+      NIA = ADDRESS12;
+}
+
+110010,5.RT,101,1.X,6.BIT,10.S1,1.S2:R6PBRI:32::BBNEZC
+"bbnezc r<RT>, <BIT>, <ADDRESS12>"
+*nanomips32r6:
+*nanomips64r6:
+{
+  int testbit = (GPR[RT] >> BIT) & 1;
+
+  check_nms_flag (SD_);
+
+  if (testbit == 1)
+      NIA = ADDRESS12;
+}
+
+:function:::void:do_lb:int rt, int offset, int base
+*nanomips32r6:
+*nanomips64r6:
+{
+  GPR[rt] = EXTEND8 (do_load (SD_, AccessLength_BYTE, GPR[base], offset));
+}
+
+:function:::void:do_lh:int rt, int offset, int base
+*nanomips32r6:
+*nanomips64r6:
+{
+  GPR[rt] = EXTEND16 (do_load (SD_, AccessLength_HALFWORD, GPR[base], offset));
+}
+
+:function:::void:do_lw:int rt, int offset, int base
+*nanomips32r6:
+*nanomips64r6:
+{
+  GPR[rt] = EXTEND32 (do_load (SD_, AccessLength_WORD, GPR[base], offset));
+}
+
+:function:::void:do_lhu:int rt, int offset, int base
+*nanomips32r6:
+*nanomips64r6:
+{
+  GPR[rt] = do_load (SD_, AccessLength_HALFWORD, GPR[base], offset);
+}
+
+:function:::void:do_addiu:int rs, int rt, int immediate
+*nanomips32r6:
+*nanomips64r6:
+{
+  if (NotWordValue (GPR[rs]))
+    Unpredictable ();
+  TRACE_ALU_INPUT2 (GPR[rs], immediate);
+  GPR[rt] = EXTEND32 (GPR[rs] + immediate);
+  TRACE_ALU_RESULT (GPR[rt]);
+}
diff --git a/sim/mips/nanomipsrun.c b/sim/mips/nanomipsrun.c
new file mode 100644
index 00000000000..8698726a9fa
--- /dev/null
+++ b/sim/mips/nanomipsrun.c
@@ -0,0 +1,109 @@
+/*  Run function for the nanomips simulator
+
+    Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+    Written by Andrew Bennett <andrew.bennett@imgtec.com>.
+
+    This file is part of GDB, the GNU debugger.
+
+    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, see <http://www.gnu.org/licenses/>.  */
+
+#include "sim-main.h"
+#include "nanomips16_idecode.h"
+#include "nanomips32_idecode.h"
+#include "bfd.h"
+
+
+#define SD sd
+#define CPU cpu
+#define SIM_MONITOR_ADDRESS 0xBFC00000
+
+void
+sim_engine_run (SIM_DESC sd, int next_cpu_nr, int nr_cpus, int signal);
+
+address_word
+nanomips_instruction_decode (SIM_DESC sd, sim_cpu * cpu,
+            address_word cia,
+            int instruction_size);
+
+address_word
+nanomips_instruction_decode (SIM_DESC sd, sim_cpu * cpu,
+			      address_word cia,
+			      int instruction_size)
+{
+
+  nanomips16_instruction_word instruction_0 = IMEM16_NANOMIPS (cia);
+
+  if((cia & 0xFFF00000) == SIM_MONITOR_ADDRESS) {
+    nanomips32_instruction_word instruction_0 = IMEM32 (cia);
+    return nanomips32_idecode_issue (sd, instruction_0, cia);
+  } else if ((STATE_ARCHITECTURE (sd)->mach == bfd_mach_nanomipsisa32r6
+	  || STATE_ARCHITECTURE (sd)->mach == bfd_mach_nanomipsisa64r6)
+	     && (NANOMIPS_MAJOR_OPCODE_3_5 (instruction_0) & 0x4) == 4)
+	return nanomips16_idecode_issue (sd, instruction_0, cia);
+      else
+	{
+	  nanomips32_instruction_word instruction_0 = IMEM32_NANOMIPS (cia);
+	  return nanomips32_idecode_issue (sd, instruction_0, cia);
+	}
+}
+
+void
+sim_engine_run (SIM_DESC sd, int next_cpu_nr, int nr_cpus,
+		int signal)
+{
+  nanomips32_instruction_word instruction_0;
+  sim_cpu *cpu = STATE_CPU (sd, next_cpu_nr);
+  nanomips32_instruction_address cia = CPU_PC_GET (cpu);
+  unsigned long bfdmach;
+  IS_NANOMIPS = 1;
+
+  bfdmach = STATE_ARCHITECTURE(SD)->mach;
+
+  if (is_nms_flag_set == 0 && (bfdmach == bfd_mach_nanomipsisa64r6
+      || bfdmach == bfd_mach_nanomipsisa32r6))
+    set_nms_flag (sd);
+
+  while (1)
+    {
+      nanomips32_instruction_address nia;
+
+	    cia = cia & ~0x1;
+
+#if defined (ENGINE_ISSUE_PREFIX_HOOK)
+      ENGINE_ISSUE_PREFIX_HOOK ();
+#endif
+
+    nia =
+      nanomips_instruction_decode (sd, cpu, cia,
+            MICROMIPS_DELAYSLOT_SIZE_ANY);
+
+#if defined (ENGINE_ISSUE_POSTFIX_HOOK)
+      ENGINE_ISSUE_POSTFIX_HOOK ();
+#endif
+      // Cycle counting
+      COP0_COUNT++;
+
+      /* Update the instruction address */
+      cia = nia;
+
+      /* process any events */
+      if (sim_events_tick (sd))
+	{
+	  CPU_PC_SET (CPU, cia);
+	  sim_events_process (sd);
+	  cia = CPU_PC_GET (CPU);
+	}
+    }
+}
diff --git a/sim/mips/nms.c b/sim/mips/nms.c
new file mode 100644
index 00000000000..fd957d69e8b
--- /dev/null
+++ b/sim/mips/nms.c
@@ -0,0 +1,44 @@
+/*  Run function for the nanomips simulator
+
+    Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+    Written by Andrew Bennett <andrew.bennett@imgtec.com>.
+
+    This file is part of GDB, the GNU debugger.
+
+    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, see <http://www.gnu.org/licenses/>.  */
+
+#include "sim-main.h"
+#include "elf/mips-common.h"
+#include "elf/nanomips.h"
+
+/* NMS Flag */
+int nms_flag = -1;
+
+int is_nms_flag_set = 0;
+
+void
+set_nms_flag (SIM_DESC sd)
+{
+  Elf_Internal_ABIFlags_v0 *abiflags;
+  abiflags = bfd_nanomips_elf_get_abiflags (STATE_PROG_BFD(sd));
+
+  nms_flag = 0;
+
+  if (abiflags != NULL
+      && ((abiflags->ases & NANOMIPS_ASE_xNMS) != 0))
+    nms_flag = 1;
+
+  is_nms_flag_set = 1;
+}
diff --git a/sim/mips/sim-main.h b/sim/mips/sim-main.h
index 418c6599118..e6b2b47ede7 100644
--- a/sim/mips/sim-main.h
+++ b/sim/mips/sim-main.h
@@ -318,9 +318,9 @@ struct _sim_cpu {
 #define LAST_EMBED_REGNUM (96)
 #define NUM_REGS (LAST_EMBED_REGNUM + 1)
 
-#define FP0_REGNUM 38           /* Floating point register 0 (single float) */
-#define FCRCS_REGNUM 70         /* FP control/status */
-#define FCRIR_REGNUM 71         /* FP implementation/revision */
+#define FP0_REGNUM ((CPU)->is_nanomips ? 36 : 38)           /* Floating point register 0 (single float) */
+#define FCRCS_REGNUM ((CPU)->is_nanomips ? 68 : 70)         /* FP control/status */
+#define FCRIR_REGNUM ((CPU)->is_nanomips ? 69 : 71)         /* FP implementation/revision */
 #endif
 
 
@@ -336,16 +336,19 @@ struct _sim_cpu {
 #define GPR     (&REGISTERS[0])
 #define GPR_SET(N,VAL) (REGISTERS[(N)] = (VAL))
 
-#define LO      (REGISTERS[33])
-#define HI      (REGISTERS[34])
-#define PCIDX	37
+#define HIIDX   ((CPU)->is_nanomips ? 70 : 33)
+#define LOIDX   ((CPU)->is_nanomips ? 71 : 34)
+#define HI      (REGISTERS[HIIDX])
+#define LO      (REGISTERS[LOIDX])
+#define PCIDX	  ((CPU)->is_nanomips ? 32 : 37)
 #define PC      (REGISTERS[PCIDX])
-#define CAUSE   (REGISTERS[36])
+#define COUSEIDX ((CPU)->is_nanomips ? 34 : 36)
+#define CAUSE   (REGISTERS[COUSEIDX])
 #define SRIDX   (32)
 #define SR      (REGISTERS[SRIDX])      /* CPU status register */
-#define FCR0IDX  (71)
+#define FCR0IDX  ((CPU)->is_nanomips ? 69 : 71)
 #define FCR0    (REGISTERS[FCR0IDX])    /* really a 32bit register */
-#define FCR31IDX (70)
+#define FCR31IDX ((CPU)->is_nanomips ? 68 : 70)
 #define FCR31   (REGISTERS[FCR31IDX])   /* really a 32bit register */
 #define FCSR    (FCR31)
 #define Debug	(REGISTERS[86])
@@ -362,10 +365,10 @@ struct _sim_cpu {
 #define AC3LOIDX	(94)
 #define AC3HIIDX	(95)
 
-#define DSPLO(N)	(REGISTERS[DSPLO_REGNUM[N]])
-#define DSPHI(N)	(REGISTERS[DSPHI_REGNUM[N]])
+#define DSPLO(N)	(REGISTERS[((CPU)->is_nanomips ? (LOIDX + 2 * N) : DSPLO_REGNUM[N])])
+#define DSPHI(N)	(REGISTERS[((CPU)->is_nanomips ? (HIIDX + 2 * N) : DSPHI_REGNUM[N])])
 
-#define DSPCRIDX	(96)	/* DSP control register */
+#define DSPCRIDX	((CPU)->is_nanomips ? 79 : 96)	/* DSP control register */
 #define DSPCR		(REGISTERS[DSPCRIDX])
 
 #define DSPCR_POS_SHIFT		(0)
@@ -420,6 +423,8 @@ struct _sim_cpu {
 #define A3      (REGISTERS[7])
 #define T8IDX   24
 #define T8	(REGISTERS[T8IDX])
+#define GPIDX   28
+#define GP      (REGISTERS[GPIDX])
 #define SPIDX   29
 #define SP      (REGISTERS[SPIDX])
 #define RAIDX   31
@@ -433,6 +438,7 @@ struct _sim_cpu {
   unsigned_word cop0_gpr[NR_COP0_GPR];
 #define COP0_GPR	((CPU)->cop0_gpr)
 #define COP0_BADVADDR	(COP0_GPR[8])
+#define COP0_COUNT (COP0_GPR[9])
 
   /* While space is allocated for the floating point registers in the
      main registers array, they are stored separatly.  This is because
@@ -472,10 +478,21 @@ struct _sim_cpu {
   hilo_history lo_history;
 #define LOHISTORY (&(CPU)->lo_history)
 
+  int is_nanomips;
+#define IS_NANOMIPS ((CPU)->is_nanomips)
 
   sim_cpu_base base;
 };
 
+#define SET_RV0(VAL)        \
+  do {                      \
+    if ((CPU)->is_nanomips) \
+      A0 = VAL;             \
+    else                    \
+      V0 = VAL;             \
+  } while (0)
+
+
 extern void mips_sim_close (SIM_DESC sd, int quitting);
 #define SIM_CLOSE_HOOK(...) mips_sim_close (__VA_ARGS__)
 
@@ -643,13 +660,16 @@ enum ExceptionCause {
    is used by gdb for break-points.  NOTE: Care must be taken, since
    this value may be used in later revisions of the MIPS ISA. */
 #define HALT_INSTRUCTION_MASK   (0x03FFFFC0)
+#define HALT_INSTRUCTION_MASK_NANOMIPS (0x0007FFFF)
 
 #define HALT_INSTRUCTION        (0x03ff000d)
 #define HALT_INSTRUCTION2       (0x0000ffcd)
+#define HALT_INSTRUCTION_NANOMIPS      (0x001003FF)
 
 
 #define BREAKPOINT_INSTRUCTION  (0x0005000d)
 #define BREAKPOINT_INSTRUCTION2 (0x0000014d)
+#define BREAKPOINT_INSTRUCTION_NANOMIPS  (0x00101400)
 
 
 
@@ -1022,6 +1042,16 @@ INLINE_SIM_MAIN (uint16_t) ifetch16 (SIM_DESC sd, sim_cpu *cpu, address_word cia
 #define MICROMIPS_DELAYSLOT_SIZE_16 2
 #define MICROMIPS_DELAYSLOT_SIZE_32 4
 
+#define IMEM32_NANOMIPS(CIA) \
+  (ifetch16 (SD, CPU, (CIA), (CIA)) << 16 | ifetch16 (SD, CPU, (CIA + 2), \
+                  (CIA + 2)))
+#define IMEM16_NANOMIPS(CIA) ifetch16 (SD, CPU, (CIA), ((CIA)))
+
+
+#define NANOMIPS_MAJOR_OPCODE_3_5(INSN) ((INSN & 0x1c00) >> 10)
+
+#define NANOMIPS_DELAYSLOT_SIZE_ANY 0
+
 extern int isa_mode;
 
 #define ISA_MODE_MIPS32 0
@@ -1041,6 +1071,13 @@ extern FILE *tracefh;
 extern int DSPLO_REGNUM[4];
 extern int DSPHI_REGNUM[4];
 
+/* NMS Flag */
+extern int nms_flag;
+extern int is_nms_flag_set;
+
+void
+set_nms_flag (SIM_DESC sd);
+
 INLINE_SIM_MAIN (void) pending_tick (SIM_DESC sd, sim_cpu *cpu, address_word cia);
 extern SIM_CORE_SIGNAL_FN mips_core_signal;
 
-- 
2.25.1


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

* [PATCH v3 2/2] gdb: Add nanoMIPS port
  2022-11-21 11:06   ` [PATCH v3 1/2] " Aleksandar Rikalo
@ 2022-11-21 11:06     ` Aleksandar Rikalo
  2022-12-12  9:42       ` Mike Frysinger
  2022-12-12  9:45       ` Mike Frysinger
  2022-11-25 12:11     ` [PATCH v3 1/2] sim: " Mike Frysinger
  1 sibling, 2 replies; 13+ messages in thread
From: Aleksandar Rikalo @ 2022-11-21 11:06 UTC (permalink / raw)
  To: gdb-patches; +Cc: aleksandar.rikalo, arikalo

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>
---
 config.sub                                    |    1 +
 configure                                     |    3 +
 configure.ac                                  |    3 +
 gdb/Makefile.in                               |    2 +
 gdb/NEWS                                      |    1 +
 gdb/configure.host                            |    1 +
 gdb/configure.tgt                             |   11 +
 gdb/features/Makefile                         |    4 +
 gdb/features/nanomips-cp0.xml                 |   13 +
 gdb/features/nanomips-cpu.xml                 |   44 +
 gdb/features/nanomips-dsp.xml                 |   20 +
 gdb/features/nanomips-fpu.xml                 |   45 +
 gdb/features/nanomips.c                       |   54 +
 gdb/features/nanomips.xml                     |   12 +
 gdb/features/nanomips64-cp0.xml               |   13 +
 gdb/features/nanomips64-cpu.xml               |   44 +
 gdb/features/nanomips64-dsp.xml               |   20 +
 gdb/nanomips-tdep.c                           | 3407 +++++++++++++++++
 gdb/nanomips-tdep.h                           |  144 +
 gdb/testsuite/gdb.asm/asm-source.exp          |    9 +-
 gdb/testsuite/gdb.asm/nanomips.inc            |   49 +
 .../gdb.base/catch-gdb-caused-signals.c       |    3 +
 gdb/testsuite/gdb.base/float.exp              |    2 +-
 gdb/testsuite/gdb.trace/trace-common.h        |    2 +-
 gdb/testsuite/lib/gdb.exp                     |    1 +
 25 files changed, 3905 insertions(+), 3 deletions(-)
 create mode 100644 gdb/features/nanomips-cp0.xml
 create mode 100644 gdb/features/nanomips-cpu.xml
 create mode 100644 gdb/features/nanomips-dsp.xml
 create mode 100644 gdb/features/nanomips-fpu.xml
 create mode 100644 gdb/features/nanomips.c
 create mode 100644 gdb/features/nanomips.xml
 create mode 100644 gdb/features/nanomips64-cp0.xml
 create mode 100644 gdb/features/nanomips64-cpu.xml
 create mode 100644 gdb/features/nanomips64-dsp.xml
 create mode 100644 gdb/nanomips-tdep.c
 create mode 100644 gdb/nanomips-tdep.h
 create mode 100644 gdb/testsuite/gdb.asm/nanomips.inc

diff --git a/config.sub b/config.sub
index dba16e84c77..b562e37aa09 100755
--- a/config.sub
+++ b/config.sub
@@ -1243,6 +1243,7 @@ case $cpu-$vendor in
 			| moxie \
 			| mt \
 			| msp430 \
+			| nanomips | nanomipseb \
 			| nds32 | nds32le | nds32be \
 			| nfp \
 			| nios | nios2 | nios2eb | nios2el \
diff --git a/configure b/configure
index 80b2b02fe7e..626fe6de084 100755
--- a/configure
+++ b/configure
@@ -4064,6 +4064,9 @@ case "${target}" in
   mips*-*-*)
     noconfigdirs="$noconfigdirs gprof"
     ;;
+  nanomips*-*-elf*)
+    noconfigdirs="$noconfigdirs gas binutils ld gprof"
+    ;;
   nvptx*-*-*)
     noconfigdirs="$noconfigdirs target-libssp target-libstdc++-v3 target-libobjc"
     ;;
diff --git a/configure.ac b/configure.ac
index 36267d85785..352ff79fce7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1297,6 +1297,9 @@ case "${target}" in
   mips*-*-*)
     noconfigdirs="$noconfigdirs gprof"
     ;;
+  nanomips*-*-elf*)
+    noconfigdirs="$noconfigdirs gas binutils ld gprof"
+    ;;
   nvptx*-*-*)
     noconfigdirs="$noconfigdirs target-libssp target-libstdc++-v3 target-libobjc"
     ;;
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index fb4d42c7baa..3ef458477f9 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -824,6 +824,7 @@ ALL_TARGET_OBS = \
 	mn10300-tdep.o \
 	moxie-tdep.o \
 	msp430-tdep.o \
+	nanomips-tdep.o \
 	netbsd-tdep.o \
 	nds32-tdep.o \
 	nios2-linux-tdep.o \
@@ -1394,6 +1395,7 @@ HFILES_NO_SRCDIR = \
 	mips-tdep.h \
 	mn10300-tdep.h \
 	moxie-tdep.h \
+	nanomips-tdep.h \
 	netbsd-nat.h \
 	netbsd-tdep.h \
 	nds32-tdep.h \
diff --git a/gdb/NEWS b/gdb/NEWS
index dddef6525de..57f74da652d 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -480,6 +480,7 @@ winheight
 
 * New targets
 
+GNU/ELF/nanoMIPS      nanomips*-*-*
 GNU/Linux/LoongArch		loongarch*-*-linux*
 
 * Removed targets
diff --git a/gdb/configure.host b/gdb/configure.host
index da71675b201..3a9799ee56e 100644
--- a/gdb/configure.host
+++ b/gdb/configure.host
@@ -61,6 +61,7 @@ i[34567]86*)		gdb_host_cpu=i386 ;;
 loongarch*)		gdb_host_cpu=loongarch ;;
 m68*)			gdb_host_cpu=m68k ;;
 mips*)			gdb_host_cpu=mips ;;
+nanomips*)		gdb_host_cpu=nanomips ;;
 powerpc* | rs6000)	gdb_host_cpu=powerpc ;;
 sparcv9 | sparc64)	gdb_host_cpu=sparc ;;
 s390*)			gdb_host_cpu=s390 ;;
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index e84e222ba0d..f4dba706a9c 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -448,6 +448,16 @@ msp430-*-elf*)
 	gdb_target_obs="msp430-tdep.o"
 	;;
 
+mt-*-*)
+	# Target: Morpho Technologies ms1 processor
+	gdb_target_obs="mt-tdep.o"
+	;;
+
+nanomips*-*-*)
+	# Target: nanomips ELF
+	gdb_target_obs="nanomips-tdep.o"
+	;;
+
 nds32*-*-elf)
 	# Target: AndesTech NDS32 core
 	gdb_target_obs="nds32-tdep.o"
@@ -766,6 +776,7 @@ m32r-*-*)		gdb_sim=m32r ;;
 m68hc11-*-*|m6811-*-*)	gdb_sim=m68hc11 ;;
 microblaze*-*-*)	gdb_sim=microblaze ;;
 mips*-*-*)		gdb_sim=mips ;;
+nanomips*-*-*)	gdb_sim=mips ;;
 mn10300*-*-*)		gdb_sim=mn10300 ;;
 moxie-*-*)		gdb_sim=moxie ;;
 msp430*-*-*)		gdb_sim=msp430 ;;
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index c3e07809db3..f89823a3f31 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -46,6 +46,7 @@
 # List of .dat files to create in ../regformats/
 WHICH = mips-linux mips-dsp-linux \
 	mips64-linux mips64-dsp-linux \
+	nanomips \
 	nios2-linux \
 	or1k-linux \
 	rs6000/powerpc-32 \
@@ -73,6 +74,8 @@ mips-expedite = r29,pc
 mips-dsp-expedite = r29,pc
 mips64-expedite = r29,pc
 mips64-dsp-expedite = r29,pc
+microblaze-expedite = r1,rpc
+nanomips-expedite = r29,pc
 nios2-linux-expedite = sp,pc
 or1k-expedite = r1,npc
 powerpc-expedite = r1,pc
@@ -106,6 +109,7 @@ XMLTOC = \
 	mips-linux.xml \
 	mips64-dsp-linux.xml \
 	mips64-linux.xml \
+	nanomips.xml \
 	nds32.xml \
 	nios2.xml \
 	or1k.xml \
diff --git a/gdb/features/nanomips-cp0.xml b/gdb/features/nanomips-cp0.xml
new file mode 100644
index 00000000000..7a3995f0fd7
--- /dev/null
+++ b/gdb/features/nanomips-cp0.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.nanomips.cp0">
+  <reg name="status" bitsize="32"/>
+  <reg name="badvaddr" bitsize="32"/>
+  <reg name="cause" bitsize="32"/>
+</feature>
diff --git a/gdb/features/nanomips-cpu.xml b/gdb/features/nanomips-cpu.xml
new file mode 100644
index 00000000000..bb04a24d6f6
--- /dev/null
+++ b/gdb/features/nanomips-cpu.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.nanomips.cpu">
+  <reg name="r0" bitsize="32"/>
+  <reg name="r1" bitsize="32"/>
+  <reg name="r2" bitsize="32"/>
+  <reg name="r3" bitsize="32"/>
+  <reg name="r4" bitsize="32"/>
+  <reg name="r5" bitsize="32"/>
+  <reg name="r6" bitsize="32"/>
+  <reg name="r7" bitsize="32"/>
+  <reg name="r8" bitsize="32"/>
+  <reg name="r9" bitsize="32"/>
+  <reg name="r10" bitsize="32"/>
+  <reg name="r11" bitsize="32"/>
+  <reg name="r12" bitsize="32"/>
+  <reg name="r13" bitsize="32"/>
+  <reg name="r14" bitsize="32"/>
+  <reg name="r15" bitsize="32"/>
+  <reg name="r16" bitsize="32"/>
+  <reg name="r17" bitsize="32"/>
+  <reg name="r18" bitsize="32"/>
+  <reg name="r19" bitsize="32"/>
+  <reg name="r20" bitsize="32"/>
+  <reg name="r21" bitsize="32"/>
+  <reg name="r22" bitsize="32"/>
+  <reg name="r23" bitsize="32"/>
+  <reg name="r24" bitsize="32"/>
+  <reg name="r25" bitsize="32"/>
+  <reg name="r26" bitsize="32"/>
+  <reg name="r27" bitsize="32"/>
+  <reg name="r28" bitsize="32"/>
+  <reg name="r29" bitsize="32"/>
+  <reg name="r30" bitsize="32"/>
+  <reg name="r31" bitsize="32"/>
+
+  <reg name="pc" bitsize="32"/>
+</feature>
diff --git a/gdb/features/nanomips-dsp.xml b/gdb/features/nanomips-dsp.xml
new file mode 100644
index 00000000000..659fc3850c2
--- /dev/null
+++ b/gdb/features/nanomips-dsp.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.nanomips.dsp">
+  <reg name="hi0" bitsize="32"/>
+  <reg name="lo0" bitsize="32"/>
+  <reg name="hi1" bitsize="32"/>
+  <reg name="lo1" bitsize="32"/>
+  <reg name="hi2" bitsize="32"/>
+  <reg name="lo2" bitsize="32"/>
+  <reg name="hi3" bitsize="32"/>
+  <reg name="lo3" bitsize="32"/>
+
+  <reg name="dspctl" bitsize="32"/>
+</feature>
diff --git a/gdb/features/nanomips-fpu.xml b/gdb/features/nanomips-fpu.xml
new file mode 100644
index 00000000000..cac1d51f2ac
--- /dev/null
+++ b/gdb/features/nanomips-fpu.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.nanomips.fpu">
+  <reg name="f0" bitsize="64" type="ieee_double"/>
+  <reg name="f1" bitsize="64" type="ieee_double"/>
+  <reg name="f2" bitsize="64" type="ieee_double"/>
+  <reg name="f3" bitsize="64" type="ieee_double"/>
+  <reg name="f4" bitsize="64" type="ieee_double"/>
+  <reg name="f5" bitsize="64" type="ieee_double"/>
+  <reg name="f6" bitsize="64" type="ieee_double"/>
+  <reg name="f7" bitsize="64" type="ieee_double"/>
+  <reg name="f8" bitsize="64" type="ieee_double"/>
+  <reg name="f9" bitsize="64" type="ieee_double"/>
+  <reg name="f10" bitsize="64" type="ieee_double"/>
+  <reg name="f11" bitsize="64" type="ieee_double"/>
+  <reg name="f12" bitsize="64" type="ieee_double"/>
+  <reg name="f13" bitsize="64" type="ieee_double"/>
+  <reg name="f14" bitsize="64" type="ieee_double"/>
+  <reg name="f15" bitsize="64" type="ieee_double"/>
+  <reg name="f16" bitsize="64" type="ieee_double"/>
+  <reg name="f17" bitsize="64" type="ieee_double"/>
+  <reg name="f18" bitsize="64" type="ieee_double"/>
+  <reg name="f19" bitsize="64" type="ieee_double"/>
+  <reg name="f20" bitsize="64" type="ieee_double"/>
+  <reg name="f21" bitsize="64" type="ieee_double"/>
+  <reg name="f22" bitsize="64" type="ieee_double"/>
+  <reg name="f23" bitsize="64" type="ieee_double"/>
+  <reg name="f24" bitsize="64" type="ieee_double"/>
+  <reg name="f25" bitsize="64" type="ieee_double"/>
+  <reg name="f26" bitsize="64" type="ieee_double"/>
+  <reg name="f27" bitsize="64" type="ieee_double"/>
+  <reg name="f28" bitsize="64" type="ieee_double"/>
+  <reg name="f29" bitsize="64" type="ieee_double"/>
+  <reg name="f30" bitsize="64" type="ieee_double"/>
+  <reg name="f31" bitsize="64" type="ieee_double"/>
+
+  <reg name="fcsr" bitsize="32" group="float"/>
+  <reg name="fir" bitsize="32" group="float"/>
+</feature>
diff --git a/gdb/features/nanomips.c b/gdb/features/nanomips.c
new file mode 100644
index 00000000000..43cdc8a95d5
--- /dev/null
+++ b/gdb/features/nanomips.c
@@ -0,0 +1,54 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: nanomips.xml */
+
+#include "defs.h"
+#include "osabi.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_nanomips;
+static void
+initialize_tdesc_nanomips (void)
+{
+  struct target_desc *result;
+  result = allocate_target_description ().release();
+  struct tdesc_feature *feature;
+
+  set_tdesc_architecture (result, bfd_scan_arch ("nanomips"));
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.nanomips.cpu");
+  tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r13", 13, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r14", 14, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r15", 15, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r16", 16, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r17", 17, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r18", 18, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r19", 19, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r20", 20, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r21", 21, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r22", 22, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r23", 23, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r24", 24, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r25", 25, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r26", 26, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r27", 27, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r28", 28, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r29", 29, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r30", 30, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "r31", 31, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pc", 32, 1, NULL, 32, "int");
+
+  tdesc_nanomips = result;
+}
diff --git a/gdb/features/nanomips.xml b/gdb/features/nanomips.xml
new file mode 100644
index 00000000000..ae05a91e935
--- /dev/null
+++ b/gdb/features/nanomips.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>nanomips</architecture>
+  <xi:include href="nanomips-cpu.xml"/>
+</target>
diff --git a/gdb/features/nanomips64-cp0.xml b/gdb/features/nanomips64-cp0.xml
new file mode 100644
index 00000000000..6af2e2c369d
--- /dev/null
+++ b/gdb/features/nanomips64-cp0.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.nanomips.cp0">
+  <reg name="status" bitsize="32"/>
+  <reg name="badvaddr" bitsize="64"/>
+  <reg name="cause" bitsize="32"/>
+</feature>
diff --git a/gdb/features/nanomips64-cpu.xml b/gdb/features/nanomips64-cpu.xml
new file mode 100644
index 00000000000..30a237050a6
--- /dev/null
+++ b/gdb/features/nanomips64-cpu.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.nanomips.cpu">
+  <reg name="r0" bitsize="64"/>
+  <reg name="r1" bitsize="64"/>
+  <reg name="r2" bitsize="64"/>
+  <reg name="r3" bitsize="64"/>
+  <reg name="r4" bitsize="64"/>
+  <reg name="r5" bitsize="64"/>
+  <reg name="r6" bitsize="64"/>
+  <reg name="r7" bitsize="64"/>
+  <reg name="r8" bitsize="64"/>
+  <reg name="r9" bitsize="64"/>
+  <reg name="r10" bitsize="64"/>
+  <reg name="r11" bitsize="64"/>
+  <reg name="r12" bitsize="64"/>
+  <reg name="r13" bitsize="64"/>
+  <reg name="r14" bitsize="64"/>
+  <reg name="r15" bitsize="64"/>
+  <reg name="r16" bitsize="64"/>
+  <reg name="r17" bitsize="64"/>
+  <reg name="r18" bitsize="64"/>
+  <reg name="r19" bitsize="64"/>
+  <reg name="r20" bitsize="64"/>
+  <reg name="r21" bitsize="64"/>
+  <reg name="r22" bitsize="64"/>
+  <reg name="r23" bitsize="64"/>
+  <reg name="r24" bitsize="64"/>
+  <reg name="r25" bitsize="64"/>
+  <reg name="r26" bitsize="64"/>
+  <reg name="r27" bitsize="64"/>
+  <reg name="r28" bitsize="64"/>
+  <reg name="r29" bitsize="64"/>
+  <reg name="r30" bitsize="64"/>
+  <reg name="r31" bitsize="64"/>
+
+  <reg name="pc" bitsize="64"/>
+</feature>
diff --git a/gdb/features/nanomips64-dsp.xml b/gdb/features/nanomips64-dsp.xml
new file mode 100644
index 00000000000..84bf7b06cc6
--- /dev/null
+++ b/gdb/features/nanomips64-dsp.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.nanomips.dsp">
+  <reg name="hi0" bitsize="64"/>
+  <reg name="lo0" bitsize="64"/>
+  <reg name="hi1" bitsize="64"/>
+  <reg name="lo1" bitsize="64"/>
+  <reg name="hi2" bitsize="64"/>
+  <reg name="lo2" bitsize="64"/>
+  <reg name="hi3" bitsize="64"/>
+  <reg name="lo3" bitsize="64"/>
+
+  <reg name="dspctl" bitsize="32"/>
+</feature>
diff --git a/gdb/nanomips-tdep.c b/gdb/nanomips-tdep.c
new file mode 100644
index 00000000000..664d5d30a3a
--- /dev/null
+++ b/gdb/nanomips-tdep.c
@@ -0,0 +1,3407 @@
+/* Target-dependent code for the nanoMIPS architecture, for GDB,
+   the GNU Debugger.
+
+   Copyright (C) 2017-2022 Free Software Foundation, Inc.
+   Contributed by:
+    Jaydeep Patil <jaydeep.patil@imgtec.com>
+    Matthew Fortune <matthew.fortune@imgtec.com>
+    Maciej W. Rozycki <macro@mips.com>
+    Stefan Markovic <stefan.markovic@mips.com>
+    Sara Popadic <sara.popadic@imgtec.com>
+    Dragan Mladjenovic <dragan.mladjenovic@syrmia.com>
+    Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
+
+   This file is part of GDB.
+
+   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, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "gdbcore.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "target.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "osabi.h"
+#include "nanomips-tdep.h"
+#include "block.h"
+#include "reggroups.h"
+#include "opcode/nanomips.h"
+#include "elf/mips-common.h"
+#include "elf/nanomips.h"
+#include "elf-bfd.h"
+#include "symcat.h"
+#include "sim-regno.h"
+#include "dis-asm.h"
+#include "disasm.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+#include "infcall.h"
+#include "floatformat.h"
+#include "remote.h"
+#include "target-descriptions.h"
+#include "dwarf2/frame.h"
+#include "user-regs.h"
+#include "valprint.h"
+#include "ax.h"
+#include "target-float.h"
+#include <algorithm>
+
+#include "features/nanomips.c"
+
+/* The sizes of registers.  */
+
+enum
+{
+  NANOMIPS32_REGSIZE = 4,
+  NANOMIPS64_REGSIZE = 8
+};
+
+static const char *const nanomips_abi_strings[] = {
+  "auto",
+  "p32",
+  "p64",
+  NULL
+};
+
+/* Enum describing the different kinds of breakpoints.  */
+
+enum nanomips_breakpoint_kind
+{
+  /* 16-bit breakpoint.  */
+  NANOMIPS_BP_KIND_16 = 3,
+
+  /* 32-bit breakpoint.  */
+  NANOMIPS_BP_KIND_32 = 5,
+};
+
+/* The standard register names, and all the valid aliases for them.  */
+struct register_alias
+{
+  const char *name;
+  int regnum;
+};
+
+
+static unsigned int nanomips_debug = 0;
+
+const struct nanomips_regnum *
+nanomips_regnum (struct gdbarch *gdbarch)
+{
+  return gdbarch_tdep<nanomips_gdbarch_tdep> (gdbarch)->regnum;
+}
+
+static int
+nanomips_fp_arg_regnum (struct gdbarch *gdbarch)
+{
+  gdb_assert (nanomips_regnum (gdbarch)->fpr != -1);
+
+  return nanomips_regnum (gdbarch)->fpr + NANOMIPS_FP0_REGNUM;
+}
+
+/* Return 1 if REGNUM refers to a floating-point general register, raw
+   or cooked.  Otherwise return 0.  */
+
+static int
+nanomips_float_register_p (struct gdbarch *gdbarch, int regnum)
+{
+  int rawnum = regnum % gdbarch_num_regs (gdbarch);
+  int fprnum = nanomips_regnum (gdbarch)->fpr;
+
+  return (fprnum != -1
+	  && rawnum >= fprnum + NANOMIPS_FP0_REGNUM
+	  && rawnum < fprnum + NANOMIPS_FCSR_REGNUM);
+}
+
+/* Return 1 if REGNUM refers to a floating-point control register, raw
+   or cooked.  Otherwise return 0.  */
+
+static int
+nanomips_float_control_register_p (struct gdbarch *gdbarch, int regnum)
+{
+  int rawnum = regnum % gdbarch_num_regs (gdbarch);
+  int fprnum = nanomips_regnum (gdbarch)->fpr;
+
+  return (fprnum != -1
+	  && (rawnum == fprnum + NANOMIPS_FCSR_REGNUM
+	      || rawnum == fprnum + NANOMIPS_FIR_REGNUM));
+}
+
+/* Return 1 if REGNUM refers to a DSP accumulator register, raw or cooked.
+   Otherwise return 0.  */
+
+static int
+nanomips_dspacc_register_p (struct gdbarch *gdbarch, int regnum)
+{
+  int rawnum = regnum % gdbarch_num_regs (gdbarch);
+  int dspnum = nanomips_regnum (gdbarch)->dsp;
+
+  return (dspnum != -1
+	  && rawnum >= dspnum + NANOMIPS_DSPHI0_REGNUM
+	  && rawnum < dspnum + NANOMIPS_DSPCTL_REGNUM);
+}
+
+#define FPU_TYPE(gdbarch) (gdbarch_tdep<nanomips_gdbarch_tdep> (gdbarch)->fpu_type)
+
+/* Return the nanoMIPS ABI associated with GDBARCH.  */
+enum nanomips_abi
+nanomips_abi (struct gdbarch *gdbarch)
+{
+  return (gdbarch_tdep<nanomips_gdbarch_tdep> (gdbarch))->nanomips_abi;
+}
+
+int
+nanomips_isa_regsize (struct gdbarch *gdbarch)
+{
+  return gdbarch_tdep<nanomips_gdbarch_tdep> (gdbarch)->register_size;
+}
+
+/* Return the currently configured (or set) saved register size.  */
+
+unsigned int
+nanomips_abi_regsize (struct gdbarch *gdbarch)
+{
+  switch (nanomips_abi (gdbarch))
+    {
+    case NANOMIPS_ABI_P32:
+      return 4;
+    case NANOMIPS_ABI_P64:
+      return 8;
+    case NANOMIPS_ABI_UNKNOWN:
+    default:
+      internal_error_loc (__FILE__, __LINE__, _("bad switch"));
+    }
+}
+
+static void
+nanomips_xfer_register (struct gdbarch *gdbarch, struct regcache *regcache,
+        int reg_num, int length,
+        enum bfd_endian endian, gdb_byte *in,
+        const gdb_byte *out, int buf_offset)
+{
+  int reg_offset = 0;
+
+  gdb_assert (reg_num >= gdbarch_num_regs (gdbarch));
+  /* Need to transfer the left or right part of the register, based on
+     the targets byte order.  */
+  switch (endian)
+    {
+    case BFD_ENDIAN_BIG:
+      reg_offset = register_size (gdbarch, reg_num) - length;
+      break;
+    case BFD_ENDIAN_LITTLE:
+      reg_offset = 0;
+      break;
+    case BFD_ENDIAN_UNKNOWN:  /* Indicates no alignment.  */
+      reg_offset = 0;
+      break;
+    default:
+      internal_error_loc (__FILE__, __LINE__, _("bad switch"));
+    }
+  if (nanomips_debug)
+    gdb_printf (gdb_stderr,
+      "xfer $%d, reg offset %d, buf offset %d, length %d, ",
+      reg_num, reg_offset, buf_offset, length);
+  if (nanomips_debug && out != NULL)
+    {
+      int i;
+      gdb_printf (gdb_stdlog, "out ");
+      for (i = 0; i < length; i++)
+  gdb_printf (gdb_stdlog, "%02x", out[buf_offset + i]);
+    }
+  if (in != NULL)
+    regcache->cooked_read_part (reg_num, reg_offset, length, in + buf_offset);
+  if (out != NULL)
+    regcache->cooked_write_part (reg_num, reg_offset, length, out + buf_offset);
+  if (nanomips_debug && in != NULL)
+    {
+      int i;
+      gdb_printf (gdb_stdlog, "in ");
+      for (i = 0; i < length; i++)
+  gdb_printf (gdb_stdlog, "%02x", in[buf_offset + i]);
+    }
+  if (nanomips_debug)
+    gdb_printf (gdb_stdlog, "\n");
+}
+
+#define VM_MIN_ADDRESS (CORE_ADDR)0x400000
+
+static CORE_ADDR heuristic_proc_start (struct gdbarch *, CORE_ADDR);
+
+static void reinit_frame_cache_sfunc (const char *, int, struct cmd_list_element *);
+
+/* The list of available "set nanomips " and "show nanomips " commands.  */
+
+static struct cmd_list_element *setnanomipscmdlist = NULL;
+static struct cmd_list_element *shownanomipscmdlist = NULL;
+
+/* Return the name of the register corresponding to REGNO.  */
+
+static const char *
+nanomips_register_name (struct gdbarch *gdbarch, int regno)
+{
+  /* GPR names for p32 and p64 ABIs.  */
+  static const char *const gpr_names[]  = {
+    "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", "raw_fp", "ra"
+  };
+
+  const char *name;
+  /* Map [gdbarch_num_regs .. 2*gdbarch_num_regs) onto the raw registers,
+     but then don't make the raw register names visible.  This (upper)
+     range of user visible register numbers are the pseudo-registers.
+
+     This approach was adopted accommodate the following scenario:
+     It is possible to debug a 64-bit device using a 32-bit
+     programming model.  In such instances, the raw registers are
+     configured to be 64-bits wide, while the pseudo registers are
+     configured to be 32-bits wide.  The registers that the user
+     sees - the pseudo registers - match the users expectations
+     given the programming model being used.  */
+  int rawnum = regno % gdbarch_num_regs (gdbarch);
+  if (regno < gdbarch_num_regs (gdbarch))
+    return "";
+
+  name = tdesc_register_name (gdbarch, rawnum);
+
+  if (rawnum >= 0 && rawnum < 32)
+    {
+      gdb_assert (name != NULL && name[0] != 0);
+      gdb_assert ((sizeof (gpr_names) / sizeof (gpr_names[0])) == 32);
+      return gpr_names[rawnum];
+    }
+
+  return name;
+}
+
+/* Return the groups that a nanoMIPS register can be categorised into.  */
+
+static int
+nanomips_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+			      const struct reggroup *reggroup)
+{
+  int vector_p;
+  int float_p;
+  int raw_p;
+  int rawnum = regnum % gdbarch_num_regs (gdbarch);
+  int pseudo = regnum / gdbarch_num_regs (gdbarch);
+  if (reggroup == all_reggroup)
+    return pseudo;
+  vector_p = (register_type (gdbarch, regnum))->is_vector ();
+  float_p = (nanomips_float_register_p (gdbarch, rawnum)
+	     || nanomips_float_control_register_p (gdbarch, rawnum));
+  /* FIXME: cagney/2003-04-13: Can't yet use gdbarch_num_regs
+     (gdbarch), as not all architectures are multi-arch.  */
+  raw_p = rawnum < gdbarch_num_regs (gdbarch);
+  if (gdbarch_register_name (gdbarch, regnum) == NULL
+      || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
+    return 0;
+  if (reggroup == float_reggroup)
+    return float_p && pseudo;
+  if (reggroup == vector_reggroup)
+    return vector_p && pseudo;
+  if (reggroup == general_reggroup)
+    return (!vector_p && !float_p) && pseudo;
+  /* Save the pseudo registers.  Need to make certain that any code
+     extracting register values from a saved register cache also uses
+     pseudo registers.  */
+  if (reggroup == save_reggroup)
+    return raw_p && pseudo;
+  /* Restore the same pseudo register.  */
+  if (reggroup == restore_reggroup)
+    return raw_p && pseudo;
+  return 0;
+}
+
+/* Return the groups that a nanoMIPS register can be categorised into.
+   This version is only used if we have a target description which
+   describes real registers (and their groups).  */
+
+static int
+nanomips_tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+				    const struct reggroup *reggroup)
+{
+  int rawnum = regnum % gdbarch_num_regs (gdbarch);
+  int pseudo = regnum / gdbarch_num_regs (gdbarch);
+  int ret;
+
+  /* Only save, restore, and display the pseudo registers.  Need to
+     make certain that any code extracting register values from a
+     saved register cache also uses pseudo registers.
+
+     Note: saving and restoring the pseudo registers is slightly
+     strange; if we have 64 bits, we should save and restore all
+     64 bits.  But this is hard and has little benefit.  */
+  if (!pseudo)
+    return 0;
+
+  ret = tdesc_register_in_reggroup_p (gdbarch, rawnum, reggroup);
+  if (ret != -1)
+    return ret;
+
+  return nanomips_register_reggroup_p (gdbarch, regnum, reggroup);
+}
+
+/* Map the symbol table registers which live in the range [1 *
+   gdbarch_num_regs .. 2 * gdbarch_num_regs) back onto the corresponding raw
+   registers.  Take care of alignment and size problems.  */
+
+static enum register_status
+nanomips_pseudo_register_read (struct gdbarch *gdbarch,
+			       struct readable_regcache *regcache,
+			       int cookednum, gdb_byte *buf)
+{
+  int rawnum = cookednum % gdbarch_num_regs (gdbarch);
+  gdb_assert (cookednum >= gdbarch_num_regs (gdbarch)
+	      && cookednum < 2 * gdbarch_num_regs (gdbarch));
+  if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum))
+    return regcache->raw_read (rawnum, buf);
+  else if (register_size (gdbarch, rawnum) >
+	   register_size (gdbarch, cookednum))
+    {
+      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+      LONGEST regval;
+      enum register_status status;
+
+      status = regcache->raw_read (rawnum, &regval);
+      if (status == REG_VALID)
+        store_signed_integer (buf, 4, byte_order, regval);
+      return status;
+    }
+  else
+    internal_error_loc (__FILE__, __LINE__, _("bad register size"));
+}
+
+static void
+nanomips_pseudo_register_write (struct gdbarch *gdbarch,
+				struct regcache *regcache, int cookednum,
+				const gdb_byte *buf)
+{
+  int rawnum = cookednum % gdbarch_num_regs (gdbarch);
+  gdb_assert (cookednum >= gdbarch_num_regs (gdbarch)
+	      && cookednum < 2 * gdbarch_num_regs (gdbarch));
+  if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum))
+    regcache->raw_write (rawnum, buf);
+  else if (register_size (gdbarch, rawnum) >
+	   register_size (gdbarch, cookednum))
+    {
+      /* Sign extend the shortened version of the register prior
+         to placing it in the raw register.  This is required for
+         some mips64 parts in order to avoid unpredictable behavior.  */
+      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+      LONGEST regval = extract_signed_integer (buf, 4, byte_order);
+      regcache_raw_write_signed (regcache, rawnum, regval);
+    }
+  else
+    internal_error_loc (__FILE__, __LINE__, _("bad register size"));
+}
+
+static int
+nanomips_ax_pseudo_register_collect (struct gdbarch *gdbarch,
+				     struct agent_expr *ax, int reg)
+{
+  int rawnum = reg % gdbarch_num_regs (gdbarch);
+  gdb_assert (reg >= gdbarch_num_regs (gdbarch)
+	      && reg < 2 * gdbarch_num_regs (gdbarch));
+
+  ax_reg_mask (ax, rawnum);
+
+  return 0;
+}
+
+static int
+nanomips_ax_pseudo_register_push_stack (struct gdbarch *gdbarch,
+				    struct agent_expr *ax, int reg)
+{
+  int rawnum = reg % gdbarch_num_regs (gdbarch);
+  gdb_assert (reg >= gdbarch_num_regs (gdbarch)
+	      && reg < 2 * gdbarch_num_regs (gdbarch));
+  if (register_size (gdbarch, rawnum) >= register_size (gdbarch, reg))
+    {
+      ax_reg (ax, rawnum);
+
+      if (register_size (gdbarch, rawnum) > register_size (gdbarch, reg))
+        {
+	  if (gdbarch_byte_order (gdbarch) != BFD_ENDIAN_BIG)
+	    {
+	      ax_const_l (ax, 32);
+	      ax_simple (ax, aop_lsh);
+	    }
+	  ax_const_l (ax, 32);
+	  ax_simple (ax, aop_rsh_signed);
+	}
+    }
+  else
+    internal_error_loc (__FILE__, __LINE__, _("bad register size"));
+
+  return 0;
+}
+
+/* Table to translate nanomips 3-bit register field to
+   actual register number.  */
+static const signed char reg3_to_reg[8] = { 16, 17, 18, 19, 4, 5, 6, 7 };
+
+/* Heuristic_proc_start may hunt through the text section for a long
+   time across a 2400 baud serial line.  Allows the user to limit this
+   search.  */
+
+static int heuristic_fence_post = 0;
+
+/* Convert to/from a register and the corresponding memory value.  */
+
+/* This predicate tests for the case of a 4 byte floating point
+   value that is being transferred to or from a floating point
+   register which is 8 bytes wide.  */
+
+static int
+nanomips_convert_register_float_case_p (struct gdbarch *gdbarch, int regnum,
+					struct type *type)
+{
+  return (register_size (gdbarch, regnum) == 8
+	  && nanomips_float_register_p (gdbarch, regnum)
+	  && type->code () == TYPE_CODE_FLT && type->length () == 4);
+}
+
+/* This predicate tests for the case of a value of less than 8
+   bytes in width that is being transfered to or from an 8 byte
+   general purpose register.  */
+static int
+nanomips_convert_register_gpreg_case_p (struct gdbarch *gdbarch, int regnum,
+					struct type *type)
+{
+  int num_regs = gdbarch_num_regs (gdbarch);
+
+  return (register_size (gdbarch, regnum) == 8
+          && regnum % num_regs > 0 && regnum % num_regs < 32
+          && type->length () < 8);
+}
+
+static int
+nanomips_convert_register_p (struct gdbarch *gdbarch,
+			     int regnum, struct type *type)
+{
+  return (nanomips_convert_register_float_case_p (gdbarch, regnum, type)
+	  || nanomips_convert_register_gpreg_case_p (gdbarch, regnum, type));
+}
+
+static int
+nanomips_register_to_value (frame_info_ptr frame, int regnum,
+			    struct type *type, gdb_byte *to,
+			    int *optimizedp, int *unavailablep)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+
+  if (nanomips_convert_register_float_case_p (gdbarch, regnum, type))
+    {
+      /* single comes from low half of 64-bit register */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	{
+	  if (!get_frame_register_bytes (frame, regnum, 4, {to + 0, 4},
+					 optimizedp, unavailablep))
+	    return 0;
+	}
+      else
+	{
+	  if (!get_frame_register_bytes (frame, regnum, 0, {to + 0, 4},
+					 optimizedp, unavailablep))
+	    return 0;
+	}
+      *optimizedp = *unavailablep = 0;
+      return 1;
+    }
+  else if (nanomips_convert_register_gpreg_case_p (gdbarch, regnum, type))
+    {
+      int len = type->length ();
+      CORE_ADDR offset;
+
+      offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 8 - len : 0;
+      if (!get_frame_register_bytes (frame, regnum, offset, {to, (size_t)len},
+				     optimizedp, unavailablep))
+	return 0;
+
+      *optimizedp = *unavailablep = 0;
+      return 1;
+    }
+  else
+    {
+      internal_error_loc (__FILE__, __LINE__,
+                      _("nanomips_register_to_value: unrecognized case"));
+    }
+}
+
+static void
+nanomips_value_to_register (frame_info_ptr frame, int regnum,
+			    struct type *type, const gdb_byte *from)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+
+  if (nanomips_convert_register_float_case_p (gdbarch, regnum, type))
+    {
+      /* single goes in low half of 64-bit register */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	put_frame_register_bytes (frame, regnum, 4, {from, 4});
+      else
+	put_frame_register_bytes (frame, regnum, 0, {from, 4});
+    }
+  else if (nanomips_convert_register_gpreg_case_p (gdbarch, regnum, type))
+    {
+      gdb_byte fill[8];
+      int len = type->length ();
+
+      /* Sign extend values, irrespective of type, that are stored to
+         a 64-bit general purpose register.  (32-bit unsigned values
+	 are stored as signed quantities within a 64-bit register.
+	 When performing an operation, in compiled code, that combines
+	 a 32-bit unsigned value with a signed 64-bit value, a type
+	 conversion is first performed that zeroes out the high 32 bits.)  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	{
+	  if (from[0] & 0x80)
+	    store_signed_integer (fill, 8, BFD_ENDIAN_BIG, -1);
+	  else
+	    store_signed_integer (fill, 8, BFD_ENDIAN_BIG, 0);
+	  put_frame_register_bytes (frame, regnum, 0, {fill, (size_t)(8 - len)});
+	  put_frame_register_bytes (frame, regnum, 8 - len, {from, (size_t)len});
+	}
+      else
+	{
+	  if (from[len-1] & 0x80)
+	    store_signed_integer (fill, 8, BFD_ENDIAN_LITTLE, -1);
+	  else
+	    store_signed_integer (fill, 8, BFD_ENDIAN_LITTLE, 0);
+	  put_frame_register_bytes (frame, regnum, 0, {from, (size_t)len});
+	  put_frame_register_bytes (frame, regnum, len, {fill, (size_t)(8 - len)});
+	}
+    }
+  else
+    {
+      internal_error_loc (__FILE__, __LINE__,
+                      _("nanomips_value_to_register: unrecognized case"));
+    }
+}
+
+/* Return the GDB type for the pseudo register REGNUM, which is the
+   ABI-level view.  This function is only called if there is a target
+   description which includes registers, so we know precisely the
+   types of hardware registers.  */
+
+static struct type *
+nanomips_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
+{
+  const int num_regs = gdbarch_num_regs (gdbarch);
+  int rawnum = regnum % num_regs;
+  struct type *rawtype;
+
+  gdb_assert (regnum >= num_regs && regnum < 2 * num_regs);
+
+  /* Absent registers are still absent.  */
+  rawtype = gdbarch_register_type (gdbarch, rawnum);
+  if (rawtype->length () == 0)
+    return rawtype;
+
+  /* Present the floating point registers however the hardware did;
+     do not try to convert between FPU layouts.  */
+  if (nanomips_float_register_p (gdbarch, rawnum))
+    return rawtype;
+
+  /* Floating-point control registers are always 32-bit even though for
+     backwards compatibility reasons 64-bit targets will transfer them
+     as 64-bit quantities even if using XML descriptions.  */
+  if (nanomips_float_control_register_p (gdbarch, rawnum))
+    return builtin_type (gdbarch)->builtin_int32;
+
+  /* Use pointer types for registers if we can.  For n32 we can not,
+     since we do not have a 64-bit pointer type.  */
+  if (nanomips_abi_regsize (gdbarch)
+      == (builtin_type (gdbarch)->builtin_data_ptr)->length())
+    {
+      if (rawnum == NANOMIPS_SP_REGNUM
+	  || rawnum == nanomips_regnum (gdbarch)->badvaddr)
+	return builtin_type (gdbarch)->builtin_data_ptr;
+      else if (rawnum == NANOMIPS_PC_REGNUM)
+	return builtin_type (gdbarch)->builtin_func_ptr;
+    }
+
+  if (nanomips_abi_regsize (gdbarch) == 4 && rawtype->length () == 8
+      && ((rawnum >= NANOMIPS_ZERO_REGNUM && rawnum <= NANOMIPS_PC_REGNUM)
+	  || rawnum == nanomips_regnum (gdbarch)->badvaddr
+	  || rawnum == nanomips_regnum (gdbarch)->status
+	  || rawnum == nanomips_regnum (gdbarch)->cause
+	  || nanomips_dspacc_register_p (gdbarch, rawnum)))
+    return builtin_type (gdbarch)->builtin_int32;
+
+  /* For all other registers, pass through the hardware type.  */
+  return rawtype;
+}
+
+/* Should the upper word of 64-bit addresses be zeroed?  */
+static enum auto_boolean mask_address_var = AUTO_BOOLEAN_AUTO;
+
+static int
+nanomips_mask_address_p (const struct nanomips_gdbarch_tdep *tdep)
+{
+  switch (mask_address_var)
+    {
+    case AUTO_BOOLEAN_TRUE:
+      return 1;
+    case AUTO_BOOLEAN_FALSE:
+      return 0;
+      break;
+    case AUTO_BOOLEAN_AUTO:
+      return tdep->default_mask_address_p;
+    default:
+      internal_error_loc (__FILE__, __LINE__,
+		      _("nanomips_mask_address_p: bad switch"));
+      return -1;
+    }
+}
+
+static void
+show_mask_address (struct ui_file *file, int from_tty,
+		   struct cmd_list_element *c, const char *value)
+{
+  struct nanomips_gdbarch_tdep *tdep = (struct nanomips_gdbarch_tdep*) (target_gdbarch ());
+
+  deprecated_show_value_hack (file, from_tty, c, value);
+  switch (mask_address_var)
+    {
+    case AUTO_BOOLEAN_TRUE:
+      gdb_printf ("The 32 bit nanomips address mask is enabled\n");
+      break;
+    case AUTO_BOOLEAN_FALSE:
+      gdb_printf ("The 32 bit nanomips address mask is disabled\n");
+      break;
+    case AUTO_BOOLEAN_AUTO:
+      gdb_printf
+	("The 32 bit address mask is set automatically.  Currently %s\n",
+	 nanomips_mask_address_p (tdep) ? "enabled" : "disabled");
+      break;
+    default:
+      internal_error_loc (__FILE__, __LINE__, _("show_mask_address: bad switch"));
+      break;
+    }
+}
+
+/* nanoMIPS believes that the PC has a sign extended value.  Perhaps
+   all registers should be sign extended for simplicity?  */
+
+static CORE_ADDR
+nanomips_read_pc (struct readable_regcache *regcache)
+{
+  int regnum = gdbarch_pc_regnum (regcache->arch ());
+  LONGEST pc;
+
+  regcache->cooked_read (regnum, &pc);
+  return pc;
+}
+
+static CORE_ADDR
+nanomips_unwind_pc (struct gdbarch *gdbarch, frame_info_ptr next_frame)
+{
+  return frame_unwind_register_signed
+	   (next_frame, gdbarch_pc_regnum (gdbarch));
+}
+
+static CORE_ADDR
+nanomips_unwind_sp (struct gdbarch *gdbarch, frame_info_ptr next_frame)
+{
+  return frame_unwind_register_signed
+	   (next_frame, gdbarch_num_regs (gdbarch) + NANOMIPS_SP_REGNUM);
+}
+
+/* Assuming THIS_FRAME is a dummy, return the frame ID of that
+   dummy frame.  The frame ID's base needs to match the TOS value
+   saved by save_dummy_frame_tos(), and the PC match the dummy frame's
+   breakpoint.  */
+
+static struct frame_id
+nanomips_dummy_id (struct gdbarch *gdbarch, frame_info_ptr this_frame)
+{
+  return frame_id_build
+	   (get_frame_register_signed (this_frame,
+				       gdbarch_num_regs (gdbarch)
+				       + NANOMIPS_SP_REGNUM),
+	    get_frame_pc (this_frame));
+}
+
+/* Implement the "write_pc" gdbarch method.  */
+
+void
+nanomips_write_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+  int regnum = gdbarch_pc_regnum (regcache->arch ());
+  regcache_cooked_write_unsigned (regcache, regnum, pc);
+}
+
+/* Fetch and return 16-bit instruction from the specified location.  */
+
+static ULONGEST
+nanomips_fetch_stack_slot (struct gdbarch *gdbarch, CORE_ADDR sp, int offset)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  return read_memory_unsigned_integer (sp + offset, 4, byte_order);
+}
+
+static ULONGEST
+nanomips_fetch_instruction (struct gdbarch *gdbarch,
+			    CORE_ADDR addr, int *errp)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  gdb_byte buf[INSN16_SIZE];
+  int err;
+
+  err = target_read_memory (addr, buf, INSN16_SIZE);
+  if (errp != NULL)
+    *errp = err;
+  if (err != 0)
+    {
+      if (errp == NULL)
+	memory_error (TARGET_XFER_E_IO, addr);
+      return 0;
+    }
+  return extract_unsigned_integer (buf, INSN16_SIZE, byte_order);
+}
+
+/* MicroMIPS instruction fields.  */
+#define micromips_op(x) ((x) >> 10)
+
+/* 16-bit/32-bit-high-part instruction formats, B and S refer to the lowest
+   bit and the size respectively of the field extracted.  */
+#define b0s4_imm(x) ((x) & 0xf)
+#define b0s5_imm(x) ((x) & 0x1f)
+#define b0s5_reg(x) ((x) & 0x1f)
+#define b0s7_imm(x) ((x) & 0x7f)
+#define b0s8_imm(x) ((x) & 0xff)
+#define b0s10_imm(x) ((x) & 0x3ff)
+#define b0u13_15s1_imm(x) (((x) & 0x1fff) | (((x) & 0x8000) >> 2))
+#define b1s4_imm(x) (((x) >> 1) & 0xf)
+#define b1s9_imm(x) (((x) >> 1) & 0x1ff)
+#define b2s1_op(x) (((x) >> 2) & 0x1)
+#define b2s3_cc(x) (((x) >> 2) & 0x7)
+#define b3s2_op(x) (((x) >> 3) & 0x3)
+#define b3s9_imm(x) (((x) >> 3) & 0x1ff)
+#define b4s2_regl(x) (((x) >> 4) & 0x3)
+#define b4s3_reg(x) (((x) >> 4) & 0x7)
+#define b4s4_imm(x) (((x) >> 4) & 0xf)
+#define b5s5_op(x) (((x) >> 5) & 0x1f)
+#define b5s5_reg(x) (((x) >> 5) & 0x1f)
+#define b6s4_op(x) (((x) >> 6) & 0xf)
+#define b7s3_reg(x) (((x) >> 7) & 0x7)
+#define b8s2_regl(x) (((x) >> 8) & 0x3)
+#define b8s7_op(x) (((x) >> 8) & 0x7f)
+
+/* 32-bit instruction formats, B and S refer to the lowest bit and the size
+   respectively of the field extracted.  */
+#define b0s6_op(x) ((x) & 0x3f)
+#define b0s10_op(x) ((x) & 0x3ff)
+#define b0s11_op(x) ((x) & 0x7ff)
+#define b0s12_imm(x) ((x) & 0xfff)
+#define b0u16_imm(x) ((x) & 0xffff)
+#define b0s21_imm(x) ((x) & 0x1fffff)
+#define b0s26_imm(x) ((x) & 0x3ffffff)
+#define b6s10_ext(x) (((x) >> 6) & 0x3ff)
+#define b9s3_op(x) (((x) >> 9) & 0x7)
+#define b11s5_reg(x) (((x) >> 11) & 0x1f)
+#define b16s5_reg(x) (((x) >> 16) & 0x1f)
+#define b21s5_reg(x) (((x) >> 21) & 0x1f)
+#define b11s7_imm(x) (((x) >> 11) & 0x7f)
+#define b12s4_op(x) (((x) >> 12) & 0xf)
+#define b12s5_op(x) (((x) >> 12) & 0x1f)
+#define b14s2_op(x) (((x) >> 14) & 0x3)
+#define b16s4_imm(x) (((x) >> 16) & 0xf)
+
+/* Return the size in bytes of the instruction INSN encoded in the ISA
+   instruction set.  */
+
+static int
+nanomips_insn_size (ULONGEST insn)
+{
+  if (micromips_op (insn) == 0x18)
+    return 3 * INSN16_SIZE;
+  else if ((micromips_op (insn) & 0x4) == 0x0)
+    return 2 * INSN16_SIZE;
+  else
+    return INSN16_SIZE;
+}
+
+/* Calculate the address of the next nanoMIPS instruction to execute
+   after the instruction at the address PC.  The nanomips_next_pc
+   function supports single_step when the remote target monitor or stub
+   is not developed enough to do a single_step.  It works by decoding the
+   current instruction and predicting where a branch will go.  This isn't
+   hard because all the data is available.  */
+
+static CORE_ADDR
+nanomips_next_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ULONGEST insn;
+  CORE_ADDR offset, sp, ra;
+  int op, sreg, treg, uimm, count;
+  LONGEST val_rs, val_rt;
+
+  insn = nanomips_fetch_instruction (gdbarch, pc, NULL);
+  pc += INSN16_SIZE;
+  switch (nanomips_insn_size (insn))
+    {
+    /* 48-bit instructions.  */
+    case 3 * INSN16_SIZE:
+      /* No branch or jump instructions in this category.  */
+      pc += 2 * INSN16_SIZE;
+      break;
+
+    /* 32-bit instructions.  */
+    case 2 * INSN16_SIZE:
+      insn <<= 16;
+      insn |= nanomips_fetch_instruction (gdbarch, pc, NULL);
+      pc += INSN16_SIZE;
+      switch (micromips_op (insn >> 16))
+      	{
+      	case 0x0: /* P32 */
+      	  op = b5s5_op (insn >> 16);
+      	  switch (op)
+      	    {
+      	    case 0x0: /* P.RI */
+      	      switch (b3s2_op (insn >> 16))
+      		{
+      		case 0x1: /* SYSCALL */
+      		  if (b2s1_op (insn >> 16) == 0)
+      		    {
+      		      struct nanomips_gdbarch_tdep *tdep;
+
+      		      tdep = gdbarch_tdep<nanomips_gdbarch_tdep> (gdbarch);
+      		      if (tdep->syscall_next_pc != NULL)
+      			pc = tdep->syscall_next_pc (get_current_frame (), pc);
+      		    }
+      		  break;
+      		}
+      	      break;
+      	    }
+      	  break;
+
+      	case 0x2: /* MOVE.BALC */
+      	  offset = ((insn & 1) << 20 | ((insn >> 1) & 0xfffff)) << 1;
+      	  offset = (offset ^ 0x200000) - 0x200000;
+      	  pc += offset;
+      	  break;
+
+      	case 0xa: /* BALC, BC */
+      	  offset = ((insn & 1) << 24 | ((insn >> 1) & 0xffffff)) << 1;
+      	  offset = (offset ^ 0x2000000) - 0x2000000;
+      	  pc += offset;
+      	  break;
+
+      	case 0x12: /* P.J P.BREG P.BALRC P.BALRSC */
+      	  op = b12s4_op (insn);
+      	  sreg = b0s5_reg (insn >> 16);
+      	  treg = b5s5_reg (insn >> 16);
+      	  if (op == 0x8) /* BALRSC, BRSC */
+      	    {
+      	      val_rs = regcache_raw_get_signed (regcache, sreg);
+      	      pc += (val_rs << 1);
+      	    }
+      	  else if (op == 0 || op == 1) /* JALRC JALRC.HB */
+      	    pc = regcache_raw_get_signed (regcache, sreg);
+      	  break;
+
+      	case 0x20: /* PP.SR */
+      	  if ((b12s4_op (insn) == 0x3) && ((insn & 3) == 3)) /* RESTORE.JRC */
+      	   {
+                   sp = regcache_raw_get_signed (regcache, NANOMIPS_SP_REGNUM);
+                   ra = regcache_raw_get_signed (regcache, NANOMIPS_RA_REGNUM);
+                   sp += (((insn >> 3) & 0x1ff) << 3);
+                   count = ((insn >> 16) & 0xf);
+                   treg = b5s5_reg(insn >> 16);
+                   if (count != 0 && treg <= 31 && (treg + count) > 31)
+                     ra = nanomips_fetch_stack_slot (gdbarch, sp, -(31 - treg + 1) * 4);
+                   pc = ra;
+                 }
+      	  break;
+
+      	case 0x22: /* P.BR1 */
+      	  op = b14s2_op (insn);
+      	  sreg = b0s5_reg (insn >> 16);
+      	  treg = b5s5_reg (insn >> 16);
+      	  val_rs = regcache_raw_get_signed (regcache, sreg);
+      	  val_rt = regcache_raw_get_signed (regcache, treg);
+      	  offset = ((insn & 1) << 13 | ((insn >> 1) & 0x1fff)) << 1;
+      	  offset = (offset ^ 0x4000) - 0x4000;
+      	  if ((op == 0 && val_rs == val_rt) /* BEQC */
+      	      || (op == 2 && val_rs >= val_rt) /* BGEC */
+      	      || (op == 3
+      		  && (ULONGEST) val_rs >= (ULONGEST) val_rt)) /* BGEUC */
+      	    pc += offset;
+      	  break;
+
+      	case 0x2a: /* P.BR2 */
+      	  op = b14s2_op (insn);
+      	  sreg = b0s5_reg (insn >> 16);
+      	  treg = b5s5_reg (insn >> 16);
+      	  val_rs = regcache_raw_get_signed (regcache, sreg);
+      	  val_rt = regcache_raw_get_signed (regcache, treg);
+      	  offset = ((insn & 1) << 13 | ((insn >> 1) & 0x1fff)) << 1;
+      	  offset = (offset ^ 0x4000) - 0x4000;
+      	  if ((op == 0 && val_rs != val_rt) /* BNEC */
+      	      || (op == 2 && val_rs < val_rt) /* BLTC */
+      	      || (op == 3
+      		  && (ULONGEST) val_rs < (ULONGEST) val_rt)) /* BLTUC */
+      	    pc += offset;
+      	  break;
+
+      	case 0x32: /* P.BRI */
+      	  op = b2s3_cc (insn >> 16);
+      	  treg = b5s5_reg (insn >> 16);
+      	  val_rt = regcache_raw_get_signed (regcache, treg);
+      	  offset = ((insn & 1) << 10 | ((insn >> 1) & 0x3ff)) << 1;
+      	  offset = (offset ^ 0x800) - 0x800;
+      	  uimm = b11s7_imm (insn);
+      	  if ((op == 0 && val_rt == uimm) /* BEQIC */
+                    || (op == 1 && ((val_rt &  (1 << uimm)) == 0)) /* BBEQZC */
+      	      || (op == 2 && val_rt >= uimm) /* BGEIC */
+      	      || (op == 3 && (ULONGEST) val_rt >= uimm) /* BGEIUC */
+      	      || (op == 4 && val_rt != uimm) /* BNEIC */
+                    || (op == 5 && ((val_rt &  (1 << uimm)) != 0)) /* BBNEZC */
+      	      || (op == 6 && val_rt < uimm) /* BLTIC */
+      	      || (op == 7 && (ULONGEST) val_rt < uimm)) /* BLTIUC */
+      	    pc += offset;
+      	  break;
+
+      	case 0x3a: /* P.BZ */
+      	  op = (insn & 0x80000); /* 20th bit */
+      	  treg = b5s5_reg (insn >> 16);
+      	  val_rt = regcache_raw_get_signed (regcache, treg);
+      	  offset = ((insn & 1) << 19 | ((insn >> 1) & 0x7ffff)) << 1;
+      	  offset = (offset ^ 0x100000) - 0x100000;
+      	  if ((op == 0 && val_rt == 0) /* BEQZC */
+      	      || (op != 0 && val_rt != 0)) /* BNEZC */
+      	    pc += offset;
+      	  break;
+
+      	default:
+      	  break;
+      	}
+      break;
+
+    /* 16-bit instructions.  */
+    case INSN16_SIZE:
+      switch (micromips_op (insn))
+	{
+	case 0x4: /* P16 */
+	  op = b5s5_op (insn);
+	  switch (op)
+	    {
+	    case 0x0: /* P16.RI */
+	      switch (b3s2_op (insn))
+		{
+		case 0x1: /* SYSCALL[16] */
+		  if (b2s1_op (insn) == 0)
+		    {
+		      struct nanomips_gdbarch_tdep *tdep;
+
+		      tdep = gdbarch_tdep<nanomips_gdbarch_tdep> (gdbarch);
+		      if (tdep->syscall_next_pc != NULL)
+			pc = tdep->syscall_next_pc (get_current_frame (), pc);
+		    }
+		  break;
+		}
+	      break;
+	    }
+	  break;
+
+	case 0x6: /* BC[16] */
+	case 0xe: /* BALC[16] */
+	  offset = ((insn & 1) << 9 | ((insn >> 1) & 0x1ff)) << 1;
+	  offset = (offset ^ 0x400) - 0x400;
+	  pc += offset;
+	  break;
+
+	case 0x7: /* RESTORE.JRC[16] */
+	  if ((insn & 1) == 0 && (insn & 0x20) == 0x20 && ((insn >> 8) & 1) == 1)
+          {
+            sp = regcache_raw_get_signed (regcache, NANOMIPS_SP_REGNUM);
+	    ra = regcache_raw_get_signed (regcache, NANOMIPS_RA_REGNUM);
+            sp += (((insn >> 4) & 0xf) << 4);
+            count = insn & 0xf;
+            treg = ((insn >> 9) & 0x1) ? NANOMIPS_RA_REGNUM : NANOMIPS_FP_REGNUM;
+            if (count != 0 && treg + count > 31) {
+                ra = nanomips_fetch_stack_slot (gdbarch, sp, -(31 - treg + 1) * 4);
+            }
+            pc = ra;
+          }
+	  break;
+
+	case 0x26: /* BEQZC[16] */
+	  treg = reg3_to_reg[b7s3_reg (insn)];
+	  val_rt = regcache_raw_get_signed (regcache, treg);
+	  offset = ((insn & 1) << 6 | ((insn >> 1) & 0x3f)) << 1;
+	  offset = (offset ^ 0x80) - 0x80;
+	  if (val_rt == 0)
+	    pc += offset;
+	  break;
+
+	case 0x2e: /* BNEZC[16] */
+	  treg = reg3_to_reg[b7s3_reg (insn)];
+	  val_rt = regcache_raw_get_signed (regcache, treg);
+	  offset = ((insn & 1) << 6 | ((insn >> 1) & 0x3f)) << 1;
+	  offset = (offset ^ 0x80) - 0x80;
+	  if (val_rt != 0)
+	    pc += offset;
+	  break;
+
+	case 0x36: /* P16.BR P16.JRC */
+	  sreg = b4s3_reg (insn);
+	  treg = b7s3_reg (insn);
+	  val_rs = regcache_raw_get_signed (regcache, reg3_to_reg[sreg]);
+	  val_rt = regcache_raw_get_signed (regcache, reg3_to_reg[treg]);
+	  offset = insn & 0xf;
+	  /* BEQC[16] BEQC[16] */
+	  if ((sreg < treg && offset != 0 && val_rs == val_rt)
+	      || (sreg >= treg && offset != 0 && val_rs != val_rt))
+	    pc += (offset << 1);
+	  else if (offset == 0) /* JALRC[16] JRC */
+	    pc = regcache_raw_get_signed (regcache, b5s5_reg(insn));
+	  break;
+
+	default:
+	  break;
+	}
+      break;
+
+    default:
+      break;
+    }
+  return pc;
+}
+
+struct nanomips_frame_cache
+{
+  CORE_ADDR base;
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Set a register's saved stack address in temp_saved_regs.  If an
+   address has already been set for this register, do nothing; this
+   way we will only recognize the first save of a given register in a
+   function prologue.
+
+   For simplicity, save the address in both [0 .. gdbarch_num_regs) and
+   [gdbarch_num_regs .. 2*gdbarch_num_regs).
+   Strictly speaking, only the second range is used as it is only second
+   range (the ABI instead of ISA registers) that comes into play when finding
+   saved registers in a frame.  */
+
+static void
+set_reg_offset (struct gdbarch *gdbarch, struct nanomips_frame_cache *this_cache,
+		int regnum, CORE_ADDR offset)
+{
+  if (this_cache != NULL
+      && this_cache->saved_regs[regnum].addr() == -1)
+    {
+      this_cache->saved_regs[regnum + 0 * gdbarch_num_regs (gdbarch)].set_addr(
+        offset);
+      this_cache->saved_regs[regnum + 1 * gdbarch_num_regs (gdbarch)].set_addr(
+        offset);
+    }
+}
+
+/* Analyze the function prologue from START_PC to LIMIT_PC.  Return
+   the address of the first instruction past the prologue.  */
+
+static CORE_ADDR
+nanomips_scan_prologue (struct gdbarch *gdbarch,
+			CORE_ADDR start_pc, CORE_ADDR limit_pc,
+			frame_info_ptr this_frame,
+			struct nanomips_frame_cache *this_cache)
+{
+  CORE_ADDR end_prologue_addr;
+  int prev_non_prologue_insn = 0;
+  int frame_reg = NANOMIPS_SP_REGNUM;
+  int this_non_prologue_insn;
+  int non_prologue_insns = 0;
+  long frame_offset = 0;	/* Size of stack frame.  */
+  long frame_adjust = 0;	/* Offset of FP from SP.  */
+  CORE_ADDR prev_pc;
+  CORE_ADDR cur_pc;
+  ULONGEST insn;		/* current instruction */
+  CORE_ADDR sp;
+  long offset;
+  long sp_adj;
+  long v1_off = 0;		/* The assumption is LUI will replace it.  */
+  int breg;
+  int dreg;
+  int sreg;
+  int treg;
+  int loc;
+  int op;
+
+  /* Can be called when there's no process, and hence when there's no
+     THIS_FRAME.  */
+  if (this_frame != NULL)
+    sp = get_frame_register_signed (this_frame,
+				    gdbarch_num_regs (gdbarch)
+				    + NANOMIPS_SP_REGNUM);
+  else
+    sp = 0;
+
+  if (limit_pc > start_pc + 200)
+    limit_pc = start_pc + 200;
+  prev_pc = start_pc;
+
+  /* Permit at most one non-prologue non-control-transfer instruction
+     in the middle which may have been reordered by the compiler for
+     optimisation.  */
+  for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += loc)
+    {
+      this_non_prologue_insn = 0;
+      sp_adj = 0;
+      loc = 0;
+      insn = nanomips_fetch_instruction (gdbarch, cur_pc, NULL);
+      loc += INSN16_SIZE;
+      switch (nanomips_insn_size (insn))
+	{
+	/* 48-bit instructions.  */
+	case 3 * INSN16_SIZE:
+	  if (micromips_op (insn) == 0x18)
+	    {
+	      op = b0s5_imm (insn);
+	      treg = b5s5_reg (insn);
+	      offset = nanomips_fetch_instruction (gdbarch, cur_pc + 2, NULL);
+	      offset <<= 16;
+	      offset |= nanomips_fetch_instruction (gdbarch, cur_pc + 4, NULL);
+	      if (op == 0x0 && treg == 3) /* LI48 $v1, imm32 */
+		v1_off = offset;
+	      else if (op == 0x1 /* ADDIU48 $sp, imm32 */
+		       && treg == NANOMIPS_SP_REGNUM)
+		sp_adj = offset;
+	      else
+		this_non_prologue_insn = 1;
+	    }
+	      else
+		this_non_prologue_insn = 1;
+	  break;
+
+	/* 32-bit instructions.  */
+	case 2 * INSN16_SIZE:
+	  insn <<= 16;
+	  insn |= nanomips_fetch_instruction (gdbarch,
+					  cur_pc + loc, NULL);
+	  loc += INSN16_SIZE;
+
+	  switch (micromips_op (insn >> 16))
+	    {
+	    case 0x0: /* PP.ADDIU bits 000000 */
+	      sreg = b0s5_reg (insn >> 16);
+	      treg = b5s5_reg (insn >> 16);
+	      offset = b0u16_imm (insn);
+	      if (sreg == treg
+		  && treg == NANOMIPS_SP_REGNUM) /* ADDIU $sp, $sp, imm */
+		sp_adj = offset;
+	      else if (sreg == NANOMIPS_SP_REGNUM
+		       && treg == NANOMIPS_FP_REGNUM) /* ADDIU $fp, $sp, imm */
+		{
+		  frame_adjust = offset;
+		  frame_reg = NANOMIPS_FP_REGNUM;
+		}
+	      else if (sreg != NANOMIPS_GP_REGNUM
+		       || treg != NANOMIPS_GP_REGNUM)
+		this_non_prologue_insn = 1;
+	      break;
+
+	    case 0x8: /* P32A: bits 001000 */
+	      op = b0s10_op (insn);
+	      sreg = b0s5_reg (insn >> 16);
+	      treg = b5s5_reg (insn >> 16);
+	      dreg = b11s5_reg (insn);
+	      if (op == 0x1d0	/* SUBU: bits 001000 0111010000 */
+		  && dreg == NANOMIPS_SP_REGNUM && sreg == NANOMIPS_SP_REGNUM
+		  && treg == 3)	/* SUBU $sp, $v1 */
+		sp_adj = v1_off;
+	      else
+		this_non_prologue_insn = 1;
+	      break;
+
+	    case 0x20: /* P.U12 bits 100000 */
+	      /* SAVE: bits 100000 rt 0 count 0011 */
+	      if (b12s4_op (insn) == 0x3)
+		{
+		  int rt, this_rt, gp, use_gp;
+		  int counter = 0, count = b16s4_imm (insn);
+		  long this_offset;
+		  offset = b3s9_imm (insn) << 3;
+		  rt = b21s5_reg (insn);
+		  sp_adj = -offset;
+		  gp = (insn >> 2) & 1;
+		  while (counter != count)
+		    {
+		      use_gp = gp & (counter == count - 1);
+		      if (use_gp)
+			this_rt = NANOMIPS_GP_REGNUM;
+		      else
+			this_rt = (((rt >> 4) & 1) << 4) | (rt + counter);
+		      this_offset = (counter + 1) << 2;
+		      set_reg_offset (gdbarch, this_cache, this_rt,
+				      sp + offset - this_offset);
+		      counter++;
+		    }
+		}
+	      else if (b12s4_op (insn) == 8) /* ADDIU[NEG]: bits 100000 1000 */
+		{
+		  sreg = b0s5_reg (insn >> 16);
+		  treg = b5s5_reg (insn >> 16);
+		  if (sreg == treg && sreg == NANOMIPS_SP_REGNUM)
+			  /* ADDIU[NEG] $sp, $sp, imm */
+		    {
+		      offset = b0s11_op (insn);
+		      sp_adj = -offset;
+		    }
+		}
+	      else if (b12s4_op (insn) == 0) /* ORI: bits 100000 0000 */
+		{
+		  sreg = b0s5_reg (insn >> 16);
+		  treg = b5s5_reg (insn >> 16);
+		  if (sreg == treg && treg == 3) /* ORI $v1, $v1, imm */
+		    v1_off |= b0s11_op (insn);
+		  else
+		    this_non_prologue_insn = 1;
+		}
+		else
+		  this_non_prologue_insn = 1;
+	      break;
+
+	    case 0x21: /* P.LS.U12 bits 100001 */
+	      if (b12s4_op (insn) == 0x9) /* SW 100001 1001 */
+		{
+		  breg = b0s5_reg (insn >> 16);
+		  sreg = b5s5_reg (insn >> 16);
+		  offset = b0s12_imm (insn);
+		  if (breg == NANOMIPS_SP_REGNUM) /* SW reg,offset($sp) */
+		    set_reg_offset (gdbarch, this_cache, sreg, sp + offset);
+		  else
+		    this_non_prologue_insn = 1;
+		}
+	      break;
+
+	    case 0x29: /* P.LS.S9 bits 101001 */
+	      if (b8s7_op (insn) == 0x48) /* SW[S9] 101001 1001 0 00 */
+		{
+		  breg = b0s5_reg (insn >> 16);
+		  sreg = b5s5_reg (insn >> 16);
+		  offset = (((insn >> 15) & 1) << 8) | b0s8_imm (insn);
+		  offset = (offset ^ 0x100) - 0x100;
+		  if (breg == NANOMIPS_SP_REGNUM) /* SW[S9] reg,offset($sp) */
+		    set_reg_offset (gdbarch, this_cache, sreg, sp + offset);
+		  else
+		    this_non_prologue_insn = 1;
+		}
+	      break;
+
+	    case 0x38: /* P.LUI bits 111000 */
+	      treg = b5s5_reg (insn >> 16);
+	      if ((insn & 2) == 0 /* LU20I bits 111000 0 */
+		  && treg == 3) /* LU20I $v1, imm */
+		{
+		  v1_off = ((insn & 1) << 19)
+			    | (((insn >> 2) & 0x3ff) << 9)
+			    | (((insn >> 12) & 0x1ff));
+		  v1_off = v1_off << 12;
+		}
+	      else
+		this_non_prologue_insn = 1;
+	      break;
+
+	   default:
+	     this_non_prologue_insn = 1;
+	     break;
+	   }
+
+	  insn >>= 16;
+	  break;
+
+	/* 16-bit instructions.  */
+	case INSN16_SIZE:
+	  switch (micromips_op (insn))
+	    {
+	    case 0x4: /* MOVE: bits 000100 */
+	      sreg = b0s5_reg (insn);
+	      dreg = b5s5_reg (insn);
+	      if (sreg == NANOMIPS_SP_REGNUM && dreg == NANOMIPS_FP_REGNUM)
+				/* MOVE  $fp, $sp */
+		frame_reg = NANOMIPS_FP_REGNUM;
+	      else
+		this_non_prologue_insn = 1;
+	      break;
+
+	    case 0x7: /* SAVE: bits 000111 */
+	      {
+		int rt, rt1, this_rt;
+		int counter = 0, count = b0s4_imm (insn);
+		long this_offset;
+		offset = b4s4_imm (insn) << 4;
+		rt1 = (insn >> 9) & 1;
+		rt = 30 | rt1;
+		sp_adj = -offset;
+		while (counter != count)
+		  {
+		    this_rt = (((rt >> 4) & 1) << 4) | (rt + counter);
+		    this_offset = (counter + 1) << 2;
+		    set_reg_offset (gdbarch, this_cache, this_rt,
+				    sp + offset - this_offset);
+		    counter++;
+		  }
+		break;
+	      }
+
+	    case 0x35: /* SW[SP]: bits 110101 */
+	      treg = b5s5_reg (insn);
+	      offset = b0s5_imm (insn);
+	      set_reg_offset (gdbarch, this_cache, treg, sp + offset);
+	      break;
+
+	    default:
+	      this_non_prologue_insn = 1;
+	      break;
+	    }
+	  break;
+	}
+
+      if (sp_adj < 0)
+	frame_offset -= sp_adj;
+
+      non_prologue_insns += this_non_prologue_insn;
+
+      if (non_prologue_insns > 1 || sp_adj > 0)
+  break;
+
+      prev_non_prologue_insn = this_non_prologue_insn;
+      prev_pc = cur_pc;
+    }
+
+  if (this_cache != NULL)
+    {
+      this_cache->base =
+	(get_frame_register_signed (this_frame,
+				    gdbarch_num_regs (gdbarch) + frame_reg)
+	 + frame_offset - frame_adjust);
+      /* FIXME: brobecker/2004-10-10: Just as in the mips32 case, we should
+	 be able to get rid of the assignment below, evetually. But it's
+	 still needed for now.  */
+      this_cache->saved_regs[gdbarch_num_regs (gdbarch) + NANOMIPS_PC_REGNUM]
+	= this_cache->saved_regs[gdbarch_num_regs (gdbarch)
+				 + NANOMIPS_RA_REGNUM];
+    }
+
+  /* Set end_prologue_addr to the address of the instruction immediately
+     after the last one we scanned.  Unless the last one looked like a
+     non-prologue instruction (and we looked ahead), in which case use
+     its address instead.  */
+  end_prologue_addr
+    = prev_non_prologue_insn ? prev_pc : cur_pc;
+
+  return end_prologue_addr;
+}
+
+/* Heuristic unwinder for procedures using nanoMIPS instructions.
+   Procedures that use the 32-bit instruction set are handled by the
+   mips_insn32 unwinder.  Likewise MIPS16 and the mips_insn16 unwinder. */
+
+static struct nanomips_frame_cache *
+nanomips_frame_cache (frame_info_ptr this_frame, void **this_cache)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct nanomips_frame_cache *cache;
+
+  if ((*this_cache) != NULL)
+    return (struct nanomips_frame_cache *) (*this_cache);
+
+  cache = FRAME_OBSTACK_ZALLOC (struct nanomips_frame_cache);
+  (*this_cache) = cache;
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+  /* Analyze the function prologue.  */
+  {
+    const CORE_ADDR pc = get_frame_address_in_block (this_frame);
+    CORE_ADDR start_addr;
+
+    find_pc_partial_function (pc, NULL, &start_addr, NULL);
+    if (start_addr == 0)
+      start_addr = heuristic_proc_start (get_frame_arch (this_frame), pc);
+    /* We can't analyze the prologue if we couldn't find the begining
+       of the function.  */
+    if (start_addr == 0)
+      return cache;
+
+    nanomips_scan_prologue (gdbarch, start_addr, pc, this_frame,
+			    (struct nanomips_frame_cache *) *this_cache);
+  }
+
+  /* gdbarch_sp_regnum contains the value and not the address.  */
+  cache->saved_regs[gdbarch_num_regs (gdbarch)
+        + NANOMIPS_SP_REGNUM].set_value (cache->base);
+
+  return (struct nanomips_frame_cache *) (*this_cache);
+}
+
+static void
+nanomips_frame_this_id (frame_info_ptr this_frame, void **this_cache,
+			struct frame_id *this_id)
+{
+  struct nanomips_frame_cache *info = nanomips_frame_cache (this_frame,
+							    this_cache);
+  /* This marks the outermost frame.  */
+  if (info->base == 0)
+    return;
+  (*this_id) = frame_id_build (info->base, get_frame_func (this_frame));
+}
+
+static struct value *
+nanomips_frame_prev_register (frame_info_ptr this_frame,
+			      void **this_cache, int regnum)
+{
+  struct nanomips_frame_cache *info = nanomips_frame_cache (this_frame,
+							    this_cache);
+  return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
+}
+
+static int
+nanomips_frame_sniffer (const struct frame_unwind *self,
+			frame_info_ptr this_frame, void **this_cache)
+{
+  return 1;
+}
+
+static const struct frame_unwind nanomips_frame_unwind =
+{
+  "nanoMIPS insn prologue",
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  nanomips_frame_this_id,
+  nanomips_frame_prev_register,
+  NULL,
+  nanomips_frame_sniffer
+};
+
+static CORE_ADDR
+nanomips_frame_base_address (frame_info_ptr this_frame,
+			     void **this_cache)
+{
+  struct nanomips_frame_cache *info = nanomips_frame_cache (this_frame,
+							    this_cache);
+  return info->base;
+}
+
+static const struct frame_base nanomips_frame_base =
+{
+  &nanomips_frame_unwind,
+  nanomips_frame_base_address,
+  nanomips_frame_base_address,
+  nanomips_frame_base_address
+};
+
+static const struct frame_base *
+nanomips_frame_base_sniffer (frame_info_ptr this_frame)
+{
+  return &nanomips_frame_base;
+}
+
+/* nanomips_addr_bits_remove - remove useless address bits  */
+
+static CORE_ADDR
+nanomips_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  struct nanomips_gdbarch_tdep *tdep = gdbarch_tdep<nanomips_gdbarch_tdep> (gdbarch);
+
+  if (nanomips_mask_address_p (tdep)
+      && (((ULONGEST) addr) >> 32 == 0xffffffffUL))
+    /* This hack is a work-around for existing boards using PMON, the
+       simulator, and any other 64-bit targets that doesn't have true
+       64-bit addressing.  On these targets, the upper 32 bits of
+       addresses are ignored by the hardware.  Thus, the PC or SP are
+       likely to have been sign extended to all 1s by instruction
+       sequences that load 32-bit addresses.  For example, a typical
+       piece of code that loads an address is this:
+
+       lui $r2, <upper 16 bits>
+       ori $r2, <lower 16 bits>
+
+       But the lui sign-extends the value such that the upper 32 bits
+       may be all 1s.  The workaround is simply to mask off these
+       bits.  In the future, gcc may be changed to support true 64-bit
+       addressing, and this masking will have to be disabled.  */
+    return addr &= 0xffffffffUL;
+  else
+    return addr;
+}
+
+
+/* Checks for an atomic sequence of instructions beginning with a LL/LLD
+   instruction and ending with a SC/SCD instruction.  If such a sequence
+   is found, attempt to step through it.  A breakpoint is placed at the end of
+   the sequence.  */
+
+static std::vector<CORE_ADDR>
+nanomips_deal_with_atomic_sequence (struct gdbarch *gdbarch,
+				    CORE_ADDR pc)
+{
+  const int atomic_sequence_length = 16; /* Instruction sequence length.  */
+  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */
+  CORE_ADDR breaks[2] = {CORE_ADDR_MAX, CORE_ADDR_MAX};
+  CORE_ADDR branch_bp = 0; /* Breakpoint at branch instruction's
+			      destination.  */
+  CORE_ADDR loc = pc;
+  int sc_found = 0;
+  ULONGEST insn;
+  int insn_count;
+  int index;
+
+  /* Assume all atomic sequences start with a ll/lld instruction.  */
+  insn = nanomips_fetch_instruction (gdbarch, loc, NULL);
+  if (micromips_op (insn) != 0x29)	/* P.LL: bits 101001 */
+    return {};
+  loc += INSN16_SIZE;
+  insn <<= 16;
+  insn |= nanomips_fetch_instruction (gdbarch, loc, NULL);
+  if (b8s7_op (insn) != 0x51)	/* LL: bits 101001 1010 0 01 */
+    return {};
+  loc += INSN16_SIZE;
+
+  /* Assume all atomic sequences end with an sc/scd instruction.  Assume
+     that no atomic sequence is longer than "atomic_sequence_length"
+     instructions.  */
+  for (insn_count = 0;
+       !sc_found && insn_count < atomic_sequence_length;
+       ++insn_count)
+    {
+      int is_branch = 0, op;
+      CORE_ADDR offset;
+
+      insn = nanomips_fetch_instruction (gdbarch, loc, NULL);
+      loc += INSN16_SIZE;
+
+      /* Assume that there is at most one conditional branch in the
+         atomic sequence.  If a branch is found, put a breakpoint in
+         its destination address.  */
+      switch (nanomips_insn_size (insn))
+	{
+	/* 32-bit instructions.  */
+	case 2 * INSN16_SIZE:
+	  insn <<= 16;
+	  insn |= nanomips_fetch_instruction (gdbarch, loc, NULL);
+	  loc += INSN16_SIZE;
+
+	  switch (micromips_op (insn >> 16))
+	    {
+	    case 0xa: /* BALC, BC */
+	      offset = ((insn & 1) << 24 | ((insn >> 1) & 0xffffff)) << 1;
+	      offset = (offset ^ 0x2000000) - 0x2000000;
+	      branch_bp = loc + offset;
+	      is_branch = 1;
+	      break;
+
+	    case 0x12:
+	      op = b12s4_op (insn);
+	      if (op == 0x8) /* BALRC, BALRSC */
+		return {}; /* Fall back to the standard single-step code. */
+	      else if (op == 0 || op == 1) /* JALRC JALRC.HB */
+		return {}; /* Fall back to the standard single-step code. */
+	      break;
+
+	    case 0x20: /* PP.SR */
+	      if (b12s5_op (insn) == 0x13) /* RESTORE.JRC */
+		return {}; /* Fall back to the standard single-step code. */
+	      break;
+
+	    case 0x22: /* P.BR1 */
+	    case 0x2a: /* P.BR2 */
+	      op = b14s2_op (insn);
+	      offset = ((insn & 1) << 13 | ((insn >> 1) & 0x1fff)) << 1;
+	      offset = (offset ^ 0x4000) - 0x4000;
+	      if (op == 0 /* BEQC, BNEC */
+		  || op == 2 /* BGEC, BLTC */
+		  || op == 3) /* BGEUC, BLTUC */
+		{
+		  branch_bp = loc + offset;
+		  is_branch = 1;
+		}
+	      break;
+
+	    case 0x32: /* P.BRI */
+	      op = b2s3_cc (insn >> 16);
+	      offset = ((insn & 1) << 10 | ((insn >> 1) & 0x3ff)) << 1;
+	      offset = (offset ^ 0x800) - 0x800;
+	      if (op == 0 /* BEQIC */
+		  || op == 2 /* BGEIC */
+		  || op == 3 /* BGEIUC */
+		  || op == 4 /* BNEIC */
+		  || op == 6 /* BLTIC */
+		  || op == 7 ) /* BLTIUC */
+		{
+		  branch_bp = loc + offset;
+		  is_branch = 1;
+		}
+	      break;
+
+	    case 0x3a: /* P.BZ */
+	      op = (insn & 0x80000); /* 20th bit */
+	      offset = ((insn & 1) << 19 | ((insn >> 1) & 0x7ffff)) << 1;
+	      offset = (offset ^ 0x100000) - 0x100000;
+	      if (op == 0 /* BEQZC */
+	          || op != 0 ) /* BNEZC */
+		{
+		  branch_bp = loc + offset;
+		  is_branch = 1;
+		}
+	      break;
+
+	    case 0x29: /* P.SC: bits 101001 */
+	      if (b8s7_op (insn) == 0x59) /* SC: bits 101001 1011 0 01 */
+		sc_found = 1;
+	      break;
+	    }
+	  break;
+
+	/* 16-bit instructions.  */
+	case INSN16_SIZE:
+	  switch (micromips_op (insn))
+	    {
+	    case 0x6: /* BC[16] */
+	    case 0xe: /* BALC[16] */
+	      offset = ((insn & 1) << 9 | ((insn >> 1) & 0x1ff)) << 1;
+	      offset = (offset ^ 0x400) - 0x400;
+	      branch_bp = loc + offset;
+	      is_branch = 1;
+	      break;
+
+	    case 0x7: /* RESTORE.JRC[16] */
+	      if ((insn & 1) == 0 && (insn & 0x20) == 0x20)
+		return {}; /* Fall back to the standard single-step code. */
+	      break;
+
+	    case 0x26: /* BEQZC[16] */
+	    case 0x2e: /* BNEZC[16] */
+	      offset = ((insn & 1) << 6 | ((insn >> 1) & 0x3f)) << 1;
+	      offset = (offset ^ 0x80) - 0x80;
+	      branch_bp = loc + offset;
+	      is_branch = 1;
+	      break;
+
+	    case 0x36: /* P16.BR P16.JRC */
+	      offset = insn & 0xf;
+	      /* BEQC[16] BEQC[16] */
+	      if (offset != 0)
+		{
+		  branch_bp = loc + offset;
+		  is_branch = 1;
+		}
+	      else if (offset == 0) /* JALRC[16] JRC */
+		return {}; /* Fall back to the standard single-step code. */
+	      break;
+	    }
+	  break;
+	}
+
+      if (is_branch)
+	{
+	  if (last_breakpoint >= 1)
+	    return {}; /* More than one branch found, fallback to the
+			 standard single-step code.  */
+	  breaks[1] = branch_bp;
+	  last_breakpoint++;
+	}
+    }
+  if (!sc_found)
+    return {};
+
+  /* Insert a breakpoint right after the end of the atomic sequence.  */
+  breaks[0] = loc;
+
+  /* Check for duplicated breakpoints.  Check also for a breakpoint
+     placed (branch instruction's destination) in the atomic sequence */
+  if (last_breakpoint && pc <= breaks[1] && breaks[1] <= breaks[0])
+    last_breakpoint = 0;
+
+  std::vector<CORE_ADDR> next_pcs;
+
+  /* Effectively inserts the breakpoints.  */
+  for (index = 0; index <= last_breakpoint; index++)
+    next_pcs.push_back (breaks[index]);
+
+  return next_pcs;
+}
+
+/* nanomips_software_single_step() is called just before we want to resume
+   the inferior, if we want to single-step it but there is no hardware
+   or kernel single-step support (nanoMIPS on GNU/Linux for example).  We find
+   the target of the coming instruction and breakpoint it.  */
+
+std::vector<CORE_ADDR>
+nanomips_software_single_step (struct regcache *regcache)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  CORE_ADDR pc, next_pc;
+
+  pc = regcache_read_pc (regcache);
+  std::vector<CORE_ADDR> next_pcs =
+			nanomips_deal_with_atomic_sequence (gdbarch, pc);
+
+  if (!next_pcs.empty ())
+    return next_pcs;
+
+  next_pc = nanomips_next_pc (regcache, pc);
+
+  return {next_pc};
+}
+
+/* This fencepost looks highly suspicious to me.  Removing it also
+   seems suspicious as it could affect remote debugging across serial
+   lines.  */
+
+static CORE_ADDR
+heuristic_proc_start (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR start_pc;
+  CORE_ADDR fence;
+  int instlen;
+  struct inferior *inf;
+
+  pc = gdbarch_addr_bits_remove (gdbarch, pc);
+  start_pc = pc;
+  fence = start_pc - heuristic_fence_post;
+  if (start_pc == 0)
+    return 0;
+
+  if (heuristic_fence_post == -1 || fence < VM_MIN_ADDRESS)
+    fence = VM_MIN_ADDRESS;
+
+  instlen = INSN16_SIZE;
+
+  inf = current_inferior ();
+
+  /* Search back for previous return.  */
+  for (start_pc -= instlen;; start_pc -= instlen)
+    if (start_pc < fence)
+      {
+	/* It's not clear to me why we reach this point when
+	   stop_soon, but with this test, at least we
+	   don't print out warnings for every child forked (eg, on
+	   decstation).  22apr93 rich@cygnus.com.  */
+	if (inf->control.stop_soon == NO_STOP_QUIETLY)
+	  {
+	    static int blurb_printed = 0;
+
+	    warning (_("GDB can't find the start of the function at %s."),
+		     paddress (gdbarch, pc));
+
+	    if (!blurb_printed)
+	      {
+		/* This actually happens frequently in embedded
+		   development, when you first connect to a board
+		   and your stack pointer and pc are nowhere in
+		   particular.  This message needs to give people
+		   in that situation enough information to
+		   determine that it's no big deal.  */
+		gdb_printf ("\n\
+    GDB is unable to find the start of the function at %s\n\
+and thus can't determine the size of that function's stack frame.\n\
+This means that GDB may be unable to access that stack frame, or\n\
+the frames below it.\n\
+    This problem is most likely caused by an invalid program counter or\n\
+stack pointer.\n\
+    However, if you think GDB should simply search farther back\n\
+from %s for code which looks like the beginning of a\n\
+function, you can increase the range of the search using the `set\n\
+heuristic-fence-post' command.\n",
+			paddress (gdbarch, pc), paddress (gdbarch, pc));
+		blurb_printed = 1;
+	      }
+	  }
+
+	return 0;
+      }
+    else
+      {
+	ULONGEST insn;
+	int size;
+
+	/* On nanomips, SAVE is likely to be the start of a function.  */
+	insn = nanomips_fetch_instruction (gdbarch, pc, NULL);
+	size = nanomips_insn_size (insn);
+	if ((size == 2 && micromips_op (insn) == 0x7) ||
+	    (size == 4 && micromips_op (insn) == 0x20))
+	    break;
+      }
+
+  return start_pc;
+}
+
+/* On p32, argument passing in GPRs depends on the alignment of the type being
+   passed.  Return 1 if this type must be aligned to a doubleword boundary.  */
+
+static int
+type_needs_double_align (struct type *type)
+{
+  enum type_code typecode = type->code ();
+
+  if ((typecode == TYPE_CODE_FLT || typecode == TYPE_CODE_INT)
+      && type->length () == 8)
+    return 1;
+  else if (typecode == TYPE_CODE_STRUCT)
+    {
+      if (type->num_fields () > 1)
+	return 0;
+      return type_needs_double_align (type->field (0).type ());
+    }
+  else if (typecode == TYPE_CODE_UNION)
+    {
+      int i, n;
+
+      n = type->num_fields ();
+      for (i = 0; i < n; i++)
+	if (type_needs_double_align (type->field (i).type ()))
+	  return 1;
+      return 0;
+    }
+  return 0;
+}
+
+/* Adjust the address downward (direction of stack growth) so that it
+   is correctly aligned for a new stack frame.  */
+static CORE_ADDR
+nanomips_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  return align_down (addr, 16);
+}
+
+/* Implement the "push_dummy_code" gdbarch method.  */
+
+static CORE_ADDR
+nanomips_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
+			  CORE_ADDR funaddr, struct value **args,
+			  int nargs, struct type *value_type,
+			  CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+			  struct regcache *regcache)
+{
+  /* Reserve enough room on the stack for our breakpoint instruction.  */
+  sp = sp - 4;
+  *bp_addr = sp;
+
+  /* Inferior resumes at the function entry point.  */
+  *real_pc = funaddr;
+
+  return sp;
+}
+
+/* p32, p64 ABI stuff.  */
+
+#define MAX_REG_ARGS	8	/* Maximum 8 arguments in registers */
+
+static CORE_ADDR
+nanomips_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+			  struct regcache *regcache, CORE_ADDR bp_addr,
+			  int nargs, struct value **args, CORE_ADDR sp,
+			  function_call_return_method return_method, CORE_ADDR struct_addr)
+{
+  int arg_gpr = 0, arg_fpr = 0;
+  int argnum;
+  int stack_offset = 0, stack_size = 0;
+  int seen_on_stack = 0;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int regsize = nanomips_abi_regsize (gdbarch);
+
+  /* Set the return address register to point to the entry point of
+     the program, where a breakpoint lies in wait.  */
+  regcache_cooked_write_signed (regcache, NANOMIPS_RA_REGNUM, bp_addr);
+
+  /* First ensure that the stack and structure return address (if any)
+     are properly aligned.  The stack has to be at least 64-bit
+     aligned even on 32-bit machines, because doubles must be 64-bit
+     aligned.  */
+
+  sp = align_down (sp, 16);
+  struct_addr = align_down (struct_addr, 16);
+
+  /* Calculate space required on the stack for the args.  */
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      struct type *arg_type = check_typedef (value_type (args[argnum]));
+
+      /* Align to double-word if necessary.  */
+      if (type_needs_double_align (arg_type))
+	stack_size = align_up (stack_size, NANOMIPS32_REGSIZE * 2);
+
+      /* Allocate space on the stack.  */
+      stack_size += align_up (arg_type->length(), NANOMIPS32_REGSIZE);
+    }
+  stack_size = align_up (stack_size, 16);
+
+  if (nanomips_debug)
+    gdb_printf (gdb_stdlog, "nanomips_push_dummy_call (stack_size=%d)\n", stack_size);
+
+  /* The struct_return pointer occupies the first parameter-passing reg.  */
+  if (return_method == return_method_struct)
+    {
+      if (nanomips_debug)
+	gdb_printf (gdb_stdlog,
+			    "  struct_return reg=%d %s\n",
+			    arg_gpr + NANOMIPS_A0_REGNUM,
+			    paddress (gdbarch, struct_addr));
+
+      regcache_cooked_write_unsigned (regcache, arg_gpr + NANOMIPS_A0_REGNUM,
+				      struct_addr);
+
+      /* occupy first argument reg */
+      arg_gpr++;
+    }
+
+  /* Now load as many as possible of the first arguments into
+     registers, and push the rest onto the stack.  Loop thru args
+     from first to last.  */
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      const gdb_byte *val;
+      gdb_byte valbuf[NANOMIPS64_REGSIZE];
+      struct value *arg = args[argnum];
+      struct type *arg_type = check_typedef (value_type (arg));
+      int len = arg_type->length();
+      enum type_code typecode = arg_type->code ();
+
+      if (typecode == TYPE_CODE_STRUCT && arg_type->num_fields () == 1)
+      {
+          if ((arg_type->field (0).type ())->code () == TYPE_CODE_TYPEDEF)
+            {
+              struct type *type = check_typedef (arg_type->field (0).type ());
+              typecode = type->code ();
+              len = arg_type->length();
+            }
+          else if ((arg_type->field (0).type ())->code () == TYPE_CODE_FLT)
+            {
+              typecode = TYPE_CODE_FLT;
+            }
+      }
+
+      /* The P32 ABI passes structures larger than 8 bytes by reference. */
+      if ((typecode == TYPE_CODE_ARRAY || typecode == TYPE_CODE_STRUCT
+          || typecode == TYPE_CODE_UNION || typecode == TYPE_CODE_COMPLEX)
+          && len > regsize * 2)
+        {
+          store_unsigned_integer (valbuf, regsize, byte_order,
+                value_address (arg));
+          typecode = TYPE_CODE_PTR;
+          len = 4;
+          val = valbuf;
+
+          if (nanomips_debug)
+            gdb_printf (gdb_stdlog, " push");
+        }
+          else
+        val = value_contents (arg).data ();
+
+
+      while (len > 0)
+	{
+	  int partial_len = (len < NANOMIPS32_REGSIZE ? len : NANOMIPS32_REGSIZE);
+	  LONGEST regval;
+	  int use_stack = 0;
+
+	  /* Align the argument register for double and long long types.  */
+	  if ((arg_gpr < MAX_REG_ARGS) && (arg_gpr & 1) && (len == 8)
+        && ((typecode == TYPE_CODE_FLT
+        && FPU_TYPE(gdbarch) == NANOMIPS_FPU_SOFT)
+        || typecode == TYPE_CODE_INT))
+	    {
+	      arg_gpr++;
+	      stack_offset += 4;
+	    }
+
+    if (typecode == TYPE_CODE_STRUCT && (len <= 8 && len > 4) && arg_gpr == 7)
+      arg_gpr ++;
+
+	  /* double type occupies only one register.  */
+	  if (typecode == TYPE_CODE_FLT && len == 8)
+	    partial_len = (FPU_TYPE(gdbarch) == NANOMIPS_FPU_HARD ? 8 : 4);
+
+	  regval = extract_unsigned_integer (val, partial_len, byte_order);
+
+	  /* Check if any argument register is available.  */
+	  if (typecode == TYPE_CODE_FLT && FPU_TYPE(gdbarch) == NANOMIPS_FPU_HARD)
+	    {
+        if(arg_fpr < MAX_REG_ARGS)
+          {
+            if (nanomips_debug)
+              {
+                int r_num = arg_fpr + nanomips_fp_arg_regnum (gdbarch)
+                  + gdbarch_num_regs (gdbarch);
+                const char *r = nanomips_register_name (gdbarch, r_num);
+                gdb_printf (gdb_stdlog,
+                        "  argnum=%d,reg=%s,len=%d,val=%ld\n",
+                        argnum + 1, r, partial_len, regval);
+              }
+
+           /* Update the register with specified value.  */
+           regcache_cooked_write_unsigned (regcache,
+                    arg_fpr + nanomips_fp_arg_regnum (gdbarch),
+                    regval);
+            arg_fpr++;
+          }
+        else
+          use_stack = 1;
+	    }
+	  else
+	    {
+		    if (arg_gpr < MAX_REG_ARGS)
+          {
+            if (nanomips_debug)
+              {
+                int r_num = arg_gpr + NANOMIPS_A0_REGNUM
+                  + gdbarch_num_regs (gdbarch);
+                const char *r = nanomips_register_name (gdbarch, r_num);
+                gdb_printf (gdb_stdlog,
+                        "  argnum=%d,reg=%s,len=%d,val=%ld\n",
+                        argnum + 1, r, partial_len, regval);
+              }
+
+            /* Update the register with specified value.  */
+            regcache_cooked_write_unsigned (regcache,
+                     arg_gpr + NANOMIPS_A0_REGNUM, regval);
+            arg_gpr++;
+
+	        }
+	      else
+	        use_stack = 1;
+
+	    }
+
+	  if (use_stack)
+	    {
+	      CORE_ADDR addr;
+
+	      if (nanomips_debug)
+		{
+		  LONGEST valreg = extract_unsigned_integer (val, len,
+							     byte_order);
+		  gdb_printf (gdb_stdlog,
+				      "  argnum=%d,off=%d,len=%d,val=%ld\n",
+				      argnum + 1, stack_offset, partial_len,
+				      valreg);
+		}
+
+	      addr = (sp - stack_size) + stack_offset;
+	      write_memory (addr, val, partial_len);
+
+	      seen_on_stack = 1;
+	      stack_offset += (partial_len <= NANOMIPS32_REGSIZE)
+                            ? NANOMIPS32_REGSIZE : partial_len;
+	      use_stack = 0;
+	    } /* argument on stack */
+
+	  val += partial_len;
+	  len -= partial_len;
+	}
+    }
+
+  if (seen_on_stack)
+    sp -= stack_size;
+
+  regcache_cooked_write_signed (regcache, NANOMIPS_SP_REGNUM, sp);
+
+  /* Return adjusted stack pointer.  */
+  return sp;
+}
+
+static enum return_value_convention
+nanomips_return_value (struct gdbarch *gdbarch, struct value *function,
+           struct type *type, struct regcache *regcache,
+           gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+  if ((type->code () == TYPE_CODE_ARRAY
+      || type->code () == TYPE_CODE_STRUCT
+      || type->code () == TYPE_CODE_COMPLEX)
+      && type->length () > 2 * NANOMIPS32_REGSIZE)
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  else if (type->code () == TYPE_CODE_COMPLEX
+     && FPU_TYPE(gdbarch) == NANOMIPS_FPU_HARD)
+    {
+      gdb_assert (nanomips_regnum (gdbarch)->fpr != -1);
+
+      nanomips_xfer_register (gdbarch, regcache,
+			      (gdbarch_num_regs (gdbarch)
+			       + nanomips_regnum (gdbarch)->fpr
+			       + NANOMIPS_FP0_REGNUM),
+			      4, gdbarch_byte_order (gdbarch),
+			      readbuf, writebuf, 0);
+      nanomips_xfer_register (gdbarch, regcache,
+			      (gdbarch_num_regs (gdbarch)
+			       + nanomips_regnum (gdbarch)->fpr
+			       + NANOMIPS_FP0_REGNUM + 1),
+			      4, gdbarch_byte_order (gdbarch),
+			      readbuf, writebuf, 4);
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  else if (type->code () == TYPE_CODE_FLT
+     && FPU_TYPE(gdbarch) == NANOMIPS_FPU_HARD)
+    {
+      gdb_assert (nanomips_regnum (gdbarch)->fpr != -1);
+
+      nanomips_xfer_register (gdbarch, regcache,
+			      (gdbarch_num_regs (gdbarch)
+			       + nanomips_regnum (gdbarch)->fpr
+			       + NANOMIPS_FP0_REGNUM),
+			      type->length (), gdbarch_byte_order (gdbarch),
+			      readbuf, writebuf, 0);
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  else
+    {
+      int offset;
+      int regnum;
+      for (offset = 0, regnum = NANOMIPS_A0_REGNUM;
+     offset < type->length ();
+     offset += NANOMIPS32_REGSIZE, regnum++)
+  {
+    int xfer = NANOMIPS32_REGSIZE;
+    if (offset + xfer > type->length ())
+      xfer = type->length () - offset;
+    if (nanomips_debug)
+      gdb_printf (gdb_stderr, "Return scalar+%d:%d in $%d\n",
+        offset, xfer, regnum);
+    nanomips_xfer_register (gdbarch, regcache,
+            gdbarch_num_regs (gdbarch) + regnum, xfer,
+            gdbarch_byte_order (gdbarch),
+            readbuf, writebuf, offset);
+  }
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+}
+
+/* Copy a 32-bit single-precision value from the current frame
+   into rare_buffer.  */
+
+static void
+read_fp_register_single (frame_info_ptr frame, int regno,
+			 gdb_byte *rare_buffer)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int raw_size = register_size (gdbarch, regno);
+  int offset;
+  gdb_byte *raw_buffer = (gdb_byte *) alloca (raw_size);
+
+  if (!deprecated_frame_register_read (frame, regno, raw_buffer))
+    error (_("can't read register %d (%s)"),
+	   regno, gdbarch_register_name (gdbarch, regno));
+
+  /* We have a 64-bit value for this register.  Find the low-order 32 bits.  */
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+    offset = 4;
+  else
+    offset = 0;
+
+  memcpy (rare_buffer, raw_buffer + offset, 4);
+}
+
+/* Copy a 64-bit double-precision value from the current frame into
+   rare_buffer.  */
+
+static void
+read_fp_register_double (frame_info_ptr frame, int regno,
+			 gdb_byte *rare_buffer)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+
+  /* We have a 64-bit value for this register, use all 64 bits.  */
+  if (!deprecated_frame_register_read (frame, regno, rare_buffer))
+      error (_("can't read register %d (%s)"),
+	     regno, gdbarch_register_name (gdbarch, regno));
+}
+
+static void
+print_fp_register (struct ui_file *file, frame_info_ptr frame,
+		   int regnum)
+{		/* Do values for FP (float) regs.  */
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  gdb_byte *raw_buffer;
+  std::string flt_str, dbl_str;
+  struct value_print_options opts;
+
+  const struct type *flt_type = builtin_type (gdbarch)->builtin_float;
+  const struct type *dbl_type = builtin_type (gdbarch)->builtin_double;
+
+  gdb_assert (nanomips_regnum (gdbarch)->fpr != -1);
+
+  raw_buffer
+    = ((gdb_byte *)
+       alloca (2 * register_size (gdbarch,
+				  (nanomips_regnum (gdbarch)->fpr
+				   + NANOMIPS_FP0_REGNUM))));
+
+  gdb_printf (file, "%s:", gdbarch_register_name (gdbarch, regnum));
+  gdb_printf (file, "%*s",
+		    4 - (int) strlen (gdbarch_register_name (gdbarch, regnum)),
+		    "");
+
+  /* Eight byte registers: print each one as hex, float and double.  */
+  read_fp_register_single (frame, regnum, raw_buffer);
+  flt_str = target_float_to_string (raw_buffer, flt_type, "%-17.9g");
+
+  read_fp_register_double (frame, regnum, raw_buffer);
+  dbl_str = target_float_to_string (raw_buffer, dbl_type, "%-24.17g");
+
+  get_formatted_print_options (&opts, 'x');
+  print_scalar_formatted (raw_buffer,
+			  builtin_type (gdbarch)->builtin_uint64,
+			  &opts, 'g', file);
+
+  gdb_printf (file, " flt: %s", flt_str.c_str ());
+
+  gdb_printf (file, " dbl: %s", dbl_str.c_str ());
+}
+
+static void
+nanomips_print_register (struct ui_file *file, frame_info_ptr frame,
+			 int regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct value_print_options opts;
+  struct value *val;
+
+  if (nanomips_float_register_p (gdbarch, regnum))
+    {
+      print_fp_register (file, frame, regnum);
+      return;
+    }
+
+  val = get_frame_register_value (frame, regnum);
+
+  gdb_puts (gdbarch_register_name (gdbarch, regnum), file);
+
+  /* The problem with printing numeric register names (r26, etc.) is that
+     the user can't use them on input.  Probably the best solution is to
+     fix it so that either the numeric or the funky (a2, etc.) names
+     are accepted on input.  */
+  if (regnum < NUMREGS)
+    gdb_printf (file, "(r%d): ", regnum);
+  else
+    gdb_printf (file, ": ");
+
+  get_formatted_print_options (&opts, 'x');
+  value_print_scalar_formatted (val, &opts, 0, file);
+}
+
+/* Print IEEE exception condition bits in FLAGS.  */
+
+static void
+print_fpu_flags (struct ui_file *file, int flags)
+{
+  if (flags & (1 << 0))
+    gdb_puts (" inexact", file);
+  if (flags & (1 << 1))
+    gdb_puts (" uflow", file);
+  if (flags & (1 << 2))
+    gdb_puts (" oflow", file);
+  if (flags & (1 << 3))
+    gdb_puts (" div0", file);
+  if (flags & (1 << 4))
+    gdb_puts (" inval", file);
+  if (flags & (1 << 5))
+    gdb_puts (" unimp", file);
+  gdb_putc ('\n', file);
+}
+
+/* Print interesting information about the floating point processor
+   (if present) or emulator.  */
+
+static void
+nanomips_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
+			   frame_info_ptr frame, const char *args)
+{
+  int fcsr = nanomips_regnum (gdbarch)->fpr + NANOMIPS_FCSR_REGNUM;
+  enum fpu_type type = FPU_TYPE (gdbarch);
+  ULONGEST fcs = 0;
+  int i;
+
+  if (nanomips_regnum (gdbarch)->fpr == -1
+      || !read_frame_register_unsigned (frame, fcsr, &fcs))
+    type = NANOMIPS_FPU_NONE;
+
+  gdb_printf (file, "fpu type: %s\n",
+		    type == NANOMIPS_FPU_HARD ? "64bit hardware floating point"
+		    : type == NANOMIPS_FPU_SOFT ? "Software floating point"
+		    : "none / unused");
+
+  if (type == NANOMIPS_FPU_NONE)
+    return;
+
+  gdb_printf (file, "reg size: %d bits\n",
+		    register_size (gdbarch,
+				   (nanomips_regnum (gdbarch)->fpr
+				    + NANOMIPS_FP0_REGNUM)) * 8);
+
+  gdb_puts ("cond    :", file);
+  if (fcs & (1 << 23))
+    gdb_puts (" 0", file);
+  for (i = 1; i <= 7; i++)
+    if (fcs & (1 << (24 + i)))
+      gdb_printf (file, " %d", i);
+  gdb_putc ('\n', file);
+
+  gdb_puts ("cause   :", file);
+  print_fpu_flags (file, (fcs >> 12) & 0x3f);
+  fputs ("mask    :", stdout);
+  print_fpu_flags (file, (fcs >> 7) & 0x1f);
+  fputs ("flags   :", stdout);
+  print_fpu_flags (file, (fcs >> 2) & 0x1f);
+
+  gdb_puts ("rounding: ", file);
+  switch (fcs & 3)
+    {
+    case 0: gdb_puts ("nearest\n", file); break;
+    case 1: gdb_puts ("zero\n", file); break;
+    case 2: gdb_puts ("+inf\n", file); break;
+    case 3: gdb_puts ("-inf\n", file); break;
+    }
+
+  gdb_puts ("flush   :", file);
+  if (fcs & (1 << 21))
+    gdb_puts (" nearest", file);
+  if (fcs & (1 << 22))
+    gdb_puts (" override", file);
+  if (fcs & (1 << 24))
+    gdb_puts (" zero", file);
+  if ((fcs & (0xb << 21)) == 0)
+    gdb_puts (" no", file);
+  gdb_putc ('\n', file);
+
+  gdb_printf (file, "nan2008 : %s\n", fcs & (1 << 18) ? "yes" : "no");
+  gdb_printf (file, "abs2008 : %s\n", fcs & (1 << 19) ? "yes" : "no");
+  gdb_putc ('\n', file);
+
+  default_print_float_info (gdbarch, file, frame, args);
+}
+
+/* Replacement for generic do_registers_info.
+   Print regs in pretty columns.  */
+
+static int
+print_fp_register_row (struct ui_file *file, frame_info_ptr frame,
+		       int regnum)
+{
+  gdb_printf (file, " ");
+  print_fp_register (file, frame, regnum);
+  gdb_printf (file, "\n");
+  return regnum + 1;
+}
+
+
+/* Print a row's worth of GP (int) registers, with name labels above.  */
+
+static int
+print_gp_register_row (struct ui_file *file, frame_info_ptr frame,
+		       int start_regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  /* Do values for GP (int) regs.  */
+  gdb_byte raw_buffer[NANOMIPS64_REGSIZE];
+  int ncols = (nanomips_abi_regsize (gdbarch) == 8 ? 4 : 8);    /* display cols
+							       per row.  */
+  int col, byte;
+  int regnum;
+
+  /* For GP registers, we print a separate row of names above the vals.  */
+  for (col = 0, regnum = start_regnum;
+       col < ncols && regnum < gdbarch_num_regs (gdbarch)
+			       + gdbarch_num_pseudo_regs (gdbarch);
+       regnum++)
+    {
+      if (*gdbarch_register_name (gdbarch, regnum) == '\0')
+	continue;		/* unused register */
+      if (nanomips_float_register_p (gdbarch, regnum))
+	break;			/* End the row: reached FP register.  */
+      /* Large registers are handled separately.  */
+      if (register_size (gdbarch, regnum) > nanomips_abi_regsize (gdbarch))
+	{
+	  if (col > 0)
+	    break;		/* End the row before this register.  */
+
+	  /* Print this register on a row by itself.  */
+	  nanomips_print_register (file, frame, regnum);
+	  gdb_printf (file, "\n");
+	  return regnum + 1;
+	}
+      if (col == 0)
+	gdb_printf (file, "     ");
+      gdb_printf (file,
+			nanomips_abi_regsize (gdbarch) == 8 ? "%17s" : "%9s",
+			gdbarch_register_name (gdbarch, regnum));
+      col++;
+    }
+
+  if (col == 0)
+    return regnum;
+
+  /* Print the R0 to R31 names.  */
+  if ((start_regnum % gdbarch_num_regs (gdbarch)) < NUMREGS)
+    gdb_printf (file, "\n R%-4d",
+		      start_regnum % gdbarch_num_regs (gdbarch));
+  else
+    gdb_printf (file, "\n      ");
+
+  /* Now print the values in hex, 4 or 8 to the row.  */
+  for (col = 0, regnum = start_regnum;
+       col < ncols && regnum < gdbarch_num_regs (gdbarch)
+			       + gdbarch_num_pseudo_regs (gdbarch);
+       regnum++)
+    {
+      if (*gdbarch_register_name (gdbarch, regnum) == '\0')
+	continue;		/* unused register */
+      if (nanomips_float_register_p (gdbarch, regnum))
+	break;			/* End row: reached FP register.  */
+      if (register_size (gdbarch, regnum) > nanomips_abi_regsize (gdbarch))
+	break;			/* End row: large register.  */
+
+      /* OK: get the data in raw format.  */
+      if (!deprecated_frame_register_read (frame, regnum, raw_buffer))
+	error (_("can't read register %d (%s)"),
+	       regnum, gdbarch_register_name (gdbarch, regnum));
+      /* pad small registers */
+      for (byte = 0;
+	   byte < (nanomips_abi_regsize (gdbarch)
+		   - register_size (gdbarch, regnum)); byte++)
+	gdb_printf ("  ");
+      /* Now print the register value in hex, endian order.  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	for (byte =
+	     register_size (gdbarch, regnum) - register_size (gdbarch, regnum);
+	     byte < register_size (gdbarch, regnum); byte++)
+	  gdb_printf (file, "%02x", raw_buffer[byte]);
+      else
+	for (byte = register_size (gdbarch, regnum) - 1;
+	     byte >= 0; byte--)
+	  gdb_printf (file, "%02x", raw_buffer[byte]);
+      gdb_printf (file, " ");
+      col++;
+    }
+  if (col > 0)			/* ie. if we actually printed anything...  */
+    gdb_printf (file, "\n");
+
+  return regnum;
+}
+
+/* MIPS_DO_REGISTERS_INFO(): called by "info register" command.  */
+
+static void
+nanomips_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
+			       frame_info_ptr frame, int regnum, int all)
+{
+  if (regnum != -1)		/* Do one specified register.  */
+    {
+      gdb_assert (regnum >= gdbarch_num_regs (gdbarch));
+      if (*(gdbarch_register_name (gdbarch, regnum)) == '\0')
+	error (_("Not a valid register for the current processor type"));
+
+      nanomips_print_register (file, frame, regnum);
+      gdb_printf (file, "\n");
+    }
+  else
+    /* Do all (or most) registers.  */
+    {
+      regnum = gdbarch_num_regs (gdbarch);
+      while (regnum < gdbarch_num_regs (gdbarch)
+		      + gdbarch_num_pseudo_regs (gdbarch))
+	{
+	  if (nanomips_float_register_p (gdbarch, regnum))
+	    {
+	      if (all)		/* True for "INFO ALL-REGISTERS" command.  */
+		regnum = print_fp_register_row (file, frame, regnum);
+	      else
+		regnum += NUMREGS;	/* Skip floating point regs.  */
+	    }
+	  else
+	    regnum = print_gp_register_row (file, frame, regnum);
+	}
+    }
+}
+
+/* To skip prologues, I use this predicate.  Returns either PC itself
+   if the code at PC does not look like a function prologue; otherwise
+   returns an address that (if we're lucky) follows the prologue.  If
+   LENIENT, then we must skip everything which is involved in setting
+   up the frame (it's OK to skip more, just so long as we don't skip
+   anything which might clobber the registers which are being saved.
+   We must skip more in the case where part of the prologue is in the
+   delay slot of a non-prologue instruction).  */
+
+static CORE_ADDR
+nanomips_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR limit_pc;
+  CORE_ADDR func_addr;
+
+  /* See if we can determine the end of the prologue via the symbol table.
+     If so, then return either PC, or the PC after the prologue, whichever
+     is greater.  */
+  if (find_pc_partial_function (pc, NULL, &func_addr, NULL))
+    {
+      CORE_ADDR post_prologue_pc
+	= skip_prologue_using_sal (gdbarch, func_addr);
+      if (post_prologue_pc != 0)
+	return std::max (pc, post_prologue_pc);
+    }
+
+  /* Can't determine prologue from the symbol table, need to examine
+     instructions.  */
+
+  /* Find an upper limit on the function prologue using the debug
+     information.  If the debug information could not be used to provide
+     that bound, then use an arbitrary large number as the upper bound.  */
+  limit_pc = skip_prologue_using_sal (gdbarch, pc);
+  if (limit_pc == 0)
+    limit_pc = pc + 100;          /* Magic.  */
+
+  return nanomips_scan_prologue (gdbarch, pc, limit_pc, NULL, NULL);
+}
+
+/* Implement the stack_frame_destroyed_p gdbarch method (nanoMIPS version).
+   This is a helper function for mips_stack_frame_destroyed_p.  */
+
+static int
+nanomips_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR func_addr = 0;
+  CORE_ADDR func_end = 0;
+  CORE_ADDR addr;
+  ULONGEST insn;
+  int dreg;
+  int sreg;
+  int treg, op;
+  int loc;
+
+  if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+    return 0;
+
+  /* The nanoMIPS epilogue is max. 12 bytes long.  */
+  addr = func_end - 12;
+
+  if (addr < func_addr + 2)
+    addr = func_addr + 2;
+  if (pc < addr)
+    return 0;
+
+  for (; pc < func_end; pc += loc)
+    {
+      loc = 0;
+      insn = nanomips_fetch_instruction (gdbarch, pc, NULL);
+      loc += INSN16_SIZE;
+      switch (nanomips_insn_size (insn))
+	{
+	/* 48-bit instructions.  */
+	case 3 * INSN16_SIZE:
+	  if (micromips_op (insn) == 0x18)
+	    {
+	      op = b0s5_imm (insn);
+	      treg = b5s5_reg (insn);
+	      if (op == 0x0) /* LI48 xx, imm32 */
+		break; /* continue scan */
+	      else if (op == 0x1 /* ADDIU48 $sp, imm32 */
+		       && treg == NANOMIPS_SP_REGNUM)
+		return 1;
+	    }
+	  return 0;
+
+	/* 32-bit instructions.  */
+	case 2 * INSN16_SIZE:
+	  insn <<= 16;
+	  insn |= nanomips_fetch_instruction (gdbarch, pc + loc, NULL);
+	  loc += INSN16_SIZE;
+
+	  switch (micromips_op (insn >> 16))
+	    {
+	    case 0x0: /* PP.ADDIU bits 000000 */
+	      treg = b5s5_reg (insn >> 16);
+	      sreg = b0s5_reg (insn >> 16);
+	      if (sreg == treg
+		  && treg == NANOMIPS_SP_REGNUM) /* ADDIU $sp, $sp, imm */
+		return 1;
+	      else if (sreg == NANOMIPS_SP_REGNUM && treg == 30)
+		break; /* continue scan */
+	      return 0;
+
+	    case 0x8: /* _POOL32A0 */
+	      if ((insn & 0x1ff) == 0x150) /* ADDU */
+		{
+		  dreg = b11s5_reg (insn);
+		  sreg = b0s5_reg (insn >> 16);
+		  if ((dreg == sreg && sreg == NANOMIPS_SP_REGNUM)
+		      /* ADDU $sp, $sp, xx */
+		      || (dreg == NANOMIPS_SP_REGNUM && sreg == 30))
+		      /* ADDU $sp, $fp, xx */
+		    break; /* continue scan */
+		}
+	      else if (((insn & 0xffff) == 0xE37F) /* DERET */
+		       || ((insn & 0x1ffff) == 0xF37F) /* ERET */
+		       || ((insn & 0x1ffff) == 0x1F37F)) /* ERETNC */
+		return 1;
+	      return 0;
+
+	    case 0x20: /* P.U12 bits 100000 */
+	      if (b12s4_op (insn) == 0) /* ORI: bits 100000 0000 */
+		{
+		  sreg = b0s5_reg (insn >> 16);
+		  treg = b5s5_reg (insn >> 16);
+		  if (sreg == treg && treg == 3) /* ORI $v1, $v1, imm */
+		    break; /* continue scan */
+		}
+	      else if (b12s5_op (insn) == 0x13) /* RESTORE, RESTORE.JRC */
+		return 1;
+	      return 0;
+
+	    case 0x38: /* P.LUI bits 111000 */
+	      treg = b5s5_reg (insn >> 16);
+	      if ((insn & 2) == 0 /* LU20I bits 111000 0 */
+		  && treg == 3) /* LU20I $v1, imm */
+		break; /* continue scan */
+	      return 0;
+
+	    default:
+	      return 0;
+	    }
+	  break;
+
+	/* 16-bit instructions.  */
+	case INSN16_SIZE:
+	  switch (micromips_op (insn))
+	    {
+	    case 0x4: /* MOVE: bits 000100 */
+	      sreg = b0s5_reg (insn);
+	      dreg = b5s5_reg (insn);
+	      if (sreg == NANOMIPS_SP_REGNUM && dreg == 30)
+			/* MOVE  $fp, $sp */
+		return 1;
+	      return 0;
+
+	    case 0x7: /* RESTORE[16], RESTORE.JRC[16] */
+	      if ((insn & 0x20) == 0x20)
+		return 1;
+	      return 0;
+
+	    case 0x36: /* JRC[16] $31 */
+	      if ((insn & 0x1f) == 0 && b5s5_reg (insn) == 31)
+		return 1;
+	      return 0;
+
+	    default:
+		return 0;
+	    }
+	  break;
+	}
+    }
+
+  return 1;
+}
+
+/* Root of all "set nanomips "/"show nanomips " commands.  This will eventually be
+   used for all nanoMIPS-specific commands.  */
+
+static void
+show_nanomips_command (const char *args, int from_tty)
+{
+  help_list (shownanomipscmdlist, "show nanomips ", all_commands, gdb_stdout);
+}
+
+static void
+set_nanomips_command (const char *args, int from_tty)
+{
+  printf_unfiltered
+    ("\"set nanomips\" must be followed by an appropriate subcommand.\n");
+  help_list (setnanomipscmdlist, "set nanomips ", all_commands, gdb_stdout);
+}
+
+/* Just like reinit_frame_cache, but with the right arguments to be
+   callable as an sfunc.  */
+
+static void
+reinit_frame_cache_sfunc (const char *args, int from_tty,
+			  struct cmd_list_element *c)
+{
+  reinit_frame_cache ();
+}
+
+static int
+gdb_print_insn_nanomips_p32 (bfd_vma memaddr, struct disassemble_info *info)
+{
+  info->mach = bfd_mach_nanomipsisa32r6;
+  info->flavour = bfd_target_elf_flavour;
+  info->disassembler_options = "gpr-names=p32";
+
+  return print_insn_nanomips (memaddr, info);
+}
+
+static int
+gdb_print_insn_nanomips_p64 (bfd_vma memaddr, struct disassemble_info *info)
+{
+  info->mach = bfd_mach_nanomipsisa64r6;
+  info->flavour = bfd_target_elf_flavour;
+  info->disassembler_options = "gpr-names=p64";
+
+  return print_insn_nanomips (memaddr, info);
+}
+
+/* Implement the breakpoint_kind_from_pc gdbarch method.  */
+
+static int
+nanomips_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
+{
+  CORE_ADDR pc = *pcptr;
+  ULONGEST insn;
+  int status;
+
+  insn = nanomips_fetch_instruction (gdbarch, pc, &status);
+  if (status || (nanomips_insn_size (insn) == 2))
+    return NANOMIPS_BP_KIND_16;
+  else
+    return NANOMIPS_BP_KIND_32;
+}
+
+/* Implement the sw_breakpoint_from_kind gdbarch method.  */
+
+static const gdb_byte *
+nanomips_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
+{
+  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+
+  switch (kind)
+    {
+    case NANOMIPS_BP_KIND_16:
+      {
+	static gdb_byte be16_break[] = { 0x10, 0x10 };
+	static gdb_byte le16_break[] = { 0x10, 0x10 };
+
+	*size = 2;
+
+	if (byte_order_for_code == BFD_ENDIAN_BIG)
+	  return be16_break;
+	else
+	  return le16_break;
+      }
+    case NANOMIPS_BP_KIND_32:
+      {
+	static gdb_byte be32_break[] = { 0, 0x10, 0, 0 };
+	static gdb_byte le32_break[] = { 0x10, 0, 0, 0 };
+
+	*size = 4;
+	if (byte_order_for_code == BFD_ENDIAN_BIG)
+	  return be32_break;
+	else
+	  return le32_break;
+      }
+    default:
+      gdb_assert_not_reached ("unexpected nanomips breakpoint kind");
+    };
+}
+
+/* Convert a dbx stab register number (from `r' declaration) to a GDB
+   [1 * gdbarch_num_regs .. 2 * gdbarch_num_regs) REGNUM.  */
+
+static int
+nanomips_stab_reg_to_regnum (struct gdbarch *gdbarch, int num)
+{
+  int regnum;
+  if (num >= 0 && num < 32)
+    regnum = num;
+  else if (nanomips_regnum (gdbarch)->fpr != -1 && num >= 36 && num < 70)
+    regnum = num + nanomips_regnum (gdbarch)->fpr + NANOMIPS_FP0_REGNUM - 36;
+  else if (nanomips_regnum (gdbarch)->dsp != -1 && num >= 70 && num < 78)
+    regnum
+      = num + nanomips_regnum (gdbarch)->dsp + NANOMIPS_DSPHI0_REGNUM - 70;
+  else
+    return -1;
+  return gdbarch_num_regs (gdbarch) + regnum;
+}
+
+
+/* Convert a dwarf, dwarf2, or ecoff register number to a GDB [1 *
+   gdbarch_num_regs .. 2 * gdbarch_num_regs) REGNUM.  */
+
+static int
+nanomips_dwarf_dwarf2_ecoff_reg_to_regnum (struct gdbarch *gdbarch, int num)
+{
+  int regnum;
+  if (num >= 0 && num < 32)
+    regnum = num;
+  else if (nanomips_regnum (gdbarch)->fpr != -1 && num >= 32 && num < 64)
+    regnum = num + nanomips_regnum (gdbarch)->fpr + NANOMIPS_FP0_REGNUM - 32;
+  else if (nanomips_regnum (gdbarch)->dsp != -1 && num >= 64 && num < 72)
+    regnum
+      = num + nanomips_regnum (gdbarch)->dsp + NANOMIPS_DSPHI0_REGNUM - 64;
+  else
+    return -1;
+  return gdbarch_num_regs (gdbarch) + regnum;
+}
+
+static int
+nanomips_register_sim_regno (struct gdbarch *gdbarch, int regnum)
+{
+  /* Only makes sense to supply raw registers.  */
+  gdb_assert (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch));
+  /* FIXME: cagney/2002-05-13: Need to look at the pseudo register to
+     decide if it is valid.  Should instead define a standard sim/gdb
+     register numbering scheme.  */
+  if (gdbarch_register_name (gdbarch,
+			     gdbarch_num_regs (gdbarch) + regnum) != NULL
+      && gdbarch_register_name (gdbarch,
+			        gdbarch_num_regs (gdbarch)
+				+ regnum)[0] != '\0')
+    return regnum;
+  else
+    return LEGACY_SIM_REGNO_IGNORE;
+}
+
+
+/* Convert an integer into an address.  Extracting the value signed
+   guarantees a correctly sign extended address.  */
+
+static CORE_ADDR
+nanomips_integer_to_address (struct gdbarch *gdbarch,
+			     struct type *type, const gdb_byte *buf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  return extract_signed_integer (buf, type->length (), byte_order);
+}
+
+/* Dummy virtual frame pointer method.  This is no more or less accurate
+   than most other architectures; we just need to be explicit about it,
+   because the pseudo-register gdbarch_sp_regnum will otherwise lead to
+   an assertion failure.  */
+
+static void
+nanomips_virtual_frame_pointer (struct gdbarch *gdbarch,
+				CORE_ADDR pc, int *reg, LONGEST *offset)
+{
+  *reg = NANOMIPS_SP_REGNUM;
+  *offset = 0;
+}
+
+static struct gdbarch *
+nanomips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  static const char *const mips_gprs[] = {
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+    "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+    "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+  };
+  static const char *const mips_fprs[] = {
+    "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 mips_dsprs[] = {
+    "hi0", "lo0", "hi1", "lo1", "hi2", "lo2", "hi3", "lo3"
+  };
+  const struct tdesc_feature *feature;
+  struct gdbarch *gdbarch;
+  struct nanomips_gdbarch_tdep *tdep;
+  int elf_flags;
+  enum nanomips_abi nanomips_abi, found_abi;
+  int i, num_regs;
+  enum fpu_type fpu_type;
+  tdesc_arch_data_up tdesc_data;
+  const struct target_desc *tdesc = info.target_desc;
+  int elf_fpu_type = Val_GNU_NANOMIPS_ABI_FP_ANY;
+  struct nanomips_regnum nanomips_regnum, *regnum;
+  int register_size;
+  int valid_p;
+
+  num_regs = 0;
+
+  nanomips_regnum.cause = -1;
+  nanomips_regnum.status = -1;
+  nanomips_regnum.badvaddr = -1;
+  nanomips_regnum.fpr = -1;
+  nanomips_regnum.dsp = -1;
+  nanomips_regnum.restart = -1;
+
+  /* If there's no target description, then use the default.  */
+  if (!tdesc_has_registers (tdesc))
+    tdesc = tdesc_nanomips;
+
+  /* The CPU feature and the registers within are mandatory.  */
+  feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.cpu");
+  if (feature == NULL)
+    return NULL;
+
+  tdesc_data = tdesc_data_alloc ();
+
+  valid_p = 1;
+  for (i = 0; i < 32; i++, num_regs++)
+    valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs,
+					mips_gprs[i]);
+  valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs++, "pc");
+  if (!valid_p)
+      return NULL;
+  register_size = tdesc_register_bitsize (feature, "r0") / 8;
+
+  /* All the remaining target description features are optional.  */
+
+  /* Check for and assign a number to the syscall restart PC register.  */
+  feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.linux");
+  if (feature != NULL)
+    {
+      if (tdesc_numbered_register (feature, tdesc_data.get (), num_regs, "restart"))
+	nanomips_regnum.restart = num_regs++;
+
+      /* Check for and assign numbers to particular CP0 registers.
+	 These are only special and need known numbers with Linux
+	 targets, due to the use in signal frames, etc.  Bare metal
+	 stubs can simply include them along with other CP0 registers.  */
+      feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.cp0");
+      if (feature != NULL)
+	{
+	  if (tdesc_numbered_register (feature, tdesc_data.get (), num_regs,
+				       "badvaddr"))
+	    nanomips_regnum.badvaddr = num_regs++;
+	  if (tdesc_numbered_register (feature, tdesc_data.get (), num_regs,
+				       "status"))
+	    nanomips_regnum.status = num_regs++;
+	  if (tdesc_numbered_register (feature, tdesc_data.get (), num_regs,
+				       "cause"))
+	    nanomips_regnum.cause = num_regs++;
+	}
+    }
+
+  /* Check for and assign numbers to FPU registers.  */
+  feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.fpu");
+  if (feature != NULL)
+    {
+      nanomips_regnum.fpr = num_regs;
+      for (i = 0; i < 32; i++, num_regs++)
+	valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs,
+					    mips_fprs[i]);
+      valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs++,
+					  "fcsr");
+      valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs++,
+					  "fir");
+      if (!valid_p)
+      return NULL;
+    }
+
+  /* Check for and assign numbers to DSP registers.  */
+  feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.dsp");
+  if (feature != NULL)
+    {
+      nanomips_regnum.dsp = num_regs;
+      for (i = 0; i < 8; i++, num_regs++)
+	valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs,
+					    mips_dsprs[i]);
+      valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs++,
+					  "dspctl");
+      if (!valid_p)
+        return NULL;
+    }
+
+  /* First of all, extract the elf_flags, if available.  */
+  if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else if (arches != NULL)
+    elf_flags = (gdbarch_tdep<nanomips_gdbarch_tdep> (arches->gdbarch))->elf_flags;
+  else
+    elf_flags = 0;
+
+  if (gdbarch_debug)
+    gdb_printf (gdb_stdlog,
+			"nanomips_gdbarch_init: elf_flags = 0x%08x\n",
+			elf_flags);
+
+  /* Check ELF_FLAGS to see if it specifies the ABI being used.  */
+  switch ((elf_flags & EF_NANOMIPS_ABI))
+    {
+    case E_NANOMIPS_ABI_P32:
+      found_abi = NANOMIPS_ABI_P32;
+      break;
+    case E_NANOMIPS_ABI_P64:
+      found_abi = NANOMIPS_ABI_P64;
+      break;
+    default:
+      found_abi = NANOMIPS_ABI_UNKNOWN;
+      break;
+    }
+
+  /* If we have no useful BFD information, use the ABI from the last
+     nanoMIPS architecture (if there is one).  */
+  if (found_abi == NANOMIPS_ABI_UNKNOWN && info.abfd == NULL && arches != NULL)
+    found_abi = (gdbarch_tdep<nanomips_gdbarch_tdep> (arches->gdbarch))->found_abi;
+
+  /* Try the architecture for any hint of the correct ABI.  */
+  if (found_abi == NANOMIPS_ABI_UNKNOWN
+      && info.bfd_arch_info != NULL
+      && info.bfd_arch_info->arch == bfd_arch_nanomips)
+    {
+      switch (info.bfd_arch_info->mach)
+	{
+	case bfd_mach_nanomipsisa32r6:
+	  found_abi = NANOMIPS_ABI_P32;
+	  break;
+	case bfd_mach_nanomipsisa64r6:
+	  found_abi = NANOMIPS_ABI_P64;
+	  break;
+	}
+    }
+
+  /* Default 64-bit objects to P64 instead of P32.  */
+  if (found_abi == NANOMIPS_ABI_UNKNOWN
+      && info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour
+      && elf_elfheader (info.abfd)->e_ident[EI_CLASS] == ELFCLASS64)
+    found_abi = NANOMIPS_ABI_P64;
+
+  if (gdbarch_debug)
+    gdb_printf (gdb_stdlog, "nanomips_gdbarch_init: found_abi = %d\n",
+			found_abi);
+
+  /* Now that we have found what the ABI for this binary would be,
+     check whether the user is overriding it.  */
+  if (found_abi != NANOMIPS_ABI_UNKNOWN)
+    nanomips_abi = found_abi;
+  else
+    nanomips_abi = NANOMIPS_ABI_P32;
+  if (gdbarch_debug)
+    gdb_printf (gdb_stdlog,
+			"nanomips_gdbarch_init: nanomips_abi = %d\n",
+			nanomips_abi);
+
+  /* Determine the nanoMIPS FPU type.  */
+  if (info.abfd
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    {
+      Elf_Internal_ABIFlags_v0 *abiflags;
+      abiflags = bfd_nanomips_elf_get_abiflags (info.abfd);
+      if (abiflags != NULL)
+	elf_fpu_type = abiflags->fp_abi;
+    }
+
+  if (elf_fpu_type != Val_GNU_NANOMIPS_ABI_FP_ANY)
+    {
+      switch (elf_fpu_type)
+	{
+	case Val_GNU_NANOMIPS_ABI_FP_SOFT:
+	  fpu_type = NANOMIPS_FPU_SOFT;
+	  break;
+	default:
+	  fpu_type = NANOMIPS_FPU_HARD;
+	  break;
+	}
+    }
+  else if (arches != NULL)
+    fpu_type = (gdbarch_tdep<nanomips_gdbarch_tdep> (arches->gdbarch))->fpu_type;
+  else
+    fpu_type = NANOMIPS_FPU_HARD;
+
+  if (gdbarch_debug)
+    gdb_printf (gdb_stdlog,
+			"nanomips_gdbarch_init: fpu_type = %d\n", fpu_type);
+
+  /* Check for blatant incompatibilities.  */
+
+  /* If we have only 32-bit registers, then we can't debug a 64-bit ABI.  */
+  if (register_size == 4 && nanomips_abi != NANOMIPS_ABI_P32)
+    {
+      return NULL;
+    }
+
+  /* Try to find a pre-existing architecture.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      /* nanoMIPS needs to be pedantic about which ABI and the compressed
+         ISA variation the object is using.  */
+      if (gdbarch_tdep<nanomips_gdbarch_tdep> (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+      if (gdbarch_tdep<nanomips_gdbarch_tdep> (arches->gdbarch)->nanomips_abi != nanomips_abi)
+	continue;
+      /* Be pedantic about which FPU is selected.  */
+      if (gdbarch_tdep<nanomips_gdbarch_tdep> (arches->gdbarch)->fpu_type != fpu_type)
+	continue;
+
+      return arches->gdbarch;
+    }
+
+  /* Need a new architecture.  Fill in a target specific vector.  */
+  tdep = new (struct nanomips_gdbarch_tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+  tdep->elf_flags = elf_flags;
+  tdep->found_abi = found_abi;
+  tdep->nanomips_abi = nanomips_abi;
+  tdep->fpu_type = fpu_type;
+  tdep->register_size = register_size;
+
+  /* Initially set everything according to the default ABI/ISA.  */
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 32);
+  set_gdbarch_float_bit (gdbarch, 32);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_register_reggroup_p (gdbarch, nanomips_register_reggroup_p);
+  set_gdbarch_pseudo_register_read (gdbarch, nanomips_pseudo_register_read);
+  set_gdbarch_pseudo_register_write (gdbarch, nanomips_pseudo_register_write);
+  set_gdbarch_ax_pseudo_register_collect (gdbarch,
+					  nanomips_ax_pseudo_register_collect);
+  set_gdbarch_ax_pseudo_register_push_stack
+      (gdbarch, nanomips_ax_pseudo_register_push_stack);
+
+  tdep->default_mask_address_p = 0;
+
+  set_gdbarch_push_dummy_call (gdbarch, nanomips_push_dummy_call);
+  set_gdbarch_return_value (gdbarch, nanomips_return_value);
+
+  switch (nanomips_abi)
+    {
+    case NANOMIPS_ABI_P32:
+      set_gdbarch_long_bit (gdbarch, 32);
+      set_gdbarch_ptr_bit (gdbarch, 32);
+      set_gdbarch_long_long_bit (gdbarch, 64);
+      break;
+    case NANOMIPS_ABI_P64:
+      set_gdbarch_long_bit (gdbarch, 64);
+      set_gdbarch_ptr_bit (gdbarch, 64);
+      set_gdbarch_long_long_bit (gdbarch, 64);
+      set_gdbarch_long_double_bit (gdbarch, 128);
+      set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
+      break;
+    default:
+      internal_error_loc (__FILE__, __LINE__, _("unknown ABI in switch"));
+    }
+
+  set_gdbarch_read_pc (gdbarch, nanomips_read_pc);
+  set_gdbarch_write_pc (gdbarch, nanomips_write_pc);
+
+  /* Add/remove bits from an address.  The nanoMIPS needs be careful to
+     ensure that all 32 bit addresses are sign extended to 64 bits.  */
+  set_gdbarch_addr_bits_remove (gdbarch, nanomips_addr_bits_remove);
+
+  /* Unwind the frame.  */
+  set_gdbarch_unwind_pc (gdbarch, nanomips_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, nanomips_unwind_sp);
+  set_gdbarch_dummy_id (gdbarch, nanomips_dummy_id);
+
+  /* Map debug register numbers onto internal register numbers.  */
+  set_gdbarch_stab_reg_to_regnum (gdbarch, nanomips_stab_reg_to_regnum);
+  set_gdbarch_ecoff_reg_to_regnum (gdbarch,
+				   nanomips_dwarf_dwarf2_ecoff_reg_to_regnum);
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch,
+				    nanomips_dwarf_dwarf2_ecoff_reg_to_regnum);
+  set_gdbarch_register_sim_regno (gdbarch, nanomips_register_sim_regno);
+
+  /* nanoMIPS version of CALL_DUMMY.  */
+
+  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+  set_gdbarch_push_dummy_code (gdbarch, nanomips_push_dummy_code);
+  set_gdbarch_frame_align (gdbarch, nanomips_frame_align);
+
+  set_gdbarch_print_float_info (gdbarch, nanomips_print_float_info);
+
+  set_gdbarch_convert_register_p (gdbarch, nanomips_convert_register_p);
+  set_gdbarch_register_to_value (gdbarch, nanomips_register_to_value);
+  set_gdbarch_value_to_register (gdbarch, nanomips_value_to_register);
+
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_breakpoint_kind_from_pc (gdbarch,
+				       nanomips_breakpoint_kind_from_pc);
+  set_gdbarch_sw_breakpoint_from_kind (gdbarch,
+				       nanomips_sw_breakpoint_from_kind);
+
+  set_gdbarch_skip_prologue (gdbarch, nanomips_skip_prologue);
+
+  set_gdbarch_stack_frame_destroyed_p (gdbarch,
+				       nanomips_stack_frame_destroyed_p);
+
+  set_gdbarch_pointer_to_address (gdbarch, signed_pointer_to_address);
+  set_gdbarch_address_to_pointer (gdbarch, address_to_signed_pointer);
+  set_gdbarch_integer_to_address (gdbarch, nanomips_integer_to_address);
+
+  set_gdbarch_print_registers_info (gdbarch, nanomips_print_registers_info);
+
+  if (nanomips_abi == NANOMIPS_ABI_P64)
+    set_gdbarch_print_insn (gdbarch, gdb_print_insn_nanomips_p64);
+  else
+    set_gdbarch_print_insn (gdbarch, gdb_print_insn_nanomips_p32);
+
+  /* FIXME: cagney/2003-08-29: The macros target_have_steppable_watchpoint,
+     HAVE_NONSTEPPABLE_WATCHPOINT, and target_have_continuable_watchpoint
+     need to all be folded into the target vector.  Since they are
+     being used as guards for target_stopped_by_watchpoint, why not have
+     target_stopped_by_watchpoint return the type of watchpoint that the code
+     is sitting on?  */
+  set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
+
+  /* Virtual tables.  */
+  set_gdbarch_vbit_in_delta (gdbarch, 0);
+
+  /* Hook in OS ABI-specific overrides, if they have been registered.  */
+  info.target_desc = tdesc;
+  info.tdesc_data = tdesc_data.get ();
+  gdbarch_init_osabi (info, gdbarch);
+
+  /* Unwind the frame.  */
+  dwarf2_append_unwinders (gdbarch);
+  frame_unwind_append_unwinder (gdbarch, &nanomips_frame_unwind);
+  frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
+  frame_base_append_sniffer (gdbarch, nanomips_frame_base_sniffer);
+
+  regnum = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct nanomips_regnum);
+  *regnum = nanomips_regnum;
+  tdep->regnum = regnum;
+
+  set_gdbarch_num_regs (gdbarch, num_regs);
+  set_tdesc_pseudo_register_type (gdbarch, nanomips_pseudo_register_type);
+  tdesc_use_registers (gdbarch, info.target_desc, std::move (tdesc_data));
+
+  /* Override the normal target description methods to handle our
+     dual real and pseudo registers.  */
+  set_gdbarch_register_name (gdbarch, nanomips_register_name);
+  set_gdbarch_register_reggroup_p (gdbarch,
+				   nanomips_tdesc_register_reggroup_p);
+
+  /* The target description may have adjusted num_regs, fetch the final
+     value and set pc_regnum and sp_regnum now that it has been fixed.  */
+  num_regs = gdbarch_num_regs (gdbarch);
+  set_gdbarch_num_pseudo_regs (gdbarch, num_regs);
+  set_gdbarch_pc_regnum (gdbarch, NANOMIPS_PC_REGNUM + num_regs);
+  set_gdbarch_sp_regnum (gdbarch, NANOMIPS_SP_REGNUM + num_regs);
+  if (regnum->fpr != -1)
+    set_gdbarch_fp0_regnum (gdbarch, regnum->fpr + NANOMIPS_FP0_REGNUM);
+  set_gdbarch_virtual_frame_pointer (gdbarch, nanomips_virtual_frame_pointer);
+
+  return gdbarch;
+}
+
+static void
+nanomips_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
+{
+  struct nanomips_gdbarch_tdep *tdep = gdbarch_tdep<nanomips_gdbarch_tdep> (gdbarch);
+  if (tdep != NULL)
+    {
+      int ef_mips_arch;
+      int ef_mips_32bitmode;
+      /* Determine the ISA.  */
+      switch (tdep->elf_flags & EF_NANOMIPS_ARCH)
+	{
+	case E_NANOMIPS_ARCH_32R6:
+	  ef_mips_arch = 1;
+	  break;
+	case E_NANOMIPS_ARCH_64R6:
+	  ef_mips_arch = 2;
+	  break;
+	default:
+	  ef_mips_arch = 0;
+	  break;
+	}
+      /* Determine the size of a pointer.  */
+      ef_mips_32bitmode = (tdep->elf_flags & EF_NANOMIPS_32BITMODE);
+      gdb_printf (file,
+			  "nanomips_dump_tdep: tdep->elf_flags = 0x%x\n",
+			  tdep->elf_flags);
+      gdb_printf (file,
+			  "nanomips_dump_tdep: ef_mips_32bitmode = %d\n",
+			  ef_mips_32bitmode);
+      gdb_printf (file,
+			  "nanomips_dump_tdep: ef_mips_arch = %d\n",
+			  ef_mips_arch);
+      gdb_printf (file,
+			  "nanomips_dump_tdep: tdep->nanomips_abi = %d (%s)\n",
+			  tdep->nanomips_abi,
+			  nanomips_abi_strings[tdep->nanomips_abi]);
+      gdb_printf (file,
+			  "nanomips_dump_tdep: "
+			  "nanomips_mask_address_p() %d (default %d)\n",
+			  nanomips_mask_address_p (tdep),
+			  tdep->default_mask_address_p);
+    }
+
+  gdb_printf (file,
+		      "nanomips_dump_tdep: FPU_TYPE = %d (%s)\n",
+		      FPU_TYPE (gdbarch),
+		      (FPU_TYPE (gdbarch) == NANOMIPS_FPU_NONE ? "unknown"
+		       : FPU_TYPE (gdbarch) == NANOMIPS_FPU_HARD ?
+						"64bit hardware floating point"
+		       : FPU_TYPE (gdbarch) == NANOMIPS_FPU_SOFT ?
+						"Software floating point"
+		       : "???"));
+}
+
+void _initialize_nanomips_tdep(); /* -Wmissing-prototypes */
+
+void
+_initialize_nanomips_tdep ()
+{
+  gdbarch_register (bfd_arch_nanomips, nanomips_gdbarch_init,
+		    nanomips_dump_tdep);
+
+  initialize_tdesc_nanomips ();
+
+  /* Add root prefix command for all "set/show nanomips" commands.  */
+  add_prefix_cmd ("nanomips", no_class, set_nanomips_command,
+		  _("Various nanoMIPS specific commands."),
+		  &setnanomipscmdlist, 0, &setlist);
+
+  add_prefix_cmd ("nanomips", no_class, show_nanomips_command,
+		  _("Various nanoMIPS specific commands."),
+		  &shownanomipscmdlist, 0, &showlist);
+
+  /* We really would like to have both "0" and "unlimited" work, but
+     command.c doesn't deal with that.  So make it a var_zinteger
+     because the user can always use "999999" or some such for unlimited.  */
+  add_setshow_zinteger_cmd ("heuristic-fence-post", class_support,
+			    &heuristic_fence_post, _("\
+Set the distance searched for the start of a function."), _("\
+Show the distance searched for the start of a function."), _("\
+If you are debugging a stripped executable, GDB needs to search through the\n\
+program for the start of a function.  This command sets the distance of the\n\
+search.  The only need to set it is when debugging a stripped executable."),
+			    reinit_frame_cache_sfunc,
+			    NULL, /* FIXME: i18n: The distance searched for
+				     the start of a function is %s.  */
+			    &setlist, &showlist);
+
+  /* Allow the user to control whether the upper bits of 64-bit
+     addresses should be zeroed.  */
+  add_setshow_auto_boolean_cmd ("mask-address", no_class,
+				&mask_address_var, _("\
+Set zeroing of upper 32 bits of 64-bit addresses."), _("\
+Show zeroing of upper 32 bits of 64-bit addresses."), _("\
+Use \"on\" to enable the masking, \"off\" to disable it and \"auto\" to\n\
+allow GDB to determine the correct value."),
+				NULL, show_mask_address,
+				&setnanomipscmdlist, &shownanomipscmdlist);
+
+  /* Debug this files internals.  */
+  add_setshow_zuinteger_cmd ("nanomips", class_maintenance,
+			     &nanomips_debug, _("\
+Set nanomips debugging."), _("\
+Show nanomips debugging."), _("\
+When non-zero, nanomips specific debugging is enabled."),
+			     NULL,
+			     NULL, /* FIXME: i18n: Mips debugging is
+				      currently %s.  */
+			     &setdebuglist, &showdebuglist);
+}
diff --git a/gdb/nanomips-tdep.h b/gdb/nanomips-tdep.h
new file mode 100644
index 00000000000..97d85ec89d6
--- /dev/null
+++ b/gdb/nanomips-tdep.h
@@ -0,0 +1,144 @@
+/* Target-dependent header for the nanoMIPS architecture, for GDB,
+   the GNU Debugger.
+
+   Copyright (C) 2002-2022 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef NANOMIPS_TDEP_H
+#define NANOMIPS_TDEP_H
+
+#include "objfiles.h"
+
+struct gdbarch;
+
+/* All the possible nanoMIPS ABIs.  */
+enum nanomips_abi
+  {
+    NANOMIPS_ABI_UNKNOWN = 0,
+    NANOMIPS_ABI_P32,
+    NANOMIPS_ABI_P64,
+  };
+
+/* Return the nanoMIPS ABI associated with GDBARCH.  */
+enum nanomips_abi nanomips_abi (struct gdbarch *gdbarch);
+
+/* Return the current index for various nanoMIPS registers.  */
+struct nanomips_regnum
+{
+  int fpr;		/* Floating-point unit registers.  */
+  int badvaddr;		/* Bad vaddr for addressing exception.  */
+  int status;		/* Status register.  */
+  int cause;		/* Describes last exception.  */
+  int dsp;		/* DSP registers.  */
+  int restart;		/* Linux syscall restart flag.  */
+};
+
+extern const struct nanomips_regnum *nanomips_regnum (struct gdbarch *gdbarch);
+
+/* nanoMIPS floating-point operations.  */
+
+enum fpu_type
+{
+  NANOMIPS_FPU_NONE,	/* Unknown floating point.  */
+  NANOMIPS_FPU_HARD,	/* Double precision floating point.  */
+  NANOMIPS_FPU_SOFT	/* Software floating point.  */
+};
+
+/* nanoMIPS specific per-architecture information.  */
+struct nanomips_gdbarch_tdep : gdbarch_tdep_base
+{
+  /* from the elf header */
+  int elf_flags;
+
+  /* nanomips options */
+  enum nanomips_abi nanomips_abi;
+  enum nanomips_abi found_abi;
+  enum fpu_type fpu_type;
+  int mips_last_arg_regnum;
+  int default_mask_address_p;
+
+  /* Indexes for various registers determined dynamically at run time.
+     This contains the "public" fields.  Don't add any that do not need
+     to be public.  */
+  struct nanomips_regnum *regnum;
+
+  /* The size of register data available from the target.  */
+  int register_size;
+
+  /* Return the expected next PC if FRAME is stopped at a syscall
+     instruction.  */
+  CORE_ADDR (*syscall_next_pc) (frame_info_ptr frame, CORE_ADDR pc);
+};
+
+/* Register numbers of various important registers from the fixed
+   GPR+PC register set that is always present.  The rest is determined
+   dynamically at run time and held in `gdbarch_tdep->regnum'.  */
+
+enum
+{
+  NANOMIPS_ZERO_REGNUM = 0,
+  NANOMIPS_AT_REGNUM = 1,
+  NANOMIPS_T4_REGNUM = 2,
+  NANOMIPS_A0_REGNUM = 4,
+  NANOMIPS_GP_REGNUM = 28,
+  NANOMIPS_SP_REGNUM = 29,
+  NANOMIPS_FP_REGNUM = 30,
+  NANOMIPS_RA_REGNUM = 31,
+  NANOMIPS_PC_REGNUM = 32
+};
+
+/* Floating-point register offsets relative to `gdbarch_tdep->regnum->fpr'.  */
+
+enum
+{
+  NANOMIPS_FP0_REGNUM = 0,
+  NANOMIPS_FCSR_REGNUM = 32,
+  NANOMIPS_FIR_REGNUM = 33
+};
+
+/* DSP register offsets, relative to `gdbarch_tdep->regnum->dsp'.  */
+
+enum
+{
+  NANOMIPS_DSPHI0_REGNUM = 0,
+  NANOMIPS_DSPLO0_REGNUM = 1,
+  NANOMIPS_DSPCTL_REGNUM = 8
+};
+
+/* Instruction sizes and other useful constants.  */
+enum
+{
+  INSN16_SIZE = 2,
+  INSN32_SIZE = 4,
+  /* The number of floating-point or integer registers.  */
+  NUMREGS = 32
+};
+
+/* Single step based on where the current instruction will take us.  */
+extern std::vector<CORE_ADDR>
+nanomips_software_single_step (struct regcache *regcache);
+
+/* Return the currently determined ISA register size.  */
+extern int nanomips_isa_regsize (struct gdbarch *gdbarch);
+
+/* Return the currently configured (or set) saved register size.  */
+extern unsigned int nanomips_abi_regsize (struct gdbarch *gdbarch);
+
+/* Make PC the address of the next instruction to execute.  */
+extern void nanomips_write_pc (struct regcache *regcache, CORE_ADDR pc);
+
+#endif /* NANOMIPS_TDEP_H */
diff --git a/gdb/testsuite/gdb.asm/asm-source.exp b/gdb/testsuite/gdb.asm/asm-source.exp
index d56a5076b44..c2ec299a81f 100644
--- a/gdb/testsuite/gdb.asm/asm-source.exp
+++ b/gdb/testsuite/gdb.asm/asm-source.exp
@@ -100,6 +100,13 @@ switch -glob -- [istarget] {
     "mips*-*" {
         set asm-arch mips
     }
+    "nanomips*-elf" {
+        set asm-arch nanomips
+	append link-flags " -Ttext 0x80020000 -Tdata 0x80030000"
+	set board [target_info name]
+	set old_ldscript [board_info $board ldscript]
+	set_board_info ldscript ""
+    }
     "powerpc64le-*" {
         set asm-arch powerpc64le
         set asm-flags "-a64 -I${srcdir}/${subdir} $obj_include"
@@ -260,7 +267,7 @@ if {[target_link [list $asm1obj $asm2obj] "${binfile}" ${link-flags}] != "" } th
 }
 
 # Restore the target board linker script for HC11/HC12.
-if { [istarget "m6811-*-*"] || [istarget "m6812-*-*"] } {
+if { [istarget "m6811-*-*"] || [istarget "m6812-*-*"] || [istarget "nanomips*-elf"] } {
     set_board_info ldscript $old_ldscript
 }
 
diff --git a/gdb/testsuite/gdb.asm/nanomips.inc b/gdb/testsuite/gdb.asm/nanomips.inc
new file mode 100644
index 00000000000..6e2ead15d2c
--- /dev/null
+++ b/gdb/testsuite/gdb.asm/nanomips.inc
@@ -0,0 +1,49 @@
+	comment "subroutine declare"
+	.purgem gdbasm_declare
+	.macro gdbasm_declare name
+	.align	1
+	.ent	\name
+	.type	\name,@function
+\name:
+	.endm
+
+	comment "subroutine prologue"
+	.macro gdbasm_enter
+	save 32, $fp, $ra
+	addiu $fp, $sp, -4080
+	.endm
+
+	comment "subroutine epilogue"
+	.macro gdbasm_leave
+	restore.jrc 32, $fp, $ra
+	.endm
+
+	comment "subroutine end"
+	.purgem gdbasm_end
+	.macro gdbasm_end name
+	.end	\name
+	.endm
+
+	.macro gdbasm_call subr
+        li     $t9, \subr
+        jalrc  $ra, $t9
+	.endm
+
+	.macro gdbasm_several_nops
+	nop
+	nop
+	nop
+	nop
+	.endm
+
+	comment "exit (0)"
+	.macro gdbasm_exit0
+	comment "Don't know how to exit, but this will certainly halt..."
+	lw 	$a3, 0($zero)
+	.endm
+
+	comment "crt0 startup"
+	.macro gdbasm_startup
+	li $sp, 0x8007fff0
+	li $fp, 0
+	.endm
diff --git a/gdb/testsuite/gdb.base/catch-gdb-caused-signals.c b/gdb/testsuite/gdb.base/catch-gdb-caused-signals.c
index e9923814b01..a2064b3bb2e 100644
--- a/gdb/testsuite/gdb.base/catch-gdb-caused-signals.c
+++ b/gdb/testsuite/gdb.base/catch-gdb-caused-signals.c
@@ -27,6 +27,9 @@ main (void)
 {
   int i = 0;
 
+  /* Ensure printf function is available.  */
+  printf ("printf available %d\n", i);
+
   gdb_unbuffer_output ();
 
   i++; /* set dprintf here */
diff --git a/gdb/testsuite/gdb.base/float.exp b/gdb/testsuite/gdb.base/float.exp
index 7fff2b90727..76a274e936a 100644
--- a/gdb/testsuite/gdb.base/float.exp
+++ b/gdb/testsuite/gdb.base/float.exp
@@ -67,7 +67,7 @@ if { [is_aarch64_target] } then {
             pass "info float (without FPU)"
 	}
     }
-} elseif [istarget "mips*-*-*"] then {
+} elseif { [istarget "mips*-*-*"] || [istarget "nanomips*-*-*"] } then {
     gdb_test_multiple "info float" "info float" {
 	-re "fpu type: none / unused\r\n$gdb_prompt $" {
 	      pass "info float (without FPU)"
diff --git a/gdb/testsuite/gdb.trace/trace-common.h b/gdb/testsuite/gdb.trace/trace-common.h
index f8cd654ba2b..6dfab081f1e 100644
--- a/gdb/testsuite/gdb.trace/trace-common.h
+++ b/gdb/testsuite/gdb.trace/trace-common.h
@@ -43,7 +43,7 @@ x86_trace_dummy ()
        "    call " SYMBOL(x86_trace_dummy) "\n" \
        )
 
-#elif (defined __aarch64__) || (defined __powerpc__)
+#elif (defined __aarch64__) || (defined __powerpc__) || (__nanomips__)
 
 #define FAST_TRACEPOINT_LABEL(name) \
   asm ("    .global " SYMBOL(name) "\n" \
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 7d05fbe557b..2df0d35ffa0 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -3284,6 +3284,7 @@ gdb_caching_proc supports_memtag {
 proc can_hardware_single_step {} {
 
     if { [istarget "arm*-*-*"] || [istarget "mips*-*-*"]
+	 || [istarget "nanomips*-*-*"]
 	 || [istarget "tic6x-*-*"] || [istarget "sparc*-*-linux*"]
 	 || [istarget "nios2-*-*"] || [istarget "riscv*-*-linux*"] } {
 	return 0
-- 
2.25.1


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

* Re: [PATCH v3 1/2] sim: Add nanoMIPS port
  2022-11-21 11:06   ` [PATCH v3 1/2] " Aleksandar Rikalo
  2022-11-21 11:06     ` [PATCH v3 2/2] gdb: " Aleksandar Rikalo
@ 2022-11-25 12:11     ` Mike Frysinger
  2022-11-25 15:36       ` Aleksandar Rikalo
  1 sibling, 1 reply; 13+ messages in thread
From: Mike Frysinger @ 2022-11-25 12:11 UTC (permalink / raw)
  To: Aleksandar Rikalo; +Cc: gdb-patches, arikalo

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

this patch is large, and you haven't explicitly responded to the previous
review, or documented how you've incorporated (or not) the feedback.  please
be clear as to what you've done rather than keep throwing patches up without
any response.  i'm not inclined to go through the feedback myself and figure
out what you've changed.
-mike

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* [PATCH v3 1/2] sim: Add nanoMIPS port
@ 2022-11-25 15:36       ` Aleksandar Rikalo
  2022-12-12 11:11         ` Mike Frysinger
  0 siblings, 1 reply; 13+ messages in thread
From: Aleksandar Rikalo @ 2022-11-25 15:36 UTC (permalink / raw)
  To: Mike Frysinger; +Cc: gdb-patches, arikalo

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

Hello Mike,

Compared to the first version, all of your comments have been addressed and patches are re-based onto the current master branch.

These changes depend on the patches(*) for Binutils, which we just updated, so I'm also preparing a new version (v4) for sim and gdb.
The changes will be minor, so the review can be done on this version (v3) as well.

(*) https://sourceware.org/pipermail/binutils/2022-November/124640.html

> is everyone's copyright papers in place ?

As far as I know, everyone's copyright papers are in place.

> seems odd that you're using a new "nanomips*" tuple instead of existing
> "mips*" space.  but i guess if you've convinced everyone else that this
> isn't wrong, then sim/ will just follow.

I think all the other tools use "nanomips*" tuple. I'm sure about GCC, QEMU, and Valgrind.

Thank you for your time.

Aleksandar


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

* Re: [PATCH v3 2/2] gdb: Add nanoMIPS port
  2022-11-21 11:06     ` [PATCH v3 2/2] gdb: " Aleksandar Rikalo
@ 2022-12-12  9:42       ` Mike Frysinger
  2022-12-12  9:45       ` Mike Frysinger
  1 sibling, 0 replies; 13+ messages in thread
From: Mike Frysinger @ 2022-12-12  9:42 UTC (permalink / raw)
  To: Aleksandar Rikalo; +Cc: gdb-patches, arikalo

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

On 21 Nov 2022 12:06, Aleksandar Rikalo wrote:
>  config.sub                                    |    1 +
>  configure                                     |    3 +
>  configure.ac                                  |    3 +

changes to these files should be landed separately, and usually are sent to
the binutils list.  config.{guess,sub} updates are taken from gcc, and they
in turn take them from the gnuconfig project.  so if you can point to those
projects merging things, we sync on our side without question.  we do not
fork these files though.
-mike

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v3 2/2] gdb: Add nanoMIPS port
  2022-11-21 11:06     ` [PATCH v3 2/2] gdb: " Aleksandar Rikalo
  2022-12-12  9:42       ` Mike Frysinger
@ 2022-12-12  9:45       ` Mike Frysinger
  1 sibling, 0 replies; 13+ messages in thread
From: Mike Frysinger @ 2022-12-12  9:45 UTC (permalink / raw)
  To: Aleksandar Rikalo; +Cc: gdb-patches, arikalo

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

On 21 Nov 2022 12:06, Aleksandar Rikalo wrote:
> --- a/gdb/configure.tgt
> +++ b/gdb/configure.tgt
> @@ -448,6 +448,16 @@ msp430-*-elf*)
>  	gdb_target_obs="msp430-tdep.o"
>  	;;
>  
> +mt-*-*)
> +	# Target: Morpho Technologies ms1 processor
> +	gdb_target_obs="mt-tdep.o"
> +	;;

this patch is about nanomips, not this thing

> --- /dev/null
> +++ b/gdb/nanomips-tdep.c

this file seems to duplicate a lot of existing mips-tdep.c logic.
can't they be merged/kept in sync better ?
-mike

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v3 1/2] sim: Add nanoMIPS port
  2022-11-25 15:36       ` Aleksandar Rikalo
@ 2022-12-12 11:11         ` Mike Frysinger
  0 siblings, 0 replies; 13+ messages in thread
From: Mike Frysinger @ 2022-12-12 11:11 UTC (permalink / raw)
  To: Aleksandar Rikalo; +Cc: gdb-patches, arikalo

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

On 25 Nov 2022 15:36, Aleksandar Rikalo wrote:
> Compared to the first version, all of your comments have been addressed and patches are re-based onto the current master branch.
> 
> These changes depend on the patches(*) for Binutils, which we just updated, so I'm also preparing a new version (v4) for sim and gdb.
> The changes will be minor, so the review can be done on this version (v3) as well.
> 
> (*) https://sourceware.org/pipermail/binutils/2022-November/124640.html

let's circle back once GDB 13 branches, and some pending sim changes are
merged.  then you can rebase on top of that and send out a new version.
-mike

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

end of thread, other threads:[~2022-12-12 11:11 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20220429155813.388328-1-aleksandar.rikalo@syrmia.com>
2022-04-29 15:58 ` [PATCH 1/3] bfd: Add support for nanoMIPS architecture Aleksandar Rikalo
2022-05-01 22:56   ` Maciej W. Rozycki
2022-04-29 15:58 ` [PATCH 2/3] sim: Add nanoMIPS port Aleksandar Rikalo
2022-05-04 12:45   ` Mike Frysinger
2022-11-21 11:06   ` [PATCH v3 1/2] " Aleksandar Rikalo
2022-11-21 11:06     ` [PATCH v3 2/2] gdb: " Aleksandar Rikalo
2022-12-12  9:42       ` Mike Frysinger
2022-12-12  9:45       ` Mike Frysinger
2022-11-25 12:11     ` [PATCH v3 1/2] sim: " Mike Frysinger
2022-11-25 15:36       ` Aleksandar Rikalo
2022-12-12 11:11         ` Mike Frysinger
2022-04-29 15:58 ` [PATCH 3/3] gdb: " Aleksandar Rikalo
2022-04-29 16:15   ` Eli Zaretskii

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).