Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 1/5] Code for nds32 target
@ 2013-07-08  9:28 Wei-cheng Wang
  2013-07-08 23:58 ` Joseph S. Myers
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Wei-cheng Wang @ 2013-07-08  9:28 UTC (permalink / raw)
  To: gdb-patches

2013-07-08  Wei-Cheng Wang  <cole945@gmail.com>

	* Makefile.in (ALL_TARGET_OBS): Add nds32-tdep.o, nds32-linux-tdep.o,
	nds32-utils.o and nds32-remote.o.
	(ALLDEPFILES): Add nds32-tdep.c, nds32-linux-tdep.c, nds32-utils.c and
	nds32-remote.c.
	* configure.host: Add nds32*-linux* as host.
	* configure.tgt: Add nds32* and nds32*-linux* as target.
	* nds32-linux-nat.c: New file.
	* nds32-linux-tdep.c: New file.
	* nds32-linux-tdep.h: New file.
	* nds32-remote.c: New file.
	* nds32-remote.h: New file.
	* nds32-tdep.c: New file.
	* nds32-tdep.h: New file.
	* nds32-utils.c: New file.
	* nds32-utils.h: New file.
	* config/nds32/linux.mh: New file.
	* features/Makefile (WHICH): Add nds32-linux, nds32-freg0-linux,
	nds32-freg1-linux and nds32-freg2-linux.
	* features/nds32-linux.xml: New file.
	* features/nds32-core.xml: New file.
	* features/nds32-freg0.xml: New file.
	* features/nds32-freg1.xml: New file.
	* features/nds32-freg2.xml: New file.
	* features/nds32-freg3.xml: New file.
	* features/nds32-freg3-linux.xml: New file.
	* features/nds32-freg0-linux.xml: New file.
	* features/nds32-freg1-linux.xml: New file.
	* features/nds32-freg2-linux.xml: New file.
	* features/nds32-linux.c: New file (autogenerated).
	* features/nds32-freg0-linux.c: New file (autogenerated).
	* features/nds32-freg1-linux.c: New file (autogenerated).
	* features/nds32-freg2-linux.c: New file (autogenerated).
	* features/nds32-freg3-linux.c: New file (autogenerated).
	* regformats/nds32-linux.dat: New file (autogenerated).
	* regformats/nds32-freg0-linux.dat: New file (autogenerated).
	* regformats/nds32-freg1-linux.dat: New file (autogenerated).
	* regformats/nds32-freg2-linux.dat: New file (autogenerated).
	* regformats/nds32-freg3-linux.dat: New file (autogenerated).

---

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 4694adc..a116fea 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -574,6 +574,7 @@ ALL_TARGET_OBS = \
 	moxie-tdep.o \
 	msp430-tdep.o \
 	mt-tdep.o \
+	nds32-tdep.o nds32-linux-tdep.o nds32-utils.o nds32-remote.o \
 	nios2-tdep.o nios2-linux-tdep.o \
 	nto-tdep.o \
 	ppc-linux-tdep.o ppcfbsd-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o  \
@@ -1519,6 +1520,7 @@ ALLDEPFILES = \
 	mipsnbsd-nat.c mipsnbsd-tdep.c \
 	mips64obsd-nat.c mips64obsd-tdep.c \
 	msp430-tdep.c \
+	nds32-tdep.c nds32-linux-tdep.c nds32-utils.c nds32-remote.c \
 	nios2-tdep.c nios2-linux-tdep.c \
 	nbsd-nat.c nbsd-tdep.c obsd-tdep.c \
 	solib-osf.c \
diff --git a/gdb/config/nds32/linux.mh b/gdb/config/nds32/linux.mh
new file mode 100644
index 0000000..eab0e57
--- /dev/null
+++ b/gdb/config/nds32/linux.mh
@@ -0,0 +1,10 @@
+# Host: nds32 based machine running GNU/Linux
+
+NAT_FILE= config/nm-linux.h
+NATDEPFILES= inf-ptrace.o fork-child.o \
+	nds32-linux-nat.o \
+	proc-service.o linux-thread-db.o \
+	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o
+NAT_CDEPS = $(srcdir)/proc-service.list
+
+LOADLIBES= -ldl $(RDYNAMIC)
diff --git a/gdb/configure.host b/gdb/configure.host
index 85f4491..a4c4135 100644
--- a/gdb/configure.host
+++ b/gdb/configure.host
@@ -54,6 +54,7 @@ sh*)			gdb_host_cpu=sh ;;
 tilegx*)		gdb_host_cpu=tilegx ;;
 x86_64*)		gdb_host_cpu=i386 ;;
 m32r*)			gdb_host_cpu=m32r ;;
+nds32*)			gdb_host_cpu=nds32 ;;
 xtensa*)		gdb_host_cpu=xtensa ;;
 *)			gdb_host_cpu=$host_cpu ;;

@@ -126,6 +127,8 @@ mips*-*-netbsd* | mips*-*-knetbsd*-gnu)
 			gdb_host=nbsd ;;
 mips64*-*-openbsd*)	gdb_host=obsd64 ;;

+nds32*-linux*)		gdb_host=linux ;;
+
 powerpc-*-aix* | rs6000-*-*)
 			gdb_host=aix ;;
 powerpc*-*-freebsd*)	gdb_host=fbsd ;;
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 260a0df..a65f483 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -401,6 +401,20 @@ mt-*-*)
 	gdb_target_obs="mt-tdep.o"
 	;;

+nds32*-*-linux*)
+	# Target: GNU/Linux NDS32
+	gdb_target_obs="nds32-tdep.o nds32-linux-tdep.o nds32-utils.o nds32-remote.o \
+			glibc-tdep.o solib-svr4.o symfile-mem.o linux-tdep.o"
+	build_gdbserver=yes
+	gdb_sim=../sim/nds32/libsim.a
+	;;
+
+nds32*)
+	# Target: AndesTech nds32 core
+	gdb_target_obs="nds32-tdep.o nds32-utils.o nds32-remote.o monitor.o dsrec.o"
+	gdb_sim=../sim/nds32/libsim.a
+	;;
+
 nios2*-*-linux*)
 	# Target: Altera Nios II running Linux
 	gdb_target_obs="nios2-tdep.o nios2-linux-tdep.o solib-svr4.o \
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index aee57d2..53f3bed 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -42,6 +42,8 @@ WHICH = aarch64 \
 	i386/x32-avx i386/x32-avx-linux \
 	mips-linux mips-dsp-linux \
 	mips64-linux mips64-dsp-linux \
+	nds32-linux nds32-freg0-linux nds32-freg1-linux nds32-freg2-linux \
+	nds32-freg3-linux \
 	nios2-linux \
 	rs6000/powerpc-32 \
 	rs6000/powerpc-32l rs6000/powerpc-altivec32l rs6000/powerpc-e500l \
@@ -74,6 +76,11 @@ mips-expedite = r29,pc
 mips-dsp-expedite = r29,pc
 mips64-expedite = r29,pc
 mips64-dsp-expedite = r29,pc
+nds32-linux-expedite = fp,sp,pc
+nds32-freg0-linux-expedite = fp,sp,pc
+nds32-freg1-linux-expedite = fp,sp,pc
+nds32-freg2-linux-expedite = fp,sp,pc
+nds32-freg3-linux-expedite = fp,sp,pc
 nios2-linux-expedite = sp,pc
 powerpc-expedite = r1,pc
 rs6000/powerpc-cell32l-expedite = r1,pc,r0,orig_r3,r4
diff --git a/gdb/features/feature_to_c.sh b/gdb/features/feature_to_c.sh
old mode 100644
new mode 100755
diff --git a/gdb/features/nds32-core.xml b/gdb/features/nds32-core.xml
new file mode 100644
index 0000000..8de8059
--- /dev/null
+++ b/gdb/features/nds32-core.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 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.nds32.core">
+  <reg name="r0" bitsize="32" regnum="0"/>
+  <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" regnum="15"/>
+  <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"/>
+  <!-- r26, r27 is reserved for linux kernel
+       keep the space for compatibility,
+       but hide them from users -->
+  <reg name="" bitsize="32"/>
+  <reg name="" bitsize="32"/>
+
+  <reg name="fp" bitsize="32" type="data_ptr" regnum="28"/>
+  <reg name="gp" bitsize="32" type="data_ptr"/>
+  <reg name="lp" bitsize="32" type="code_ptr"/>
+  <reg name="sp" bitsize="32" type="data_ptr"/>
+
+  <reg name="pc" bitsize="32" type="code_ptr"/>
+
+  <reg name="d0lo" bitsize="32"/>
+  <reg name="d0hi" bitsize="32"/>
+  <reg name="d1lo" bitsize="32"/>
+  <reg name="d1hi" bitsize="32"/>
+
+  <reg name="orig_r0" bitsize="32" regnum="37" group="system"/>
+  <reg name="fucpr" bitsize="32" regnum="38" group="system"/>
+</feature>
diff --git a/gdb/features/nds32-freg0-linux.c b/gdb/features/nds32-freg0-linux.c
new file mode 100644
index 0000000..ecea1ce
--- /dev/null
+++ b/gdb/features/nds32-freg0-linux.c
@@ -0,0 +1,67 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: nds32-freg0-linux.xml */
+
+#include "defs.h"
+#include "osabi.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_nds32_freg0_linux;
+static void
+initialize_tdesc_nds32_freg0_linux (void)
+{
+  struct target_desc *result = allocate_target_description ();
+  struct tdesc_feature *feature;
+
+  set_tdesc_architecture (result, bfd_scan_arch ("n1h"));
+
+  set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux"));
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.nds32.core");
+  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, "", 26, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "", 27, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fp", 28, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "gp", 29, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "lp", 30, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "sp", 31, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "pc", 32, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "d0lo", 33, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d0hi", 34, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d1lo", 35, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d1hi", 36, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "orig_r0", 37, 1, "system", 32, "int");
+  tdesc_create_reg (feature, "fucpr", 38, 1, "system", 32, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.nds32.fpu");
+  tdesc_create_reg (feature, "fd0", 39, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd1", 40, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd2", 41, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd3", 42, 1, NULL, 64, "ieee_single");
+
+  tdesc_nds32_freg0_linux = result;
+}
diff --git a/gdb/features/nds32-freg0-linux.xml
b/gdb/features/nds32-freg0-linux.xml
new file mode 100644
index 0000000..5af24d0
--- /dev/null
+++ b/gdb/features/nds32-freg0-linux.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 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>nds32</architecture>
+  <osabi>GNU/Linux</osabi>
+  <xi:include href="nds32-core.xml"/>
+  <xi:include href="nds32-freg0.xml"/>
+</target>
diff --git a/gdb/features/nds32-freg0.xml b/gdb/features/nds32-freg0.xml
new file mode 100644
index 0000000..2287222
--- /dev/null
+++ b/gdb/features/nds32-freg0.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 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.nds32.fpu">
+  <reg name="fd0" bitsize="64" type="ieee_single"/>
+  <reg name="fd1" bitsize="64" type="ieee_single"/>
+  <reg name="fd2" bitsize="64" type="ieee_single"/>
+  <reg name="fd3" bitsize="64" type="ieee_single"/>
+</feature>
diff --git a/gdb/features/nds32-freg1-linux.c b/gdb/features/nds32-freg1-linux.c
new file mode 100644
index 0000000..8023081
--- /dev/null
+++ b/gdb/features/nds32-freg1-linux.c
@@ -0,0 +1,71 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: nds32-freg1-linux.xml */
+
+#include "defs.h"
+#include "osabi.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_nds32_freg1_linux;
+static void
+initialize_tdesc_nds32_freg1_linux (void)
+{
+  struct target_desc *result = allocate_target_description ();
+  struct tdesc_feature *feature;
+
+  set_tdesc_architecture (result, bfd_scan_arch ("n1h"));
+
+  set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux"));
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.nds32.core");
+  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, "", 26, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "", 27, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fp", 28, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "gp", 29, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "lp", 30, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "sp", 31, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "pc", 32, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "d0lo", 33, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d0hi", 34, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d1lo", 35, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d1hi", 36, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "orig_r0", 37, 1, "system", 32, "int");
+  tdesc_create_reg (feature, "fucpr", 38, 1, "system", 32, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.nds32.fpu");
+  tdesc_create_reg (feature, "fd0", 39, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd1", 40, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd2", 41, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd3", 42, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd4", 43, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd5", 44, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd6", 45, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd7", 46, 1, NULL, 64, "ieee_single");
+
+  tdesc_nds32_freg1_linux = result;
+}
diff --git a/gdb/features/nds32-freg1-linux.xml
b/gdb/features/nds32-freg1-linux.xml
new file mode 100644
index 0000000..656e3b9
--- /dev/null
+++ b/gdb/features/nds32-freg1-linux.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 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>nds32</architecture>
+  <osabi>GNU/Linux</osabi>
+  <xi:include href="nds32-core.xml"/>
+  <xi:include href="nds32-freg1.xml"/>
+</target>
diff --git a/gdb/features/nds32-freg1.xml b/gdb/features/nds32-freg1.xml
new file mode 100644
index 0000000..1d0dfd2
--- /dev/null
+++ b/gdb/features/nds32-freg1.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 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.nds32.fpu">
+  <reg name="fd0" bitsize="64" type="ieee_single"/>
+  <reg name="fd1" bitsize="64" type="ieee_single"/>
+  <reg name="fd2" bitsize="64" type="ieee_single"/>
+  <reg name="fd3" bitsize="64" type="ieee_single"/>
+  <reg name="fd4" bitsize="64" type="ieee_single"/>
+  <reg name="fd5" bitsize="64" type="ieee_single"/>
+  <reg name="fd6" bitsize="64" type="ieee_single"/>
+  <reg name="fd7" bitsize="64" type="ieee_single"/>
+</feature>
diff --git a/gdb/features/nds32-freg2-linux.c b/gdb/features/nds32-freg2-linux.c
new file mode 100644
index 0000000..9640710
--- /dev/null
+++ b/gdb/features/nds32-freg2-linux.c
@@ -0,0 +1,79 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: nds32-freg2-linux.xml */
+
+#include "defs.h"
+#include "osabi.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_nds32_freg2_linux;
+static void
+initialize_tdesc_nds32_freg2_linux (void)
+{
+  struct target_desc *result = allocate_target_description ();
+  struct tdesc_feature *feature;
+
+  set_tdesc_architecture (result, bfd_scan_arch ("n1h"));
+
+  set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux"));
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.nds32.core");
+  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, "", 26, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "", 27, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fp", 28, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "gp", 29, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "lp", 30, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "sp", 31, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "pc", 32, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "d0lo", 33, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d0hi", 34, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d1lo", 35, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d1hi", 36, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "orig_r0", 37, 1, "system", 32, "int");
+  tdesc_create_reg (feature, "fucpr", 38, 1, "system", 32, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.nds32.fpu");
+  tdesc_create_reg (feature, "fd0", 39, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd1", 40, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd2", 41, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd3", 42, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd4", 43, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd5", 44, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd6", 45, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd7", 46, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd8", 47, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd9", 48, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd10", 49, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd11", 50, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd12", 51, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd13", 52, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd14", 53, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd15", 54, 1, NULL, 64, "ieee_single");
+
+  tdesc_nds32_freg2_linux = result;
+}
diff --git a/gdb/features/nds32-freg2-linux.xml
b/gdb/features/nds32-freg2-linux.xml
new file mode 100644
index 0000000..8fa0e0d
--- /dev/null
+++ b/gdb/features/nds32-freg2-linux.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 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>nds32</architecture>
+  <osabi>GNU/Linux</osabi>
+  <xi:include href="nds32-core.xml"/>
+  <xi:include href="nds32-freg2.xml"/>
+</target>
diff --git a/gdb/features/nds32-freg2.xml b/gdb/features/nds32-freg2.xml
new file mode 100644
index 0000000..6b4c1d3
--- /dev/null
+++ b/gdb/features/nds32-freg2.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 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.nds32.fpu">
+  <reg name="fd0" bitsize="64" type="ieee_single"/>
+  <reg name="fd1" bitsize="64" type="ieee_single"/>
+  <reg name="fd2" bitsize="64" type="ieee_single"/>
+  <reg name="fd3" bitsize="64" type="ieee_single"/>
+  <reg name="fd4" bitsize="64" type="ieee_single"/>
+  <reg name="fd5" bitsize="64" type="ieee_single"/>
+  <reg name="fd6" bitsize="64" type="ieee_single"/>
+  <reg name="fd7" bitsize="64" type="ieee_single"/>
+  <reg name="fd8" bitsize="64" type="ieee_single"/>
+  <reg name="fd9" bitsize="64" type="ieee_single"/>
+  <reg name="fd10" bitsize="64" type="ieee_single"/>
+  <reg name="fd11" bitsize="64" type="ieee_single"/>
+  <reg name="fd12" bitsize="64" type="ieee_single"/>
+  <reg name="fd13" bitsize="64" type="ieee_single"/>
+  <reg name="fd14" bitsize="64" type="ieee_single"/>
+  <reg name="fd15" bitsize="64" type="ieee_single"/>
+</feature>
diff --git a/gdb/features/nds32-freg3-linux.c b/gdb/features/nds32-freg3-linux.c
new file mode 100644
index 0000000..f0dc18b
--- /dev/null
+++ b/gdb/features/nds32-freg3-linux.c
@@ -0,0 +1,95 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: nds32-freg3-linux.xml */
+
+#include "defs.h"
+#include "osabi.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_nds32_freg3_linux;
+static void
+initialize_tdesc_nds32_freg3_linux (void)
+{
+  struct target_desc *result = allocate_target_description ();
+  struct tdesc_feature *feature;
+
+  set_tdesc_architecture (result, bfd_scan_arch ("n1h"));
+
+  set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux"));
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.nds32.core");
+  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, "", 26, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "", 27, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fp", 28, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "gp", 29, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "lp", 30, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "sp", 31, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "pc", 32, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "d0lo", 33, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d0hi", 34, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d1lo", 35, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d1hi", 36, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "orig_r0", 37, 1, "system", 32, "int");
+  tdesc_create_reg (feature, "fucpr", 38, 1, "system", 32, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.nds32.fpu");
+  tdesc_create_reg (feature, "fd0", 39, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd1", 40, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd2", 41, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd3", 42, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd4", 43, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd5", 44, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd6", 45, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd7", 46, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd8", 47, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd9", 48, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd10", 49, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd11", 50, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd12", 51, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd13", 52, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd14", 53, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd15", 54, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd16", 55, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd17", 56, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd18", 57, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd19", 58, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd20", 59, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd21", 60, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd22", 61, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd23", 62, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd24", 63, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd25", 64, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd26", 65, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd27", 66, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd28", 67, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd29", 68, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd30", 69, 1, NULL, 64, "ieee_single");
+  tdesc_create_reg (feature, "fd31", 70, 1, NULL, 64, "ieee_single");
+
+  tdesc_nds32_freg3_linux = result;
+}
diff --git a/gdb/features/nds32-freg3-linux.xml
b/gdb/features/nds32-freg3-linux.xml
new file mode 100644
index 0000000..b472420
--- /dev/null
+++ b/gdb/features/nds32-freg3-linux.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 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>nds32</architecture>
+  <osabi>GNU/Linux</osabi>
+  <xi:include href="nds32-core.xml"/>
+  <xi:include href="nds32-freg3.xml"/>
+</target>
diff --git a/gdb/features/nds32-freg3.xml b/gdb/features/nds32-freg3.xml
new file mode 100644
index 0000000..766e570
--- /dev/null
+++ b/gdb/features/nds32-freg3.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 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.nds32.fpu">
+  <reg name="fd0" bitsize="64" type="ieee_single"/>
+  <reg name="fd1" bitsize="64" type="ieee_single"/>
+  <reg name="fd2" bitsize="64" type="ieee_single"/>
+  <reg name="fd3" bitsize="64" type="ieee_single"/>
+  <reg name="fd4" bitsize="64" type="ieee_single"/>
+  <reg name="fd5" bitsize="64" type="ieee_single"/>
+  <reg name="fd6" bitsize="64" type="ieee_single"/>
+  <reg name="fd7" bitsize="64" type="ieee_single"/>
+  <reg name="fd8" bitsize="64" type="ieee_single"/>
+  <reg name="fd9" bitsize="64" type="ieee_single"/>
+  <reg name="fd10" bitsize="64" type="ieee_single"/>
+  <reg name="fd11" bitsize="64" type="ieee_single"/>
+  <reg name="fd12" bitsize="64" type="ieee_single"/>
+  <reg name="fd13" bitsize="64" type="ieee_single"/>
+  <reg name="fd14" bitsize="64" type="ieee_single"/>
+  <reg name="fd15" bitsize="64" type="ieee_single"/>
+  <reg name="fd16" bitsize="64" type="ieee_single"/>
+  <reg name="fd17" bitsize="64" type="ieee_single"/>
+  <reg name="fd18" bitsize="64" type="ieee_single"/>
+  <reg name="fd19" bitsize="64" type="ieee_single"/>
+  <reg name="fd20" bitsize="64" type="ieee_single"/>
+  <reg name="fd21" bitsize="64" type="ieee_single"/>
+  <reg name="fd22" bitsize="64" type="ieee_single"/>
+  <reg name="fd23" bitsize="64" type="ieee_single"/>
+  <reg name="fd24" bitsize="64" type="ieee_single"/>
+  <reg name="fd25" bitsize="64" type="ieee_single"/>
+  <reg name="fd26" bitsize="64" type="ieee_single"/>
+  <reg name="fd27" bitsize="64" type="ieee_single"/>
+  <reg name="fd28" bitsize="64" type="ieee_single"/>
+  <reg name="fd29" bitsize="64" type="ieee_single"/>
+  <reg name="fd30" bitsize="64" type="ieee_single"/>
+  <reg name="fd31" bitsize="64" type="ieee_single"/>
+</feature>
diff --git a/gdb/features/nds32-linux.c b/gdb/features/nds32-linux.c
new file mode 100644
index 0000000..3dee14d
--- /dev/null
+++ b/gdb/features/nds32-linux.c
@@ -0,0 +1,61 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: nds32-linux.xml */
+
+#include "defs.h"
+#include "osabi.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_nds32_linux;
+static void
+initialize_tdesc_nds32_linux (void)
+{
+  struct target_desc *result = allocate_target_description ();
+  struct tdesc_feature *feature;
+
+  set_tdesc_architecture (result, bfd_scan_arch ("n1h"));
+
+  set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux"));
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.nds32.core");
+  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, "", 26, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "", 27, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fp", 28, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "gp", 29, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "lp", 30, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "sp", 31, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "pc", 32, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "d0lo", 33, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d0hi", 34, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d1lo", 35, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "d1hi", 36, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "orig_r0", 37, 1, "system", 32, "int");
+  tdesc_create_reg (feature, "fucpr", 38, 1, "system", 32, "int");
+
+  tdesc_nds32_linux = result;
+}
diff --git a/gdb/features/nds32-linux.xml b/gdb/features/nds32-linux.xml
new file mode 100644
index 0000000..74e41ce
--- /dev/null
+++ b/gdb/features/nds32-linux.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 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>nds32</architecture>
+  <osabi>GNU/Linux</osabi>
+  <xi:include href="nds32-core.xml"/>
+</target>
diff --git a/gdb/nds32-linux-nat.c b/gdb/nds32-linux-nat.c
new file mode 100644
index 0000000..2f87822
--- /dev/null
+++ b/gdb/nds32-linux-nat.c
@@ -0,0 +1,299 @@
+/* Common target dependent code for GDB on nds32 systems.
+
+   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   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 "inferior.h"
+#include "gdbcore.h"
+#include "gdb_string.h"
+#include "regcache.h"
+#include "target.h"
+#include "linux-nat.h"
+#include "target-descriptions.h"
+#include "auxv.h"
+
+#include <elf/common.h>
+#include <sys/user.h>
+#include <sys/ptrace.h>
+#include <sys/utsname.h>
+#include <sys/procfs.h>
+
+/* Prototypes for supply_gregset etc. */
+#include "gregset.h"
+
+/* Defines ps_err_e, struct ps_prochandle.  */
+#include "gdb_proc_service.h"
+
+#include "nds32-tdep.h"
+#include "nds32-linux-tdep.h"
+#include "features/nds32-linux.c"
+
+void _initialize_nds32_linux_nat (void);
+
+#define GET_THREAD_ID(PTID)	get_thread_id (PTID)
+
+/* On GNU/Linux, threads are implemented as pseudo-processes, in which
+   case we may be tracing more than one process at a time.  In that
+   case, inferior_ptid will contain the main process ID and the
+   individual thread (process) ID.  get_thread_id () is used to get
+   the thread id if it's available, and the process id otherwise.  */
+
+int
+get_thread_id (ptid_t ptid)
+{
+  int tid = TIDGET (ptid);
+
+  if (0 == tid)
+    tid = PIDGET (ptid);
+  return tid;
+}
+
+/* Fetch a general register of the process and store into register
+   cache REGCACHE.  See: arch/nds32/include/asm/ptrace.h */
+
+static void
+fetch_register (struct regcache *regcache, int regno)
+{
+  int ret, tid;
+  elf_gregset_t regs;
+
+  /* Check whether the size of gregset is consistent with kernel.  */
+  gdb_assert (sizeof (elf_gregset_t) >= (sizeof (long) * 50));
+
+  /* Get the thread id for the ptrace call.  */
+  tid = GET_THREAD_ID (inferior_ptid);
+
+  ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
+  if (ret < 0)
+    {
+      warning (_("Unable to fetch general register."));
+      return;
+    }
+
+  if (regno >= NDS32_R0_REGNUM && regno < NDS32_LINUX_NUM_GPRS
+      && nds32_ptreg_map[regno] != -1)
+    regcache_raw_supply (regcache, regno,
+			 (char *) &regs[nds32_ptreg_map[regno]]);
+}
+
+/* Fetch all general registers of the process and store into register
+   cache REGCACHE.  */
+
+static void
+fetch_regs (struct regcache *regcache)
+{
+  int ret, regno, tid;
+  elf_gregset_t regs;
+
+  /* Get the thread id for the ptrace call.  */
+  tid = GET_THREAD_ID (inferior_ptid);
+
+  ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
+  if (ret < 0)
+    {
+      warning (_("Unable to fetch general registers."));
+      return;
+    }
+
+  for (regno = NDS32_R0_REGNUM; regno < NDS32_LINUX_NUM_GPRS; regno++)
+    {
+      if (nds32_ptreg_map[regno] == -1)
+	continue;
+      regcache_raw_supply (regcache, regno,
+			   (char *) &regs[nds32_ptreg_map[regno]]);
+    }
+}
+
+/* Store all general registers of the process from the values in
+   register cache REGCACHE.  */
+
+static void
+store_register (const struct regcache *regcache, int regno)
+{
+  int ret, tid;
+  elf_gregset_t regs;
+
+  if (REG_VALID != regcache_register_status (regcache, regno))
+    return;
+
+  /* Get the thread id for the ptrace call.  */
+  tid = GET_THREAD_ID (inferior_ptid);
+
+  /* Get the general registers from the process.  */
+  ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
+  if (ret < 0)
+    {
+      warning (_("Unable to fetch general registers."));
+      return;
+    }
+
+  if (regno >= NDS32_R0_REGNUM && regno < NDS32_LINUX_NUM_GPRS
+      && nds32_ptreg_map[regno] != -1)
+    regcache_raw_collect (regcache, regno,
+			  (char *) &regs[nds32_ptreg_map[regno]]);
+
+  ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
+  if (ret < 0)
+    {
+      warning (_("Unable to store general register."));
+      return;
+    }
+}
+
+static void
+store_regs (const struct regcache *regcache)
+{
+  int ret, regno, tid;
+  elf_gregset_t regs;
+
+  /* Get the thread id for the ptrace call.  */
+  tid = GET_THREAD_ID (inferior_ptid);
+
+  /* Fetch the general registers.  */
+  ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
+  if (ret < 0)
+    {
+      warning (_("Unable to fetch general registers."));
+      return;
+    }
+
+  for (regno = 0; regno < NDS32_LINUX_NUM_GPRS; regno++)
+    {
+      if (nds32_ptreg_map[regno] == -1)
+	continue;
+      if (REG_VALID != regcache_register_status (regcache, regno))
+	regcache_raw_collect (regcache, regno,
+			      (char *) &regs[nds32_ptreg_map[regno]]);
+    }
+
+  ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
+
+  if (ret < 0)
+    {
+      warning (_("Unable to store general registers."));
+      return;
+    }
+}
+
+/* Fetch registers from the child process.  Fetch all registers if
+   REGNO == -1, otherwise fetch all general registers or all floating
+   point registers depending upon the value of REGNO.  */
+
+static void
+nds32_linux_fetch_inferior_registers (struct target_ops *ops,
+				      struct regcache *regcache,
+				      int regno)
+{
+  /* TODO: Handle AUDIO and FPU registers.  */
+
+  if (-1 == regno)
+    fetch_regs (regcache);
+  else
+    fetch_register (regcache, regno);
+}
+
+/* Store registers back into the inferior.  Store all registers if
+   REGNO == -1, otherwise store all general registers or all floating
+   point registers depending upon the value of REGNO.  */
+
+static void
+nds32_linux_store_inferior_registers (struct target_ops *ops,
+				      struct regcache *regcache,
+				      int regno)
+{
+  /* TODO: Handle AUDIO and FPU registers.  */
+
+  if (-1 == regno)
+    store_regs (regcache);
+  else
+    store_register (regcache, regno);
+}
+
+/* Wrapper functions for the standard regset handling, used by
+   thread debugging.  */
+
+void
+fill_gregset (const struct regcache *regcache,
+	      gdb_gregset_t *gregsetp, int regno)
+{
+  nds32_linux_collect_gregset (NULL, regcache, regno, gregsetp, 0);
+}
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
+{
+  nds32_linux_supply_gregset (NULL, regcache, -1, gregsetp, 0);
+}
+
+void
+fill_fpregset (const struct regcache *regcache,
+	       gdb_fpregset_t *fpregsetp, int regno)
+{
+  warning (_("fill_fpregset not implemented"));
+}
+
+/* Fill GDB's register array with the floating-point register values
+   in *fpregsetp.  */
+
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
+{
+  warning (_("supply_fpregset not implemented"));
+}
+
+/* Fetch the thread-local storage pointer for libthread_db.  */
+
+#if 0
+/* TODO: TLS is not supported, yet.  */
+
+ps_err_e
+ps_get_thread_area (const struct ps_prochandle *ph,
+		    lwpid_t lwpid, int idx, void **base)
+{
+}
+#endif
+
+static const struct target_desc *
+nds32_linux_read_description (struct target_ops *ops)
+{
+  CORE_ADDR nds32_hwcap = 0;
+
+  /* TODO: FPU registers.  */
+
+  return tdesc_nds32_linux;
+}
+
+void
+_initialize_nds32_linux_nat (void)
+{
+  struct target_ops *t;
+
+  /* Fill in the generic GNU/Linux methods.  */
+  t = linux_target ();
+
+  /* Add our register access methods.  */
+  t->to_fetch_registers = nds32_linux_fetch_inferior_registers;
+  t->to_store_registers = nds32_linux_store_inferior_registers;
+
+  t->to_read_description = nds32_linux_read_description;
+
+  /* Register the target.  */
+  linux_nat_add_target (t);
+  initialize_tdesc_nds32_linux ();
+}
diff --git a/gdb/nds32-linux-tdep.c b/gdb/nds32-linux-tdep.c
new file mode 100644
index 0000000..79d51cd
--- /dev/null
+++ b/gdb/nds32-linux-tdep.c
@@ -0,0 +1,320 @@
+/* Common target dependent code for GDB on nds32 systems.
+
+   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   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 "gdbcore.h"
+#include "frame.h"
+#include "value.h"
+#include "regcache.h"
+#include "inferior.h"
+#include "osabi.h"
+#include "reggroups.h"
+#include "regset.h"
+#include "target-descriptions.h"
+
+#include "gdb_string.h"
+
+#include "glibc-tdep.h"
+#include "solib-svr4.h"
+
+#include "trad-frame.h"
+#include "frame-unwind.h"
+
+#include "nds32-tdep.h"
+#include "nds32-linux-tdep.h"
+
+extern struct nds32_gdb_config nds32_config;
+
+void _initialize_nds32_linux_tdep (void);
+
+/* Recognizing signal handler frames.  */
+
+/* GNU/Linux has two flavors of signals.  Normal signal handlers, and
+   "realtime" (RT) signals.  The RT signals can provide additional
+   information to the signal handler if the SA_SIGINFO flag is set
+   when establishing a signal handler using `sigaction'.  It is not
+   unlikely that future versions of GNU/Linux will support SA_SIGINFO
+   for normal signals too.  */
+
+/* When the NDS32 Linux kernel calls a signal handler and the
+   SA_RESTORER flag isn't set, the return address points to a bit of
+   code on the stack.  This function returns whether the PC appears to
+   be within this bit of code.
+
+   The instructions for normal and realtime signals are
+       syscall   #__NR_sigreturn ( 0x26 0x01 0xDC 0x0B)
+       or
+       syscall   #__NR_rt_sigreturn ( 0x26 0x02 0xB4 0x0B)
+
+   Checking for the code sequence should be somewhat reliable, because
+   the effect is to call the system call sigreturn.  This is unlikely
+   to occur anywhere other than in a signal trampoline.
+
+   It kind of sucks that we have to read memory from the process in
+   order to identify a signal trampoline, but there doesn't seem to be
+   any other way.  Therefore we only do the memory reads if no
+   function name could be identified, which should be the case since
+   the code is on the stack.
+
+   Detection of signal trampolines for handlers that set the
+   SA_RESTORER flag is in general not possible.  Unfortunately this is
+   what the GNU C Library has been doing for quite some time now.
+   However, as of version 2.1.2, the GNU C Library uses signal
+   trampolines (named __restore and __restore_rt) that are identical
+   to the ones used by the kernel.  Therefore, these trampolines are
+   supported too.  */
+
+/* syscall #0x5077 */
+static const unsigned char NDS32_SIGRETURN_INSN[] =
+{
+  0x64, 0x0a, 0x0e, 0xeb
+};
+
+/* syscall #0x50ad */
+static const unsigned char NDS32_RT_SIGRETURN_INSN[] =
+{
+  0x64, 0x0a, 0x15, 0xab
+};
+
+int nds32_linux_sc_reg_offset[] =
+{
+  /* r0 - r9 */
+  12, 16, 20, 24, 28, 32, 36, 40, 44, 48,
+  /* r10 - r19 */
+  52, 56, 60, 64, 68, 72, 76, 80, 84, 88,
+  /* r20 - r25, 26, 27 */
+  92, 96, 100, 104, 108, 112, -1, -1,
+  /* fp, gp, lr, sp */
+  116, 120, 124, 128,
+  /* pc, d0lo, d0hi, d1lo, d1hi */
+  148, 140, 144, 132, 136
+};
+
+struct nds32_frame_cache
+{
+  CORE_ADDR base, pc;
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Find start of signal frame.  */
+
+static CORE_ADDR
+nds32_linux_sigtramp_start (struct frame_info *this_frame)
+{
+  const int SIGLEN = sizeof (NDS32_SIGRETURN_INSN);
+  CORE_ADDR pc = get_frame_pc (this_frame);
+  gdb_byte buf[SIGLEN];
+
+  if (!safe_frame_unwind_memory (this_frame, pc, buf, SIGLEN))
+    return 0;
+
+  if (memcmp (buf, NDS32_SIGRETURN_INSN, SIGLEN) != 0)
+    return 0;
+
+  return pc;
+}
+
+/* Find start of rt_signal frame.  */
+
+static CORE_ADDR
+nds32_linux_rt_sigtramp_start (struct frame_info *this_frame)
+{
+  const int SIGLEN = sizeof (NDS32_RT_SIGRETURN_INSN);
+  CORE_ADDR pc = get_frame_pc (this_frame);
+  gdb_byte buf[SIGLEN];
+
+  if (!safe_frame_unwind_memory (this_frame, pc, buf, SIGLEN))
+    return 0;
+
+  if (memcmp (buf, NDS32_RT_SIGRETURN_INSN, SIGLEN) != 0)
+    return 0;
+
+  return pc;
+}
+
+/* Return whether the frame preceding NEXT_FRAME corresponds to a
+   GNU/Linux sigtramp routine.  */
+
+static int
+nds32_linux_sigtramp_p (struct frame_info *this_frame)
+{
+  CORE_ADDR pc = get_frame_pc (this_frame);
+  const char *name;
+
+  find_pc_partial_function (pc, &name, NULL, NULL);
+
+  /* If we have NAME, we can optimize the search.  The trampolines are
+     named __restore and __restore_rt.  However, they aren't dynamically
+     exported from the shared C library, so the trampoline may appear to
+     be part of the preceding function.  This should always be sigaction,
+     __sigaction, or __libc_sigaction (all aliases to the same function).  */
+  if (name == NULL)
+    return (nds32_linux_sigtramp_start (this_frame) != 0
+	    || nds32_linux_rt_sigtramp_start (this_frame) != 0);
+
+  return (strcmp ("__default_sa_restorer", name) == 0
+	  || strcmp ("__default_rt_sa_restorer", name) == 0);
+}
+
+/* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>.  */
+#define NDS32_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 0x18
+
+/* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp
+   routine, return the address of the associated sigcontext structure.  */
+
+static CORE_ADDR
+nds32_linux_sigcontext_addr (struct frame_info *this_frame)
+{
+  CORE_ADDR pc;
+  CORE_ADDR sp;
+  gdb_byte buf[4];
+
+  sp = get_frame_sp (this_frame);
+
+  /* sigcontext is at sp for sigtramp */
+  pc = nds32_linux_sigtramp_start (this_frame);
+  if (pc)
+    return sp;
+
+  pc = nds32_linux_rt_sigtramp_start (this_frame);
+  if (pc)
+    {
+      CORE_ADDR ucontext_addr;
+      int r2;
+
+      /* Cole, Dec. 31th, 2010
+	 sigcontext is stored in frame->uc.uc_mcontext, Therefore,
+	 there are two ways to get sigcontext.
+	 The first way, direct access it in the stack.In this way,
+	 we needs more knowledge of rt_sigtramp
+	 The second way, &us is passed as parameter 3 of handler,
+	 that would be R2 in NDS32 ABI.As long as we use generic
+	 ucontext struct, I think it's easier to get sigcontext.  */
+
+      r2 = get_frame_register_unsigned (this_frame, NDS32_R0_REGNUM + 2);
+      sp = r2;
+      /* This value is dependent on kernel.  */
+      sp += NDS32_LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
+      return sp;
+    }
+
+  error (_("Couldn't recognize signal trampoline."));
+  return 0;
+}
+
+/* Supply GPR regset.
+
+   Fill GDB register array with the general-purpose register values
+   in *GREGSETP.  */
+
+void
+nds32_linux_supply_gregset (const struct regset *regset,
+			    struct regcache *regcache, int regnum,
+			    const void *gregs, size_t size)
+{
+  int i;
+  const char *regp = gregs;
+
+  /* pseudo_shift = size == 200 ? 24 : 0; */
+  for (i = NDS32_R0_REGNUM; i < NDS32_LINUX_NUM_GPRS; i++)
+    {
+      /* FIXME: Review me after <linux/user.h>, <asm/ptrace.h>, and SR regs
+	 spec clear. [Harry@Mar.14.2006] */
+      if (nds32_ptreg_map[i] == -1)
+	continue;
+
+      regcache_raw_supply (regcache, i, regp + nds32_ptreg_map[i] * 4);
+    }
+}
+
+/* Collect GPR regset.  */
+
+void
+nds32_linux_collect_gregset (const struct regset *regset,
+			     const struct regcache *regcache,
+			     int regnum, void *gregs_buf, size_t len)
+{
+  gdb_byte *regp = gregs_buf;
+  int regno;
+
+  for (regno = NDS32_R0_REGNUM; regno < NDS32_LINUX_NUM_GPRS; regno++)
+    {
+      if (nds32_ptreg_map[regno] == -1)
+	continue;
+
+      if (regnum == -1 || regnum == regno)
+	regcache_raw_collect (regcache, regno,
+			      regp + nds32_ptreg_map[regno] * 4);
+    }
+}
+
+/* Implement gdbarch_regset_from_core_section method.  */
+
+static const struct regset *
+nds32_linux_regset_from_core_section (struct gdbarch *core_arch,
+				      const char *sect_name, size_t sect_size)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (core_arch);
+
+  if (strcmp (sect_name, ".reg") == 0)
+    return regset_alloc (core_arch, nds32_linux_supply_gregset,
+			 nds32_linux_collect_gregset);
+
+  /* TODO: fpreg ".reg2" */
+  return NULL;
+}
+
+static void
+nds32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  const struct target_desc *tdesc = info.target_desc;
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info;
+  const struct tdesc_feature *feature;
+
+  tdep->sigtramp_p = nds32_linux_sigtramp_p;
+  tdep->sigcontext_addr = nds32_linux_sigcontext_addr;
+  tdep->sc_pc_offset = 37 * 4;	/* sc.fault_address */
+  tdep->sc_sp_offset = 32 * 4;	/* sc.sp */
+  tdep->sc_lp_offset = 31 * 4;	/* sc.lp */
+  tdep->sc_fp_offset = 29 * 4;	/* sc.fp */
+
+  tdep->sc_reg_offset = nds32_linux_sc_reg_offset;
+  tdep->sc_num_regs = ARRAY_SIZE (nds32_linux_sc_reg_offset);
+
+  /* GNU/Linux uses SVR4-style shared libraries.  */
+  set_solib_svr4_fetch_link_map_offsets (gdbarch,
+					 svr4_ilp32_fetch_link_map_offsets);
+
+  /* Core file support.  */
+  /* FIXME: Cole, Dec 31th, 2010
+     It seems this doesn't work? */
+  set_gdbarch_regset_from_core_section (gdbarch,
+					nds32_linux_regset_from_core_section);
+
+  set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
+}
+
+void
+_initialize_nds32_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_nds32, 0, GDB_OSABI_LINUX,
+			  nds32_linux_init_abi);
+}
diff --git a/gdb/nds32-linux-tdep.h b/gdb/nds32-linux-tdep.h
new file mode 100644
index 0000000..40684fe
--- /dev/null
+++ b/gdb/nds32-linux-tdep.h
@@ -0,0 +1,77 @@
+/* Common target dependent code for GDB on nds32 systems.
+
+   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   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 NDS32_LINUX_TDEP_H
+#define NDS32_LINUX_TDEP_H
+
+extern struct target_desc *tdesc_nds32_linux;
+
+void nds32_linux_supply_gregset (const struct regset *regset,
+				 struct regcache *regcache, int regnum,
+				 const void *gregs, size_t size);
+void nds32_linux_collect_gregset (const struct regset *regset,
+				  const struct regcache *regcache, int regnum,
+				  void *gregs_buf, size_t len);
+
+/* Mapping between the general-purpose registers in `struct user'
+   format and GDB's register array layout.
+
+   FIXME: fix me after <linux/user.h>, <asm/ptrace.h>,
+   and SR regs spec clear. [Harry@Mar.14.2006]
+
+   Current remap layout depend on Tom's implementation in kernel header,
+   in ptrace.h and IR spec 0.1 (Jan.20.2006 version)
+   [Harry@Mar.16.2006]
+
+   Note: -1 means unable to get from ptrace syscall
+
+   Renumber according to arch/nds32/include/asm/ptrace.h
+   Not sure whether NDS32_r0 or NDS32_ORIG_r0 represents real $r0.
+   (current use NDS32_ORIG_r0)
+   Registers not mapped: NDS32_FUCOP_CTL, NDS32_osp. (42 & 43)
+   [Rudolph@Aug.18.2010]  */
+
+/* Map gdb regnum to pt_regs index.  */
+static int nds32_ptreg_map[] =
+{
+    /* nds32-core */
+
+    /* r0 - r25 */
+    13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+    23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+    33, 34, 35, 36, 37, 38,
+    /* r26 and r27 are reserved for kernel */
+    -1, -1,
+    /* fp, gp, lp, sp */
+    39, 40, 41, 3,
+    /* pc */
+    2,
+    /* d0lo, d0hi, d1lo, d1hi */
+    10,  9, 12, 11,
+
+    /* nds32-linux */
+
+    /* orig_r0, fucop */
+    4, 42
+};
+
+#define NDS32_LINUX_NUM_GPRS (ARRAY_SIZE(nds32_ptreg_map))
+
+#endif
diff --git a/gdb/nds32-remote.c b/gdb/nds32-remote.c
new file mode 100644
index 0000000..c088f0d
--- /dev/null
+++ b/gdb/nds32-remote.c
@@ -0,0 +1,778 @@
+/* Common target dependent code for GDB on nds32 systems.
+
+   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   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 "gdb_string.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "gdbtypes.h"
+#include "cli/cli-decode.h"
+#include "remote.h"
+#include "regcache.h"
+#include "user-regs.h"
+#include "inferior.h"		/* get_inferior_args () */
+#include "top.h"		/* set_prompt () */
+#include "ui-out.h"		/* current_uiout */
+#include "exceptions.h"		/* TRY_CATCH */
+#include <ctype.h>
+
+#include "nds32-remote.h"
+#include "nds32-tdep.h"
+
+char *nds32_qparts [] =
+{
+  "qPart:nds32:ask:de",
+  "qPart:nds32:ask:mach",
+  "qPart:nds32:ask:base16",
+  "qPart:nds32:ask:pex1",
+  "qPart:nds32:ask:pex2",
+  "qPart:nds32:ask:div",
+  "qPart:nds32:ask:abi",
+  "qPart:nds32:ask:mfusr_pc",
+  "qPart:nds32:ask:fpu",
+  "qPart:nds32:ask:audio",
+  "qPart:nds32:ask:string",
+  "qPart:nds32:ask:reduced_regs",
+  "qPart:nds32:ask:video",
+  "qPart:nds32:ask:ifc",
+  "qPart:nds32:ask:elf_ver",
+  "qPart:nds32:ask:l2c",
+  "qPart:nds32:ask:mac",
+  "qPart:nds32:ask:cpu", /* core0, cpu, etc */
+  "qPart:nds32:ask:target", /* SID, ICE */
+
+  "qPart:nds32:request:InvalidateCache",
+  "qPart:nds32:request:MemAccBus",
+  "qPart:nds32:request:MemAccCPU"
+};
+
+enum nds32_qparts_enum
+{
+  NDS32_Q_ENDIAN,
+  NDS32_Q_MACH,
+  NDS32_Q_BASE16,
+  NDS32_Q_PEX1,
+  NDS32_Q_PEX2,
+  NDS32_Q_DIV,
+  NDS32_Q_ABI,
+  NDS32_Q_MFUSR_PC,
+  NDS32_Q_FPU,
+  NDS32_Q_AUDIO,
+  NDS32_Q_STRING,
+  NDS32_Q_REDUCED_REGS,
+  NDS32_Q_VIDEO,
+  NDS32_Q_IFC,
+  NDS32_Q_ELF_VER,
+  NDS32_Q_L2C,
+  NDS32_Q_MAC,
+  NDS32_Q_CPU,
+  NDS32_Q_TARGET,
+
+  NDS32_Q_INVALIDATE_CACHE,
+  NDS32_Q_ACC_BUS,
+  NDS32_Q_ACC_CPU,
+  NDS32_Q_END
+};
+
+enum nds32_remote_type
+{
+  nds32_rt_unknown = 0,
+  nds32_rt_sid,
+  nds32_rt_ice,
+  nds32_rt_ocd,
+};
+
+struct
+{
+  /* Target type of remote, SID, ICE or OpenOCD.  */
+  enum nds32_remote_type type;
+  /* CPU/CORE name read from remote.  */
+  char cpu[16];
+  /* Default endian of remote.  */
+  enum bfd_endian endian;
+} nds32_remote_info;
+
+void
+nds32_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
+				 int *kindptr)
+{
+  if ((*pcptr) & 1)
+    error (_("bad address %p for inserting breakpoint"), (void *) *pcptr);
+
+  /* ICEman/AICE have trouble on reading memory when the pcptr is P/A,
+     but CPU is in V/A mode.  This code prevent GDB from reading memory.
+     ICEman will read memory itself if needed.
+
+     See: Bug 7430 - GDB can't set a hardware break point with PA
+	  if IT/DT is on.  */
+
+  *kindptr = 2;
+}
+
+/* Wrapper for execute a GDB CLI command.  */
+
+static void
+nds32_execute_command (char *cmd, char *arg, int from_tty)
+{
+  int len;
+  char *line;
+
+  if (arg == NULL)
+    arg = "";
+  len = strlen (arg) + strlen (cmd) + 2;
+  if (len > 1024)
+    error (_("Command line too long."));
+
+  line = alloca (len);
+  memset (line, 0, len);
+  if (arg != NULL)
+    snprintf (line, len, "%s %s", cmd, arg);
+  else
+    snprintf (line, len, "%s", cmd);
+  execute_command (line, from_tty);
+}
+
+static void
+nds32_restore_remote_timeout (void *p)
+{
+  int value = *(int *) p;
+
+  remote_timeout = value;
+}
+
+/* Reset-target.
+   Set remote_timeout to 1000 sec to avoid timeout.  */
+
+static void
+nds32_reset_target_command (char *args, int from_tty)
+{
+  int saved_remote_timeout = remote_timeout;
+  struct cleanup *back_to;
+
+  back_to = make_cleanup (nds32_restore_remote_timeout, &saved_remote_timeout);
+  remote_timeout = 1000;
+  nds32_execute_command ("monitor reset target", NULL, from_tty);
+  registers_changed ();
+  do_cleanups (back_to);
+}
+
+/* Callback for "nds32 reset-hold" command.  */
+
+static void
+nds32_reset_hold_command (char *args, int from_tty)
+{
+  int saved_remote_timeout = remote_timeout;
+  struct cleanup *back_to;
+
+  back_to =
+    make_cleanup (nds32_restore_remote_timeout, &saved_remote_timeout);
+  remote_timeout = 1000;
+  nds32_execute_command ("monitor reset hold", NULL, from_tty);
+  registers_changed ();
+  do_cleanups (back_to);
+}
+
+/* Callback for "nds32 pipeline on" command.  */
+
+static void
+nds32_pipeline_on_command (char *args, int from_tty)
+{
+  char cmd[256];
+
+  snprintf (cmd, sizeof (cmd), "monitor set %s pipeline-on 1",
+	    args == NULL ? "cpu" : args);
+  nds32_execute_command (cmd, NULL, from_tty);
+}
+
+/* Callback for "nds32 pipeline off" command.  */
+
+static void
+nds32_pipeline_off_command (char *args, int from_tty)
+{
+  char cmd[256];
+
+  snprintf (cmd, sizeof (cmd), "monitor set %s pipeline-on 0",
+	    args == NULL ? "cpu" : args);
+  nds32_execute_command (cmd, NULL, from_tty);
+}
+
+/* Callback for "nds32 pipeline" command.  */
+
+static void
+nds32_pipeline_command (char *args, int from_tty)
+{
+  error (_("Usage: nds32 pipeline (on|off) [cpu]"));
+}
+
+/* Callback for "nds32 query" command.  */
+
+static void
+nds32_query_command (char *args, int from_tty)
+{
+  error (_("Usage: nds32 query (profiling|perf-meter) [cpu] [human|ide]"));
+}
+
+/* Callback for "nds32 reset" command.  */
+
+static void
+nds32_reset_command (char *args, int from_tty)
+{
+  error (_("Usage: nds32 reset (profiling|perf-meter) [cpu]"));
+}
+
+/* Pretty-print for profiling data.  */
+
+static void
+nds32_print_human_table (int col, int row, const char *scsv)
+{
+  int i;
+  struct cleanup *table_cleanup = NULL;
+  struct cleanup *row_cleanup = NULL;
+  char *buf = NULL;
+  char **col_fldname;
+  char **col_hdrtext;
+  int *col_width;
+  enum ui_align *col_align;
+  struct bound_minimal_symbol msymbol;
+  CORE_ADDR addr;
+  char symbol_text[256];
+
+  buf = xstrdup (scsv);
+  make_cleanup (xfree, buf);
+
+  /* Allocate header structures.  */
+  col_fldname = (char **) xmalloc (sizeof (col_fldname[0]) * col);
+  col_hdrtext = (char **) xmalloc (sizeof (col_hdrtext[0]) * col);
+  col_width = (int *) xmalloc (sizeof (col_width[0]) * col);
+  col_align = (enum ui_align *) xmalloc (sizeof (col_align[0]) * col);
+
+  make_cleanup (xfree, col_fldname);
+  make_cleanup (xfree, col_hdrtext);
+  make_cleanup (xfree, col_width);
+  make_cleanup (xfree, col_align);
+
+  /* Parsing column header.  */
+  i = 0;
+  while (*buf != '\0' && i < col)
+    {
+      CORE_ADDR addr = 0;
+      char *sc = strchr (buf, ';');
+
+      *sc = '\0';
+      col_fldname[i] = buf;
+      col_hdrtext[i] = col_fldname[i];
+      if (col_fldname[i][0] == '%')
+	col_width[i] = 6;
+      else
+	col_width[i] = strlen (col_hdrtext[i]) + 1;
+
+      col_align[i] = ui_right;
+
+      i++;
+      buf = sc + 1;
+    }
+
+  gdb_assert (col == i);
+
+  /* Output table.  */
+  table_cleanup = make_cleanup_ui_out_table_begin_end
+    (current_uiout, col, row - 1, "ProfilingTable");
+  for (i = 0; i < col; i++)
+    ui_out_table_header (current_uiout, col_width[i], col_align[i],
+			 col_fldname[i], col_hdrtext[i]);
+
+  ui_out_table_body (current_uiout);
+
+  /* Parse buf into col/row.  */
+  i = 0;
+  row_cleanup = make_cleanup_ui_out_tuple_begin_end (current_uiout, "row");
+  while (*buf != '\0')
+    {
+      char *sc = strchr (buf, ';');
+      int offset;
+
+      *sc = '\0';
+      switch (i)
+	{
+	case 0:
+	  ui_out_field_string (current_uiout, col_fldname[i], buf);
+
+	  /* Assume first column is address.  */
+	  strcpy (symbol_text, "\n");
+	  addr = strtol (buf, NULL, 16);
+	  msymbol = lookup_minimal_symbol_by_pc (addr);
+	  if (!msymbol.minsym)
+	    break;
+
+	  offset = addr - SYMBOL_VALUE_ADDRESS (msymbol.minsym);
+	  if (offset)
+	    snprintf (symbol_text, sizeof (symbol_text), "%s + 0x%x\n",
+		      SYMBOL_PRINT_NAME (msymbol.minsym), offset);
+	  else
+	    snprintf (symbol_text, sizeof (symbol_text), "%s\n",
+		      SYMBOL_PRINT_NAME (msymbol.minsym));
+	  break;
+	case 1: case 2: case 3: case 4: case 5: case 6:
+	  ui_out_field_string (current_uiout, col_fldname[i], buf);
+	  break;
+	}
+
+      i++;
+      buf = sc + 1;
+      if (i == col)
+	{
+	  ui_out_text (current_uiout, symbol_text);
+	  do_cleanups (row_cleanup);
+	  i = 0;
+	  row_cleanup = make_cleanup_ui_out_tuple_begin_end
+	    (current_uiout, "row");
+	}
+    }
+
+  do_cleanups (table_cleanup);
+}
+
+/* Callback for "nds32 query profiling" command.  */
+
+static void
+nds32_query_profiling_command (char *args, int from_tty)
+{
+  /* For profiling, there will be multiple responses.  */
+  int row, col;
+  struct ui_file *res;
+  int i;
+  long int pkt_size;
+  char *pkt_buf = NULL;
+  struct ui_file_buffer ui_buf;
+  char *arg_cpu = "cpu";
+  int arg_human = TRUE;
+  struct cleanup *back_to = NULL;
+  char **argv = NULL;
+  char *p;
+
+  /* Initial size. It may be resized by getpkt.  */
+  pkt_size = 1024;
+
+  res = mem_fileopen ();
+  back_to = make_cleanup_ui_file_delete (res);
+
+  ui_buf.buf_size = 2048;
+  ui_buf.buf = xmalloc (ui_buf.buf_size);
+  pkt_buf = xmalloc (pkt_size);
+
+  make_cleanup (free_current_contents, &ui_buf.buf);
+  make_cleanup (free_current_contents, &pkt_buf);
+  make_cleanup_restore_ui_file (&gdb_stdtarg);
+
+  gdb_stdtarg = res;
+
+  if (args != NULL)
+    {
+      /* Parse arguments.  */
+      argv = gdb_buildargv (args);
+      make_cleanup_freeargv (argv);
+    }
+
+  for (i = 0; argv && argv[i]; i++)
+    {
+      switch (i)
+	{
+	case 0:
+	  arg_cpu = argv[i];
+	  break;
+	case 1:
+	  arg_human = strcmp (argv[i], "ide");	/* default human */
+	  break;
+	}
+    }
+
+  /* Fill BUF with monitor command. */
+  snprintf ((char *) ui_buf.buf, ui_buf.buf_size, "set %s profiling ide-query",
+	    args == NULL ? "cpu" : arg_cpu);
+  target_rcmd ((char *) ui_buf.buf, res);
+  memset (ui_buf.buf, 0, ui_buf.buf_size);
+  ui_file_put (res, do_ui_file_put_memcpy, &ui_buf);
+
+  if (!arg_human)
+    {
+      fprintf_unfiltered (gdb_stdtarg,
+			  "=profiling,reason=\"fast_l1_profiling\",data=\"%s\"\n",
+			  ui_buf.buf);
+      goto bye;
+    }
+
+  /* The first response is Row=%d;Column=%d;
+     and then comes 'Row' rows, including head row */
+  i = sscanf ((char *) ui_buf.buf, "Row=%d;Column=%d;", &row, &col);
+  if (i != 2)
+    error (_("Failed to query profiling data"));
+
+  p = (char *) ui_buf.buf;
+
+  /* Skip "Row=r;Column=c;".  */
+  for (i = 0; i < 2 && p; i++)
+    p = strchr (p + 1, ';');
+  p++;
+
+  /* Print human-mode table here.  */
+  nds32_print_human_table (col, row, p);
+
+bye:
+  do_cleanups (back_to);
+}
+
+/* Callback for "nds32 query perfmeter" command.  */
+
+static void
+nds32_query_perfmeter_command (char *args, int from_tty)
+{
+  /* For perfmeter, there will be only one response.  */
+  char cmd[128];
+
+  snprintf (cmd, sizeof (cmd), "set %s perf-meter query",
+	    args == NULL ? "cpu" : args);
+  target_rcmd (cmd, gdb_stdtarg);
+}
+
+/* Callback for "nds32 reset profiling" command.  */
+
+static void
+nds32_reset_profiling_command (char *args, int from_tty)
+{
+  char cmd[256];
+
+  snprintf (cmd, sizeof (cmd), "set %s profiling reset",
+	    args == NULL ? "cpu" : args);
+  target_rcmd (cmd, gdb_stdtarg);
+}
+
+/* Callback for "nds32 reset perfmeter" command.  */
+
+static void
+nds32_reset_perfmeter_command (char *args, int from_tty)
+{
+  char cmd[256];
+
+  snprintf (cmd, sizeof (cmd), "set %s perf-meter reset",
+	    args == NULL ? "cpu" : args);
+  target_rcmd (cmd, gdb_stdtarg);
+}
+
+static void
+nds32_remote_info_init (void)
+{
+  nds32_remote_info.type = nds32_rt_unknown;
+  nds32_remote_info.endian = BFD_ENDIAN_UNKNOWN;
+  strcpy (nds32_remote_info.cpu, "cpu");
+}
+
+/* Query target information.  */
+
+static struct value *
+nds32_target_type_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+			      void *ignore)
+{
+  int val = 0;
+
+  if (strcmp (target_shortname, "remote") == 0
+      || strcmp (target_shortname, "extended-remote") == 0)
+    val = target_has_registers ? nds32_remote_info.type
+			       : nds32_rt_unknown;
+
+  return value_from_longest (builtin_type (gdbarch)->builtin_int,
+			     val);
+}
+
+static int
+nds32_query_target_using_qpart (void)
+{
+  char *buf;
+  long size = 64;
+  struct cleanup *back_to;
+  int ret = FALSE;
+
+  /* The buffer passed to getpkt must be allocated using xmalloc,
+     because it might be xrealloc by read_frame.
+     See remote.c for details.  `buf' must be freed before return.  */
+  buf = xmalloc (size);
+
+  /* Let caller clean it up.  */
+  back_to = make_cleanup (free_current_contents, &buf);
+
+  /* qPart:nds32:ask:target - SID or ICE.  */
+  nds32_remote_info.type = nds32_rt_unknown;
+  putpkt (nds32_qparts[NDS32_Q_TARGET]);
+  getpkt (&buf, &size, 0);
+  if (strcmp (buf, "SID") == 0)
+    nds32_remote_info.type = nds32_rt_sid;
+  else if (strcmp (buf, "ICE") == 0)
+    nds32_remote_info.type = nds32_rt_ice;
+  else
+    goto out;
+
+  /* qPart:nds32:ask:cpu - prompt, e.g., "core0(gdb) ".  */
+  putpkt (nds32_qparts[NDS32_Q_CPU]);
+  getpkt (&buf, &size, 0);
+  if (strlen (buf) > 0 && buf[0] != 'E')
+    {
+      const int csize = sizeof (nds32_remote_info.cpu);
+      memset (nds32_remote_info.cpu, 0, csize);
+      strncpy (nds32_remote_info.cpu, buf, csize - 1);
+    }
+
+  /* qPart:nds32:ask:de - endian, e.g., LE or BE.  */
+  putpkt (nds32_qparts[NDS32_Q_ENDIAN]);
+  getpkt (&buf, &size, 0);
+  if (strcmp (buf, "LE") == 0)
+    nds32_remote_info.endian = BFD_ENDIAN_LITTLE;
+  else if (strcmp (buf, "BE") == 0)
+    nds32_remote_info.endian = BFD_ENDIAN_BIG;
+  else
+    nds32_remote_info.endian = BFD_ENDIAN_UNKNOWN;
+  ret = TRUE;
+
+out:
+  do_cleanups (back_to);
+  return ret;
+}
+
+static int
+nds32_query_target_using_qrcmd (void)
+{
+  struct cleanup *back_to;
+  struct ui_file *res;
+  struct ui_file_buffer ui_buf;
+  char buf[64];
+  int ret = FALSE;
+  volatile struct gdb_exception except;
+  int len;
+
+  /* ui_file for qRcmd.  */
+  res = mem_fileopen ();
+  back_to = make_cleanup_ui_file_delete (res);
+
+  /* ui_file_buffer for reading ui_file.  */
+  ui_buf.buf_size = 64;
+  ui_buf.buf = xmalloc (ui_buf.buf_size);
+  make_cleanup (free_current_contents, &ui_buf.buf);
+
+  /* make_cleanup outside TRY_CACHE,
+     because it save and reset cleanup-chain.  */
+  make_cleanup_restore_ui_file (&gdb_stdtarg);
+  /* Supress error messages from gdbserver
+     if gdbserver doesn't support the monitor command.  */
+  gdb_stdtarg = res;
+
+  TRY_CATCH (except, RETURN_MASK_ERROR)
+    {
+      target_rcmd ("nds query target", res);
+    }
+  if (except.reason < 0)
+    goto out;
+
+  /* Read data in ui_file.  */
+  memset (ui_buf.buf, 0, ui_buf.buf_size);
+  ui_file_put (res, do_ui_file_put_memcpy, &ui_buf);
+
+  /* Trim trailing newline characters.  */
+  len = strlen ((char *) ui_buf.buf);
+  while (isspace (ui_buf.buf[len - 1]) && len > 0)
+    len--;
+  ui_buf.buf[len] = '\0';
+
+  if (strcmp ((char *) ui_buf.buf, "OCD") == 0)
+    nds32_remote_info.type = nds32_rt_ocd;
+  else
+    {
+      printf_unfiltered (_("Unknown remote target %s\n"),
+			 ui_buf.buf);
+      goto out;
+    }
+
+  ret = TRUE;
+out:
+  do_cleanups (back_to);
+  return ret;
+}
+
+static void
+nds32_query_target_command (char *arg, int from_tty)
+{
+  nds32_remote_info_init ();
+
+  if (strcmp (target_shortname, "remote") != 0)
+    return;
+  /* FIXME if we don't know, use ELF. */
+
+  /* Try to find out the type of target - SID, ICE or OCD.  */
+  if (!nds32_query_target_using_qpart ())
+    nds32_query_target_using_qrcmd ();
+
+end_query:
+  /* Set cpu name if ICE and CPU!="cpu".  */
+  if (strcmp ("cpu", nds32_remote_info.cpu) != 0)
+    {
+      char buf[64];
+      snprintf (buf, sizeof (buf), "%s(gdb) ", nds32_remote_info.cpu);
+      set_prompt (buf);
+    }
+  else
+    {
+      /* Restore to DEFAULT_PROMPT.  */
+      set_prompt ("(gdb) ");
+    }
+}
+
+/* This is only used for SID.  Set command-line string.  */
+
+static void
+nds32_set_gloss_command (char *arg, int from_tty)
+{
+  int i;
+  struct ui_file *out;
+  char *arg0;
+  char *args;
+  char *f;
+  char cmdline[0x1000];		/* 4K for max command line.  */
+  struct cleanup *back_to;
+  asection *s = NULL;
+  const char *sectnames[] = { ".text", "code", ".bss", "bss" };
+
+  /* set gloss for SID only. */
+  if (nds32_remote_info.type != nds32_rt_sid)
+    return;
+
+  back_to = make_cleanup (null_cleanup, 0);
+  if (exec_bfd == NULL)
+    error (_("Cannot set gloss without executable.\n"
+	     "Use the \"file\" or \"exec-file\" command."));
+
+  /* ui_file for target_rcmd.  */
+  out = stdio_fileopen (stdout);
+  make_cleanup_ui_file_delete (out);
+
+  /* start_code, end_code, start_bss, end_bss,
+     brk, command-line.  */
+  for (s = exec_bfd->sections; s; s = s->next)
+    {
+      bfd_vma start, size;
+      const char *attr;
+
+      for (i = 0; i < ARRAY_SIZE (sectnames); i += 2)
+	if (strcmp (bfd_get_section_name (exec_bfd, s), sectnames[i]) == 0)
+	  break;
+
+      if (i >= ARRAY_SIZE (sectnames))
+	continue;
+
+      start = bfd_get_section_vma (exec_bfd, s);
+      size = bfd_section_size (exec_bfd, s);
+
+      /* Set gloss (start|end)_XXX.  */
+      snprintf (cmdline, sizeof (cmdline), "set gloss start_%s %u",
+		sectnames[i + 1], (unsigned int) start);
+      target_rcmd (cmdline, out);
+      snprintf (cmdline, sizeof (cmdline), "set gloss end_%s %u",
+		sectnames[i + 1], (unsigned int) (start + size));
+      target_rcmd (cmdline, out);
+    }
+
+  /* Set gloss command-line for "set args".  */
+  arg0 = bfd_get_filename(exec_bfd);
+  args = get_inferior_args ();
+
+  f = strrchr (arg0, '/');
+  if (f == NULL)
+    f = strrchr (arg0, '\\');
+
+  if (f == NULL)
+    f = "a.out";
+  else
+    f++; /* skip separator.  */
+
+  snprintf (cmdline, sizeof (cmdline),
+	    "set gloss command-line \"%s %s\"", f, args);
+  target_rcmd (cmdline, out);
+
+  do_cleanups (back_to);
+}
+
+static struct cmd_list_element *nds32_pipeline_cmdlist;
+static struct cmd_list_element *nds32_query_cmdlist;
+static struct cmd_list_element *nds32_reset_cmdlist;
+static struct cmd_list_element *nds32_maint_cmdlist;
+
+static const struct internalvar_funcs nds32_target_type_funcs =
+{
+    nds32_target_type_make_value,
+    NULL,
+    NULL
+};
+
+void
+nds32_init_remote_cmds (void)
+{
+  nds32_remote_info_init ();
+
+  /* nds32 set-gloss COMMAND_LINE */
+  add_cmd ("set-gloss", class_files, nds32_set_gloss_command,
+	   _("Check elf/target compatibility before loading. "
+	     "Throwing error if failed."),
+	   &nds32_cmdlist);
+
+  /* nds32 reset-target */
+  add_cmd ("reset-target", no_class, nds32_reset_target_command,
+	   _("Turn on pipeline for profiling."), &nds32_cmdlist);
+  /* nds32 reset-hold */
+  add_cmd ("reset-hold", no_class, nds32_reset_hold_command,
+	   _("Turn off pipeline for profiling."), &nds32_cmdlist);
+
+  /* nds32 pipeline (on|off) */
+  add_prefix_cmd ("pipeline", no_class, nds32_pipeline_command,
+		  _("nds32-sid profiling commands."),
+		  &nds32_pipeline_cmdlist, "nds32 ", 0, &nds32_cmdlist);
+  add_cmd ("on", no_class, nds32_pipeline_on_command,
+	   _("Turn on pipeline for profiling."), &nds32_pipeline_cmdlist);
+  add_cmd ("off", no_class, nds32_pipeline_off_command,
+	   _("Turn off pipeline for profiling."), &nds32_pipeline_cmdlist);
+
+  /* nds32 query (profiling|perf-meter|target)  */
+  add_prefix_cmd ("query", no_class, nds32_query_command,
+		  _("Query remote data."), &nds32_query_cmdlist, "query ",
+		  0, &nds32_cmdlist);
+  add_cmd ("profiling", no_class, nds32_query_profiling_command,
+	   _("Query profiling results."), &nds32_query_cmdlist);
+  add_cmd ("perf-meter", no_class, nds32_query_perfmeter_command,
+	   _("Query perf-meter results."), &nds32_query_cmdlist);
+  add_cmd ("target", no_class, nds32_query_target_command,
+	   _("Query target information."), &nds32_query_cmdlist);
+
+  /* nds32 reset (profiling|perf-meter)  */
+  add_prefix_cmd ("reset", no_class, nds32_reset_command,
+		  _("Reset profiling."), &nds32_reset_cmdlist, "reset ",
+		  0, &nds32_cmdlist);
+  add_cmd ("profiling", no_class, nds32_reset_profiling_command,
+	   _("Query profiling results."), &nds32_reset_cmdlist);
+  add_cmd ("perf-meter", no_class, nds32_reset_perfmeter_command,
+	   _("Query perf-meter results."), &nds32_reset_cmdlist);
+
+  create_internalvar_type_lazy ("_nds32_target_type", &nds32_target_type_funcs,
+				NULL);
+}
diff --git a/gdb/nds32-remote.h b/gdb/nds32-remote.h
new file mode 100644
index 0000000..629f8b6
--- /dev/null
+++ b/gdb/nds32-remote.h
@@ -0,0 +1,28 @@
+/* Common target dependent code for GDB on nds32 systems.
+
+   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   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 NDS32_REMOTE_H
+#define NDS32_REMOTE_H
+
+void nds32_init_remote_cmds (void);
+void nds32_remote_breakpoint_from_pc (struct gdbarch *gdbarch,
+				      CORE_ADDR *pcptr, int *kindptr);
+
+#endif
diff --git a/gdb/nds32-tdep.c b/gdb/nds32-tdep.c
new file mode 100644
index 0000000..f861807
--- /dev/null
+++ b/gdb/nds32-tdep.c
@@ -0,0 +1,2802 @@
+/* Common target dependent code for GDB on nds32 systems.
+
+   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   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 <assert.h>
+#include <stdint.h>
+
+#include "defs.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "gdb_string.h"
+#include "value.h"
+#include "reggroups.h"
+#include "inferior.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "osabi.h"
+#include "language.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "trad-frame.h"
+#include "dis-asm.h"
+#include "gdb_assert.h"
+#include "user-regs.h"
+#include "elf-bfd.h"
+#include "dwarf2-frame.h"
+#include "ui-file.h"
+#include "remote.h"
+#include "target-descriptions.h"
+#include "sim-regno.h"
+#include "gdb/sim-nds32.h"
+
+#include "nds32-tdep.h"
+#include "nds32-utils.h"
+#include "nds32-remote.h"
+#include "elf/nds32.h"
+#include "opcode/nds32.h"
+
+/* Simple macro for chop LSB immediate bits from an instruction.  */
+#define CHOP_BITS(insn, n)	(insn & ~__MASK (n))
+
+extern void _initialize_nds32_tdep (void);
+
+struct nds32_gdb_config nds32_config;
+
+/* The standard register names.  */
+static char *nds32_regnames[] =
+{
+  /* 32 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", "fp", "gp", "lp", "sp",
+
+  /* 5 User Registers. */
+  "pc", "d0lo", "d0hi", "d1lo", "d1hi",
+};
+
+/* Mnemonic names for registers.  */
+struct nds32_register_alias
+{
+  const char *name;
+  const char *alias;
+};
+
+/* Register alias for user_reg_map_name_to_regnum ().  */
+struct nds32_register_alias nds32_register_aliases[] =
+{
+  {"r15", "ta"},
+  {"r26", "p0"},
+  {"r27", "p1"},
+  {"fp", "r28"},
+  {"gp", "r29"},
+  {"lp", "r30"},
+  {"sp", "r31"},
+
+  {"ir0", "psw"},
+  {"ir1", "ipsw"},
+  {"ir2", "p_psw"},
+  {"ir3", "ivb"},
+  {"ir4", "eva"},
+  {"ir5", "p_eva"},
+  {"ir6", "itype"},
+  {"ir7", "p_itype"},
+  {"ir8", "merr"},
+  {"ir9", "ipc"},
+  {"ir10", "p_ipc"},
+  {"ir11", "oipc"},
+  {"ir12", "p_p0"},
+  {"ir13", "p_p1"},
+  {"ir14", "int_mask"},
+  {"ir15", "int_pend"},
+
+  {"cr0", "cpu_ver"},
+  {"cr1", "icm_cfg"},
+  {"cr2", "dcm_cfg"},
+  {"cr3", "mmu_cfg"},
+  {"cr4", "msc_cfg"},
+  {"cr5", "core_id"},
+  {"cr6", "fucop_exist"},
+
+  {"mr0", "mmu_ctl"},
+  {"mr1", "l1_pptb"},
+  {"mr2", "tlb_vpn"},
+  {"mr3", "tlb_data"},
+  {"mr4", "tlb_misc"},
+  {"mr5", "vlpt_idx"},
+  {"mr6", "ilmb"},
+  {"mr7", "dlmb"},
+  {"mr8", "cache_ctl"},
+  {"mr9", "hsmp_saddr"},
+  {"mr10", "hsmp_eaddr"},
+
+  {"pfr0", "pfmc0"},
+  {"pfr1", "pfmc1"},
+  {"pfr2", "pfmc2"},
+  {"pfr3", "pfm_ctl"},
+
+  {"dmar0", "dma_cfg"},
+  {"dmar1", "dma_gcsw"},
+  {"dmar2", "dma_chnsel"},
+  {"dmar3", "dma_act"},
+  {"dmar4", "dma_setup"},
+  {"dmar5", "dma_isaddr"},
+  {"dmar6", "dma_esaddr"},
+  {"dmar7", "dma_tcnt"},
+  {"dmar8", "dma_status"},
+  {"dmar9", "dma_2dset"},
+  {"dmar10", "dma_2dsctl"},
+};
+
+/* Value of a register alias.  BATON is register name of the alias,
+   because system registers do not have fixed register number.
+   We must look-up them when access.  */
+
+static struct value *
+nds32_value_of_reg (struct frame_info *frame, const void *baton)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int regnum;
+
+  regnum = user_reg_map_name_to_regnum (gdbarch, (const char *) baton, -1);
+
+  return value_of_register (regnum, frame);
+}
+
+/* gdbarch_frame_align () */
+
+static CORE_ADDR
+nds32_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+  /* 8-byte aligned.  */
+  return sp & ~(8 - 1);
+}
+
+/* Implement the gdbarch_breakpoint_from_pc method.  */
+
+static const gdb_byte *
+nds32_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
+			  int *lenptr)
+{
+  static const gdb_byte NDS32_BREAK16[] = { 0xEA, 0x00 };
+  const unsigned char *bp;
+
+  gdb_assert (pcptr);
+  gdb_assert (lenptr);
+
+  if ((*pcptr) & 1)
+    error (_("Bad address %p for inserting breakpoint.\n"
+	     "Address must be at least 2-byte aligned."), (void *) *pcptr);
+
+  /* Always insert 16-bit break instruction.  */
+  *lenptr = 2;
+  return NDS32_BREAK16;
+}
+
+/* Implement the gdbarch_dwarf2_reg_to_regnum method.
+   Map DWARF regnum from GCC to GDB regnum.  */
+
+static int
+nds32_dwarf_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num)
+{
+  const int GPR = 0;
+  const int DXR = 34;
+  const int FSR = 38;
+  const int FDR = FSR + 32;
+
+  if (num >= 0 && num < 32)			/* R0 - R31 */
+    return num;
+  else if (num >= DXR && num < DXR + 4)		/* D0/D1 */
+    return num - DXR + NDS32_D0LO_REGNUM;
+  else if (num >= FSR && num < FSR + 32)	/* FS */
+    return num - FSR + user_reg_map_name_to_regnum (gdbarch, "fs0",
+						    strlen ("fs0"));
+  else if (num >= FDR && num < FDR + 32)	/* FD */
+    return num - FDR + user_reg_map_name_to_regnum (gdbarch, "fd0",
+						    strlen ("fd0"));
+
+  /* No match, return a inaccessible register number.  */
+  return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
+}
+
+static int
+nds32_register_sim_regno (struct gdbarch *gdbarch, int regnum)
+{
+  const char *reg_name;
+  /* Use target-descriptions for register mapping. */
+
+  /* Only makes sense to supply raw registers.  */
+  gdb_assert (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch));
+
+  if (regnum < NDS32_NUM_REGS)
+    return regnum;
+  if (regnum >= NDS32_SIM_FD0_REGNUM && regnum < NDS32_SIM_FD0_REGNUM + 32)
+    return SIM_NDS32_FD0_REGNUM + regnum - NDS32_SIM_FD0_REGNUM;
+  switch (regnum)
+    {
+    case NDS32_SIM_IFCLP_REGNUM:
+      return SIM_NDS32_IFCLP_REGNUM;
+    case NDS32_SIM_ITB_REGNUM:
+      return SIM_NDS32_ITB_REGNUM;
+    case NDS32_SIM_PSW_REGNUM:
+      return SIM_NDS32_PSW_REGNUM;
+    }
+
+  return LEGACY_SIM_REGNO_IGNORE;
+}
+
+/* Create types for registers and insert them to type table by name.  */
+
+static void
+nds32_alloc_types (struct gdbarch *gdbarch)
+{
+  const struct builtin_type *bt = builtin_type (gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct type *type, *stype1, *stype2;
+
+  tdep->type_tab = nds32_alloc_type_tab (24);
+
+  /* fucpr */
+  type = arch_flags_type (gdbarch, "builtin_type_nds32_fucpr", 4);
+  append_flags_type_flag (type, 0, "CP0EN");
+  append_flags_type_flag (type, 1, "CP1EN");
+  append_flags_type_flag (type, 2, "CP2EN");
+  append_flags_type_flag (type, 3, "CP3EN");
+  append_flags_type_flag (type, 31, "AUEN");
+  nds32_type_insert (tdep->type_tab, "fucpr", type);
+
+  /* fpcfg */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_fpcfg");
+  nds32_append_enum (type, 0, "8SP_4DP");
+  nds32_append_enum (type, 1, "16SP_8DP");
+  nds32_append_enum (type, 2, "32SP_16DP");
+  nds32_append_enum (type, 3, "32SP_32DP");
+  stype1 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_fpcfg_type", USE_FLAGS);
+  nds32_append_flag (type, 0, "SP");
+  nds32_append_flag (type, 1, "DP");
+  nds32_append_bitfield (type, stype1, 2, 3, "FREG");
+  nds32_append_flag (type, 4, "FMA");
+  nds32_append_bitfield (type, bt->builtin_uint8, 22, 26, "IMVER");
+  nds32_append_bitfield (type, bt->builtin_uint8, 27, 31, "AVER");
+  nds32_type_insert (tdep->type_tab, "fpcfg", type);
+
+  /* fpcsr */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_fpcsr_rm");
+  nds32_append_enum (type, 0, "RTNE");
+  nds32_append_enum (type, 1, "RTPI");
+  nds32_append_enum (type, 2, "RTMI");
+  nds32_append_enum (type, 3, "RTZ");
+  stype1 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_fpcsr", USE_FLAGS);
+  nds32_append_bitfield (type, stype1, 0, 1, "RM");
+  nds32_append_flag (type, 2, "IVO");
+  nds32_append_flag (type, 3, "DBZ");
+  nds32_append_flag (type, 4, "OVF");
+  nds32_append_flag (type, 5, "UDF");
+  nds32_append_flag (type, 6, "IEX");
+  nds32_append_flag (type, 7, "IVOE");
+  nds32_append_flag (type, 8, "DBZE");
+  nds32_append_flag (type, 9, "OVFE");
+  nds32_append_flag (type, 10, "UDFE");
+  nds32_append_flag (type, 11, "IEXE");
+  nds32_append_flag (type, 12, "DNZ");
+  nds32_append_flag (type, 13, "IVOT");
+  nds32_append_flag (type, 14, "DBZT");
+  nds32_append_flag (type, 15, "OVFT");
+  nds32_append_flag (type, 16, "UDFT");
+  nds32_append_flag (type, 17, "IEXT");
+  nds32_append_flag (type, 18, "DNIT");
+  nds32_append_flag (type, 19, "RIT");
+  nds32_type_insert (tdep->type_tab, "fpcsr", type);
+
+  /* ir0 - processor status word register
+     ir1 - interruption PSW register
+     ir2 - previous IPSW register */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_psw_intl");
+  nds32_append_enum (type, 0, "NO");
+  nds32_append_enum (type, 1, "Lv1");
+  nds32_append_enum (type, 2, "Lv2");
+  nds32_append_enum (type, 3, "Lv3");
+  stype1 = type;
+
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_psw_pow");
+  nds32_append_enum (type, 0, "User");
+  nds32_append_enum (type, 1, "Superuser");
+  nds32_append_enum (type, 2, "Reserved(2)");
+  nds32_append_enum (type, 3, "Reserved(3)");
+  stype2 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_psw", USE_FLAGS);
+  nds32_append_flag (type, 0, "GIE");
+  nds32_append_bitfield (type, stype1, 1, 2, "INTL");
+  nds32_append_bitfield (type, stype2, 3, 4, "POM");
+  nds32_append_flag (type, 5, "BE");
+  nds32_append_flag (type, 6, "IT");
+  nds32_append_flag (type, 7, "DT");
+  nds32_append_flag (type, 8, "IME");
+  nds32_append_flag (type, 9, "DME");
+  nds32_append_flag (type, 10, "DEX");
+  nds32_append_flag (type, 11, "HSS");
+  nds32_append_flag (type, 12, "DRBE");
+  nds32_append_flag (type, 13, "AEN");
+  nds32_append_flag (type, 14, "WBNA");
+  nds32_append_flag (type, 15, "IFCON");
+  nds32_append_flag (type, 20, "OV");
+  nds32_type_insert (tdep->type_tab, "ir0", type);
+  nds32_type_insert (tdep->type_tab, "ir1", type);
+  nds32_type_insert (tdep->type_tab, "ir2", type);
+
+  /* ir3 - Interrupt Vector Base Register */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_ivb_esz");
+  nds32_append_enum (type, 0, "4_byte");
+  nds32_append_enum (type, 1, "16_byte");
+  nds32_append_enum (type, 2, "64_byte");
+  nds32_append_enum (type, 3, "256_byte");
+  stype1 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_ivb", USE_FLAGS);
+  nds32_append_flag (type, 13, "EVIC");
+  nds32_append_bitfield (type, stype1, 14, 15, "ESZ");
+  nds32_append_bitfield (type, bt->builtin_uint16, 16, 31, "IVBASE");
+  nds32_type_insert (tdep->type_tab, "ir3", type);
+
+  /* ir6 - Interruption Type Register
+     ir7 - Previous ITYPE */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_itype", USE_FLAGS);
+  nds32_append_bitfield (type, bt->builtin_uint8, 0, 3, "ETYPE");
+  nds32_append_flag (type, 4, "INST");
+  nds32_append_bitfield (type, bt->builtin_uint16, 16, 30, "SWID");
+  nds32_type_insert (tdep->type_tab, "ir6", type);
+  nds32_type_insert (tdep->type_tab, "ir7", type);
+
+  /* ir14 - Interruption Masking Register */
+  type = arch_flags_type (gdbarch, "builtin_type_nds32_int_mask", 4);
+  append_flags_type_flag (type, 0, "H0IM");
+  append_flags_type_flag (type, 1, "H1IM");
+  append_flags_type_flag (type, 2, "H2IM");
+  append_flags_type_flag (type, 3, "H3IM");
+  append_flags_type_flag (type, 4, "H4IM");
+  append_flags_type_flag (type, 5, "H5IM");
+  append_flags_type_flag (type, 16, "SIM");
+  append_flags_type_flag (type, 29, "ALZ");
+  append_flags_type_flag (type, 30, "IDIVZE");
+  append_flags_type_flag (type, 31, "DSSIM");
+  nds32_type_insert (tdep->type_tab, "ir14", type);
+
+  /* ir18 - Interruption Prioirty Register */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_int_pri", NO_FLAGS);
+  nds32_append_bitfield (type, bt->builtin_uint8, 0, 1, "H0PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 2, 3, "H1PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 4, 5, "H2PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 6, 7, "H3PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 8, 9, "H4PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 10, 11, "H5PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 12, 13, "H6PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 14, 15, "H7PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 16, 17, "H8PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 18, 19, "H9PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 20, 21, "H10PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 22, 23, "H11PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 24, 25, "H12PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 26, 27, "H13PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 28, 29, "H14PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 30, 31, "H15PRI");
+  nds32_type_insert (tdep->type_tab, "ir18", type);
+
+  /* mr0 - MMU Control Register */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_mmuctl_ntc");
+  nds32_append_enum (type, 0, "NCA_NCO");
+  nds32_append_enum (type, 1, "NCA_CO");
+  nds32_append_enum (type, 2, "CA_WB");
+  nds32_append_enum (type, 3, "CA_WT");
+  stype1 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_mmu_ctl", USE_FLAGS);
+  nds32_append_flag (type, 0, "D");
+  nds32_append_bitfield (type, stype1, 1, 2, "NTC0");
+  nds32_append_bitfield (type, stype1, 3, 4, "NTC1");
+  nds32_append_bitfield (type, stype1, 5, 6, "NTC2");
+  nds32_append_bitfield (type, stype1, 7, 8, "NTC3");
+  nds32_append_flag (type, 9, "TBALCK");
+  nds32_append_flag (type, 10, "MPZIU");
+  nds32_append_bitfield (type, bt->builtin_uint8, 11, 12, "NTM0");
+  nds32_append_bitfield (type, bt->builtin_uint8, 13, 14, "NTM1");
+  nds32_append_bitfield (type, bt->builtin_uint8, 15, 16, "NTM2");
+  nds32_append_bitfield (type, bt->builtin_uint8, 17, 18, "NTM3");
+  nds32_append_flag (type, 19, "DREE");
+  nds32_type_insert (tdep->type_tab, "mr0", type);
+
+  /* mr1 */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_l1_pptb", USE_FLAGS);
+  nds32_append_flag (type, 0, "NV");
+  nds32_append_bitfield (type, bt->builtin_uint32, 12, 31, "L1_PPT_BASE");
+  nds32_type_insert (tdep->type_tab, "mr1", type);
+
+  /* mr2 */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_tlb_vpn", NO_FLAGS);
+  nds32_append_bitfield (type, bt->builtin_uint32, 12, 31, "VPN");
+  nds32_type_insert (tdep->type_tab, "mr2", type);
+
+  /* mr3 */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_tlb_data", USE_FLAGS);
+  nds32_append_flag (type, 0, "V");
+  nds32_append_bitfield (type, bt->builtin_uint8, 1, 3, "M");
+  nds32_append_flag (type, 4, "D");
+  nds32_append_flag (type, 5, "X");
+  nds32_append_flag (type, 6, "A");
+  nds32_append_flag (type, 7, "G");
+  nds32_append_bitfield (type, bt->builtin_uint8, 8, 10, "C");
+  nds32_append_bitfield (type, bt->builtin_uint32, 12, 31, "PPN");
+  nds32_type_insert (tdep->type_tab, "mr3", type);
+
+  /* mr4 - TLB Access Misc Register */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_tlb_misc_acc_psz");
+  nds32_append_enum (type, 0, "4KB");
+  nds32_append_enum (type, 1, "8KB");
+  nds32_append_enum (type, 2, "16KB");
+  nds32_append_enum (type, 3, "64KB");
+  nds32_append_enum (type, 4, "256KB");
+  nds32_append_enum (type, 5, "1MB");
+  nds32_append_enum (type, 6, "4MB");
+  nds32_append_enum (type, 7, "16MB");
+  nds32_append_enum (type, 8, "64MB");
+  nds32_append_enum (type, 9, "256MB");
+  stype1 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_tlb_misc", NO_FLAGS);
+  nds32_append_bitfield (type, stype1, 0, 3, "ACC_PSZ");
+  nds32_append_bitfield (type, bt->builtin_uint32, 4, 12, "CID");
+  nds32_type_insert (tdep->type_tab, "mr4", type);
+
+  /* mr6 */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_ilm_size");
+  nds32_append_enum (type, 0, "4KB");
+  nds32_append_enum (type, 1, "8KB");
+  nds32_append_enum (type, 2, "16KB");
+  nds32_append_enum (type, 3, "32KB");
+  nds32_append_enum (type, 4, "64KB");
+  nds32_append_enum (type, 5, "128KB");
+  nds32_append_enum (type, 6, "256KB");
+  nds32_append_enum (type, 7, "512KB");
+  nds32_append_enum (type, 8, "1024KB");
+  nds32_append_enum (type, 9, "1KB");
+  nds32_append_enum (type, 10, "2KB");
+  nds32_append_enum (type, 15, "0KB");
+  stype1 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_ilmb", NO_FLAGS);
+  nds32_append_bitfield (type, bt->builtin_uint8, 0, 0, "IEN");
+  nds32_append_bitfield (type, stype1, 1, 4, "ILMSZ");
+  nds32_append_bitfield (type, bt->builtin_data_ptr, 0, 31, "(raw)");
+  nds32_type_insert (tdep->type_tab, "mr6", type);
+
+  /* mr7 */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_dlm_size");
+  nds32_append_enum (type, 0, "4KB");
+  nds32_append_enum (type, 1, "8KB");
+  nds32_append_enum (type, 2, "16KB");
+  nds32_append_enum (type, 3, "32KB");
+  nds32_append_enum (type, 4, "64KB");
+  nds32_append_enum (type, 5, "128KB");
+  nds32_append_enum (type, 6, "256KB");
+  nds32_append_enum (type, 7, "512KB");
+  nds32_append_enum (type, 8, "1024KB");
+  nds32_append_enum (type, 9, "1KB");
+  nds32_append_enum (type, 10, "2KB");
+  nds32_append_enum (type, 15, "0KB");
+  stype1 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_dlmb", NO_FLAGS);
+  nds32_append_bitfield (type, bt->builtin_uint8, 0, 0, "DEN");
+  nds32_append_bitfield (type, stype1, 1, 4, "DLMSZ");
+  nds32_append_bitfield (type, bt->builtin_uint8, 5, 5, "DBM");
+  nds32_append_bitfield (type, bt->builtin_uint8, 6, 6, "DBB");
+  nds32_append_bitfield (type, bt->builtin_data_ptr, 0, 31, "(raw)");
+  nds32_type_insert (tdep->type_tab, "mr7", type);
+
+  /* mr8 - Cache Control Register */
+  type = arch_flags_type (gdbarch, "builtin_type_nds32_cache_ctl", 4);
+  append_flags_type_flag (type, 0, "IC_EN");
+  append_flags_type_flag (type, 1, "DC_EN");
+  append_flags_type_flag (type, 2, "ICALCK");
+  append_flags_type_flag (type, 3, "DCALCK");
+  append_flags_type_flag (type, 4, "DCCWF");
+  append_flags_type_flag (type, 5, "DCPMW");
+  nds32_type_insert (tdep->type_tab, "mr8", type);
+
+  /* dr40 - EDM Configuration Register */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_edm_cfg", USE_FLAGS);
+  nds32_append_bitfield (type, bt->builtin_uint8, 0, 2, "BC");
+  nds32_append_flag (type, 3, "DIMU");
+  nds32_append_flag (type, 4, "DALM");
+  nds32_append_bitfield (type, bt->builtin_uint16, 16, 31, "VER");
+  nds32_type_insert (tdep->type_tab, "dr40", type);
+
+  /* dmar0 - DMA Configuration Register */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_dma_cfg", USE_FLAGS);
+  nds32_append_bitfield (type, bt->builtin_uint8, 0, 1, "NCHN");
+  nds32_append_flag (type, 2, "UNEA");
+  nds32_append_flag (type, 3, "2DET");
+  nds32_append_bitfield (type, bt->builtin_uint16, 16, 31, "VER");
+  nds32_type_insert (tdep->type_tab, "dmar0", type);
+
+  /* cr0 - CPU Version Register */
+  type = arch_flags_type (gdbarch, "builtin_type_nds32_cpuver_cfgid", 2);
+  append_flags_type_flag (type, 0, "PERF_EXT");
+  append_flags_type_flag (type, 1, "16_EXT");
+  append_flags_type_flag (type, 2, "PERF_EXT2");
+  append_flags_type_flag (type, 3, "COP_EXT");
+  append_flags_type_flag (type, 4, "STR_EXT");
+  stype1 = type;
+
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_cpuver_cpuid");
+  nds32_append_enum (type, 0x8, "N8");
+  nds32_append_enum (type, 0x9, "N9");
+  nds32_append_enum (type, 0xA, "N10");
+  nds32_append_enum (type, 0xC, "N12");
+  nds32_append_enum (type, 0xD, "N13");
+  nds32_append_enum (type, 0xE, "N14");
+  stype2 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_cpuver", NO_FLAGS);
+  nds32_append_bitfield (type, stype1, 0, 15, "CFGID");
+  nds32_append_bitfield (type, bt->builtin_uint8, 16, 23, "REV");
+  nds32_append_bitfield (type, stype2, 24, 31, "CPUID");
+  nds32_type_insert (tdep->type_tab, "cr0", type);
+
+  /* cr4 - Misc Configuration Register */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_msc_cfg", USE_FLAGS);
+  nds32_append_flag (type, 0, "EDM");
+  nds32_append_flag (type, 1, "LMDMA");
+  nds32_append_flag (type, 2, "PFM");
+  nds32_append_flag (type, 3, "HSMP");
+  nds32_append_flag (type, 4, "TRACE");
+  nds32_append_flag (type, 5, "DIV");
+  nds32_append_flag (type, 6, "MAC");
+  nds32_append_bitfield (type, bt->builtin_uint8, 7, 8, "AUDIO");
+  nds32_append_flag (type, 9, "L2c");
+  nds32_append_flag (type, 10, "RDREG");
+  nds32_append_flag (type, 11, "ADR24");
+  nds32_append_flag (type, 12, "INTLC");
+  nds32_append_bitfield (type, bt->builtin_uint8, 13, 15, "BASEV");
+  nds32_append_flag (type, 16, "NOD");
+  nds32_append_flag (type, 17, "IMV");
+  nds32_append_flag (type, 18, "IMR");
+  nds32_append_flag (type, 19, "IFC");
+  nds32_append_flag (type, 20, "MCU");
+  nds32_type_insert (tdep->type_tab, "cr4", type);
+
+  /* cr6 - FPU and Coprocessor Existence Configuration Register */
+  type = arch_flags_type (gdbarch, "builtin_type_nds32_fucop_exist", 4);
+  append_flags_type_flag (type, 0, "CP0EX");
+  append_flags_type_flag (type, 1, "CP1EX");
+  append_flags_type_flag (type, 2, "CP2EX");
+  append_flags_type_flag (type, 3, "CP3EX");
+  append_flags_type_flag (type, 31, "AUEX");
+  nds32_type_insert (tdep->type_tab, "cr6", type);
+}
+
+/* gdbarch_register_type ()
+
+   Return the GDB type object for the "standard" data type
+   of data in register N.
+   It get pretty messy here. I need enum-types and bit-fields
+   for better representation. But they cannot be done by
+   tdesc-xml.  */
+
+static struct type *
+nds32_register_type (struct gdbarch *gdbarch, int regnum)
+{
+  int num_regs = gdbarch_num_regs (gdbarch);
+  const struct builtin_type *bt = builtin_type (gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct type *type;
+  const char *reg_name;
+
+  /* Currently, only FSR are supported.  */
+  if (regnum >= num_regs && regnum < num_regs + 32)
+    return builtin_type (gdbarch)->builtin_float;
+  else if (regnum >= num_regs)
+    return NULL;
+
+  /* NDS32 predefined types for specific registers.  */
+  if (tdep->type_tab == NULL)
+    nds32_alloc_types (gdbarch);
+
+  reg_name = user_reg_map_regnum_to_name (gdbarch, regnum);
+  if (reg_name == NULL)
+    reg_name = "";
+  type = nds32_type_lookup (tdep->type_tab, reg_name);
+  if (type)
+    return type;
+
+  /* Type provided by target-description.  */
+  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+    {
+      type = tdesc_register_type (gdbarch, regnum);
+      if (type)
+	return type;
+    }
+
+  /* Floating pointer registers. e.g., fs0 or fd0.  */
+  if (strlen (reg_name) >= 3 && reg_name[0] == 'f' && reg_name[2] >= '0'
+      && reg_name[2] <= '9')
+    {
+      if (reg_name[1] == 's')
+	return bt->builtin_float;
+      else if (reg_name[1] == 'd')
+	return bt->builtin_double;
+    }
+
+  /* GPRs.  */
+  if (regnum == NDS32_PC_REGNUM || regnum == NDS32_LP_REGNUM)
+    return bt->builtin_func_ptr;
+  else if (regnum == NDS32_SP_REGNUM || regnum == NDS32_FP_REGNUM
+	   || regnum == NDS32_GP_REGNUM)
+    return bt->builtin_data_ptr;
+  else if (regnum < 32)
+    return bt->builtin_int32;
+
+  /* We don't know.  Display it in hex-form.  */
+  return bt->builtin_data_ptr;
+}
+
+/* nds32 register groups.  */
+static struct reggroup *nds32_cr_reggroup;
+static struct reggroup *nds32_ir_reggroup;
+static struct reggroup *nds32_mr_reggroup;
+static struct reggroup *nds32_dr_reggroup;
+static struct reggroup *nds32_pfr_reggroup;
+static struct reggroup *nds32_dmar_reggroup;
+static struct reggroup *nds32_racr_reggroup;
+static struct reggroup *nds32_idr_reggroup;
+static struct reggroup *nds32_audio_reggroup;
+
+static void
+nds32_init_reggroups (void)
+{
+  /* gpr usr sr */
+  nds32_cr_reggroup = reggroup_new ("cr", USER_REGGROUP);
+  nds32_ir_reggroup = reggroup_new ("ir", USER_REGGROUP);
+  nds32_mr_reggroup = reggroup_new ("mr", USER_REGGROUP);
+  nds32_dr_reggroup = reggroup_new ("dr", USER_REGGROUP);
+  nds32_pfr_reggroup = reggroup_new ("pfr", USER_REGGROUP);
+  nds32_dmar_reggroup = reggroup_new ("dmar", USER_REGGROUP);
+  nds32_racr_reggroup = reggroup_new ("racr", USER_REGGROUP);
+  nds32_idr_reggroup = reggroup_new ("idr", USER_REGGROUP);
+
+  nds32_audio_reggroup = reggroup_new ("audio", USER_REGGROUP);
+}
+
+static void
+nds32_add_reggroups (struct gdbarch *gdbarch)
+{
+  /* Target-independent groups.  */
+  reggroup_add (gdbarch, general_reggroup);
+  reggroup_add (gdbarch, float_reggroup);
+  reggroup_add (gdbarch, all_reggroup);
+  reggroup_add (gdbarch, system_reggroup);
+
+  /* System register groups.  */
+  reggroup_add (gdbarch, nds32_cr_reggroup);
+  reggroup_add (gdbarch, nds32_ir_reggroup);
+  reggroup_add (gdbarch, nds32_mr_reggroup);
+  reggroup_add (gdbarch, nds32_dr_reggroup);
+  reggroup_add (gdbarch, nds32_pfr_reggroup);
+  reggroup_add (gdbarch, nds32_dmar_reggroup);
+  reggroup_add (gdbarch, nds32_racr_reggroup);
+  reggroup_add (gdbarch, nds32_idr_reggroup);
+}
+
+/* Implement the gdbarch_register_reggroup_p method.  */
+
+static int
+nds32_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+			   struct reggroup *group)
+{
+  int i;
+  struct reggroup *groups[] =
+  {
+      nds32_cr_reggroup, nds32_ir_reggroup, nds32_mr_reggroup,
+      nds32_dr_reggroup, nds32_pfr_reggroup, nds32_dmar_reggroup,
+      nds32_racr_reggroup, nds32_idr_reggroup
+  };
+  static const char *prefix[] =
+  {
+      "cr", "ir", "mr", "dr", "pfr", "dmar", "racr", "idr"
+  };
+
+  gdb_assert (sizeof (groups) == sizeof (prefix));
+
+  /* GPRs. */
+  if (group == general_reggroup)
+    return regnum <= NDS32_PC_REGNUM;
+
+  /* System Registers are grouped by prefix.  */
+  else if (group == system_reggroup)
+    return (regnum > NDS32_PC_REGNUM)
+	   && TYPE_CODE (register_type (gdbarch, regnum)) != TYPE_CODE_FLT;
+
+  for (i = 0; i < ARRAY_SIZE (groups); i++)
+    {
+      if (group == groups[i])
+	{
+	  const char *regname = tdesc_register_name (gdbarch, regnum);
+
+	  if (!regname)
+	    return 0;
+	  return strstr (regname, prefix[i]) == regname;
+	}
+    }
+
+  return default_register_reggroup_p (gdbarch, regnum, group);
+}
+
+/* This function is called when
+   1. Target-description is used, and the register is pseudo.
+   2. Target-description is NOT used,
+       i. and the target is simulator.
+      ii. or the target is legacy target.  */
+
+/* Implement the tdesc_pseudo_register_name method.  */
+
+static const char *
+nds32_register_name (struct gdbarch *gdbarch, int regnum)
+{
+  static char *fpu_pseudo_names[] =
+  {
+    "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
+    "fs8", "fs9", "fs10", "fs11", "fs12", "fs13", "fs14", "fs15",
+    "fs16", "fs17", "fs18", "fs19", "fs20", "fs21", "fs22", "fs23",
+    "fs24", "fs25", "fs26", "fs27", "fs28", "fs29", "fs30", "fs31"
+  };
+  static char *sim_names[] =
+  {
+    "fd0", "fd1", "fd2", "fd3", "fd4", "fd5", "fd6", "fd7",
+    "fd8", "fd9", "fd10", "fd11", "fd12", "fd13", "fd14", "fd15",
+    "fd16", "fd17", "fd18", "fd19", "fd20", "fd21", "fd22", "fd23",
+    "fd24", "fd25", "fd26", "fd27", "fd28", "fd29", "fd30", "fd31",
+    "ifclp", "itb", "ir0"
+  };
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int num_regs = gdbarch_num_regs (gdbarch);
+
+  /* Currently, only pseudo FSR are supported.  */
+  if (regnum >= num_regs && regnum < num_regs + 32)
+    return fpu_pseudo_names[regnum - num_regs];
+
+  /* GPRs.  */
+  if (regnum < ARRAY_SIZE (nds32_regnames))
+    return nds32_regnames[regnum];
+
+  /* Registers beteen NUM_REGS and SMI_NUM_REGS are
+     simulator registers.  */
+  if (regnum >= NDS32_NUM_REGS && regnum < NDS32_SIM_NUM_REGS)
+    return sim_names[regnum - NDS32_NUM_REGS];
+
+  warning (_("Unknown nds32 pseudo register %d."), regnum);
+  return NULL;
+}
+
+/* Implement the gdbarch_pseudo_register_read method.
+
+   For legacy target, target-description and FPRs are not support.
+   Use Rcmd to access FPU registers.  */
+
+static enum register_status
+nds32_pseudo_register_read (struct gdbarch *gdbarch,
+			    struct regcache *regcache, int regnum,
+			    gdb_byte *buf)
+{
+  char name_buf[8];
+  gdb_byte reg_buf[8];
+  int offset;
+  enum register_status status = REG_UNKNOWN;
+
+  /* Sanity check.  */
+  regnum -= gdbarch_num_regs (gdbarch);
+  if (regnum > gdbarch_num_pseudo_regs (gdbarch))
+    return status;
+
+  /* Currently, only FSR are supported.  */
+  if (regnum < 32)
+    {
+      int fd_regnum;
+
+      /* fs0 is always the high-part of fd0.  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	offset = (regnum & 1) ? 4 : 0;
+      else
+	offset = (regnum & 1) ? 0 : 4;
+
+      sprintf (name_buf, "fd%d", regnum >> 1);
+      fd_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+					       strlen (name_buf));
+      status = regcache_raw_read (regcache, fd_regnum, reg_buf);
+      if (status == REG_VALID)
+	memcpy (buf, reg_buf + offset, 4);
+    }
+
+  return status;
+}
+
+/* Implement the gdbarch_pseudo_register_write method.  */
+
+static void
+nds32_pseudo_register_write (struct gdbarch *gdbarch,
+			     struct regcache *regcache, int regnum,
+			     const gdb_byte *buf)
+{
+  char name_buf[8];
+  gdb_byte reg_buf[8];
+  int offset;
+
+  /* Sanity check.  */
+  regnum -= gdbarch_num_regs (gdbarch);
+  if (regnum > gdbarch_num_pseudo_regs (gdbarch))
+    return;
+
+  /* Currently, only FSR are supported.  */
+  if (regnum < 32)
+    {
+      int fd_regnum;
+
+      /* fs0 is always the high-part of fd0.  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	offset = (regnum & 1) ? 4 : 0;
+      else
+	offset = (regnum & 1) ? 0 : 4;
+
+      sprintf (name_buf, "fd%d", regnum >> 1);
+      fd_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+					       strlen (name_buf));
+      regcache_raw_read (regcache, fd_regnum, reg_buf);
+      memcpy (reg_buf + offset, buf, 4);
+      regcache_raw_write (regcache, fd_regnum, reg_buf);
+    }
+
+  return;
+}
+
+/* Skip prologue should be conservative, and frame-unwind should be
+   relative-aggressive.*/
+
+static int
+nds32_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
+			CORE_ADDR scan_limit, CORE_ADDR *pl_endptr)
+{
+  uint32_t insn;
+  CORE_ADDR cpc = -1;		/* Candidate PC if no suitable PC is found.  */
+  LONGEST return_value;
+
+  /* If there is no buffer to store result, ignore this prologue decoding.  */
+  if (pl_endptr == NULL)
+    {
+      return 0;
+    }
+
+  /* Look up end of prologue */
+  for (; pc < scan_limit; )
+    {
+      insn = read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG);
+
+      if ((insn & 0x80000000) == 0)
+	{
+	  /* 32-bit instruction */
+
+	  pc += 4;
+	  if (insn == N32_ALU1 (ADD, REG_GP, REG_TA, REG_GP))
+	    {
+	      /* add $gp, $ta, $gp */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ADDI, REG_SP, REG_SP, 0))
+	    {
+	      /* addi $sp, $sp, imm15 */
+	      cpc = pc;
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ADDI, REG_FP, REG_FP, 0))
+	    {
+	      /* addi $fp, $sp, imm15 */
+	      cpc = pc;
+	      continue;
+	    }
+	  else if (insn == N32_ALU2 (MFUSR, REG_TA, 31, 0))
+	    {
+	      /* mfusr $ta, PC  ; group=0, sub=0x20=mfusr */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 20) == N32_TYPE1 (MOVI, REG_TA, 0))
+	    {
+	      /* movi $ta, imm20s */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 20) == N32_TYPE1 (SETHI, REG_GP, 0))
+	    {
+	      /* sethi $gp, imm20 */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ORI, REG_GP, REG_GP, 0))
+	    {
+	      /* ori $gp, $gp, imm15 */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI, REG_LP, REG_FP, 0))
+	    {
+	      /* Unlike swi, we should stop when lwi.  */
+	      /* swi $lp, [$sp + (imm15s<<2)] */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI_BI, REG_LP, REG_FP, 0))
+	    {
+	      /* swi.bi $rt, [$sp], (imm15s<<2) */
+	      continue;
+	    }
+	  else if (N32_OP6 (insn) == N32_OP6_LSMW && (insn & __BIT (5)))
+	    {
+	      /* bit-5 for SMW */
+
+	      /* smwa?.(a|b)(d|i)m? rb,[ra],re,enable4 */
+
+	      int rb, re, ra, enable4, i;
+	      int aligned;
+	      int m = 0;
+	      int di;		/* dec=-1 or inc=1 */
+	      char enb4map[2][4] = {
+		  {0, 1, 2, 3} /* smw */,
+		  {3, 1, 2, 0} /* smwa */};
+	      LONGEST base = ~1 + 1;
+
+	      rb = N32_RT5 (insn);
+	      ra = N32_RA5 (insn);
+	      re = N32_RB5 (insn);
+	      enable4 = (insn >> 6) & 0x0F;
+	      aligned = (insn & 3) ? 1 : 0;
+	      di = (insn & (1 << 3)) ? -1 : 1;
+
+	      switch (ra)
+		{
+		case NDS32_FP_REGNUM:
+		case NDS32_SP_REGNUM:
+		  cpc = pc;
+		  continue; /* found and continue */
+		default:
+		  break;
+		}
+	    }
+
+	  if (N32_OP6 (insn) == N32_OP6_COP && N32_COP_CP (insn) == 0
+	      && (N32_COP_SUB (insn) == N32_FPU_FSS
+		  || N32_COP_SUB (insn) == N32_FPU_FSD)
+	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
+	    {
+	      /* CP shoud be CP0 */
+	      /* fs[sd][.bi] $fst, [$sp + ($r0 << sv)] */
+	      continue;
+	    }
+
+	  /* fssi    $fst, [$ra + (imm12s << 2)]
+	     fssi.bi $fst, [$ra], (imm12s << 2)
+	     fsdi    $fdt, [$ra + (imm12s << 2)]
+	     fsdi.bi $fdt, [$ra], (imm12s << 2) */
+	  if ((N32_OP6 (insn) == N32_OP6_SWC || N32_OP6 (insn) == N32_OP6_SDC)
+	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
+	    {
+	      /* BI bit is dont-care.  */
+	      continue;
+	    }
+
+	  pc -= 4;
+	  break;
+	}
+      else
+	{
+	  /* 16-bit instruction */
+	  pc += 2;
+	  insn >>= 16;
+
+	  /* 1. If the instruction is j/b, then we stop
+		i.e., OP starts with 10, and beqzs8, bnezs8.
+	     2. If the operations will change sp/fp or based on sp/fp,
+		then we are in the prologue.
+	     3. If we don't know what's it, then stop.  */
+
+	  if (CHOP_BITS (insn, 10) == N16_TYPE10 (ADDI10S, 0))
+	    {
+	      /* addi10s */
+	      continue;
+	    }
+	  else if (__GF (insn, 7, 8) == N16_T25_PUSH25)
+	    {
+	      /* push25 */
+	      continue;
+	    }
+	  else if (insn == N16_TYPE55 (MOV55, REG_FP, REG_SP))
+	    {
+	      /* mov55 fp, sp */
+	      continue;
+	    }
+
+	  /* swi450 */
+	  switch (insn & ~__MF (-1, 5, 4))
+	    {
+	      case N16_TYPE45 (SWI450, 0, REG_SP):
+	      case N16_TYPE45 (SWI450, 0, REG_FP):
+		break;
+	    }
+	  /* swi37 - implied fp */
+	  if (__GF (insn, 11, 4) == N16_T37_XWI37
+	      && (insn & __BIT (7)))
+	    continue;
+
+	  /* swi37sp - implied */
+	  if (__GF (insn, 11, 4) == N16_T37_XWI37SP
+	      && (insn & __BIT (7)))
+	    continue;
+
+	  /* If the a instruction is not accepted,
+	     don't go futher.  */
+	  pc -= 2;
+	  break;
+	}
+    }
+
+  if (pc >= scan_limit)
+    {
+      /* If we can not find end of prologue before scan_limit,
+	 we assume that end of prologue is on pc_after_stack_adject. */
+      if (cpc != -1)
+	pc = cpc;
+    }
+
+  *pl_endptr = pc;
+
+  return 0;
+}
+
+/* Implement the gdbarch_skip_prologue method.
+
+   Find the end of function prologue.  */
+
+static CORE_ADDR
+nds32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR func_addr, func_end;
+  struct symtab_and_line sal = { 0 };
+  LONGEST return_value;
+  const char *func_name;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  const int search_limit = 128;
+
+  /* See what the symbol table says */
+  if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
+    {
+      sal = find_pc_line (func_addr, 0);
+
+      if (sal.line != 0 && sal.end <= func_end)
+	{
+	  func_end = sal.end;
+	}
+      else
+	{
+	  /* Either there's no line info, or the line after the prologue
+	     is after the end of the function.  In this case, there probably
+	     isn't a prologue.  */
+	  func_end = min (func_end, func_addr + search_limit);
+	}
+    }
+  else
+    func_end = pc + search_limit;
+
+  /* If current instruction is not readable, just quit.  */
+  if (!safe_read_memory_integer (pc, 4, byte_order, &return_value))
+    return pc;
+
+  /* Find the end of prologue.  */
+  if (nds32_analyze_prologue (gdbarch, pc, func_end, &sal.end) < 0)
+    return pc;
+
+  return sal.end;
+}
+
+struct nds32_unwind_cache
+{
+  /* The previous frame's inner most stack address.
+     Used as this frame ID's stack_addr.  */
+  CORE_ADDR prev_sp;
+
+  /* The frame's base, optionally used by the high-level debug info.  */
+  CORE_ADDR base;
+  int size;
+
+  /* How far the SP and FP have been offset from the start of
+     the stack frame (as defined by the previous frame's stack
+     pointer).  */
+  LONGEST sp_offset;
+  LONGEST fp_offset;
+  int use_frame;
+
+  /* Table indicating the location of each and every register.  */
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+static struct nds32_unwind_cache *
+nds32_alloc_frame_cache (struct frame_info *this_frame)
+{
+  struct nds32_unwind_cache *cache;
+  cache = FRAME_OBSTACK_ZALLOC (struct nds32_unwind_cache);
+
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+  cache->size = 0;
+  cache->sp_offset = 0;
+  cache->fp_offset = 0;
+  cache->use_frame = 0;
+  cache->base = 0;
+
+  return cache;
+}
+
+/* Implement the gdbarch_in_function_epilogue_p method.  */
+
+static int
+nds32_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  uint32_t insn;
+  int r = 0;
+
+  insn = read_memory_unsigned_integer (addr, 4, BFD_ENDIAN_BIG);
+  if ((insn & 0x80000000) == 0)
+    {
+      /* 32-bit instruction */
+
+      /* ret */
+      if (insn == N32_JREG (JR, 0, REG_LP, 0, 1))
+	r = 1;
+      /* iret */
+      else if (insn == N32_TYPE0 (MISC, N32_MISC_IRET))
+	r = 2;
+    }
+  else
+    {
+      if (insn == N16_TYPE5 (RET5, REG_LP))
+	r = 3;
+    }
+  return r > 0;
+}
+
+/* Put here the code to store, into fi->saved_regs, the addresses of
+   the saved registers of frame described by FRAME_INFO.  This
+   includes special registers such as pc and fp saved in special ways
+   in the stack frame.  sp is even more special: the address we return
+   for it IS the sp for the next frame.  */
+
+static struct nds32_unwind_cache *
+nds32_frame_unwind_cache (struct frame_info *this_frame,
+			  void **this_prologue_cache)
+{
+  CORE_ADDR pc, scan_limit;
+  ULONGEST prev_sp;
+  ULONGEST next_base;
+  ULONGEST fp_base;
+  int i;
+  int insn;
+  struct nds32_unwind_cache *info;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
+  if ((*this_prologue_cache))
+    return (*this_prologue_cache);
+
+  info = nds32_alloc_frame_cache (this_frame);
+
+  info->base = get_frame_register_unsigned (this_frame, NDS32_FP_REGNUM);
+  (*this_prologue_cache) = info;
+
+  if (info->base == 0)
+    return info;
+
+  pc = get_frame_func (this_frame);
+  scan_limit = get_frame_pc (this_frame);
+
+  for (; pc > 0 && pc < scan_limit; )
+    {
+      insn = read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG);
+
+      if ((insn & 0x80000000) == 0)
+	{
+	  /* 32-bit instruction */
+
+	  pc += 4;
+	  if (insn == N32_ALU1 (ADD, REG_GP, REG_TA, REG_GP))
+	    {
+	      /* add $gp, $ta, $gp */
+	      continue;
+	    }
+	  if (N32_OP6 (insn) == N32_OP6_ADDI)
+	    {
+	      int rt = N32_RT5 (insn);
+	      int ra = N32_RA5 (insn);
+	      int imm15s = N32_IMM15S (insn);
+
+	      if (rt == ra && rt == NDS32_SP_REGNUM)
+		{
+		  info->sp_offset += imm15s;
+		  continue;
+		}
+	      else if (rt == NDS32_FP_REGNUM && ra == NDS32_SP_REGNUM)
+		{
+		  info->fp_offset = info->sp_offset + imm15s;
+		  info->use_frame = 1;
+		  continue;
+		}
+	      else if (rt == ra)
+		/* Prevent stop analyzing form iframe.  */
+		continue;
+	    }
+
+	  if (insn == N32_ALU2 (MFUSR, REG_TA, 31, 0))
+	    {
+	      /* mfusr $ta, PC  ; group=0, sub=0x20=mfusr */
+	      continue;
+	    }
+	  if (CHOP_BITS (insn, 20) == N32_TYPE1 (MOVI, REG_TA, 0))
+	    {
+	      /* movi $ta, imm20s */
+	      continue;
+	    }
+	  if (CHOP_BITS (insn, 20) == N32_TYPE1 (SETHI, REG_GP, 0))
+	    {
+	      /* sethi $gp, imm20 */
+	      continue;
+	    }
+	  if (CHOP_BITS (insn, 15) == N32_TYPE2 (ORI, REG_GP, REG_GP, 0))
+	    {
+	      /* ori $gp, $gp, imm15 */
+	      continue;
+	    }
+	  if (N32_OP6 (insn) == N32_OP6_LSMW && (insn & __BIT (5)))
+	    {
+	      /* smwa?.(a|b)(d|i)m? rb,[ra],re,enable4 */
+
+	      int rb, re, ra, enable4, i;
+	      int aligned;
+	      int m = 0;
+	      int di;	   /* dec=-1 or inc=1 */
+	      int rn;	   /* number of registers.  */
+	      char enb4map[2][4] = {
+		  {0, 1, 2, 3} /* smw */,
+		  {3, 1, 2, 0} /* smwa */ };
+	      /* `base' is the highest/last address for access memory.
+		 e.g., [ lp ] ___ base shoule be here.
+		       [ fp ]
+		       [ r6 ] */
+	      LONGEST base = ~1 + 1;
+
+	      rb = N32_RT5 (insn);
+	      ra = N32_RA5 (insn);
+	      re = N32_RB5 (insn);
+	      enable4 = (insn >> 6) & 0x0F;
+	      aligned = (insn & 3) ? 1 : 0;
+	      di = (insn & (1 << 3)) ? -1 : 1;
+
+	      rn = 0;
+	      rn += (enable4 & 0x1) ? 1 : 0;
+	      rn += (enable4 & 0x2) ? 1 : 0;
+	      rn += (enable4 & 0x4) ? 1 : 0;
+	      rn += (enable4 & 0x8) ? 1 : 0;
+	      if (rb < NDS32_FP_REGNUM && re < NDS32_FP_REGNUM)
+		{
+		  /* reg-list should not include fp,gp,lp,sp
+		     ie, the rb==re==sp case, anyway... */
+		  rn += (re - rb) + 1;
+		}
+
+	      /* Let's consider how Ra should update.  */
+	      if (insn & (1 << 0x2))    /* m-bit is set */
+		{
+		  m = rn * 4;			/* 4*TNReg */
+		}
+	      else
+		m = 0;	  /* don't update Ra */
+
+	      switch (ra)
+		{
+		case NDS32_FP_REGNUM:
+		  base = info->fp_offset;
+		  info->fp_offset += m * di;
+		  break;
+		case NDS32_SP_REGNUM:
+		  base = info->sp_offset;
+		  info->sp_offset += m * di;
+		  break;
+		default:
+		  /* sorry, only ra==sp || ra==fp is handled */
+		  break;
+		}
+	      if (base == ~1 + 1)
+		break;	  /* skip */
+
+	      if (insn & (1 << 0x4))	/* b:0, a:1 */
+		base += 4 * di;		/* a: use Ra+4 (for i),
+					      or Ra-4 (for d) */
+	      /* else base = base;	b use Ra */
+
+	      /* Cole 3th Nov. 2010
+		 We should consider both increasing and decreasing case.
+
+		 Either case stores registers in the same order.
+		 To simplify the code (yes, the loops),
+		 I used the same pushing order, but from different side.  */
+
+	      if (di == 1)		/* Increasing.  */
+		base += (rn * 4 - 4);
+	      /* else, in des case, we already are on the top */
+
+	      for (i = 0; i < 4; i++)
+		{
+		  if (enable4 & (1 << enb4map[aligned][i]))
+		    {
+		      info->saved_regs[NDS32_SP_REGNUM -
+				       (enb4map[aligned][i])].addr = base;
+		      base -= 4;
+		    }
+		}
+
+	      /* Skip re == rb == sp > fp.  */
+	      for (i = re; i >= rb && rb < NDS32_FP_REGNUM; i--)
+		{
+		  info->saved_regs[i].addr = base;
+		  base -= 4;
+		}
+
+	      continue;
+	    }
+	  /* swi $lp, [$sp + (imm15s << 2)] */
+	  /* We must check if $rt is $lp to determine it is
+	     in prologue or not.  */
+	  if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI, REG_LP, REG_FP, 0))
+	    {
+	      int imm15s;
+
+	      /* swi $lp, [$sp + (imm15s<<2)] */
+	      imm15s = N32_IMM15S (insn);
+	      info->saved_regs[NDS32_LP_REGNUM].addr = info->sp_offset
+						       + (imm15s << 2);
+	      continue;
+	    }
+	  /* swi.bi $rt, [$sp], (imm15s << 2) */
+	  if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI_BI, REG_LP, REG_FP, 0))
+	    {
+	      unsigned int rt5 = 0;
+	      unsigned int ra5 = 0;
+	      int imm15s = 0;
+	      rt5 = N32_RT5 (insn);
+	      ra5 = N32_RA5 (insn);
+	      imm15s = N32_IMM15S (insn);
+
+	      if (ra5 == NDS32_SP_REGNUM)
+		{
+		  info->saved_regs[rt5].addr = info->sp_offset;
+		  info->sp_offset += (imm15s << 2);
+		}
+	      else if (ra5 == NDS32_FP_REGNUM)
+		{
+		  info->saved_regs[rt5].addr = info->fp_offset;
+		  info->fp_offset += (imm15s << 2);
+		}
+	      continue;
+	    }
+
+	  if (N32_OP6 (insn) == N32_OP6_COP && N32_COP_CP (insn) == 0
+	      && (N32_COP_SUB (insn) == N32_FPU_FSS
+		  || N32_COP_SUB (insn) == N32_FPU_FSD)
+	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
+	    {
+	      /* CP shoud be CP0 */
+	      /* fs[sd][.bi] $fst, [$sp + ($r0 << sv)] */
+	      continue;
+	    }
+
+	  /* fssi $fst, [$ra + (imm12s << 2)]
+	     fssi.bi $fst, [$ra], (imm12s << 2)
+	     fsdi $fdt, [$ra + (imm12s << 2)]
+	     fsdi.bi $fdt, [$ra], (imm12s << 2) */
+	  if ((N32_OP6 (insn) == N32_OP6_SWC || N32_OP6 (insn) == N32_OP6_SDC)
+	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
+	    {
+	      /* fssi and fsdi have the same form.  */
+	      /* Only .bi form should be handled to adjust reg.  */
+	      unsigned int ra5 = 0;
+	      unsigned int fs5 = 0;
+	      int imm12s = 0;
+
+	      fs5 = N32_RT5 (insn);
+	      ra5 = N32_RA5 (insn);
+	      imm12s = N32_IMM12S (insn);
+
+	      if (imm12s & 0x800)
+		imm12s = (imm12s - (0x800 << 1));
+
+	      switch (ra5)
+		{
+		case NDS32_FP_REGNUM:
+		  info->fp_offset += (imm12s << 2);
+		  break;
+		case NDS32_SP_REGNUM:
+		  info->sp_offset += (imm12s << 2);
+		  break;
+		}
+
+	      continue;
+	    }
+
+	  /* TODO: Handle mfsr and addi for interrupt handlers.  */
+	  break;
+	}
+      else
+	{
+	  /* 16-bit instruction */
+	  pc += 2;
+	  insn >>= 16;
+
+	  /* 1. If the instruction is j/b, then we stop
+		i.e., OP starts with 10, and beqzs8, bnezs8.
+	     2. If the operations will change sp/fp or based on sp/fp,
+		then we are in the prologue.
+	     3. If we don't know what's it, then stop.  */
+
+	  if (__GF (insn, 13, 2) == 2)
+	    {
+	      /* These are all branch instructions.  */
+	      pc -= 2;
+	      break;
+	    }
+	  else if (__GF (insn, 9, 6) == 0x34)
+	    {
+	      /* beqzs8, bnezs8 */
+	      pc -= 2;
+	      break;
+	    }
+
+	  if (CHOP_BITS (insn, 10) == N16_TYPE10 (ADDI10S, 0))
+	    {
+	      /* addi10s */
+	      info->sp_offset += N16_IMM10S (insn);
+	      continue;
+	    }
+
+	  if (__GF (insn, 7, 8) == N16_T25_PUSH25)
+	    {
+	      /* push25 */
+	      int imm8u = (insn & 0x1f) << 3;
+	      int re = ((insn & 0x60) >> 5) & 0x3;
+	      int res[] = {6, 8, 10, 14};
+	      int m[] = {4, 6, 8, 12};
+	      LONGEST base = info->sp_offset - 4;
+
+	      /* Operation 1 - smw.adm R6, [sp], Re, #0xe */
+	      info->saved_regs[NDS32_LP_REGNUM].addr = info->sp_offset - 0x4;
+	      info->saved_regs[NDS32_GP_REGNUM].addr = info->sp_offset - 0x8;
+	      info->saved_regs[NDS32_FP_REGNUM].addr = info->sp_offset - 0xC;
+	      info->sp_offset -= m[re] * 4;
+
+	      switch (re)
+		{
+		  case 3:
+		    info->saved_regs[NDS32_R0_REGNUM + 14].addr = info->sp_offset + 0x20;
+		    info->saved_regs[NDS32_R0_REGNUM + 13].addr = info->sp_offset + 0x1C;
+		    info->saved_regs[NDS32_R0_REGNUM + 12].addr = info->sp_offset + 0x18;
+		    info->saved_regs[NDS32_R0_REGNUM + 11].addr = info->sp_offset + 0x14;
+		  case 2:
+		    info->saved_regs[NDS32_R0_REGNUM + 10].addr = info->sp_offset + 0x10;
+		    info->saved_regs[NDS32_R0_REGNUM + 9].addr = info->sp_offset + 0xC;
+		  case 1:
+		    info->saved_regs[NDS32_R0_REGNUM + 8].addr = info->sp_offset + 0x8;
+		    info->saved_regs[NDS32_R0_REGNUM + 7].addr = info->sp_offset + 0x4;
+		  case 0:
+		    info->saved_regs[NDS32_R0_REGNUM + 6].addr = info->sp_offset;
+		}
+
+	      /* Operation 2 - sp = sp - imm5u<<3 */
+	      info->sp_offset -= imm8u;
+
+	      /* Operation 3 - if (Re >= 1) R8 = concat (PC(31,2), 2`b0) */
+	      continue;
+	    }
+
+	  /* mov55 fp, sp */
+	  if (insn == N16_TYPE55 (MOV55, REG_FP, REG_SP))
+	    {
+		info->fp_offset = info->sp_offset;
+		info->use_frame = 1;
+		continue;
+	    }
+	  /* swi450 */
+	  switch (insn & ~__MF (-1, 5, 4))
+	    {
+	      case N16_TYPE45 (SWI450, 0, REG_SP):
+	      case N16_TYPE45 (SWI450, 0, REG_FP):
+		break;
+	    }
+	  /* swi37 - implied fp */
+	  if (__GF (insn, 11, 4) == N16_T37_XWI37
+	      && (insn & __BIT (7)))
+	    continue;
+
+	  /* swi37sp - implied */
+	  if (__GF (insn, 11, 4) == N16_T37_XWI37SP
+	      && (insn & __BIT (7)))
+	    continue;
+
+	  break;
+	  }
+    }
+
+  info->size = -info->sp_offset;
+  /* Compute the previous frame's stack pointer (which is also the
+     frame's ID's stack address), and this frame's base pointer.
+
+     Assume that the FP is this frame's SP but with that pushed
+     stack space added back.  */
+  next_base = get_frame_register_unsigned (this_frame, NDS32_SP_REGNUM);
+  prev_sp = next_base + info->size;
+  fp_base = get_frame_register_unsigned (this_frame, NDS32_FP_REGNUM);
+  if (info->use_frame && fp_base > 0)
+    {
+      /* Try to use FP if possible. */
+      prev_sp = fp_base - info->fp_offset;
+    }
+
+  /* Convert that SP/BASE into real addresses.  */
+  info->prev_sp = prev_sp;
+  info->base = next_base;
+
+  /* Adjust all the saved registers so that they contain addresses and
+     not offsets.  */
+  for (i = 0; i < gdbarch_num_regs (gdbarch) - 1; i++)
+    {
+      if (trad_frame_addr_p (info->saved_regs, i))
+	{
+	  info->saved_regs[i].addr = info->prev_sp + info->saved_regs[i].addr;
+	}
+    }
+
+  /* The previous frame's SP needed to be computed.
+     Save the computed value.  */
+  trad_frame_set_value (info->saved_regs, NDS32_SP_REGNUM, prev_sp);
+
+  return info;
+}
+
+/* Implement the gdbarch_skip_permanent_breakpoint method.  */
+
+static void
+nds32_skip_permanent_breakpoint (struct regcache *regcache)
+{
+  int insn;
+  CORE_ADDR current_pc = regcache_read_pc (regcache);
+
+  /* On nds32, breakpoint may be BREAK or BREAK16.  */
+  insn = read_memory_unsigned_integer (current_pc, 4, BFD_ENDIAN_BIG);
+
+  /* FIXME: Review this code.  */
+  if (N32_OP6 (insn) == N32_OP6_MISC && N32_SUB5 (insn) == N32_MISC_BREAK)
+    current_pc += 4;
+  else if (__GF (insn, 9, 6) == 35 && N16_IMM9U (insn) < 32)
+    current_pc += 2;
+  else
+    return;
+
+  regcache_write_pc (regcache, current_pc);
+}
+
+/* Implement the gdbarch_read_pc method.  */
+
+static CORE_ADDR
+nds32_read_pc (struct regcache *regcache)
+{
+  ULONGEST pc;
+  regcache_cooked_read_unsigned (regcache, NDS32_PC_REGNUM, &pc);
+  return pc;
+}
+
+/* Implement the gdbarch_write_pc method.  */
+
+static void
+nds32_write_pc (struct regcache *regcache, CORE_ADDR val)
+{
+  regcache_cooked_write_unsigned (regcache, NDS32_PC_REGNUM, val);
+}
+
+/* Implement the gdbarch_unwind_pc method.  */
+
+static CORE_ADDR
+nds32_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  /* This snippet code is a mess.
+
+     In most case, LP is the actually register being saved.
+     Hence when unwinding pc for backtrace, LP should be the one.
+     That is, for frames (level > 0), unwinding the PC means
+     unwinding LP from the this_frame.
+
+     However, for a top frame (level==0), unwinding PC means
+     the current program counter (PC).
+     Besides, for dummy frame, PC stored in dummy_frame is the one
+     we want.
+
+     We have to have these cases to make backtrace work properly.  */
+
+  CORE_ADDR pc;
+  pc = frame_unwind_register_unsigned (this_frame, NDS32_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the gdbarch_unwind_sp method.  */
+
+static CORE_ADDR
+nds32_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return frame_unwind_register_unsigned (this_frame, NDS32_SP_REGNUM);
+}
+
+/* If these is exactly one float point type field in the struct,
+   the alignment of the struct is the size of the float pointer type.  */
+
+static int
+nds32_float_in_struct (struct type *type)
+{
+  struct type *actual_type;
+
+  type = check_typedef (type);
+  if (TYPE_CODE (type) != TYPE_CODE_STRUCT || TYPE_NFIELDS (type) != 1)
+    return 0;
+
+  actual_type = check_typedef (TYPE_FIELD_TYPE (type, 0));
+  if (TYPE_CODE (actual_type) == TYPE_CODE_FLT)
+    {
+      gdb_assert (TYPE_LENGTH (type) == 8 || TYPE_LENGTH (type) == 4);
+      return TYPE_LENGTH (type);
+    }
+  return 0;
+}
+
+/* Get the alignment of the type.
+
+   The alignment requirement of a structure is the largest alignment
+   requirement of its member, so we should traverse every member to
+   find the largest alignment.
+
+   For example,
+     struct { int a; int b; char c } is 4-byte aligned,
+   and
+     struct {long long a; char c} is 8-byte aligned.  */
+
+static int
+nds32_type_align (struct type *type)
+{
+  int align = 0;		/* Current max alignment.  */
+  int i;
+
+  gdb_assert (type != NULL);
+  if (type == NULL)
+    return 0;
+
+  if (type->main_type->nfields == 0)
+    return type->length;
+
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_ARRAY:
+      return nds32_type_align (TYPE_TARGET_TYPE (type));
+    case TYPE_CODE_ENUM:
+      return TYPE_LENGTH (type);
+    }
+
+  /* For structs with only one float/double are treated as float/double.  */
+  align = nds32_float_in_struct (type);
+  if (align)
+    return align;
+
+  for (i = 0; i < TYPE_NFIELDS (type); i++)
+    {
+      int r = nds32_type_align (TYPE_FIELD_TYPE (type, i));
+
+      if (r > align)
+	align = r;
+    }
+
+  return align;
+}
+
+/* Implement the gdbarch_push_dummy_call method.  */
+
+static CORE_ADDR
+nds32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+		       struct regcache *regcache, CORE_ADDR bp_addr,
+		       int nargs, struct value **args, CORE_ADDR sp,
+		       int struct_return, CORE_ADDR struct_addr)
+{
+  const int REND = 6;		/* Max arguments number.  */
+  int goff = 0;			/* Current gpr for argument.  */
+  int foff = 0;			/* Currnet gpr for argument.  */
+  int soff = 0;			/* Current stack offset.  */
+  int i;
+  struct type *type;
+  enum type_code typecode;
+  CORE_ADDR regval;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int use_spill;
+  int use_fpr;
+  int fs0_regnum = -1, fd0_regnum = -1;
+
+  switch (tdep->nds32_abi)
+    {
+    case NDS32_ABI_V2:
+    case NDS32_ABI_V2FP:
+      use_spill = FALSE;
+      break;
+    default:
+      use_spill = TRUE;
+    break;
+  }
+
+  /* Use FP registers for calling iff when ABI==V2FP.  */
+  use_fpr = (tdep->nds32_abi == NDS32_ABI_V2FP);
+  if (use_fpr)
+    {
+      fs0_regnum = user_reg_map_name_to_regnum (gdbarch, "fs0",
strlen ("fs0"));
+      fd0_regnum = user_reg_map_name_to_regnum (gdbarch, "fd0",
strlen ("fd0"));
+    }
+
+  /* Set the return address.  For the nds32, the return breakpoint is
+     always at BP_ADDR.  */
+  regcache_cooked_write_unsigned (regcache, NDS32_LP_REGNUM, bp_addr);
+
+  /* If STRUCT_RETURN is true, then the struct return address (in
+     STRUCT_ADDR) will consume the first argument-passing register.
+     Both adjust the register count and store that value.  */
+  if (struct_return)
+    {
+      regcache_cooked_write_unsigned (regcache, NDS32_R0_REGNUM, struct_addr);
+      goff++;
+    }
+
+  /* Now make sure there's space on the stack */
+  for (i = 0; i < nargs; i++)
+    {
+      struct type *type = value_type (args[i]);
+      int align = nds32_type_align (type);
+
+      gdb_assert (align != 0);
+      sp -= TYPE_LENGTH (type);
+      if (align)
+	{
+	  /* FIXME: Handle empty structure?  */
+	  sp &= ~(align - 1);
+	}
+    }
+
+  /* Stack must be 8-byte aligned.  */
+  sp = sp & ~7;
+
+  soff = 0;
+  for (i = 0; i < nargs; i++)
+    {
+      const gdb_byte *val;
+      int align, len;
+
+      type = value_type (args[i]);
+      typecode = TYPE_CODE (type);
+      align = nds32_float_in_struct (type);
+      if (align)
+	typecode = TYPE_CODE_FLT;
+      else
+	align = nds32_type_align (type);
+      len = TYPE_LENGTH (type);
+
+      /* TODO: handle variables-size argument and variable-length arguments
+
+	 COLE, GDB cannot know whether a type is variable-sized,
+	       so we don't know whether push it as reference or value.  */
+
+      val = value_contents (args[i]);
+
+      /* Once we start using stack, all arguments should go to stack
+	 When use_fpr, all flt must go to fs/fd; otherwise go to stack.  */
+      if (use_fpr && typecode == TYPE_CODE_FLT)
+	{
+	  /* Adjust alignment.  */
+	  foff = (foff + ((align - 1) >> 2)) & ~((align - 1) >> 2);
+
+	  if (foff < REND && !soff)
+	    {
+	      if (use_fpr && fs0_regnum == -1)
+		goto error_no_fpr;
+
+	      switch (len)
+		{
+		case 4:
+		  regcache_cooked_write (regcache, fs0_regnum + foff, val);
+		  foff++;
+		  continue;
+		case 8:
+		  regcache_cooked_write (regcache, fd0_regnum + foff / 2, val);
+		  foff += 2;
+		  continue;
+		default:
+		  /* Long double? */
+		  internal_error (__FILE__, __LINE__,
+				  "Do not know how to handle %d-byte double.\n",
+				  len);
+		  break;
+		}
+	    }
+	}
+      else if (!soff)
+	{
+	  /* Adjust alignment, and only adjust one time for one argument.  */
+	  goff = (goff + ((align - 1) >> 2)) & ~((align - 1) >> 2);
+	  if (!use_spill && len > (REND - goff) * 4)
+	    goff = REND;
+	}
+
+      /*
+	When passing arguments,
+
+	* A composite type not larger than 4 bytes is passed
+	  in $rN. The format is as if the value is loaded with
+	  load instruction of corresponding size. (i.g., LB, LH, LW)
+
+	   For example,
+
+		  r0
+		  31      0
+	  little: [x x b a]
+	     BIG: [x x a b]
+
+	 * Otherwise, a composite type is passed in consective registers.
+	   The size is rounded up to the nearest multiple of 4.
+	   The successive registers hold the parts of the argument as if
+	   were loaded using lmw instructions.
+
+	  For example,
+
+		  r0	     r1
+		  31      0 31	     0
+	  little: [d c b a] [x x x e]
+	     BIG: [a b c d] [e x x x]
+
+
+	When push an argument in stack,
+
+	* A composite type not larger than 4 bytes is copied
+	  to memory at the next free space, in little-endian.
+	  In big-endian, the last byte of the argument is aligned
+	  at the next word address.  For example,
+
+	  sp [ - ]  [ b ] hi
+	     [ - ]  [ a ]
+	     [ b ]  [ - ]
+	     [ a ]  [ - ] lo
+	    little   BIG
+       */
+
+      if (len > 4)
+	len = (len + 0x3) & ~0x3;
+
+      while (len > 0)
+	{
+	  if (soff
+	      || (typecode == TYPE_CODE_FLT && use_fpr && foff == REND)
+	      || goff == REND)
+	    {
+	      int rlen = (len > 4) ? 4 : len;
+
+	      if (byte_order == BFD_ENDIAN_BIG)
+		write_memory (sp + soff + 4 - rlen, val, rlen);
+	      else
+		write_memory (sp + soff, val, rlen);
+	      soff += 4;
+	    }
+	  else
+	    {
+	      regval = extract_unsigned_integer (val, (len > 4) ? 4 : len,
+						 byte_order);
+	      regcache_cooked_write_unsigned (regcache,
+					      goff + NDS32_R0_REGNUM, regval);
+	      goff++;
+	    }
+
+	  len -= register_size (gdbarch, goff);
+	  val += register_size (gdbarch, goff);
+	}
+    }
+
+  /* Finally, update the SP register.  */
+  regcache_cooked_write_unsigned (regcache, NDS32_SP_REGNUM, sp);
+
+  return sp;
+
+error_no_fpr:
+  /* If use_fpr, but no fs reigster exists, then it is an error.  */
+  /* FIXME: Restore stack.  */
+  error (_("Fail to call. FS0-FS5 is required."));
+}
+
+/* Given a return value in `regbuf' with a type `valtype',
+   extract and copy its value into `valbuf'.  */
+
+static void
+nds32_extract_return_value (struct type *type, struct regcache *regcache,
+			    gdb_byte *readbuf)
+{
+  int len = TYPE_LENGTH (type);
+  int typecode = TYPE_CODE (type);
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int i;
+  int fs0_regnum, fd0_regnum;
+  int use_fpr;
+
+  use_fpr = (tdep->nds32_abi == NDS32_ABI_V2FP);
+
+  /* TODO: one-float, one-double is special case in V2FP.
+     Passed in FS/FD */
+  gdb_assert (TYPE_LENGTH (type) <= 8);
+  if (nds32_float_in_struct (type))
+    typecode = TYPE_CODE_FLT;
+
+  if (typecode == TYPE_CODE_FLT && use_fpr)
+    {
+      fs0_regnum = user_reg_map_name_to_regnum (gdbarch, "fs0",
strlen ("fs0"));
+      fd0_regnum = user_reg_map_name_to_regnum (gdbarch, "fd0",
strlen ("fd0"));
+
+      if (len == 4)
+	regcache_cooked_read (regcache, fs0_regnum, readbuf);
+      else if (len == 8)
+	regcache_cooked_read (regcache, fd0_regnum, readbuf);
+      else
+	internal_error (__FILE__, __LINE__,
+			_("Cannot extract return value of %d bytes "
+			  "long floating point."),
+			len);
+    }
+  else
+    {
+      /* When returning result,
+
+	* A composite type not larger than 4 bytes is returned
+	  in $r0. The format is as if the result is loaded with
+	  load instruction of corresponding size. (i.g., LB, LH, LW)
+
+	  For example,
+
+		  r0
+		  31      0
+	  little: [x x b a]
+	     BIG: [x x a b]
+
+	* Otherwise, a composite type not larger than 8 bytes
+	  is returned in $r0 and $r1. In little-endian, the first
+	  word is loaded in $r0. In big-endian, the last word
+	  is loaded in $r1.
+
+	  For example,
+
+		  r0	    r1
+		  31      0 31      0
+	  little: [d c b a] [x x x e]
+	     BIG: [x x x a] [b c d e]
+       */
+
+      if (len <= 4)
+	{
+	  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	    regcache_raw_read_part (regcache, NDS32_R0_REGNUM, 4 - len, len,
+				    readbuf);
+	  else
+	    regcache_raw_read_part (regcache, NDS32_R0_REGNUM, 0, len,
+				    readbuf);
+	}
+      else if (len <= 8)
+	{
+	  int partial = len - 4;
+
+	  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	    {
+	      regcache_raw_read_part (regcache, NDS32_R0_REGNUM, 4 - partial,
+				      partial, readbuf);
+	      regcache_raw_read (regcache, NDS32_R0_REGNUM + 1,
+				 readbuf + partial);
+
+	    }
+	  else
+	    {
+	      regcache_raw_read (regcache, NDS32_R0_REGNUM, readbuf);
+	      regcache_raw_read_part (regcache, NDS32_R0_REGNUM + 1, 0,
+				      partial, readbuf + 4);
+	    }
+	}
+      else
+	internal_error (__FILE__, __LINE__,
+			_("Cannot extract return value of %d bytes long."),
+			len);
+    }
+}
+
+/* Write into appropriate registers a function return value
+   of type TYPE, given in virtual format.
+   Things always get returned in RET1_REGNUM, RET2_REGNUM.  */
+
+static void
+nds32_store_return_value (struct type *type, struct regcache *regcache,
+			  const gdb_byte *writebuf)
+{
+  int len = TYPE_LENGTH (type);
+  int typecode = TYPE_CODE (type);
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int i;
+  int fs0_regnum, fd0_regnum;
+  int use_fpr;
+
+  use_fpr = (tdep->nds32_abi == NDS32_ABI_V2FP);
+
+  /* TODO: one-float, one-double is special case in V2FP.
+     Passed in FS/FD */
+  gdb_assert (TYPE_LENGTH (type) <= 8);
+  if (nds32_float_in_struct (type))
+    typecode = TYPE_CODE_FLT;
+
+  if (typecode == TYPE_CODE_FLT && use_fpr)
+    {
+      fs0_regnum = user_reg_map_name_to_regnum (gdbarch, "fs0",
strlen ("fs0"));
+      fd0_regnum = user_reg_map_name_to_regnum (gdbarch, "fd0",
strlen ("fd0"));
+
+      if (len == 4)
+	regcache_cooked_write (regcache, fs0_regnum, writebuf);
+      else if (len == 8)
+	regcache_cooked_write (regcache, fd0_regnum, writebuf);
+      else
+	internal_error (__FILE__, __LINE__,
+			_("Cannot store return value of %d bytes long "
+			  "floating point."),
+			len);
+    }
+  else
+    {
+      if (len <= 4)
+	{
+	  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	    regcache_raw_write_part (regcache, NDS32_R0_REGNUM, 4 - len, len,
+				     writebuf);
+	  else
+	    regcache_raw_write_part (regcache, NDS32_R0_REGNUM, 0, len,
+				     writebuf);
+	}
+      else if (len <= 8)
+	{
+	  int partial = len - 4;
+
+	  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	    {
+	      regcache_raw_write_part (regcache, NDS32_R0_REGNUM, 4 - partial,
+				       partial, writebuf);
+	      regcache_raw_write (regcache, NDS32_R0_REGNUM + 1,
+				  writebuf + partial);
+
+	    }
+	  else
+	    {
+	      regcache_raw_write (regcache, NDS32_R0_REGNUM, writebuf);
+	      regcache_raw_write_part (regcache, NDS32_R0_REGNUM + 1, 0,
+				       partial, writebuf + 4);
+	    }
+	}
+      else
+	internal_error (__FILE__, __LINE__,
+			_("Cannot store return value of %d bytes long."),
+			len);
+    }
+}
+
+/* Implement the gdbarch_return_value method.  */
+
+static enum return_value_convention
+nds32_return_value (struct gdbarch *gdbarch, struct value *func_type,
+		    struct type *type, struct regcache *regcache,
+		    gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+  if (TYPE_LENGTH (type) > 8)
+    {
+      return RETURN_VALUE_STRUCT_CONVENTION;
+    }
+  else
+    {
+      /* `readbuf' is used for 'call' to get the return value.
+	 `writebuf' is used for 'return' to set the return value.  */
+      if (readbuf != NULL)
+	nds32_extract_return_value (type, regcache, readbuf);
+      if (writebuf != NULL)
+	nds32_store_return_value (type, regcache, writebuf);
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+}
+
+/* Assuming NEXT_FRAME->prev 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
+nds32_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp, pc;
+
+  sp = get_frame_register_unsigned (this_frame, NDS32_SP_REGNUM);
+  pc = get_frame_pc (this_frame);
+  return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+/* Given a GDB frame, determine the address of the calling function's
+   frame.  This will be used to create a new GDB frame struct.  */
+
+static void
+nds32_frame_this_id (struct frame_info *this_frame,
+		     void **this_prologue_cache, struct frame_id *this_id)
+{
+  struct nds32_unwind_cache *info;
+  CORE_ADDR base;
+  CORE_ADDR func;
+  struct minimal_symbol *msym_stack;
+  struct frame_id id;
+  enum bfd_endian byte_order_for_code = BFD_ENDIAN_BIG;
+
+  info = nds32_frame_unwind_cache (this_frame, this_prologue_cache);
+
+  /* Get function entry address */
+  func = get_frame_func (this_frame);
+
+  /* Hopefully the prologue analysis either correctly determined the
+     frame's base (which is the SP from the previous frame), or set
+     that base to "NULL".  */
+  base = info->prev_sp;
+  if (base == 0)
+    return;
+
+  id = frame_id_build (base, func);
+  (*this_id) = id;
+}
+
+/* Get the value of register REGNUM in previous frame.  */
+
+static struct value *
+nds32_frame_prev_register (struct frame_info *this_frame,
+			   void **this_prologue_cache, int regnum)
+{
+  struct nds32_unwind_cache *cache;
+  cache = nds32_frame_unwind_cache (this_frame, this_prologue_cache);
+
+  if (regnum == NDS32_PC_REGNUM)
+    {
+      CORE_ADDR lr;
+      struct frame_info *next_frame;
+
+      lr = frame_unwind_register_unsigned (this_frame, NDS32_LP_REGNUM);
+      return frame_unwind_got_constant (this_frame, regnum, lr);
+    }
+
+  return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+}
+
+/* The register in previous frame.  For example, the previous PC is
+   current LP.  */
+
+static struct value *
+nds32_dwarf2_prev_register (struct frame_info *this_frame,
+			    void **this_cache, int regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  CORE_ADDR lp;
+
+  switch (regnum)
+    {
+    case NDS32_PC_REGNUM:
+      lp = frame_unwind_register_unsigned (this_frame, NDS32_LP_REGNUM);
+      return frame_unwind_got_constant (this_frame, regnum, lp);
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unexpected register %d"), regnum);
+    }
+
+   return NULL;
+}
+
+/* Callback of dwarf2_frame_set_init_reg.  */
+
+static void
+nds32_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+			     struct dwarf2_frame_state_reg *reg,
+			     struct frame_info *this_frame)
+{
+  switch (regnum)
+    {
+    case NDS32_PC_REGNUM:
+      reg->how = DWARF2_FRAME_REG_FN;
+      reg->loc.fn = nds32_dwarf2_prev_register;
+      break;
+    case NDS32_SP_REGNUM:
+      reg->how = DWARF2_FRAME_REG_CFA;
+      break;
+    }
+}
+
+/* Implement the gdbarch_get_longjmp_target method.  */
+
+static int
+nds32_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
+{
+  gdb_byte buf[4];
+  CORE_ADDR jmp_buf_p;
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  jmp_buf_p = get_frame_register_unsigned (frame, 0);
+
+  /* Key is in setjmp():
+     lmw.bim   r6, [r0], r14
+     lmw.bim  r16, [r0], r19, 0xf */
+
+  if (target_read_memory (jmp_buf_p + 15 * 4, buf, 4))
+    return 0;
+
+  *pc = extract_unsigned_integer (buf, 4, byte_order);
+
+  return 1;
+}
+
+static const struct frame_unwind nds32_frame_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  nds32_frame_this_id,
+  nds32_frame_prev_register,
+  NULL /* unwind_data */,
+  default_frame_sniffer
+};
+
+/* Signal trampolines.  */
+
+static struct nds32_unwind_cache *
+nds32_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  struct nds32_unwind_cache *cache;
+  CORE_ADDR addr;
+  gdb_byte buf[4];
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+  if (*this_cache)
+    return *this_cache;
+
+  cache = nds32_alloc_frame_cache (this_frame);
+
+  cache->base = get_frame_register_unsigned (this_frame, NDS32_SP_REGNUM);
+
+  addr = tdep->sigcontext_addr (this_frame);
+
+  if (tdep->sc_reg_offset)
+    {
+      int i;
+
+      /* GPRs, PC and d[01](lo|hi) */
+      gdb_assert (tdep->sc_num_regs <= 37);
+
+      for (i = 0; i < tdep->sc_num_regs; i++)
+	if (tdep->sc_reg_offset[i] != -1)
+	  cache->saved_regs[i].addr = addr + tdep->sc_reg_offset[i];
+    }
+  else
+    {
+      cache->saved_regs[NDS32_PC_REGNUM].addr = addr + tdep->sc_pc_offset;
+      cache->saved_regs[NDS32_LP_REGNUM].addr = addr + tdep->sc_lp_offset;
+      cache->saved_regs[NDS32_SP_REGNUM].addr = addr + tdep->sc_sp_offset;
+      cache->saved_regs[NDS32_FP_REGNUM].addr = addr + tdep->sc_fp_offset;
+    }
+
+  *this_cache = cache;
+  return cache;
+}
+
+static void
+nds32_sigtramp_frame_this_id (struct frame_info *this_frame,
+			      void **this_cache, struct frame_id *this_id)
+{
+  struct nds32_unwind_cache *cache;
+
+  cache = nds32_sigtramp_frame_cache (this_frame, this_cache);
+
+  (*this_id) = frame_id_build (cache->base, get_frame_pc (this_frame));
+}
+
+static struct value *
+nds32_sigtramp_frame_prev_register (struct frame_info *this_frame,
+				    void **this_cache, int regnum)
+{
+  struct nds32_unwind_cache *cache;
+
+  /* Make sure we've initialized the cache.  */
+  cache = nds32_sigtramp_frame_cache (this_frame, this_cache);
+
+  /* For signal frame, unwind PC for PC and LP for LP;
+     otherwise, we will fail to unwind a leaf-function.
+     This different from unwinding a normal-frame.  */
+  return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+}
+
+static int
+nds32_sigtramp_frame_sniffer (const struct frame_unwind *self,
+			      struct frame_info *this_frame,
+			      void **this_prologue_cache)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
+
+  /* We shouldn't even bother if we don't have a sigcontext_addr
+     handler.  */
+  if (tdep->sigcontext_addr == NULL)
+    return 0;
+
+  if (tdep->sigtramp_p != NULL)
+    {
+      if (tdep->sigtramp_p (this_frame))
+	return 1;
+    }
+
+#if 0
+    /* TODO: extend the sniffer as following if (tdep->sigtramp_start != 0) */
+    {
+      CORE_ADDR pc = frame_pc_unwind (this_frame);
+
+      gdb_assert (tdep->sigtramp_end != 0);
+      if (pc >= tdep->sigtramp_start && pc < tdep->sigtramp_end)
+	return &nds32_sigtramp_frame_unwind;
+    }
+#endif
+  return 0;
+}
+
+static const struct frame_unwind nds32_sigtramp_frame_unwind =
+{
+  SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
+  nds32_sigtramp_frame_this_id,
+  nds32_sigtramp_frame_prev_register,
+  NULL /* unwind_data */,
+  nds32_sigtramp_frame_sniffer
+};
+
+static CORE_ADDR
+nds32_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+  struct nds32_unwind_cache *info;
+
+  info = nds32_frame_unwind_cache (this_frame, this_cache);
+
+  return info->base;
+}
+
+static const struct frame_base nds32_frame_base =
+{
+  &nds32_frame_unwind,
+  nds32_frame_base_address,
+  nds32_frame_base_address,
+  nds32_frame_base_address
+};
+
+static void
+nds32_simple_overlay_update (struct obj_section *osect)
+{
+  struct minimal_symbol *minsym = NULL;
+
+  minsym = lookup_minimal_symbol (".nds32.fixed.size", NULL, NULL);
+  if (minsym != NULL && osect != NULL)
+    {
+      bfd *obfd = osect->objfile->obfd;
+      asection *bsect = osect->the_bfd_section;
+      if (bfd_section_vma (obfd, bsect) < SYMBOL_VALUE_ADDRESS (minsym))
+	{
+	  osect->ovly_mapped = 1;
+	  return;
+	}
+    }
+
+  simple_overlay_update (osect);
+}
+
+static int
+gdb_print_insn_nds32 (bfd_vma memaddr, disassemble_info *info)
+{
+  struct gdbarch *gdbarch = info->application_data;
+  struct obj_section * s = find_pc_section (memaddr);
+  struct cleanup *back_to;
+
+  /* Reload symtab if abfd changed.
+     In case there are multiple ITB in different shared objects.  */
+  if (s == NULL || info->section != s->the_bfd_section)
+    {
+      xfree (info->symtab);
+      info->symtab = NULL;
+      info->symtab_size = 0;
+    }
+
+  if (info->symtab == NULL && s && s->the_bfd_section)
+    {
+      long storage = bfd_get_symtab_upper_bound (s->objfile->obfd);
+
+      if (storage <= 0)
+	goto done;
+
+      info->section = s->the_bfd_section;
+      info->symtab = xmalloc (storage);
+      info->symtab_size =
+	bfd_canonicalize_symtab (s->the_bfd_section->owner, info->symtab);
+    }
+
+done:
+  return print_insn_nds32 (memaddr, info);
+}
+
+/* Callback for gdbarch_init.  */
+
+static struct gdbarch *
+nds32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  struct gdbarch_list *best_arch;
+  const struct target_desc *tdesc = NULL;
+  unsigned int nds32_abi = NDS32_ABI_AUTO;
+  struct tdesc_arch_data *tdesc_data = NULL;
+  unsigned int eflags = 0;
+  int i;
+
+  /* Extract the elf_flags, if available.  */
+  if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    {
+      eflags = elf_elfheader (info.abfd)->e_flags;
+      nds32_abi = (eflags >> 4) & 0xF;
+    }
+
+  /* Allocate space for the new architecture.  */
+  tdep = XCALLOC (1, struct gdbarch_tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  if (tdesc_has_registers (info.target_desc))
+    {
+      int valid_p;
+      int fpregs = -1;
+      static const char *const nds32_fp_names[] = { "r28", "fp", NULL };
+      static const char *const nds32_lp_names[] = { "r30", "lp", NULL };
+      static const char *const nds32_sp_names[] = { "r31", "sp", NULL };
+      const struct tdesc_feature *feature;
+
+      /* Validate and initialize target-description here.  */
+      tdesc = info.target_desc;
+      tdesc_data = tdesc_data_alloc ();
+
+      info.tdep_info = (void *) tdesc_data;
+
+      feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nds32.core");
+      if (!feature)
+	return 0;
+
+      /* Validate  for FP, LP, GP, PC.  */
+      valid_p = 1;
+      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+						  NDS32_FP_REGNUM,
+						  nds32_fp_names);
+      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+						  NDS32_LP_REGNUM,
+						  nds32_lp_names);
+      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+						  NDS32_SP_REGNUM,
+						  nds32_sp_names);
+      valid_p &= tdesc_numbered_register (feature, tdesc_data,
+					  NDS32_PC_REGNUM, "pc");
+
+      if (!valid_p)
+	{
+	  tdesc_data_cleanup (tdesc_data);
+	  xfree (tdep);
+	  gdbarch_free (gdbarch);
+	  return NULL;
+	}
+
+      /* Number R0-R27.  */
+      for (i = NDS32_R0_REGNUM; i < NDS32_FP_REGNUM; i++)
+	tdesc_numbered_register (feature, tdesc_data, i, nds32_regnames[i]);
+
+      /* Number D0 and D1.  */
+      for (i = NDS32_D0LO_REGNUM; i <= NDS32_D1HI_REGNUM; i++)
+	tdesc_numbered_register (feature, tdesc_data, i, nds32_regnames[i]);
+
+      /* Find register configuration of FPU.  */
+      feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nds32.fpu");
+      if (feature)
+	{
+	  if (tdesc_unnumbered_register (feature, "fd31"))
+	    fpregs = 3;
+	  else if (tdesc_unnumbered_register (feature, "fd15"))
+	    fpregs = 2;
+	  else if (tdesc_unnumbered_register (feature, "fd7"))
+	    fpregs = 1;
+	  else if (tdesc_unnumbered_register (feature, "fd3"))
+	    fpregs = 0;
+	}
+      tdep->nds32_fpregs = fpregs;
+
+      /* If FS registers do not exist, make them pseudo registers
+	 of FD registers.  */
+      if (fpregs != -1 && tdesc_unnumbered_register (feature, "fs0") == 0)
+	{
+	  int fsregs = (fpregs + 1) * 8;
+
+	  if (fsregs > 32)
+	    fsregs = 32;
+
+	  set_gdbarch_num_pseudo_regs (gdbarch, fsregs);
+	  set_gdbarch_pseudo_register_read (gdbarch, nds32_pseudo_register_read);
+	  set_gdbarch_pseudo_register_write (gdbarch, nds32_pseudo_register_write);
+	  set_tdesc_pseudo_register_name (gdbarch, nds32_register_name);
+	}
+
+      set_gdbarch_num_regs (gdbarch, NDS32_NUM_REGS);
+      tdesc_use_registers (gdbarch, tdesc, tdesc_data);
+    }
+  else
+    {
+      /* Simulator or legacy target.  */
+
+      /* Physical 32 FD registers.  */
+      set_gdbarch_num_regs (gdbarch, NDS32_SIM_NUM_REGS);
+      set_gdbarch_register_name (gdbarch, nds32_register_name);
+
+      /* Pseudo 32 FS registers.  */
+      set_gdbarch_num_pseudo_regs (gdbarch, 32);
+      set_gdbarch_pseudo_register_read (gdbarch, nds32_pseudo_register_read);
+      set_gdbarch_pseudo_register_write (gdbarch, nds32_pseudo_register_write);
+    }
+
+  tdep->nds32_abi = nds32_abi;
+  tdep->eflags = eflags;
+
+  /* Overwrite ABI if set explicitly.  */
+  if (nds32_config.use_abi != NDS32_ABI_AUTO)
+    tdep->nds32_abi = nds32_config.use_abi;
+
+  /* Set offsets for signal context.  */
+  tdep->sigtramp_p = NULL;
+  tdep->sigcontext_addr = NULL;
+  tdep->sc_pc_offset = -1;
+  tdep->sc_sp_offset = -1;
+  tdep->sc_fp_offset = -1;
+
+  /* If there is already a candidate, use it.  */
+  for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
+       best_arch != NULL;
+       best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
+    {
+      struct gdbarch_tdep *idep = gdbarch_tdep (best_arch->gdbarch);
+
+      if (nds32_abi != idep->nds32_abi)
+	continue;
+
+      /* Check FPU registers.  */
+      if (idep->nds32_fpregs != tdep->nds32_fpregs)
+	continue;
+
+      /* Found a match.  */
+      break;
+    }
+
+  if (best_arch != NULL)
+    {
+      xfree (tdep);
+      gdbarch_free (gdbarch);
+      return best_arch->gdbarch;
+    }
+
+  nds32_add_reggroups (gdbarch);
+
+  gdbarch_init_osabi (info, gdbarch);
+
+  /* Override tdesc_register callbacks for system registers.  */
+  set_gdbarch_register_reggroup_p (gdbarch, nds32_register_reggroup_p);
+  set_gdbarch_register_type (gdbarch, nds32_register_type);
+
+  set_gdbarch_sp_regnum (gdbarch, NDS32_SP_REGNUM);
+  set_gdbarch_pc_regnum (gdbarch, NDS32_PC_REGNUM);
+  set_gdbarch_read_pc (gdbarch, nds32_read_pc);
+  set_gdbarch_write_pc (gdbarch, nds32_write_pc);
+  set_gdbarch_unwind_sp (gdbarch, nds32_unwind_sp);
+  set_gdbarch_unwind_pc (gdbarch, nds32_unwind_pc);
+  set_gdbarch_in_function_epilogue_p (gdbarch, nds32_in_function_epilogue_p);
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, nds32_dwarf_dwarf2_reg_to_regnum);
+  set_gdbarch_register_sim_regno (gdbarch, nds32_register_sim_regno);
+  set_gdbarch_push_dummy_call (gdbarch, nds32_push_dummy_call);
+  set_gdbarch_return_value (gdbarch, nds32_return_value);
+  set_gdbarch_skip_prologue (gdbarch, nds32_skip_prologue);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_breakpoint_from_pc (gdbarch, nds32_breakpoint_from_pc);
+  set_gdbarch_remote_breakpoint_from_pc (gdbarch,
nds32_remote_breakpoint_from_pc);
+  set_gdbarch_frame_align (gdbarch, nds32_frame_align);
+  frame_base_set_default (gdbarch, &nds32_frame_base);
+
+  /* Methods for saving / extracting a dummy frame's ID.
+     The ID's stack address must match the SP value returned by
+     PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos.  */
+  set_gdbarch_dummy_id (gdbarch, nds32_dummy_id);
+  set_gdbarch_print_insn (gdbarch, gdb_print_insn_nds32);
+  set_gdbarch_skip_permanent_breakpoint (gdbarch,
+					 nds32_skip_permanent_breakpoint);
+  /* Support simple overlay manager.  */
+  set_gdbarch_overlay_update (gdbarch, nds32_simple_overlay_update);
+
+  /* Handle longjmp.  */
+  set_gdbarch_get_longjmp_target (gdbarch, nds32_get_longjmp_target);
+
+  /* The order of appending is the order it check frame.  */
+  dwarf2_frame_set_init_reg (gdbarch, nds32_dwarf2_frame_init_reg);
+  if (nds32_config.use_cfi)
+    dwarf2_append_unwinders (gdbarch);
+  frame_unwind_append_unwinder (gdbarch, &nds32_sigtramp_frame_unwind);
+  frame_unwind_append_unwinder (gdbarch, &nds32_frame_unwind);
+
+  /* Add nds32 register aliases.  */
+  /* FIXME: This is a simple workaround to force user-reg being
+	    initialized before gdbarch initialized.
+	    Without this, calling user_reg_map_name_to_regnum ()
+	    will crash.  */
+  user_reg_add (gdbarch, "r0", nds32_value_of_reg, "r0");
+  for (i = 0; i < ARRAY_SIZE (nds32_register_aliases); i++)
+    {
+      int regnum;
+
+      regnum = user_reg_map_name_to_regnum
+	(gdbarch, nds32_register_aliases[i].name, -1);
+
+      if (regnum == -1)
+	continue;
+
+      user_reg_add (gdbarch, nds32_register_aliases[i].alias,
+		    nds32_value_of_reg, nds32_register_aliases[i].name);
+    }
+
+  return gdbarch;
+}
+
+/* Callback for "nds32 dump" command.
+
+   Dump current register and stack for debug gdb.  */
+
+static void
+nds32_dump_command (char *arg, int from_tty)
+{
+  ULONGEST val;
+  ULONGEST sp;
+  FILE *f_script;
+  char cmdline[512];
+  int i;
+
+  if (arg == NULL)
+    {
+      printf_unfiltered (_("Missing filename argument.\n"));
+      return;
+    }
+
+  regcache_raw_read_unsigned (get_current_regcache (), NDS32_SP_REGNUM, &sp);
+
+  sprintf (cmdline, "dump binary memory %s.stack 0x%lx 0x%lx",
+	   arg, (long) sp, ((long) sp + 1024 - 1) & ~(1024 - 1));
+  execute_command (cmdline, from_tty);
+
+  sprintf (cmdline, "%s.gdbinit", arg);
+  f_script = fopen (cmdline, "w");
+  if (f_script == NULL)
+    {
+      printf_unfiltered (_("Fail to generate dump .gdbinit."));
+      return ;
+    }
+
+  /* Gather all user registers.  */
+  for (i = 0; i <= NDS32_D1HI_REGNUM; i++)
+    {
+      regcache_raw_read_unsigned (get_current_regcache (), i, &val);
+      fprintf (f_script, "set $%s = 0x%lx\n", nds32_regnames[i], (long) val);
+    }
+
+  fprintf (f_script, "restore %s.stack binary 0x%lx\n", arg, (long) sp);
+  fclose (f_script);
+}
+
+static int
+nds32_config_int (const char *str, int def)
+{
+  int val = def;
+
+  if (getenv (str))
+    val = atoi (getenv (str));
+  if (val != def)
+    printf ("%s=%d\n", str, val);
+  return val;
+}
+
+static void
+nds32_load_config (struct nds32_gdb_config *config)
+{
+  config->use_cfi = nds32_config_int ("USE_CFI", 1);
+  config->use_abi = nds32_config_int ("USE_ABI", NDS32_ABI_AUTO);
+}
+
+/* Callback for "nds32" command.  */
+
+static void
+nds32_command (char *arg, int from_tty)
+{
+  printf_unfiltered (_("\"nds32\" must be followed by arguments\n"));
+}
+
+struct cmd_list_element *nds32_cmdlist;
+
+void
+_initialize_nds32_tdep (void)
+{
+  /* Internal used config for testing.  */
+  nds32_load_config (&nds32_config);
+
+  add_prefix_cmd ("nds32", no_class, nds32_command,
+		  _("Various nds32-specific commands."), &nds32_cmdlist,
+		  "nds32 ", 0, &cmdlist);
+
+  add_cmd ("dump", class_files, nds32_dump_command,
+	   _("dump stack and GPRs for debugging"), &nds32_cmdlist);
+
+  nds32_init_remote_cmds ();
+
+  /* Initialize gdbarch.  */
+  register_gdbarch_init (bfd_arch_nds32, nds32_gdbarch_init);
+
+  /* Following are NDS32 specific commands.  */
+
+  nds32_init_reggroups ();
+
+  register_remote_support_xml ("nds32");
+}
diff --git a/gdb/nds32-tdep.h b/gdb/nds32-tdep.h
new file mode 100644
index 0000000..2a71a14
--- /dev/null
+++ b/gdb/nds32-tdep.h
@@ -0,0 +1,127 @@
+/* Common target dependent code for GDB on nds32 systems.
+
+   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   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 "nds32-utils.h"
+
+#ifndef __NDS32_TDEP_H__
+#define __NDS32_TDEP_H__
+
+/* Define numbers of registers we have in NDS32 arch.  */
+
+#define NDS32_NUM_PSEUDO_REGS     (NDS32_NUM_FPR)
+
+/* NDS32 virtual registers layout for GDB.  */
+enum nds32_regnum
+{
+  /* General purpose registers.  */
+  NDS32_R0_REGNUM = 0,
+  NDS32_R5_REGNUM = 5,
+  NDS32_TA_REGNUM = 15,		/* Temp for assembler.  */
+  NDS32_FP_REGNUM = 28,		/* Frame register.  */
+  NDS32_GP_REGNUM = 29,		/* Global register.  */
+  NDS32_LP_REGNUM = 30,		/* Link pointer.  */
+  NDS32_SP_REGNUM = 31,		/* Address of stack top.  */
+
+  /* Pseudo PC.  */
+  NDS32_PC_REGNUM = 32,
+
+  /* D0/D1 User Registers.  */
+  NDS32_D0LO_REGNUM = 33,
+  NDS32_D0HI_REGNUM = 34,
+  NDS32_D1LO_REGNUM = 35,
+  NDS32_D1HI_REGNUM = 36,
+
+  /* If target-description is not supported, only assume above
+     registers are supported.  */
+  NDS32_NUM_REGS,
+
+  /* These are only used by simulator.  */
+  NDS32_SIM_FD0_REGNUM = NDS32_NUM_REGS,
+  NDS32_SIM_IFCLP_REGNUM = NDS32_SIM_FD0_REGNUM + 32,
+  NDS32_SIM_ITB_REGNUM,
+  NDS32_SIM_PSW_REGNUM,
+
+  NDS32_SIM_NUM_REGS,
+};
+
+/* All the possible NDS32 ABIs.  They must be consistent with elf/nds32.h.  */
+enum nds32_abi
+{
+  NDS32_ABI_V0 = 0,
+  NDS32_ABI_V1,
+  NDS32_ABI_V2,
+  NDS32_ABI_V2FP,
+  NDS32_ABI_AABI,
+  NDS32_ABI_END,
+  NDS32_ABI_BEGIN = NDS32_ABI_V0,
+  /* ABI flag is only 4-bits long.  */
+  NDS32_ABI_AUTO = 0xFFFFFFFF
+};
+
+/* ----------------------------------------------
+   31   28 27                 8 7   4 3       0
+   ----------------------------------------------
+   | ARCH | CONFUGURAION FIELD | ABI | VERSION  |
+   ---------------------------------------------- */
+struct htab;
+struct gdbarch_tdep
+{
+  /* ABI version */
+  enum nds32_abi nds32_abi;
+  int nds32_fpregs;
+
+  unsigned int eflags;
+
+  /* Detect sigtramp.  */
+  int (*sigtramp_p) (struct frame_info *);
+
+  /* Get address of sigcontext for sigtramp.  */
+    CORE_ADDR (*sigcontext_addr) (struct frame_info *);
+
+  /* Offset of saved PC in jmp_buf.  */
+  /* TODO: int jb_pc_offset; */
+
+  /* Offset of saved PC and SP in `struct sigcontext'. */
+  int sc_pc_offset;
+  int sc_lp_offset;
+  int sc_sp_offset;
+  int sc_fp_offset;
+
+  int *sc_reg_offset;
+  int sc_num_regs;
+
+  struct htab *type_tab;
+};
+
+/* Hidden options.  */
+struct nds32_gdb_config
+{
+  /* Use DWARF/CFI for stack frame unwinding.
+     This is much reliable than manual prologue analysis.
+     Default true.  */
+  int use_cfi;
+
+  /* ABI for Inferior Call Setup.
+     Default AUTO by reading ABI in ELF header.  */
+  int use_abi;
+};
+
+extern struct cmd_list_element *nds32_cmdlist;
+#endif
diff --git a/gdb/nds32-utils.c b/gdb/nds32-utils.c
new file mode 100644
index 0000000..27241e7
--- /dev/null
+++ b/gdb/nds32-utils.c
@@ -0,0 +1,247 @@
+/* Common target dependent code for GDB on nds32 systems.
+
+   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   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 "top.h"		/* for source_script */
+#include "exceptions.h"		/* for catch_command_errors */
+#include "ui-file.h"		/* struct ui_file_buffer */
+#include "nds32-utils.h"
+#include "gdbtypes.h"
+#include "gdb_assert.h"
+#include "floatformat.h"
+#include "hashtab.h"
+#include <stdio.h>
+#include <string.h>
+
+/* Helpers for allocating types.  */
+
+/* Allocate a new type.
+   Use this instead of arch_composite_type () or arch_type () directly,
+   because it must be a 4-byte word, but we may not append all the fields.
+   If `opt' is USE_FLAGS, then a field for flags is appended.  */
+
+struct type *
+nds32_init_type (struct gdbarch *gdbarch, char *name, enum type_option opt)
+{
+  struct type *type;
+
+  gdb_assert (opt == USE_FLAGS || opt == NO_FLAGS);
+
+  type = arch_type (gdbarch, TYPE_CODE_STRUCT, 4, name);
+  TYPE_TAG_NAME (type) = name;
+  INIT_CPLUS_SPECIFIC (type);
+
+  if (opt == USE_FLAGS)
+    {
+      int i;
+      struct type *flags_type =
+	arch_flags_type (TYPE_OWNER (type).gdbarch, "nds32_dummy_flags_type",
+			 TYPE_LENGTH (type));
+      append_composite_type_field_raw (type, "", flags_type);
+
+      /* Hide all the flags from users,
+	 only explicitly appened flags are showen to users.
+	 For example,
+	 {[ #1 #3 #16 #17 #18 ], INTL = Lv1, POM = Superuser}
+	 We don't want users to see this,
+	 INTL and POM should be hidden from users.  */
+      for (i = 0; i < TYPE_LENGTH (type) * TARGET_CHAR_BIT; i++)
+	append_flags_type_flag (flags_type, i, NULL);
+    }
+
+  return type;
+}
+
+/* Append a flags bit.  */
+
+void
+nds32_append_flag (struct type *type, int bitpos, char *name)
+{
+  struct field *f;
+  int nfields;
+
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT);
+
+  nfields = TYPE_NFIELDS (type);
+
+  if (nfields == 0
+      || TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) != TYPE_CODE_FLAGS)
+    {
+      internal_error (__FILE__, __LINE__,
+		      _("Pseudo field for flags must be the first one."));
+    }
+
+  /* Append flag in the first field.  */
+  append_flags_type_flag (TYPE_FIELD_TYPE (type, 0), bitpos, name);
+}
+
+/* Append a bit-field.  */
+
+void
+nds32_append_bitfield (struct type *type, struct type *field_type,
+		       int bitpos_from, int bitpos_to, char *name)
+{
+  struct field *f;
+
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT);
+  gdb_assert (bitpos_to >= bitpos_from);
+  gdb_assert (TYPE_NFIELDS (type) != 0 || strcmp (name, "") != 0);
+
+  f = append_composite_type_field_raw (type, xstrdup (name), field_type);
+  SET_FIELD_BITPOS (f[0], bitpos_from);
+  FIELD_BITSIZE (f[0]) = bitpos_to - bitpos_from + 1;
+}
+
+/* Allocate an enumeration type.  The only reason to call this function
+   is that we want it to be UNSIGNED instead.  This is only useful for
+   enum-type bit-field.  */
+
+struct type *
+nds32_init_enum (struct gdbarch *gdbarch, char *name)
+{
+  struct type *type;
+
+  type = arch_type (gdbarch, TYPE_CODE_ENUM, 4, name);
+  TYPE_UNSIGNED (type) = 1;
+  return type;
+}
+
+void
+nds32_append_enum (struct type *type, int enumval, char *name)
+{
+  struct field *f;
+
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_ENUM);
+  f = append_composite_type_field_raw (type, name, NULL);
+  SET_FIELD_ENUMVAL (f[0], enumval);
+}
+\f
+/* Helpers for type table.  */
+
+struct type_entry
+{
+  const char *name;
+  struct type *type;
+};
+
+/* Hash code function.  Simply a wrapper for htab_hash_string.  */
+
+static hashval_t
+type_hash_string (const PTR p)
+{
+  struct type_entry *e = (struct type_entry *) p;
+
+  return htab_hash_string (e->name);
+}
+
+/* Equal function for hash.  Simply a wrapper for strcmp.  */
+
+static int
+type_name_eq (const PTR p1, const PTR p2)
+{
+  struct type_entry *e1 = (struct type_entry *) p1;
+  struct type_entry *e2 = (struct type_entry *) p2;
+
+  return strcmp (e1->name, e2->name) == 0;
+}
+
+/* Allocate a hash table for register/type pair.  */
+
+htab_t
+nds32_alloc_type_tab (int size)
+{
+  return htab_create_alloc (size, type_hash_string, type_name_eq,
+			    NULL /* htab_del */ ,
+			    xcalloc, xfree);
+}
+
+/* Look up a register by name.  */
+
+struct type *
+nds32_type_lookup (htab_t htab, const char *name)
+{
+  struct type_entry ent;
+  struct type_entry **pe;
+
+  ent.name = name;
+  pe = (struct type_entry **) htab_find_slot (htab, &ent, NO_INSERT);
+  if (pe)
+    return (*pe)->type;
+  else
+    return NULL;
+}
+
+/* Insert a type for a specific register name.  */
+
+void
+nds32_type_insert (htab_t htab, const char *name, struct type *type)
+{
+  struct type_entry ent;
+  struct type_entry **pe;
+
+  ent.name = name;
+
+  pe = (struct type_entry **) htab_find_slot (htab, &ent, INSERT);
+
+  if (*pe != NULL)
+    return;
+
+  *pe = xmalloc (sizeof (**pe));
+  (*pe)->name = xstrdup (name);
+  (*pe)->type = type;
+}
+\f
+/* ui_file_put_method_ftype.
+
+   This is used with mem_file_put to get the content of
+   the internal stream buffer.  */
+
+void
+do_ui_file_put_memcpy (void *object, const char *buffer, long length_buffer)
+{
+  struct ui_file_buffer *ui_buf;
+
+  ui_buf = (struct ui_file_buffer *) object;
+  if (ui_buf->buf_size < length_buffer)
+    {
+      if (length_buffer < 256 * 1024)
+	ui_buf->buf_size = length_buffer += 1024;
+      else
+	ui_buf->buf_size = length_buffer * 2;
+      ui_buf->buf = xrealloc (ui_buf->buf, ui_buf->buf_size);
+    }
+
+  memcpy (ui_buf->buf, buffer, length_buffer);
+}
+
+void
+ui_file_buffer_init (struct ui_file_buffer *ub, int size)
+{
+  ub->buf_size = size;
+  ub->buf = xmalloc (size);
+}
+
+void
+free_ui_file_buffer (void *ptr)
+{
+  struct ui_file_buffer *ui_buf = (struct ui_file_buffer *) ptr;
+
+  xfree (ui_buf->buf);
+}
diff --git a/gdb/nds32-utils.h b/gdb/nds32-utils.h
new file mode 100644
index 0000000..b1f9c2c
--- /dev/null
+++ b/gdb/nds32-utils.h
@@ -0,0 +1,59 @@
+/* Common target dependent code for GDB on nds32 systems.
+
+   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   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 NDS32_UTILS_H
+#define NDS32_UTILS_H
+
+void source_nds32script (void);
+
+/* Declarations for making arch-dependent types.  */
+enum type_option
+{
+  NO_FLAGS = 0,
+  USE_FLAGS = 1,
+};
+struct field *nds32_append_type_field (struct type *type);
+struct type *nds32_init_type (struct gdbarch *gdbarch, char *name,
+			      enum type_option opt);
+void nds32_append_flag (struct type *type, int bitpos, char *name);
+void nds32_append_bitfield (struct type *type, struct type *field_type,
+			    int bitpos_from, int bitpos_to, char *name);
+struct type *nds32_init_enum (struct gdbarch *gdbarch, char *name);
+void nds32_append_enum (struct type *type, int bitpos, char *name);
+
+/* Helpers for type table.  */
+htab_t nds32_alloc_type_tab (int size);
+struct type *nds32_type_lookup (htab_t htab, const char *name);
+void nds32_type_insert (htab_t htab, const char *name, struct type *type);
+
+/* UI buffer for output redirection.  */
+struct ui_file_buffer
+{
+  unsigned char *buf;
+  long buf_size;
+};
+
+void do_ui_file_put_memcpy (void *object, const char *buffer,
+			    long length_buffer);
+
+void ui_file_buffer_init (struct ui_file_buffer *ub, int size);
+
+void free_ui_file_buffer (void *ptr);
+#endif
diff --git a/gdb/regformats/nds32-freg0-linux.dat
b/gdb/regformats/nds32-freg0-linux.dat
new file mode 100644
index 0000000..49eafd3
--- /dev/null
+++ b/gdb/regformats/nds32-freg0-linux.dat
@@ -0,0 +1,47 @@
+# DO NOT EDIT: generated from nds32-freg0-linux.xml
+name:nds32_freg0_linux
+xmltarget:nds32-freg0-linux.xml
+expedite:fp,sp,pc
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:r13
+32:r14
+32:r15
+32:r16
+32:r17
+32:r18
+32:r19
+32:r20
+32:r21
+32:r22
+32:r23
+32:r24
+32:r25
+32:
+32:
+32:fp
+32:gp
+32:lp
+32:sp
+32:pc
+32:d0lo
+32:d0hi
+32:d1lo
+32:d1hi
+32:orig_r0
+32:fucpr
+64:fd0
+64:fd1
+64:fd2
+64:fd3
diff --git a/gdb/regformats/nds32-freg1-linux.dat
b/gdb/regformats/nds32-freg1-linux.dat
new file mode 100644
index 0000000..312912e
--- /dev/null
+++ b/gdb/regformats/nds32-freg1-linux.dat
@@ -0,0 +1,51 @@
+# DO NOT EDIT: generated from nds32-freg1-linux.xml
+name:nds32_freg1_linux
+xmltarget:nds32-freg1-linux.xml
+expedite:fp,sp,pc
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:r13
+32:r14
+32:r15
+32:r16
+32:r17
+32:r18
+32:r19
+32:r20
+32:r21
+32:r22
+32:r23
+32:r24
+32:r25
+32:
+32:
+32:fp
+32:gp
+32:lp
+32:sp
+32:pc
+32:d0lo
+32:d0hi
+32:d1lo
+32:d1hi
+32:orig_r0
+32:fucpr
+64:fd0
+64:fd1
+64:fd2
+64:fd3
+64:fd4
+64:fd5
+64:fd6
+64:fd7
diff --git a/gdb/regformats/nds32-freg2-linux.dat
b/gdb/regformats/nds32-freg2-linux.dat
new file mode 100644
index 0000000..b281b50
--- /dev/null
+++ b/gdb/regformats/nds32-freg2-linux.dat
@@ -0,0 +1,59 @@
+# DO NOT EDIT: generated from nds32-freg2-linux.xml
+name:nds32_freg2_linux
+xmltarget:nds32-freg2-linux.xml
+expedite:fp,sp,pc
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:r13
+32:r14
+32:r15
+32:r16
+32:r17
+32:r18
+32:r19
+32:r20
+32:r21
+32:r22
+32:r23
+32:r24
+32:r25
+32:
+32:
+32:fp
+32:gp
+32:lp
+32:sp
+32:pc
+32:d0lo
+32:d0hi
+32:d1lo
+32:d1hi
+32:orig_r0
+32:fucpr
+64:fd0
+64:fd1
+64:fd2
+64:fd3
+64:fd4
+64:fd5
+64:fd6
+64:fd7
+64:fd8
+64:fd9
+64:fd10
+64:fd11
+64:fd12
+64:fd13
+64:fd14
+64:fd15
diff --git a/gdb/regformats/nds32-freg3-linux.dat
b/gdb/regformats/nds32-freg3-linux.dat
new file mode 100644
index 0000000..f0c33f7
--- /dev/null
+++ b/gdb/regformats/nds32-freg3-linux.dat
@@ -0,0 +1,75 @@
+# DO NOT EDIT: generated from nds32-freg3-linux.xml
+name:nds32_freg3_linux
+xmltarget:nds32-freg3-linux.xml
+expedite:fp,sp,pc
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:r13
+32:r14
+32:r15
+32:r16
+32:r17
+32:r18
+32:r19
+32:r20
+32:r21
+32:r22
+32:r23
+32:r24
+32:r25
+32:
+32:
+32:fp
+32:gp
+32:lp
+32:sp
+32:pc
+32:d0lo
+32:d0hi
+32:d1lo
+32:d1hi
+32:orig_r0
+32:fucpr
+64:fd0
+64:fd1
+64:fd2
+64:fd3
+64:fd4
+64:fd5
+64:fd6
+64:fd7
+64:fd8
+64:fd9
+64:fd10
+64:fd11
+64:fd12
+64:fd13
+64:fd14
+64:fd15
+64:fd16
+64:fd17
+64:fd18
+64:fd19
+64:fd20
+64:fd21
+64:fd22
+64:fd23
+64:fd24
+64:fd25
+64:fd26
+64:fd27
+64:fd28
+64:fd29
+64:fd30
+64:fd31
diff --git a/gdb/regformats/nds32-linux.dat b/gdb/regformats/nds32-linux.dat
new file mode 100644
index 0000000..bd79c4d
--- /dev/null
+++ b/gdb/regformats/nds32-linux.dat
@@ -0,0 +1,43 @@
+# DO NOT EDIT: generated from nds32-linux.xml
+name:nds32_linux
+xmltarget:nds32-linux.xml
+expedite:fp,sp,pc
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:r13
+32:r14
+32:r15
+32:r16
+32:r17
+32:r18
+32:r19
+32:r20
+32:r21
+32:r22
+32:r23
+32:r24
+32:r25
+32:
+32:
+32:fp
+32:gp
+32:lp
+32:sp
+32:pc
+32:d0lo
+32:d0hi
+32:d1lo
+32:d1hi
+32:orig_r0
+32:fucpr
-- 
1.7.9.5


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

* Re: [PATCH 1/5] Code for nds32 target
  2013-07-08  9:28 [PATCH 1/5] Code for nds32 target Wei-cheng Wang
@ 2013-07-08 23:58 ` Joseph S. Myers
  2013-07-09 16:18   ` Wei-cheng Wang
  2013-07-09  4:10 ` Yao Qi
  2013-07-10  5:38 ` Yao Qi
  2 siblings, 1 reply; 9+ messages in thread
From: Joseph S. Myers @ 2013-07-08 23:58 UTC (permalink / raw)
  To: Wei-cheng Wang; +Cc: gdb-patches

On Mon, 8 Jul 2013, Wei-cheng Wang wrote:

> +/* GNU/Linux has two flavors of signals.  Normal signal handlers, and
> +   "realtime" (RT) signals.  The RT signals can provide additional
> +   information to the signal handler if the SA_SIGINFO flag is set
> +   when establishing a signal handler using `sigaction'.  It is not
> +   unlikely that future versions of GNU/Linux will support SA_SIGINFO
> +   for normal signals too.  */
> +
> +/* When the NDS32 Linux kernel calls a signal handler and the
> +   SA_RESTORER flag isn't set, the return address points to a bit of
> +   code on the stack.  This function returns whether the PC appears to
> +   be within this bit of code.
> +
> +   The instructions for normal and realtime signals are
> +       syscall   #__NR_sigreturn ( 0x26 0x01 0xDC 0x0B)
> +       or
> +       syscall   #__NR_rt_sigreturn ( 0x26 0x02 0xB4 0x0B)
> +
> +   Checking for the code sequence should be somewhat reliable, because
> +   the effect is to call the system call sigreturn.  This is unlikely
> +   to occur anywhere other than in a signal trampoline.
> +
> +   It kind of sucks that we have to read memory from the process in
> +   order to identify a signal trampoline, but there doesn't seem to be
> +   any other way.  Therefore we only do the memory reads if no
> +   function name could be identified, which should be the case since
> +   the code is on the stack.
> +
> +   Detection of signal trampolines for handlers that set the
> +   SA_RESTORER flag is in general not possible.  Unfortunately this is
> +   what the GNU C Library has been doing for quite some time now.
> +   However, as of version 2.1.2, the GNU C Library uses signal
> +   trampolines (named __restore and __restore_rt) that are identical
> +   to the ones used by the kernel.  Therefore, these trampolines are
> +   supported too.  */

I advise reviewing this whole comment, and the Linux port in general, for 
whether it is still current.

I don't see the kernel port as of Linux 3.10, and Linux kernel policy as I 
understand it is that new architectures are expected to use the generic 
syscall interface, which only has rt_sigreturn.  So, references to the old 
non-realtime sigreturn are suspect for new architectures.  Similarly, 
references to glibc 2.1.2 are suspect for an architecture with no glibc 
port as of 2.18.  (If the Linux ABI isn't fully confirmed with the 
upstream Linux kernel community, you might want to submit the non-Linux 
parts of the GDB port and come back to the Linux parts later.)

> +int nds32_linux_sc_reg_offset[] =

Any reason this isn't const?  Likewise for various other arrays in the 
port.

> +      /* Cole, Dec. 31th, 2010
> +	 sigcontext is stored in frame->uc.uc_mcontext, Therefore,
> +	 there are two ways to get sigcontext.
> +	 The first way, direct access it in the stack.In this way,
> +	 we needs more knowledge of rt_sigtramp
> +	 The second way, &us is passed as parameter 3 of handler,
> +	 that would be R2 in NDS32 ABI.As long as we use generic
> +	 ucontext struct, I think it's easier to get sigcontext.  */

Comments such as "As long as we use generic ucontext struct" also suggest 
you need to sort out your Linux ABI.  And I think comments with names and 
dates are best avoided (in rare cases it may be appropriate to refer in a 
comment e.g. to the list archives on sourceware.org).

> +      /* FIXME: Review me after <linux/user.h>, <asm/ptrace.h>, and SR regs
> +	 spec clear. [Harry@Mar.14.2006] */

It's not necessarily the case that every FIXME/TODO/... comment needs 
resolving for a port to go in - its fine for a port to go in that still 
has known enhancement issues.  But I'd suggest posting the list of 
enhancement issues to a public mailing list / wiki / ... and at least 
reviewing such comments in the sources and trying to resolve them.

> +/* Mapping between the general-purpose registers in `struct user'
> +   format and GDB's register array layout.
> +
> +   FIXME: fix me after <linux/user.h>, <asm/ptrace.h>,
> +   and SR regs spec clear. [Harry@Mar.14.2006]
> +
> +   Current remap layout depend on Tom's implementation in kernel header,
> +   in ptrace.h and IR spec 0.1 (Jan.20.2006 version)
> +   [Harry@Mar.16.2006]
> +
> +   Note: -1 means unable to get from ptrace syscall
> +
> +   Renumber according to arch/nds32/include/asm/ptrace.h
> +   Not sure whether NDS32_r0 or NDS32_ORIG_r0 represents real $r0.
> +   (current use NDS32_ORIG_r0)
> +   Registers not mapped: NDS32_FUCOP_CTL, NDS32_osp. (42 & 43)
> +   [Rudolph@Aug.18.2010]  */

Likewise.

> +     See: Bug 7430 - GDB can't set a hardware break point with PA
> +	  if IT/DT is on.  */

This doesn't look like GDB bug 7430.  References to "bug N" in GDB sources 
should be to the public GDB bug tracker rather than to any other bug 
tracker.

> +/* Wrapper for execute a GDB CLI command.  */
> +
> +static void
> +nds32_execute_command (char *cmd, char *arg, int from_tty)
> +{
> +  int len;
> +  char *line;
> +
> +  if (arg == NULL)
> +    arg = "";
> +  len = strlen (arg) + strlen (cmd) + 2;
> +  if (len > 1024)
> +    error (_("Command line too long."));

GNU programs should not have arbitrary limits (on lengths of commands, 
symbol names, ...).  There appear to be quite a few stack buffers etc. in 
this port that could impose such limits.

If in fact all the arguments to this function are generated internally and 
it's never possible, for any user input, for the limit to be exceeded, it 
should maybe be a gdb_assert that it isn't exceeded.  I haven't tried to 
review the various fixed-size buffers individually, but each should be 
checked to make sure no user input could ever cause the size to be 
exceeded and cause an error / truncation.

-- 
Joseph S. Myers
joseph@codesourcery.com


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

* Re: [PATCH 1/5] Code for nds32 target
  2013-07-08  9:28 [PATCH 1/5] Code for nds32 target Wei-cheng Wang
  2013-07-08 23:58 ` Joseph S. Myers
@ 2013-07-09  4:10 ` Yao Qi
  2013-07-09 18:23   ` Wei-cheng Wang
  2013-07-10  5:38 ` Yao Qi
  2 siblings, 1 reply; 9+ messages in thread
From: Yao Qi @ 2013-07-09  4:10 UTC (permalink / raw)
  To: Wei-cheng Wang; +Cc: gdb-patches

On 07/08/2013 05:27 PM, Wei-cheng Wang wrote:

> diff --git a/gdb/features/feature_to_c.sh b/gdb/features/feature_to_c.sh
> old mode 100644
> new mode 100755

Unnecessary change.

> diff --git a/gdb/features/nds32-core.xml b/gdb/features/nds32-core.xml
> new file mode 100644
> index 0000000..8de8059
> --- /dev/null
> +++ b/gdb/features/nds32-core.xml
> @@ -0,0 +1,56 @@
> +<?xml version="1.0"?>
> +<!-- Copyright (C) 2007, 2008, 2009, 2010 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.nds32.core">
> +  <reg name="r0" bitsize="32" regnum="0"/>
> +  <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" regnum="15"/>

Do we really need "regnum="15"" here?

> diff --git a/gdb/nds32-linux-nat.c b/gdb/nds32-linux-nat.c
> new file mode 100644
> index 0000000..2f87822
> --- /dev/null
> +++ b/gdb/nds32-linux-nat.c
> @@ -0,0 +1,299 @@
> +/* Common target dependent code for GDB on nds32 systems.
> +
> +   Copyright (C) 2006-2013 Free Software Foundation, Inc.
> +   Contributed by Andes Technology Corporation.
> +
> +   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 "inferior.h"
> +#include "gdbcore.h"
> +#include "gdb_string.h"
> +#include "regcache.h"
> +#include "target.h"
> +#include "linux-nat.h"
> +#include "target-descriptions.h"
> +#include "auxv.h"
> +
> +#include <elf/common.h>
> +#include <sys/user.h>
> +#include <sys/ptrace.h>
> +#include <sys/utsname.h>
> +#include <sys/procfs.h>
> +
> +/* Prototypes for supply_gregset etc. */
> +#include "gregset.h"
> +
> +/* Defines ps_err_e, struct ps_prochandle.  */
> +#include "gdb_proc_service.h"
> +
> +#include "nds32-tdep.h"
> +#include "nds32-linux-tdep.h"
> +#include "features/nds32-linux.c"

Missing include these four files?

features/nds32-freg0-linux.c
features/nds32-freg1-linux.c
features/nds32-freg2-linux.c
features/nds32-freg3-linux.c

> +
> +/* Fetch the thread-local storage pointer for libthread_db.  */
> +
> +#if 0
> +/* TODO: TLS is not supported, yet.  */
> +
> +ps_err_e
> +ps_get_thread_area (const struct ps_prochandle *ph,
> +		    lwpid_t lwpid, int idx, void **base)
> +{
> +}
> +#endif
> +

Remove #if0 ... #endif.

> diff --git a/gdb/nds32-linux-tdep.c b/gdb/nds32-linux-tdep.c
> new file mode 100644
> index 0000000..79d51cd
> --- /dev/null
> +++ b/gdb/nds32-linux-tdep.c
> @@ -0,0 +1,320 @@
> +/* Common target dependent code for GDB on nds32 systems.

The header comment of all nds32-*.c files are "Common target dependent 
code for GDB on nds32 systems.", which makes no sense to me.  Please 
give the meaningful comment to each of them.

> +
> +   Copyright (C) 2006-2013 Free Software Foundation, Inc.
> +   Contributed by Andes Technology Corporation.
> +
> +   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 "gdbcore.h"
> +#include "frame.h"
> +#include "value.h"
> +#include "regcache.h"
> +#include "inferior.h"
> +#include "osabi.h"
> +#include "reggroups.h"
> +#include "regset.h"
> +#include "target-descriptions.h"
> +
> +#include "gdb_string.h"
> +
> +#include "glibc-tdep.h"
> +#include "solib-svr4.h"
> +
> +#include "trad-frame.h"
> +#include "frame-unwind.h"
> +
> +#include "nds32-tdep.h"
> +#include "nds32-linux-tdep.h"
> +
> +extern struct nds32_gdb_config nds32_config;
> +

nds32_config is not used in this file.  Remove this declaration.

> +void _initialize_nds32_linux_tdep (void);
> +
> +/* Recognizing signal handler frames.  */
> +
> +/* GNU/Linux has two flavors of signals.  Normal signal handlers, and
> +   "realtime" (RT) signals.  The RT signals can provide additional
> +   information to the signal handler if the SA_SIGINFO flag is set
> +   when establishing a signal handler using `sigaction'.  It is not
> +   unlikely that future versions of GNU/Linux will support SA_SIGINFO
> +   for normal signals too.  */
> +
> +/* When the NDS32 Linux kernel calls a signal handler and the
> +   SA_RESTORER flag isn't set, the return address points to a bit of
> +   code on the stack.  This function returns whether the PC appears to
> +   be within this bit of code.
> +
> +   The instructions for normal and realtime signals are
> +       syscall   #__NR_sigreturn ( 0x26 0x01 0xDC 0x0B)
> +       or
> +       syscall   #__NR_rt_sigreturn ( 0x26 0x02 0xB4 0x0B)
> +
> +   Checking for the code sequence should be somewhat reliable, because
> +   the effect is to call the system call sigreturn.  This is unlikely
> +   to occur anywhere other than in a signal trampoline.
> +
> +   It kind of sucks that we have to read memory from the process in
> +   order to identify a signal trampoline, but there doesn't seem to be
> +   any other way.  Therefore we only do the memory reads if no
> +   function name could be identified, which should be the case since
> +   the code is on the stack.
> +
> +   Detection of signal trampolines for handlers that set the
> +   SA_RESTORER flag is in general not possible.  Unfortunately this is
> +   what the GNU C Library has been doing for quite some time now.
> +   However, as of version 2.1.2, the GNU C Library uses signal
> +   trampolines (named __restore and __restore_rt) that are identical
> +   to the ones used by the kernel.  Therefore, these trampolines are
> +   supported too.  */
> +
> +/* syscall #0x5077 */
> +static const unsigned char NDS32_SIGRETURN_INSN[] =
> +{
> +  0x64, 0x0a, 0x0e, 0xeb
> +};
> +
> +/* syscall #0x50ad */
> +static const unsigned char NDS32_RT_SIGRETURN_INSN[] =
> +{
> +  0x64, 0x0a, 0x15, 0xab
> +};
> +
> +int nds32_linux_sc_reg_offset[] =
> +{
> +  /* r0 - r9 */
> +  12, 16, 20, 24, 28, 32, 36, 40, 44, 48,
> +  /* r10 - r19 */
> +  52, 56, 60, 64, 68, 72, 76, 80, 84, 88,
> +  /* r20 - r25, 26, 27 */
> +  92, 96, 100, 104, 108, 112, -1, -1,
> +  /* fp, gp, lr, sp */
> +  116, 120, 124, 128,
> +  /* pc, d0lo, d0hi, d1lo, d1hi */
> +  148, 140, 144, 132, 136
> +};
> +
> +struct nds32_frame_cache
> +{
> +  CORE_ADDR base, pc;
> +  struct trad_frame_saved_reg *saved_regs;
> +};
> +
> +/* Find start of signal frame.  */
> +
> +static CORE_ADDR
> +nds32_linux_sigtramp_start (struct frame_info *this_frame)
> +{
> +  const int SIGLEN = sizeof (NDS32_SIGRETURN_INSN);
> +  CORE_ADDR pc = get_frame_pc (this_frame);
> +  gdb_byte buf[SIGLEN];
> +
> +  if (!safe_frame_unwind_memory (this_frame, pc, buf, SIGLEN))
> +    return 0;
> +
> +  if (memcmp (buf, NDS32_SIGRETURN_INSN, SIGLEN) != 0)
> +    return 0;
> +
> +  return pc;
> +}
> +
> +/* Find start of rt_signal frame.  */
> +
> +static CORE_ADDR
> +nds32_linux_rt_sigtramp_start (struct frame_info *this_frame)
> +{
> +  const int SIGLEN = sizeof (NDS32_RT_SIGRETURN_INSN);
> +  CORE_ADDR pc = get_frame_pc (this_frame);
> +  gdb_byte buf[SIGLEN];
> +
> +  if (!safe_frame_unwind_memory (this_frame, pc, buf, SIGLEN))
> +    return 0;
> +
> +  if (memcmp (buf, NDS32_RT_SIGRETURN_INSN, SIGLEN) != 0)
> +    return 0;
> +
> +  return pc;
> +}
> +
> +/* Return whether the frame preceding NEXT_FRAME corresponds to a
> +   GNU/Linux sigtramp routine.  */
> +
> +static int
> +nds32_linux_sigtramp_p (struct frame_info *this_frame)
> +{
> +  CORE_ADDR pc = get_frame_pc (this_frame);
> +  const char *name;
> +
> +  find_pc_partial_function (pc, &name, NULL, NULL);
> +
> +  /* If we have NAME, we can optimize the search.  The trampolines are
> +     named __restore and __restore_rt.  However, they aren't dynamically
> +     exported from the shared C library, so the trampoline may appear to
> +     be part of the preceding function.  This should always be sigaction,
> +     __sigaction, or __libc_sigaction (all aliases to the same function).  */
> +  if (name == NULL)
> +    return (nds32_linux_sigtramp_start (this_frame) != 0
> +	    || nds32_linux_rt_sigtramp_start (this_frame) != 0);
> +
> +  return (strcmp ("__default_sa_restorer", name) == 0
> +	  || strcmp ("__default_rt_sa_restorer", name) == 0);
> +}
> +
> +/* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>.  */
> +#define NDS32_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 0x18
> +
> +/* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp
> +   routine, return the address of the associated sigcontext structure.  */
> +
> +static CORE_ADDR
> +nds32_linux_sigcontext_addr (struct frame_info *this_frame)
> +{
> +  CORE_ADDR pc;
> +  CORE_ADDR sp;
> +  gdb_byte buf[4];
> +
> +  sp = get_frame_sp (this_frame);
> +
> +  /* sigcontext is at sp for sigtramp */
> +  pc = nds32_linux_sigtramp_start (this_frame);
> +  if (pc)
> +    return sp;
> +
> +  pc = nds32_linux_rt_sigtramp_start (this_frame);
> +  if (pc)
> +    {
> +      CORE_ADDR ucontext_addr;
> +      int r2;
> +
> +      /* Cole, Dec. 31th, 2010
> +	 sigcontext is stored in frame->uc.uc_mcontext, Therefore,
> +	 there are two ways to get sigcontext.
> +	 The first way, direct access it in the stack.In this way,
> +	 we needs more knowledge of rt_sigtramp
> +	 The second way, &us is passed as parameter 3 of handler,
> +	 that would be R2 in NDS32 ABI.As long as we use generic
> +	 ucontext struct, I think it's easier to get sigcontext.  */
> +
> +      r2 = get_frame_register_unsigned (this_frame, NDS32_R0_REGNUM + 2);
> +      sp = r2;
> +      /* This value is dependent on kernel.  */
> +      sp += NDS32_LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
> +      return sp;
> +    }
> +
> +  error (_("Couldn't recognize signal trampoline."));
> +  return 0;
> +}

For all the signal trampoline frame stuff, why don't you use 
'tramp_frame', which is simpler than your current approach.  Please grep 
tramp_frame_prepend_unwinder to see how it is used in other *-tdep.c files.

> +
> +static void
> +nds32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> +{
> +  const struct target_desc *tdesc = info.target_desc;
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +  struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info;
> +  const struct tdesc_feature *feature;
> +
> +  tdep->sigtramp_p = nds32_linux_sigtramp_p;
> +  tdep->sigcontext_addr = nds32_linux_sigcontext_addr;
> +  tdep->sc_pc_offset = 37 * 4;	/* sc.fault_address */
> +  tdep->sc_sp_offset = 32 * 4;	/* sc.sp */
> +  tdep->sc_lp_offset = 31 * 4;	/* sc.lp */
> +  tdep->sc_fp_offset = 29 * 4;	/* sc.fp */
> +
> +  tdep->sc_reg_offset = nds32_linux_sc_reg_offset;
> +  tdep->sc_num_regs = ARRAY_SIZE (nds32_linux_sc_reg_offset);
> +
> +  /* GNU/Linux uses SVR4-style shared libraries.  */
> +  set_solib_svr4_fetch_link_map_offsets (gdbarch,
> +					 svr4_ilp32_fetch_link_map_offsets);
> +
> +  /* Core file support.  */
> +  /* FIXME: Cole, Dec 31th, 2010
> +     It seems this doesn't work? */

Does it work? :)

> diff --git a/gdb/nds32-remote.c b/gdb/nds32-remote.c
> new file mode 100644
> index 0000000..c088f0d
> --- /dev/null
> +++ b/gdb/nds32-remote.c

Since there are no comments on what nds32-remote.c is for, I assume that 
it is used to talk with remote target, like jtag ice.  IIUC, you invent 
some new rsp packets to your own targets, but it is not recommended to 
add such thing into GDB nowadays.  I can't find the mail archive about 
this decision, and other people can give a definitive answer here.

Probably, you can move nds32-remote.c to a separate patch, so that it 
won't block the other patches.  On the other hand, it is not a big deal 
to maintain nds32-remote.c by yourself.

> diff --git a/gdb/nds32-tdep.c b/gdb/nds32-tdep.c
> new file mode 100644
> index 0000000..f861807
> --- /dev/null
> +++ b/gdb/nds32-tdep.c
> @@ -0,0 +1,2802 @@
> +/* Common target dependent code for GDB on nds32 systems.
> +
> +   Copyright (C) 2006-2013 Free Software Foundation, Inc.
> +   Contributed by Andes Technology Corporation.
> +
> +   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 <assert.h>

Remove this include?

> +#include <stdint.h>
> +
> +#include "defs.h"

Include "defs.h" first.

> +#include "frame.h"
> +#include "frame-unwind.h"
> +#include "frame-base.h"
> +#include "symtab.h"
> +#include "gdbtypes.h"
> +#include "gdbcmd.h"
> +#include "gdbcore.h"
> +#include "gdb_string.h"
> +#include "value.h"
> +#include "reggroups.h"
> +#include "inferior.h"
> +#include "symfile.h"
> +#include "objfiles.h"
> +#include "osabi.h"
> +#include "language.h"
> +#include "arch-utils.h"
> +#include "regcache.h"
> +#include "trad-frame.h"
> +#include "dis-asm.h"
> +#include "gdb_assert.h"
> +#include "user-regs.h"
> +#include "elf-bfd.h"
> +#include "dwarf2-frame.h"
> +#include "ui-file.h"
> +#include "remote.h"
> +#include "target-descriptions.h"
> +#include "sim-regno.h"
> +#include "gdb/sim-nds32.h"
> +
> +#include "nds32-tdep.h"
> +#include "nds32-utils.h"
> +#include "nds32-remote.h"
> +#include "elf/nds32.h"
> +#include "opcode/nds32.h"
> +
> +/* Simple macro for chop LSB immediate bits from an instruction.  */
> +#define CHOP_BITS(insn, n)	(insn & ~__MASK (n))
> +
> +extern void _initialize_nds32_tdep (void);
> +
> +struct nds32_gdb_config nds32_config;

Make it static.

> +
> +/* Register alias for user_reg_map_name_to_regnum ().  */
> +struct nds32_register_alias nds32_register_aliases[] =

Make it static too.

> +
> +/* Value of a register alias.  BATON is register name of the alias,
> +   because system registers do not have fixed register number.
> +   We must look-up them when access.  */
> +
> +static struct value *
> +nds32_value_of_reg (struct frame_info *frame, const void *baton)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (frame);
> +  int regnum;
> +
> +  regnum = user_reg_map_name_to_regnum (gdbarch, (const char *) baton, -1);
> +
> +  return value_of_register (regnum, frame);
> +}
> +
> +/* gdbarch_frame_align () */

/* This is the implementation of gdbarch method frame_align.  */

> +
> +static CORE_ADDR
> +nds32_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
> +{
> +  /* 8-byte aligned.  */
> +  return sp & ~(8 - 1);

return align_down (sp, 8);

> +}
> +
> +/* Implement the gdbarch_breakpoint_from_pc method.  */
> +
> +static const gdb_byte *
> +nds32_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
> +			  int *lenptr)
> +{
> +  static const gdb_byte NDS32_BREAK16[] = { 0xEA, 0x00 };

Do we need to worry about big-endian and little endian here?

> +  const unsigned char *bp;
> +
> +  gdb_assert (pcptr);

      gdb_assert (pcptr != NULL);

See 16.1.4 C Usage in http://www.sourceware.org/gdb/onlinedocs/gdbint.html

> +  gdb_assert (lenptr);
> +

Likewise.

> +  if ((*pcptr) & 1)
> +    error (_("Bad address %p for inserting breakpoint.\n"
> +	     "Address must be at least 2-byte aligned."), (void *) *pcptr);

Do you know when the last bit of address is 1?  I am wondering whether 
this checking is necessary or it is caused by the bug somewhere else.

> +
> +  /* Always insert 16-bit break instruction.  */
> +  *lenptr = 2;
> +  return NDS32_BREAK16;
> +}
> +

> +
> +/* Create types for registers and insert them to type table by name.  */
> +
> +static void
> +nds32_alloc_types (struct gdbarch *gdbarch)
> +{
> +  const struct builtin_type *bt = builtin_type (gdbarch);
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +  struct type *type, *stype1, *stype2;
> +
> +  tdep->type_tab = nds32_alloc_type_tab (24);
> +
> +  /* fucpr */
> +  type = arch_flags_type (gdbarch, "builtin_type_nds32_fucpr", 4);
> +  append_flags_type_flag (type, 0, "CP0EN");
> +  append_flags_type_flag (type, 1, "CP1EN");
> +  append_flags_type_flag (type, 2, "CP2EN");
> +  append_flags_type_flag (type, 3, "CP3EN");
> +  append_flags_type_flag (type, 31, "AUEN");
> +  nds32_type_insert (tdep->type_tab, "fucpr", type);

Can you define 'fucpr' in the target description? like

   <flags id="fucpr" size="4">
      <field name="CP0EN" start="0" end="0"/>
      .....
   </flags>

which is simpler, IMO.

> +
> +/* gdbarch_register_type ()

/* This is the implementation of gdbarch method register_type.  */

> +
> +   Return the GDB type object for the "standard" data type
> +   of data in register N.
> +   It get pretty messy here. I need enum-types and bit-fields
> +   for better representation. But they cannot be done by
> +   tdesc-xml.  */

target description works for enum and bitfields.  For example, in 
features/i386/32bit-core.xml,

   <flags id="i386_eflags" size="4">
     <field name="CF" start="0" end="0"/>
     <field name="" start="1" end="1"/>
     <field name="PF" start="2" end="2"/>
     <field name="AF" start="4" end="4"/>
     <field name="ZF" start="6" end="6"/>
     <field name="SF" start="7" end="7"/>
     <field name="TF" start="8" end="8"/>
     <field name="IF" start="9" end="9"/>
     <field name="DF" start="10" end="10"/>
     <field name="OF" start="11" end="11"/>
     <field name="NT" start="14" end="14"/>
     <field name="RF" start="16" end="16"/>
     <field name="VM" start="17" end="17"/>
     <field name="AC" start="18" end="18"/>
     <field name="VIF" start="19" end="19"/>
     <field name="VIP" start="20" end="20"/>
     <field name="ID" start="21" end="21"/>
   </flags>

I have to stop reviewing here as I've run out of time of patch review 
today.  I may have a look at the rest of the patch tomorrow.

As Joseph mentioned, there are a lot of FIXME/TODO/review, probably you 
have to get rid of them first.

I noticed that some functions in nds32-utils.c are not used at all. 
Please remove them.  Some functions are only used in nds32-tdep.c, so 
probably we can move them to nds32-tdep.c, and make them static.

-- 
Yao (齐尧)


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

* Re: [PATCH 1/5] Code for nds32 target
  2013-07-08 23:58 ` Joseph S. Myers
@ 2013-07-09 16:18   ` Wei-cheng Wang
  0 siblings, 0 replies; 9+ messages in thread
From: Wei-cheng Wang @ 2013-07-09 16:18 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: gdb-patches

On 7/9/2013 7:58 AM, Joseph S. Myers wrote:
> I advise reviewing this whole comment, and the Linux port in general, for
> whether it is still current.
>
> I don't see the kernel port as of Linux 3.10, and Linux kernel policy as I
> understand it is that new architectures are expected to use the generic
> syscall interface, which only has rt_sigreturn.  So, references to the old
> non-realtime sigreturn are suspect for new architectures.  Similarly,
> references to glibc 2.1.2 are suspect for an architecture with no glibc
> port as of 2.18.  (If the Linux ABI isn't fully confirmed with the
> upstream Linux kernel community, you might want to submit the non-Linux
> parts of the GDB port and come back to the Linux parts later.)

Hi Joseph,

This part is based on our outdated glibc 2.5 porting,
and we are still working on glibc 2.18,
so I agree we withdraw this part in revised patch,
and come back when our glibc 2.18 porting is ready.

Thanks for pointing out this and the suggestions.
I will review the patch thoroughly again.

Wei-cheng



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

* Re: [PATCH 1/5] Code for nds32 target
  2013-07-09  4:10 ` Yao Qi
@ 2013-07-09 18:23   ` Wei-cheng Wang
  2013-07-25  2:35     ` Yao Qi
  0 siblings, 1 reply; 9+ messages in thread
From: Wei-cheng Wang @ 2013-07-09 18:23 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

Hi Yao Qi,

   Thanks for you reviewing and suggestion.
   I will revise the patch based on your suggestion thoroughly :)
   Here are some brief answers and questions.

On 7/9/2013 12:09 PM, Yao Qi wrote:
> On 07/08/2013 05:27 PM, Wei-cheng Wang wrote:
> Do we really need "regnum="15"" here?

   Yes, but it is unnecessary, so I will remove this.
   It was here because r11-r14 does not exist in reduced
   register configuration.

> Since there are no comments on what nds32-remote.c is for, I assume that
> it is used to talk with remote target, like jtag ice.  IIUC, you invent
> some new rsp packets to your own targets, but it is not recommended to
> add such thing into GDB nowadays.  I can't find the mail archive about
> this decision, and other people can give a definitive answer here.

   Yes, this file are used to talk with our remote OpenOCD and SID.
   If you mean those "qPart:nds32:*" packets, I agree we should
   remove them and our remote target should be changed accordingly
   for conforming GDB RSP standard.
   Or do you mean monitor commands ("qRcmd,command" packetss) are
   also not recommended in GDB nowadays?

>> +}
>> +
>> +/* Implement the gdbarch_breakpoint_from_pc method.  */
>> +
>> +static const gdb_byte *
>> +nds32_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
>> +              int *lenptr)
>> +{
>> +  static const gdb_byte NDS32_BREAK16[] = { 0xEA, 0x00 };
>
> Do we need to worry about big-endian and little endian here?

   Instructions are always big-endian.

>> +  if ((*pcptr) & 1)
>> +    error (_("Bad address %p for inserting breakpoint.\n"
>> +         "Address must be at least 2-byte aligned."), (void *) *pcptr);
>
> Do you know when the last bit of address is 1?  I am wondering whether
> this checking is necessary or it is caused by the bug somewhere else.

   Just in case users may set the breakpoint in address directly.
   (gdb) break *0x4321
   I think I would better stop them at the first place.

> Can you define 'fucpr' in the target description? like
>
>    <flags id="fucpr" size="4">
>       <field name="CP0EN" start="0" end="0"/>
>       .....
>    </flags>
>
> which is simpler, IMO.
>
>> +
>> +   Return the GDB type object for the "standard" data type
>> +   of data in register N.
>> +   It get pretty messy here. I need enum-types and bit-fields
>> +   for better representation. But they cannot be done by
>> +   tdesc-xml.  */
>
> target description works for enum and bitfields.  For example, in
> features/i386/32bit-core.xml,
>

   Target description can not describe a enum-typed bit-field.

   If bit-field struct is used, I could not specify the type for
   a bit-field.

     <struct id="id" size="size">
       <field name="name" start="start" end="end"/>
       ...
     </struct>

   If I want to specify field type, I couldn't specify size of a field.

     <struct id="id">
       <field name="name" type="type"/>
       ...
     </struct>

   All I want is to display a register in such format.

     (gdb) p $cr0
     $1 = {CFGID = [ PERF_EXT 16_EXT PERF_EXT2 COP_EXT STR_EXT ],
     REV = 16, CPUID = N13}

   (cr0 consist of config flags, revision number and CPU ID.)

   I agree all these type describing thing should be in
   target-description, but if target-description could not describe
   all the needed types, IMHO managing them in a single
   place may be better then scattering them in GDB and
   target-description.
   Or I may help to extend target-description, so we could specify
   types of bit-fields?

   Any suggestion?

> I have to stop reviewing here as I've run out of time of patch review
> today.  I may have a look at the rest of the patch tomorrow.

   Thanks for your great help :)

Wei-cheng



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

* Re: [PATCH 1/5] Code for nds32 target
  2013-07-08  9:28 [PATCH 1/5] Code for nds32 target Wei-cheng Wang
  2013-07-08 23:58 ` Joseph S. Myers
  2013-07-09  4:10 ` Yao Qi
@ 2013-07-10  5:38 ` Yao Qi
  2013-07-11 14:06   ` Wei-cheng Wang
  2013-07-11 14:26   ` Wei-cheng Wang
  2 siblings, 2 replies; 9+ messages in thread
From: Yao Qi @ 2013-07-10  5:38 UTC (permalink / raw)
  To: Wei-cheng Wang; +Cc: gdb-patches

On 07/08/2013 05:27 PM, Wei-cheng Wang wrote:

Here is the 2nd half.

> +/* Implement the gdbarch_register_reggroup_p method.  */
> +
> +static int
> +nds32_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
> +			   struct reggroup *group)
> +{
> +  int i;
> +  struct reggroup *groups[] =
> +  {
> +      nds32_cr_reggroup, nds32_ir_reggroup, nds32_mr_reggroup,
> +      nds32_dr_reggroup, nds32_pfr_reggroup, nds32_dmar_reggroup,
> +      nds32_racr_reggroup, nds32_idr_reggroup
> +  };
> +  static const char *prefix[] =
> +  {
> +      "cr", "ir", "mr", "dr", "pfr", "dmar", "racr", "idr"
> +  };
> +
> +  gdb_assert (sizeof (groups) == sizeof (prefix));

gdb_assert (ARRAY_SIZE (groups) == ARRAY_SIZE (prefix)); ?

> +
> +  /* GPRs. */
> +  if (group == general_reggroup)
> +    return regnum <= NDS32_PC_REGNUM;
> +
> +  /* System Registers are grouped by prefix.  */
> +  else if (group == system_reggroup)
> +    return (regnum > NDS32_PC_REGNUM)
> +	   && TYPE_CODE (register_type (gdbarch, regnum)) != TYPE_CODE_FLT;
> +
> +  for (i = 0; i < ARRAY_SIZE (groups); i++)
> +    {
> +      if (group == groups[i])
> +	{
> +	  const char *regname = tdesc_register_name (gdbarch, regnum);
> +
> +	  if (!regname)
> +	    return 0;
> +	  return strstr (regname, prefix[i]) == regname;
> +	}
> +    }
> +
> +  return default_register_reggroup_p (gdbarch, regnum, group);
> +}
> +
> +/* This function is called when
> +   1. Target-description is used, and the register is pseudo.
> +   2. Target-description is NOT used,
> +       i. and the target is simulator.
> +      ii. or the target is legacy target.  */
> +
> +/* Implement the tdesc_pseudo_register_name method.  */
> +
> +static const char *
> +nds32_register_name (struct gdbarch *gdbarch, int regnum)
> +{
> +  static char *fpu_pseudo_names[] =
> +  {
> +    "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
> +    "fs8", "fs9", "fs10", "fs11", "fs12", "fs13", "fs14", "fs15",
> +    "fs16", "fs17", "fs18", "fs19", "fs20", "fs21", "fs22", "fs23",
> +    "fs24", "fs25", "fs26", "fs27", "fs28", "fs29", "fs30", "fs31"
> +  };
> +  static char *sim_names[] =
> +  {
> +    "fd0", "fd1", "fd2", "fd3", "fd4", "fd5", "fd6", "fd7",
> +    "fd8", "fd9", "fd10", "fd11", "fd12", "fd13", "fd14", "fd15",
> +    "fd16", "fd17", "fd18", "fd19", "fd20", "fd21", "fd22", "fd23",
> +    "fd24", "fd25", "fd26", "fd27", "fd28", "fd29", "fd30", "fd31",
> +    "ifclp", "itb", "ir0"
> +  };
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +  int num_regs = gdbarch_num_regs (gdbarch);
> +
> +  /* Currently, only pseudo FSR are supported.  */
> +  if (regnum >= num_regs && regnum < num_regs + 32)
> +    return fpu_pseudo_names[regnum - num_regs];
> +
> +  /* GPRs.  */
> +  if (regnum < ARRAY_SIZE (nds32_regnames))
> +    return nds32_regnames[regnum];
> +
> +  /* Registers beteen NUM_REGS and SMI_NUM_REGS are
> +     simulator registers.  */
> +  if (regnum >= NDS32_NUM_REGS && regnum < NDS32_SIM_NUM_REGS)
> +    return sim_names[regnum - NDS32_NUM_REGS];
> +
> +  warning (_("Unknown nds32 pseudo register %d."), regnum);
> +  return NULL;
> +}
> +
> +/* Implement the gdbarch_pseudo_register_read method.
> +
> +   For legacy target, target-description and FPRs are not support.
> +   Use Rcmd to access FPU registers.  */
> +
> +static enum register_status
> +nds32_pseudo_register_read (struct gdbarch *gdbarch,
> +			    struct regcache *regcache, int regnum,
> +			    gdb_byte *buf)
> +{
> +  char name_buf[8];
> +  gdb_byte reg_buf[8];
> +  int offset;
> +  enum register_status status = REG_UNKNOWN;
> +
> +  /* Sanity check.  */
> +  regnum -= gdbarch_num_regs (gdbarch);
> +  if (regnum > gdbarch_num_pseudo_regs (gdbarch))
> +    return status;
> +
> +  /* Currently, only FSR are supported.  */
> +  if (regnum < 32)
> +    {
> +      int fd_regnum;
> +
> +      /* fs0 is always the high-part of fd0.  */
> +      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
> +	offset = (regnum & 1) ? 4 : 0;
> +      else
> +	offset = (regnum & 1) ? 0 : 4;
> +
> +      sprintf (name_buf, "fd%d", regnum >> 1);

xsnprintf

> +      fd_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
> +					       strlen (name_buf));
> +      status = regcache_raw_read (regcache, fd_regnum, reg_buf);
> +      if (status == REG_VALID)
> +	memcpy (buf, reg_buf + offset, 4);
> +    }
> +
> +  return status;
> +}
> +
> +/* Implement the gdbarch_pseudo_register_write method.  */
> +
> +static void
> +nds32_pseudo_register_write (struct gdbarch *gdbarch,
> +			     struct regcache *regcache, int regnum,
> +			     const gdb_byte *buf)
> +{
> +  char name_buf[8];
> +  gdb_byte reg_buf[8];
> +  int offset;
> +
> +  /* Sanity check.  */
> +  regnum -= gdbarch_num_regs (gdbarch);
> +  if (regnum > gdbarch_num_pseudo_regs (gdbarch))
> +    return;
> +
> +  /* Currently, only FSR are supported.  */
> +  if (regnum < 32)
> +    {
> +      int fd_regnum;
> +
> +      /* fs0 is always the high-part of fd0.  */
> +      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
> +	offset = (regnum & 1) ? 4 : 0;
> +      else
> +	offset = (regnum & 1) ? 0 : 4;
> +
> +      sprintf (name_buf, "fd%d", regnum >> 1);
> +      fd_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
> +					       strlen (name_buf));
> +      regcache_raw_read (regcache, fd_regnum, reg_buf);
> +      memcpy (reg_buf + offset, buf, 4);
> +      regcache_raw_write (regcache, fd_regnum, reg_buf);
> +    }
> +
> +  return;
> +}
> +
> +/* Skip prologue should be conservative, and frame-unwind should be
> +   relative-aggressive.*/
> +
> +static int
> +nds32_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
> +			CORE_ADDR scan_limit, CORE_ADDR *pl_endptr)
> +{
> +  uint32_t insn;
> +  CORE_ADDR cpc = -1;		/* Candidate PC if no suitable PC is found.  */
> +  LONGEST return_value;
> +
> +  /* If there is no buffer to store result, ignore this prologue decoding.  */
> +  if (pl_endptr == NULL)
> +    {
> +      return 0;
> +    }
> +
> +  /* Look up end of prologue */
> +  for (; pc < scan_limit; )
> +    {
> +      insn = read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG);
> +
> +      if ((insn & 0x80000000) == 0)
> +	{
> +	  /* 32-bit instruction */
> +
> +	  pc += 4;
> +	  if (insn == N32_ALU1 (ADD, REG_GP, REG_TA, REG_GP))
> +	    {
> +	      /* add $gp, $ta, $gp */
> +	      continue;
> +	    }
> +	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ADDI, REG_SP, REG_SP, 0))
> +	    {
> +	      /* addi $sp, $sp, imm15 */
> +	      cpc = pc;
> +	      continue;
> +	    }
> +	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ADDI, REG_FP, REG_FP, 0))
> +	    {
> +	      /* addi $fp, $sp, imm15 */
> +	      cpc = pc;
> +	      continue;
> +	    }
> +	  else if (insn == N32_ALU2 (MFUSR, REG_TA, 31, 0))
> +	    {
> +	      /* mfusr $ta, PC  ; group=0, sub=0x20=mfusr */
> +	      continue;
> +	    }
> +	  else if (CHOP_BITS (insn, 20) == N32_TYPE1 (MOVI, REG_TA, 0))
> +	    {
> +	      /* movi $ta, imm20s */
> +	      continue;
> +	    }
> +	  else if (CHOP_BITS (insn, 20) == N32_TYPE1 (SETHI, REG_GP, 0))
> +	    {
> +	      /* sethi $gp, imm20 */
> +	      continue;
> +	    }
> +	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ORI, REG_GP, REG_GP, 0))
> +	    {
> +	      /* ori $gp, $gp, imm15 */
> +	      continue;
> +	    }
> +	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI, REG_LP, REG_FP, 0))
> +	    {
> +	      /* Unlike swi, we should stop when lwi.  */
> +	      /* swi $lp, [$sp + (imm15s<<2)] */
> +	      continue;
> +	    }
> +	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI_BI, REG_LP, REG_FP, 0))
> +	    {
> +	      /* swi.bi $rt, [$sp], (imm15s<<2) */
> +	      continue;
> +	    }
> +	  else if (N32_OP6 (insn) == N32_OP6_LSMW && (insn & __BIT (5)))
> +	    {
> +	      /* bit-5 for SMW */
> +
> +	      /* smwa?.(a|b)(d|i)m? rb,[ra],re,enable4 */
> +
> +	      int rb, re, ra, enable4, i;
> +	      int aligned;
> +	      int m = 0;
> +	      int di;		/* dec=-1 or inc=1 */
> +	      char enb4map[2][4] = {
> +		  {0, 1, 2, 3} /* smw */,
> +		  {3, 1, 2, 0} /* smwa */};
> +	      LONGEST base = ~1 + 1;
> +
> +	      rb = N32_RT5 (insn);
> +	      ra = N32_RA5 (insn);
> +	      re = N32_RB5 (insn);
> +	      enable4 = (insn >> 6) & 0x0F;
> +	      aligned = (insn & 3) ? 1 : 0;
> +	      di = (insn & (1 << 3)) ? -1 : 1;
> +
> +	      switch (ra)
> +		{
> +		case NDS32_FP_REGNUM:
> +		case NDS32_SP_REGNUM:
> +		  cpc = pc;
> +		  continue; /* found and continue */
> +		default:
> +		  break;
> +		}
> +	    }
> +
> +	  if (N32_OP6 (insn) == N32_OP6_COP && N32_COP_CP (insn) == 0
> +	      && (N32_COP_SUB (insn) == N32_FPU_FSS
> +		  || N32_COP_SUB (insn) == N32_FPU_FSD)
> +	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
> +	    {
> +	      /* CP shoud be CP0 */
> +	      /* fs[sd][.bi] $fst, [$sp + ($r0 << sv)] */
> +	      continue;
> +	    }
> +
> +	  /* fssi    $fst, [$ra + (imm12s << 2)]
> +	     fssi.bi $fst, [$ra], (imm12s << 2)
> +	     fsdi    $fdt, [$ra + (imm12s << 2)]
> +	     fsdi.bi $fdt, [$ra], (imm12s << 2) */
> +	  if ((N32_OP6 (insn) == N32_OP6_SWC || N32_OP6 (insn) == N32_OP6_SDC)
> +	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
> +	    {
> +	      /* BI bit is dont-care.  */
> +	      continue;
> +	    }
> +
> +	  pc -= 4;
> +	  break;
> +	}
> +      else
> +	{
> +	  /* 16-bit instruction */
> +	  pc += 2;
> +	  insn >>= 16;
> +
> +	  /* 1. If the instruction is j/b, then we stop
> +		i.e., OP starts with 10, and beqzs8, bnezs8.
> +	     2. If the operations will change sp/fp or based on sp/fp,
> +		then we are in the prologue.
> +	     3. If we don't know what's it, then stop.  */
> +
> +	  if (CHOP_BITS (insn, 10) == N16_TYPE10 (ADDI10S, 0))
> +	    {
> +	      /* addi10s */
> +	      continue;
> +	    }
> +	  else if (__GF (insn, 7, 8) == N16_T25_PUSH25)
> +	    {
> +	      /* push25 */
> +	      continue;
> +	    }
> +	  else if (insn == N16_TYPE55 (MOV55, REG_FP, REG_SP))
> +	    {
> +	      /* mov55 fp, sp */
> +	      continue;
> +	    }
> +
> +	  /* swi450 */
> +	  switch (insn & ~__MF (-1, 5, 4))
> +	    {
> +	      case N16_TYPE45 (SWI450, 0, REG_SP):
> +	      case N16_TYPE45 (SWI450, 0, REG_FP):
> +		break;
> +	    }
> +	  /* swi37 - implied fp */
> +	  if (__GF (insn, 11, 4) == N16_T37_XWI37
> +	      && (insn & __BIT (7)))
> +	    continue;
> +
> +	  /* swi37sp - implied */
> +	  if (__GF (insn, 11, 4) == N16_T37_XWI37SP
> +	      && (insn & __BIT (7)))
> +	    continue;
> +
> +	  /* If the a instruction is not accepted,
> +	     don't go futher.  */
> +	  pc -= 2;
> +	  break;
> +	}
> +    }
> +
> +  if (pc >= scan_limit)
> +    {
> +      /* If we can not find end of prologue before scan_limit,
> +	 we assume that end of prologue is on pc_after_stack_adject. */
> +      if (cpc != -1)
> +	pc = cpc;
> +    }
> +
> +  *pl_endptr = pc;
> +
> +  return 0;
> +}
> +
> +/* Implement the gdbarch_skip_prologue method.
> +
> +   Find the end of function prologue.  */
> +
> +static CORE_ADDR
> +nds32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
> +{
> +  CORE_ADDR func_addr, func_end;
> +  struct symtab_and_line sal = { 0 };
> +  LONGEST return_value;
> +  const char *func_name;
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +  const int search_limit = 128;
> +
> +  /* See what the symbol table says */
> +  if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
> +    {
> +      sal = find_pc_line (func_addr, 0);
> +
> +      if (sal.line != 0 && sal.end <= func_end)
> +	{
> +	  func_end = sal.end;
> +	}

Unnecessary brackets.

> +      else
> +	{
> +	  /* Either there's no line info, or the line after the prologue
> +	     is after the end of the function.  In this case, there probably
> +	     isn't a prologue.  */
> +	  func_end = min (func_end, func_addr + search_limit);
> +	}
> +    }
> +  else
> +    func_end = pc + search_limit;
> +
> +  /* If current instruction is not readable, just quit.  */
> +  if (!safe_read_memory_integer (pc, 4, byte_order, &return_value))
> +    return pc;
> +
> +  /* Find the end of prologue.  */
> +  if (nds32_analyze_prologue (gdbarch, pc, func_end, &sal.end) < 0)
> +    return pc;
> +
> +  return sal.end;
> +}
> +
> +struct nds32_unwind_cache
> +{
> +  /* The previous frame's inner most stack address.
> +     Used as this frame ID's stack_addr.  */
> +  CORE_ADDR prev_sp;
> +
> +  /* The frame's base, optionally used by the high-level debug info.  */
> +  CORE_ADDR base;
> +  int size;
> +
> +  /* How far the SP and FP have been offset from the start of
> +     the stack frame (as defined by the previous frame's stack
> +     pointer).  */
> +  LONGEST sp_offset;
> +  LONGEST fp_offset;
> +  int use_frame;
> +
> +  /* Table indicating the location of each and every register.  */
> +  struct trad_frame_saved_reg *saved_regs;
> +};
> +
> +static struct nds32_unwind_cache *
> +nds32_alloc_frame_cache (struct frame_info *this_frame)
> +{
> +  struct nds32_unwind_cache *cache;

Blank line is needed here.

> +  cache = FRAME_OBSTACK_ZALLOC (struct nds32_unwind_cache);
> +
> +  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
> +  cache->size = 0;
> +  cache->sp_offset = 0;
> +  cache->fp_offset = 0;
> +  cache->use_frame = 0;
> +  cache->base = 0;
> +
> +  return cache;
> +}
> +
> +/* Implement the gdbarch_in_function_epilogue_p method.  */
> +
> +static int
> +nds32_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> +  uint32_t insn;
> +  int r = 0;
> +
> +  insn = read_memory_unsigned_integer (addr, 4, BFD_ENDIAN_BIG);
> +  if ((insn & 0x80000000) == 0)
> +    {
> +      /* 32-bit instruction */
> +
> +      /* ret */
> +      if (insn == N32_JREG (JR, 0, REG_LP, 0, 1))
> +	r = 1;
> +      /* iret */
> +      else if (insn == N32_TYPE0 (MISC, N32_MISC_IRET))
> +	r = 2;
> +    }
> +  else
> +    {
> +      if (insn == N16_TYPE5 (RET5, REG_LP))
> +	r = 3;
> +    }
> +  return r > 0;
> +}
> +
> +/* Put here the code to store, into fi->saved_regs, the addresses of
> +   the saved registers of frame described by FRAME_INFO.  This
> +   includes special registers such as pc and fp saved in special ways
> +   in the stack frame.  sp is even more special: the address we return
> +   for it IS the sp for the next frame.  */
> +
> +static struct nds32_unwind_cache *
> +nds32_frame_unwind_cache (struct frame_info *this_frame,
> +			  void **this_prologue_cache)
> +{
> +  CORE_ADDR pc, scan_limit;
> +  ULONGEST prev_sp;
> +  ULONGEST next_base;
> +  ULONGEST fp_base;
> +  int i;
> +  int insn;
> +  struct nds32_unwind_cache *info;
> +  struct gdbarch *gdbarch = get_frame_arch (this_frame);
> +
> +  if ((*this_prologue_cache))
> +    return (*this_prologue_cache);
> +
> +  info = nds32_alloc_frame_cache (this_frame);
> +
> +  info->base = get_frame_register_unsigned (this_frame, NDS32_FP_REGNUM);
> +  (*this_prologue_cache) = info;
> +
> +  if (info->base == 0)
> +    return info;
> +
> +  pc = get_frame_func (this_frame);
> +  scan_limit = get_frame_pc (this_frame);
> +
> +  for (; pc > 0 && pc < scan_limit; )
> +    {
> +      insn = read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG);
> +
> +      if ((insn & 0x80000000) == 0)
> +	{
> +	  /* 32-bit instruction */
> +
> +	  pc += 4;
> +	  if (insn == N32_ALU1 (ADD, REG_GP, REG_TA, REG_GP))
> +	    {
> +	      /* add $gp, $ta, $gp */
> +	      continue;
> +	    }
> +	  if (N32_OP6 (insn) == N32_OP6_ADDI)
> +	    {
> +	      int rt = N32_RT5 (insn);
> +	      int ra = N32_RA5 (insn);
> +	      int imm15s = N32_IMM15S (insn);
> +
> +	      if (rt == ra && rt == NDS32_SP_REGNUM)
> +		{
> +		  info->sp_offset += imm15s;
> +		  continue;
> +		}
> +	      else if (rt == NDS32_FP_REGNUM && ra == NDS32_SP_REGNUM)
> +		{
> +		  info->fp_offset = info->sp_offset + imm15s;
> +		  info->use_frame = 1;
> +		  continue;
> +		}
> +	      else if (rt == ra)
> +		/* Prevent stop analyzing form iframe.  */
> +		continue;
> +	    }
> +
> +	  if (insn == N32_ALU2 (MFUSR, REG_TA, 31, 0))
> +	    {
> +	      /* mfusr $ta, PC  ; group=0, sub=0x20=mfusr */
> +	      continue;
> +	    }
> +	  if (CHOP_BITS (insn, 20) == N32_TYPE1 (MOVI, REG_TA, 0))
> +	    {
> +	      /* movi $ta, imm20s */
> +	      continue;
> +	    }
> +	  if (CHOP_BITS (insn, 20) == N32_TYPE1 (SETHI, REG_GP, 0))
> +	    {
> +	      /* sethi $gp, imm20 */
> +	      continue;
> +	    }
> +	  if (CHOP_BITS (insn, 15) == N32_TYPE2 (ORI, REG_GP, REG_GP, 0))
> +	    {
> +	      /* ori $gp, $gp, imm15 */
> +	      continue;
> +	    }
> +	  if (N32_OP6 (insn) == N32_OP6_LSMW && (insn & __BIT (5)))
> +	    {
> +	      /* smwa?.(a|b)(d|i)m? rb,[ra],re,enable4 */
> +
> +	      int rb, re, ra, enable4, i;
> +	      int aligned;
> +	      int m = 0;
> +	      int di;	   /* dec=-1 or inc=1 */
> +	      int rn;	   /* number of registers.  */
> +	      char enb4map[2][4] = {
> +		  {0, 1, 2, 3} /* smw */,
> +		  {3, 1, 2, 0} /* smwa */ };
> +	      /* `base' is the highest/last address for access memory.
> +		 e.g., [ lp ] ___ base shoule be here.
> +		       [ fp ]
> +		       [ r6 ] */
> +	      LONGEST base = ~1 + 1;
> +
> +	      rb = N32_RT5 (insn);
> +	      ra = N32_RA5 (insn);
> +	      re = N32_RB5 (insn);
> +	      enable4 = (insn >> 6) & 0x0F;
> +	      aligned = (insn & 3) ? 1 : 0;
> +	      di = (insn & (1 << 3)) ? -1 : 1;
> +
> +	      rn = 0;
> +	      rn += (enable4 & 0x1) ? 1 : 0;
> +	      rn += (enable4 & 0x2) ? 1 : 0;
> +	      rn += (enable4 & 0x4) ? 1 : 0;
> +	      rn += (enable4 & 0x8) ? 1 : 0;
> +	      if (rb < NDS32_FP_REGNUM && re < NDS32_FP_REGNUM)
> +		{
> +		  /* reg-list should not include fp,gp,lp,sp
> +		     ie, the rb==re==sp case, anyway... */
> +		  rn += (re - rb) + 1;
> +		}
> +
> +	      /* Let's consider how Ra should update.  */
> +	      if (insn & (1 << 0x2))    /* m-bit is set */
> +		{
> +		  m = rn * 4;			/* 4*TNReg */
> +		}
> +	      else
> +		m = 0;	  /* don't update Ra */
> +
> +	      switch (ra)
> +		{
> +		case NDS32_FP_REGNUM:
> +		  base = info->fp_offset;
> +		  info->fp_offset += m * di;
> +		  break;
> +		case NDS32_SP_REGNUM:
> +		  base = info->sp_offset;
> +		  info->sp_offset += m * di;
> +		  break;
> +		default:
> +		  /* sorry, only ra==sp || ra==fp is handled */
> +		  break;
> +		}
> +	      if (base == ~1 + 1)
                           ^^^^^^^ ??

> +		break;	  /* skip */
> +
> +	      if (insn & (1 << 0x4))	/* b:0, a:1 */
> +		base += 4 * di;		/* a: use Ra+4 (for i),
> +					      or Ra-4 (for d) */
> +	      /* else base = base;	b use Ra */
> +
> +	      /* Cole 3th Nov. 2010
> +		 We should consider both increasing and decreasing case.
> +
> +		 Either case stores registers in the same order.
> +		 To simplify the code (yes, the loops),
> +		 I used the same pushing order, but from different side.  */
> +
> +	      if (di == 1)		/* Increasing.  */
> +		base += (rn * 4 - 4);
> +	      /* else, in des case, we already are on the top */
> +
> +	      for (i = 0; i < 4; i++)
> +		{
> +		  if (enable4 & (1 << enb4map[aligned][i]))
> +		    {
> +		      info->saved_regs[NDS32_SP_REGNUM -
> +				       (enb4map[aligned][i])].addr = base;
> +		      base -= 4;
> +		    }
> +		}
> +
> +	      /* Skip re == rb == sp > fp.  */
> +	      for (i = re; i >= rb && rb < NDS32_FP_REGNUM; i--)
> +		{
> +		  info->saved_regs[i].addr = base;
> +		  base -= 4;
> +		}
> +
> +	      continue;
> +	    }
> +	  /* swi $lp, [$sp + (imm15s << 2)] */
> +	  /* We must check if $rt is $lp to determine it is
> +	     in prologue or not.  */
> +	  if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI, REG_LP, REG_FP, 0))
> +	    {
> +	      int imm15s;
> +
> +	      /* swi $lp, [$sp + (imm15s<<2)] */
> +	      imm15s = N32_IMM15S (insn);
> +	      info->saved_regs[NDS32_LP_REGNUM].addr = info->sp_offset
> +						       + (imm15s << 2);
> +	      continue;
> +	    }
> +	  /* swi.bi $rt, [$sp], (imm15s << 2) */
> +	  if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI_BI, REG_LP, REG_FP, 0))
> +	    {
> +	      unsigned int rt5 = 0;
> +	      unsigned int ra5 = 0;
> +	      int imm15s = 0;
> +	      rt5 = N32_RT5 (insn);
> +	      ra5 = N32_RA5 (insn);
> +	      imm15s = N32_IMM15S (insn);
> +
> +	      if (ra5 == NDS32_SP_REGNUM)
> +		{
> +		  info->saved_regs[rt5].addr = info->sp_offset;
> +		  info->sp_offset += (imm15s << 2);
> +		}
> +	      else if (ra5 == NDS32_FP_REGNUM)
> +		{
> +		  info->saved_regs[rt5].addr = info->fp_offset;
> +		  info->fp_offset += (imm15s << 2);
> +		}
> +	      continue;
> +	    }
> +
> +	  if (N32_OP6 (insn) == N32_OP6_COP && N32_COP_CP (insn) == 0
> +	      && (N32_COP_SUB (insn) == N32_FPU_FSS
> +		  || N32_COP_SUB (insn) == N32_FPU_FSD)
> +	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
> +	    {
> +	      /* CP shoud be CP0 */
> +	      /* fs[sd][.bi] $fst, [$sp + ($r0 << sv)] */
> +	      continue;
> +	    }
> +
> +	  /* fssi $fst, [$ra + (imm12s << 2)]
> +	     fssi.bi $fst, [$ra], (imm12s << 2)
> +	     fsdi $fdt, [$ra + (imm12s << 2)]
> +	     fsdi.bi $fdt, [$ra], (imm12s << 2) */
> +	  if ((N32_OP6 (insn) == N32_OP6_SWC || N32_OP6 (insn) == N32_OP6_SDC)
> +	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
> +	    {
> +	      /* fssi and fsdi have the same form.  */
> +	      /* Only .bi form should be handled to adjust reg.  */
> +	      unsigned int ra5 = 0;
> +	      unsigned int fs5 = 0;
> +	      int imm12s = 0;
> +
> +	      fs5 = N32_RT5 (insn);
> +	      ra5 = N32_RA5 (insn);
> +	      imm12s = N32_IMM12S (insn);
> +
> +	      if (imm12s & 0x800)
> +		imm12s = (imm12s - (0x800 << 1));
> +
> +	      switch (ra5)
> +		{
> +		case NDS32_FP_REGNUM:
> +		  info->fp_offset += (imm12s << 2);
> +		  break;
> +		case NDS32_SP_REGNUM:
> +		  info->sp_offset += (imm12s << 2);
> +		  break;
> +		}
> +
> +	      continue;
> +	    }
> +
> +	  /* TODO: Handle mfsr and addi for interrupt handlers.  */

Need to handle mfsr and addi now?

> +	  break;
> +	}
> +      else
> +	{
> +	  /* 16-bit instruction */
> +	  pc += 2;
> +	  insn >>= 16;
> +
> +	  /* 1. If the instruction is j/b, then we stop
> +		i.e., OP starts with 10, and beqzs8, bnezs8.
> +	     2. If the operations will change sp/fp or based on sp/fp,
> +		then we are in the prologue.
> +	     3. If we don't know what's it, then stop.  */
> +
> +	  if (__GF (insn, 13, 2) == 2)
> +	    {
> +	      /* These are all branch instructions.  */
> +	      pc -= 2;
> +	      break;
> +	    }
> +	  else if (__GF (insn, 9, 6) == 0x34)
> +	    {
> +	      /* beqzs8, bnezs8 */
> +	      pc -= 2;
> +	      break;
> +	    }
> +
> +	  if (CHOP_BITS (insn, 10) == N16_TYPE10 (ADDI10S, 0))
> +	    {
> +	      /* addi10s */
> +	      info->sp_offset += N16_IMM10S (insn);
> +	      continue;
> +	    }
> +
> +	  if (__GF (insn, 7, 8) == N16_T25_PUSH25)
> +	    {
> +	      /* push25 */
> +	      int imm8u = (insn & 0x1f) << 3;
> +	      int re = ((insn & 0x60) >> 5) & 0x3;
> +	      int res[] = {6, 8, 10, 14};
> +	      int m[] = {4, 6, 8, 12};
> +	      LONGEST base = info->sp_offset - 4;
> +
> +	      /* Operation 1 - smw.adm R6, [sp], Re, #0xe */
> +	      info->saved_regs[NDS32_LP_REGNUM].addr = info->sp_offset - 0x4;
> +	      info->saved_regs[NDS32_GP_REGNUM].addr = info->sp_offset - 0x8;
> +	      info->saved_regs[NDS32_FP_REGNUM].addr = info->sp_offset - 0xC;
> +	      info->sp_offset -= m[re] * 4;
> +
> +	      switch (re)
> +		{
> +		  case 3:
> +		    info->saved_regs[NDS32_R0_REGNUM + 14].addr = info->sp_offset + 0x20;
> +		    info->saved_regs[NDS32_R0_REGNUM + 13].addr = info->sp_offset + 0x1C;
> +		    info->saved_regs[NDS32_R0_REGNUM + 12].addr = info->sp_offset + 0x18;
> +		    info->saved_regs[NDS32_R0_REGNUM + 11].addr = info->sp_offset + 0x14;
> +		  case 2:
> +		    info->saved_regs[NDS32_R0_REGNUM + 10].addr = info->sp_offset + 0x10;
> +		    info->saved_regs[NDS32_R0_REGNUM + 9].addr = info->sp_offset + 0xC;
> +		  case 1:
> +		    info->saved_regs[NDS32_R0_REGNUM + 8].addr = info->sp_offset + 0x8;
> +		    info->saved_regs[NDS32_R0_REGNUM + 7].addr = info->sp_offset + 0x4;
> +		  case 0:
> +		    info->saved_regs[NDS32_R0_REGNUM + 6].addr = info->sp_offset;
> +		}
> +
> +	      /* Operation 2 - sp = sp - imm5u<<3 */
> +	      info->sp_offset -= imm8u;
> +
> +	      /* Operation 3 - if (Re >= 1) R8 = concat (PC(31,2), 2`b0) */
> +	      continue;
> +	    }
> +
> +	  /* mov55 fp, sp */
> +	  if (insn == N16_TYPE55 (MOV55, REG_FP, REG_SP))
> +	    {
> +		info->fp_offset = info->sp_offset;
> +		info->use_frame = 1;
> +		continue;
> +	    }
> +	  /* swi450 */
> +	  switch (insn & ~__MF (-1, 5, 4))
> +	    {
> +	      case N16_TYPE45 (SWI450, 0, REG_SP):
> +	      case N16_TYPE45 (SWI450, 0, REG_FP):
> +		break;
> +	    }
> +	  /* swi37 - implied fp */
> +	  if (__GF (insn, 11, 4) == N16_T37_XWI37
> +	      && (insn & __BIT (7)))
> +	    continue;
> +
> +	  /* swi37sp - implied */
> +	  if (__GF (insn, 11, 4) == N16_T37_XWI37SP
> +	      && (insn & __BIT (7)))
> +	    continue;
> +
> +	  break;
> +	  }
> +    }
> +
> +  info->size = -info->sp_offset;
> +  /* Compute the previous frame's stack pointer (which is also the
> +     frame's ID's stack address), and this frame's base pointer.
> +
> +     Assume that the FP is this frame's SP but with that pushed
> +     stack space added back.  */
> +  next_base = get_frame_register_unsigned (this_frame, NDS32_SP_REGNUM);
> +  prev_sp = next_base + info->size;
> +  fp_base = get_frame_register_unsigned (this_frame, NDS32_FP_REGNUM);
> +  if (info->use_frame && fp_base > 0)
> +    {
> +      /* Try to use FP if possible. */
> +      prev_sp = fp_base - info->fp_offset;
> +    }
> +
> +  /* Convert that SP/BASE into real addresses.  */
> +  info->prev_sp = prev_sp;
> +  info->base = next_base;
> +
> +  /* Adjust all the saved registers so that they contain addresses and
> +     not offsets.  */
> +  for (i = 0; i < gdbarch_num_regs (gdbarch) - 1; i++)
> +    {
> +      if (trad_frame_addr_p (info->saved_regs, i))
> +	{
> +	  info->saved_regs[i].addr = info->prev_sp + info->saved_regs[i].addr;
> +	}
> +    }
> +
> +  /* The previous frame's SP needed to be computed.
> +     Save the computed value.  */
> +  trad_frame_set_value (info->saved_regs, NDS32_SP_REGNUM, prev_sp);
> +
> +  return info;
> +}
> +


> +/* Implement the gdbarch_skip_permanent_breakpoint method.  */
> +
> +static void
> +nds32_skip_permanent_breakpoint (struct regcache *regcache)
> +{
> +  int insn;
> +  CORE_ADDR current_pc = regcache_read_pc (regcache);
> +
> +  /* On nds32, breakpoint may be BREAK or BREAK16.  */
> +  insn = read_memory_unsigned_integer (current_pc, 4, BFD_ENDIAN_BIG);
> +
> +  /* FIXME: Review this code.  */
> +  if (N32_OP6 (insn) == N32_OP6_MISC && N32_SUB5 (insn) == N32_MISC_BREAK)
> +    current_pc += 4;
> +  else if (__GF (insn, 9, 6) == 35 && N16_IMM9U (insn) < 32)
> +    current_pc += 2;
> +  else
> +    return;

Looks like there are two kinds of breakpoint instructions, 16-bit one 
and 32-bit one.  It is inconsistent with nds32_breakpoint_from_pc, where 
only 16-bit breakpoint instruction is used.

> +
> +  regcache_write_pc (regcache, current_pc);
> +}
> +

> +
> +/* Implement the gdbarch_push_dummy_call method.  */
> +
> +static CORE_ADDR
> +nds32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
> +		       struct regcache *regcache, CORE_ADDR bp_addr,
> +		       int nargs, struct value **args, CORE_ADDR sp,
> +		       int struct_return, CORE_ADDR struct_addr)
> +{
> +  const int REND = 6;		/* Max arguments number.  */
> +  int goff = 0;			/* Current gpr for argument.  */
> +  int foff = 0;			/* Currnet gpr for argument.  */
> +  int soff = 0;			/* Current stack offset.  */
> +  int i;
> +  struct type *type;
> +  enum type_code typecode;
> +  CORE_ADDR regval;
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +  int use_spill;
> +  int use_fpr;
> +  int fs0_regnum = -1, fd0_regnum = -1;
> +
> +  switch (tdep->nds32_abi)
> +    {
> +    case NDS32_ABI_V2:
> +    case NDS32_ABI_V2FP:
> +      use_spill = FALSE;
> +      break;
> +    default:
> +      use_spill = TRUE;
> +    break;
> +  }
> +
> +  /* Use FP registers for calling iff when ABI==V2FP.  */
> +  use_fpr = (tdep->nds32_abi == NDS32_ABI_V2FP);
> +  if (use_fpr)
> +    {
> +      fs0_regnum = user_reg_map_name_to_regnum (gdbarch, "fs0",
> strlen ("fs0"));
> +      fd0_regnum = user_reg_map_name_to_regnum (gdbarch, "fd0",
> strlen ("fd0"));
> +    }
> +
> +  /* Set the return address.  For the nds32, the return breakpoint is
> +     always at BP_ADDR.  */
> +  regcache_cooked_write_unsigned (regcache, NDS32_LP_REGNUM, bp_addr);
> +
> +  /* If STRUCT_RETURN is true, then the struct return address (in
> +     STRUCT_ADDR) will consume the first argument-passing register.
> +     Both adjust the register count and store that value.  */
> +  if (struct_return)
> +    {
> +      regcache_cooked_write_unsigned (regcache, NDS32_R0_REGNUM, struct_addr);
> +      goff++;
> +    }
> +
> +  /* Now make sure there's space on the stack */
> +  for (i = 0; i < nargs; i++)
> +    {
> +      struct type *type = value_type (args[i]);
> +      int align = nds32_type_align (type);
> +
> +      gdb_assert (align != 0);
> +      sp -= TYPE_LENGTH (type);
> +      if (align)
> +	{
> +	  /* FIXME: Handle empty structure?  */
> +	  sp &= ~(align - 1);
> +	}
> +    }
> +
> +  /* Stack must be 8-byte aligned.  */
> +  sp = sp & ~7;

I prefer using align_down (sp, 8) here.

> +
> +/* Given a return value in `regbuf' with a type `valtype',
> +   extract and copy its value into `valbuf'.  */

The comment is inconsistent with the parameters of this functions.

> +
> +static void
> +nds32_extract_return_value (struct type *type, struct regcache *regcache,
> +			    gdb_byte *readbuf)
> +{
> +  int len = TYPE_LENGTH (type);
> +  int typecode = TYPE_CODE (type);
> +  struct gdbarch *gdbarch = get_regcache_arch (regcache);
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +  int i;
> +  int fs0_regnum, fd0_regnum;
> +  int use_fpr;
> +
> +  use_fpr = (tdep->nds32_abi == NDS32_ABI_V2FP);
> +
> +  /* TODO: one-float, one-double is special case in V2FP.
> +     Passed in FS/FD */
> +  gdb_assert (TYPE_LENGTH (type) <= 8);
> +  if (nds32_float_in_struct (type))
> +    typecode = TYPE_CODE_FLT;
> +
> +  if (typecode == TYPE_CODE_FLT && use_fpr)
> +    {
> +      fs0_regnum = user_reg_map_name_to_regnum (gdbarch, "fs0",
> strlen ("fs0"));
> +      fd0_regnum = user_reg_map_name_to_regnum (gdbarch, "fd0",
> strlen ("fd0"));
> +

Looks your mailer wrap up your patch, so that it can't be applied cleanly.

> +
> +static int
> +nds32_sigtramp_frame_sniffer (const struct frame_unwind *self,
> +			      struct frame_info *this_frame,
> +			      void **this_prologue_cache)
> +{
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
> +
> +  /* We shouldn't even bother if we don't have a sigcontext_addr
> +     handler.  */
> +  if (tdep->sigcontext_addr == NULL)
> +    return 0;
> +
> +  if (tdep->sigtramp_p != NULL)
> +    {
> +      if (tdep->sigtramp_p (this_frame))
> +	return 1;
> +    }
> +
> +#if 0
> +    /* TODO: extend the sniffer as following if (tdep->sigtramp_start != 0) */
> +    {
> +      CORE_ADDR pc = frame_pc_unwind (this_frame);
> +
> +      gdb_assert (tdep->sigtramp_end != 0);
> +      if (pc >= tdep->sigtramp_start && pc < tdep->sigtramp_end)
> +	return &nds32_sigtramp_frame_unwind;
> +    }
> +#endif

Remove it?

> +  return 0;
> +}
> +

> +
> +static int
> +gdb_print_insn_nds32 (bfd_vma memaddr, disassemble_info *info)
> +{
> +  struct gdbarch *gdbarch = info->application_data;
> +  struct obj_section * s = find_pc_section (memaddr);
> +  struct cleanup *back_to;
> +
> +  /* Reload symtab if abfd changed.

I am sorry that I can't get the points of doing this.  Can you elaborate 
please?

> +     In case there are multiple ITB in different shared objects.  */
> +  if (s == NULL || info->section != s->the_bfd_section)
> +    {
> +      xfree (info->symtab);
> +      info->symtab = NULL;
> +      info->symtab_size = 0;
> +    }
> +
> +  if (info->symtab == NULL && s && s->the_bfd_section)
> +    {
> +      long storage = bfd_get_symtab_upper_bound (s->objfile->obfd);
> +
> +      if (storage <= 0)
> +	goto done;
> +
> +      info->section = s->the_bfd_section;
> +      info->symtab = xmalloc (storage);
> +      info->symtab_size =
> +	bfd_canonicalize_symtab (s->the_bfd_section->owner, info->symtab);
> +    }
> +
> +done:
> +  return print_insn_nds32 (memaddr, info);
> +}
> +

> +
> +/* Callback for "nds32 dump" command.
> +
> +   Dump current register and stack for debug gdb.  */
> +

Do we really need this command?  You can examine registers via command 
'info registers', and examine stack as a piece of memory via command 'x'.

> +static void
> +nds32_dump_command (char *arg, int from_tty)
> +{
> +  ULONGEST val;
> +  ULONGEST sp;
> +  FILE *f_script;
> +  char cmdline[512];
> +  int i;
> +
> +  if (arg == NULL)
> +    {
> +      printf_unfiltered (_("Missing filename argument.\n"));
> +      return;
> +    }
> +
> +  regcache_raw_read_unsigned (get_current_regcache (), NDS32_SP_REGNUM, &sp);
> +
> +  sprintf (cmdline, "dump binary memory %s.stack 0x%lx 0x%lx",
> +	   arg, (long) sp, ((long) sp + 1024 - 1) & ~(1024 - 1));
> +  execute_command (cmdline, from_tty);
> +
> +  sprintf (cmdline, "%s.gdbinit", arg);
> +  f_script = fopen (cmdline, "w");
> +  if (f_script == NULL)
> +    {
> +      printf_unfiltered (_("Fail to generate dump .gdbinit."));
> +      return ;
> +    }
> +
> +  /* Gather all user registers.  */
> +  for (i = 0; i <= NDS32_D1HI_REGNUM; i++)
> +    {
> +      regcache_raw_read_unsigned (get_current_regcache (), i, &val);
> +      fprintf (f_script, "set $%s = 0x%lx\n", nds32_regnames[i], (long) val);
> +    }
> +
> +  fprintf (f_script, "restore %s.stack binary 0x%lx\n", arg, (long) sp);
> +  fclose (f_script);
> +}
> +
> +static int
> +nds32_config_int (const char *str, int def)
> +{
> +  int val = def;
> +
> +  if (getenv (str))
> +    val = atoi (getenv (str));
> +  if (val != def)
> +    printf ("%s=%d\n", str, val);

It is not good to print in this way.  If you really need to print some 
debug message, please add a flag "nds32_debug",

   if (nds32_debug)
     fprintf_unfiltered (gdb_stdlog, "%s = %d\n", str, val));

and add a command to contrl this flag.

See 'arm_debug' in arm-tdep.c.

> +  return val;
> +}
> +
> +static void
> +nds32_load_config (struct nds32_gdb_config *config)
> +{
> +  config->use_cfi = nds32_config_int ("USE_CFI", 1);
> +  config->use_abi = nds32_config_int ("USE_ABI", NDS32_ABI_AUTO);
> +}
> +
> +/* Callback for "nds32" command.  */
> +
> +static void
> +nds32_command (char *arg, int from_tty)
> +{
> +  printf_unfiltered (_("\"nds32\" must be followed by arguments\n"));
> +}
> +
> +struct cmd_list_element *nds32_cmdlist;
> +
> +void
> +_initialize_nds32_tdep (void)
> +{
> +  /* Internal used config for testing.  */
> +  nds32_load_config (&nds32_config);
> +
> +  add_prefix_cmd ("nds32", no_class, nds32_command,
> +		  _("Various nds32-specific commands."), &nds32_cmdlist,
> +		  "nds32 ", 0, &cmdlist);
> +
> +  add_cmd ("dump", class_files, nds32_dump_command,
> +	   _("dump stack and GPRs for debugging"), &nds32_cmdlist);

Not sure the command is necessary.  If it is, don't forget to update 
gdb/doc/gdb.texinfo about the new command.

> +
> +  nds32_init_remote_cmds ();
> +
> +  /* Initialize gdbarch.  */
> +  register_gdbarch_init (bfd_arch_nds32, nds32_gdbarch_init);
> +
> +  /* Following are NDS32 specific commands.  */
> +
> +  nds32_init_reggroups ();
> +
> +  register_remote_support_xml ("nds32");
> +}
> diff --git a/gdb/nds32-tdep.h b/gdb/nds32-tdep.h
> new file mode 100644
> index 0000000..2a71a14
> --- /dev/null
> +++ b/gdb/nds32-tdep.h
> @@ -0,0 +1,127 @@
> +/* Common target dependent code for GDB on nds32 systems.
> +

> +
> +/* All the possible NDS32 ABIs.  They must be consistent with elf/nds32.h.  */
> +enum nds32_abi
> +{
> +  NDS32_ABI_V0 = 0,
> +  NDS32_ABI_V1,
> +  NDS32_ABI_V2,
> +  NDS32_ABI_V2FP,
> +  NDS32_ABI_AABI,
> +  NDS32_ABI_END,
> +  NDS32_ABI_BEGIN = NDS32_ABI_V0,
> +  /* ABI flag is only 4-bits long.  */
> +  NDS32_ABI_AUTO = 0xFFFFFFFF
> +};

The ABI stuff should go to binutils, and GDB only uses them, right?

> +
> +/* ----------------------------------------------
> +   31   28 27                 8 7   4 3       0
> +   ----------------------------------------------
> +   | ARCH | CONFUGURAION FIELD | ABI | VERSION  |
> +   ---------------------------------------------- */

What does this comment mean?

The last but not least, the binutils patch hasn't go in yet, so it is 
pity that I can't build GDB with you patches for nds32 target.

You also need a news entry in gdb/NEWS about this new port.  Open 
gdb/NEWS, and then you will know how to add one entry for nds32 port :)

-- 
Yao (齐尧)


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

* Re: [PATCH 1/5] Code for nds32 target
  2013-07-10  5:38 ` Yao Qi
@ 2013-07-11 14:06   ` Wei-cheng Wang
  2013-07-11 14:26   ` Wei-cheng Wang
  1 sibling, 0 replies; 9+ messages in thread
From: Wei-cheng Wang @ 2013-07-11 14:06 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

Hi Yao,

I've fix the first patch according to your suggestions.
Here is the revised version.

1. nds32-linux-tdep* are removed, since they are based on outdated glibc-2.5.
2. nds32-utils* are merged in nds32-tdep.
3. nds32-remote are removed.  They are mainly monitor commands for
   communicating with our OpenOCD poring.  http://openocd.zylin.com/#/c/1259/
   We may contribute them later.
4. All the issues mentioned are fixed.
   a. Review and fix TODO/FIXME.
   b. Add static/const if possible.
   c. Fix and review comments.
   d. Use align_up/align_down.
   e. 16.1.4 C usage
   f. Use xsnprintf instead of sprintf.
   g. Fix missing blank line and unnecessary brackets.
   h. Fix skip_permanent_breakpoint

Thank you for your great help.

Wei-Cheng
---
2013-07-11  Wei-Cheng Wang  <cole945@gmail.com>

	* Makefile.in (ALL_TARGET_OBS): Add nds32-tdep.o.
	(ALLDEPFILES): Add nds32-tdep.c.
	* configure.tgt: Add nds32* as target.
	* nds32-tdep.c: New file.
	* nds32-tdep.h: New file.
	* features/nds32-core.xml: New file.

---
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 4694adc..3a4da94 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -574,6 +574,7 @@ ALL_TARGET_OBS = \
 	moxie-tdep.o \
 	msp430-tdep.o \
 	mt-tdep.o \
+	nds32-tdep.o \
 	nios2-tdep.o nios2-linux-tdep.o \
 	nto-tdep.o \
 	ppc-linux-tdep.o ppcfbsd-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o  \
@@ -1519,6 +1520,7 @@ ALLDEPFILES = \
 	mipsnbsd-nat.c mipsnbsd-tdep.c \
 	mips64obsd-nat.c mips64obsd-tdep.c \
 	msp430-tdep.c \
+	nds32-tdep.c \
 	nios2-tdep.c nios2-linux-tdep.c \
 	nbsd-nat.c nbsd-tdep.c obsd-tdep.c \
 	solib-osf.c \
diff --git a/gdb/configure.host b/gdb/configure.host
index 85f4491..22aff67 100644
--- a/gdb/configure.host
+++ b/gdb/configure.host
@@ -54,6 +54,7 @@ sh*)			gdb_host_cpu=sh ;;
 tilegx*)		gdb_host_cpu=tilegx ;;
 x86_64*)		gdb_host_cpu=i386 ;;
 m32r*)			gdb_host_cpu=m32r ;;
+nds32*)			gdb_host_cpu=nds32 ;;
 xtensa*)		gdb_host_cpu=xtensa ;;
 *)			gdb_host_cpu=$host_cpu ;;

diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 260a0df..50d7904 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -401,6 +401,12 @@ mt-*-*)
 	gdb_target_obs="mt-tdep.o"
 	;;

+nds32*)
+	# Target: AndesTech nds32 core
+	gdb_target_obs="nds32-tdep.o monitor.o dsrec.o"
+	gdb_sim=../sim/nds32/libsim.a
+	;;
+
 nios2*-*-linux*)
 	# Target: Altera Nios II running Linux
 	gdb_target_obs="nios2-tdep.o nios2-linux-tdep.o solib-svr4.o \
diff --git a/gdb/features/nds32-core.xml b/gdb/features/nds32-core.xml
new file mode 100644
index 0000000..6164a28
--- /dev/null
+++ b/gdb/features/nds32-core.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 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.nds32.core">
+  <reg name="r0" bitsize="32" regnum="0"/>
+  <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="fp" bitsize="32" type="data_ptr" regnum="28"/>
+  <reg name="gp" bitsize="32" type="data_ptr"/>
+  <reg name="lp" bitsize="32" type="code_ptr"/>
+  <reg name="sp" bitsize="32" type="data_ptr"/>
+
+  <reg name="pc" bitsize="32" type="code_ptr"/>
+
+  <reg name="d0lo" bitsize="32"/>
+  <reg name="d0hi" bitsize="32"/>
+  <reg name="d1lo" bitsize="32"/>
+  <reg name="d1hi" bitsize="32"/>
+</feature>
diff --git a/gdb/nds32-tdep.c b/gdb/nds32-tdep.c
new file mode 100644
index 0000000..404a8e4
--- /dev/null
+++ b/gdb/nds32-tdep.c
@@ -0,0 +1,2756 @@
+/* Target-dependent code for NDS32 architecture, for GDB.
+
+   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   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 <stdint.h>
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "gdb_string.h"
+#include "value.h"
+#include "reggroups.h"
+#include "inferior.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "osabi.h"
+#include "language.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "trad-frame.h"
+#include "dis-asm.h"
+#include "gdb_assert.h"
+#include "user-regs.h"
+#include "elf-bfd.h"
+#include "dwarf2-frame.h"
+#include "ui-file.h"
+#include "remote.h"
+#include "target-descriptions.h"
+#include "sim-regno.h"
+#include "gdb/sim-nds32.h"
+
+#include "nds32-tdep.h"
+#include "elf/nds32.h"
+#include "opcode/nds32.h"
+
+/* Simple macro for chop LSB immediate bits from an instruction.  */
+#define CHOP_BITS(insn, n)	(insn & ~__MASK (n))
+
+extern void _initialize_nds32_tdep (void);
+
+/* "break16 0" for breakpoint_from_pc.
+   It is always supported now, so always insert break16.  */
+static const gdb_byte NDS32_BREAK16[] = { 0xEA, 0x00 };
+
+/* The standard register names.  */
+static const char *nds32_regnames[] =
+{
+  /* 32 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", "fp", "gp", "lp", "sp",
+
+  /* 5 User Registers. */
+  "pc", "d0lo", "d0hi", "d1lo", "d1hi",
+};
+
+/* Mnemonic names for registers.  */
+struct nds32_register_alias
+{
+  const char *name;
+  const char *alias;
+};
+
+/* Register alias for user_reg_map_name_to_regnum ().  */
+static const struct nds32_register_alias nds32_register_aliases[] =
+{
+  {"r15", "ta"},
+  {"r26", "p0"},
+  {"r27", "p1"},
+  {"fp", "r28"},
+  {"gp", "r29"},
+  {"lp", "r30"},
+  {"sp", "r31"},
+
+  {"ir0", "psw"},
+  {"ir1", "ipsw"},
+  {"ir2", "p_psw"},
+  {"ir3", "ivb"},
+  {"ir4", "eva"},
+  {"ir5", "p_eva"},
+  {"ir6", "itype"},
+  {"ir7", "p_itype"},
+  {"ir8", "merr"},
+  {"ir9", "ipc"},
+  {"ir10", "p_ipc"},
+  {"ir11", "oipc"},
+  {"ir12", "p_p0"},
+  {"ir13", "p_p1"},
+  {"ir14", "int_mask"},
+  {"ir15", "int_pend"},
+
+  {"cr0", "cpu_ver"},
+  {"cr1", "icm_cfg"},
+  {"cr2", "dcm_cfg"},
+  {"cr3", "mmu_cfg"},
+  {"cr4", "msc_cfg"},
+  {"cr5", "core_id"},
+  {"cr6", "fucop_exist"},
+
+  {"mr0", "mmu_ctl"},
+  {"mr1", "l1_pptb"},
+  {"mr2", "tlb_vpn"},
+  {"mr3", "tlb_data"},
+  {"mr4", "tlb_misc"},
+  {"mr5", "vlpt_idx"},
+  {"mr6", "ilmb"},
+  {"mr7", "dlmb"},
+  {"mr8", "cache_ctl"},
+  {"mr9", "hsmp_saddr"},
+  {"mr10", "hsmp_eaddr"},
+
+  {"pfr0", "pfmc0"},
+  {"pfr1", "pfmc1"},
+  {"pfr2", "pfmc2"},
+  {"pfr3", "pfm_ctl"},
+
+  {"dmar0", "dma_cfg"},
+  {"dmar1", "dma_gcsw"},
+  {"dmar2", "dma_chnsel"},
+  {"dmar3", "dma_act"},
+  {"dmar4", "dma_setup"},
+  {"dmar5", "dma_isaddr"},
+  {"dmar6", "dma_esaddr"},
+  {"dmar7", "dma_tcnt"},
+  {"dmar8", "dma_status"},
+  {"dmar9", "dma_2dset"},
+  {"dmar10", "dma_2dsctl"},
+};
+
+/* Value of a register alias.  BATON is register name of the alias,
+   because system registers do not have fixed register number.
+   We must look-up them when access.  */
+
+static struct value *
+nds32_value_of_reg (struct frame_info *frame, const void *baton)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int regnum;
+
+  regnum = user_reg_map_name_to_regnum (gdbarch, (const char *) baton, -1);
+
+  return value_of_register (regnum, frame);
+}
+
+/* Implement the gdbarch_frame_align method.  */
+
+static CORE_ADDR
+nds32_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+  /* 8-byte aligned.  */
+  return align_down (sp, 8);
+}
+
+/* Implement the gdbarch_breakpoint_from_pc method.  */
+
+static const gdb_byte *
+nds32_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
+			  int *lenptr)
+{
+  gdb_assert (pcptr != NULL);
+  gdb_assert (lenptr != NULL);
+
+  if ((*pcptr) & 1)
+    error (_("Bad address %p for inserting breakpoint.\n"
+	     "Address must be at least 2-byte aligned."), (void *) *pcptr);
+
+  /* Always insert 16-bit break instruction.  */
+  *lenptr = 2;
+  return NDS32_BREAK16;
+}
+
+/* Implement the gdbarch_remote_breakpoint_from_pc method.  */
+
+static void
+nds32_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
+				 int *kindptr)
+{
+  if ((*pcptr) & 1)
+    error (_("bad address %p for inserting breakpoint"), (void *) *pcptr);
+
+  /* ICEman/AICE have trouble on reading memory when the pcptr is P/A,
+     but CPU is in V/A mode.  This code prevent GDB from reading memory.
+     ICEman will read memory itself if needed.  */
+
+  *kindptr = 2;
+}
+
+/* Implement the gdbarch_dwarf2_reg_to_regnum method.
+   Map DWARF regnum from GCC to GDB regnum.  */
+
+static int
+nds32_dwarf_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num)
+{
+  const int DXR = 34;
+  const int FSR = 38;
+  const int FDR = FSR + 32;
+
+  if (num >= 0 && num < 32)			/* R0 - R31 */
+    return num;
+  else if (num >= DXR && num < DXR + 4)		/* D0/D1 */
+    return num - DXR + NDS32_D0LO_REGNUM;
+  else if (num >= FSR && num < FSR + 32)	/* FS */
+    return num - FSR + user_reg_map_name_to_regnum (gdbarch, "fs0", -1);
+  else if (num >= FDR && num < FDR + 32)	/* FD */
+    return num - FDR + user_reg_map_name_to_regnum (gdbarch, "fd0", -1);
+
+  /* No match, return a inaccessible register number.  */
+  return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
+}
+
+/* Implement gdbarch_register_sim_regno method.  */
+
+static int
+nds32_register_sim_regno (struct gdbarch *gdbarch, int regnum)
+{
+  /* Use target-descriptions for register mapping. */
+
+  /* Only makes sense to supply raw registers.  */
+  gdb_assert (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch));
+
+  if (regnum < NDS32_NUM_REGS)
+    return regnum;
+  if (regnum >= NDS32_SIM_FD0_REGNUM && regnum < NDS32_SIM_FD0_REGNUM + 32)
+    return SIM_NDS32_FD0_REGNUM + regnum - NDS32_SIM_FD0_REGNUM;
+  switch (regnum)
+    {
+    case NDS32_SIM_IFCLP_REGNUM:
+      return SIM_NDS32_IFCLP_REGNUM;
+    case NDS32_SIM_ITB_REGNUM:
+      return SIM_NDS32_ITB_REGNUM;
+    case NDS32_SIM_PSW_REGNUM:
+      return SIM_NDS32_PSW_REGNUM;
+    }
+
+  return LEGACY_SIM_REGNO_IGNORE;
+}
+\f
+enum type_option
+{
+  NO_FLAGS = 0,
+  USE_FLAGS = 1,
+};
+
+/* Allocate a new type.  Use this instead of arch_composite_type () or
+   arch_type () directly, because it must be a 4-byte word, but we may
+   not append all the fields.  If `opt' is USE_FLAGS, then a field for
+   flags is appended.  */
+
+static struct type *
+nds32_init_type (struct gdbarch *gdbarch, char *name, enum type_option opt)
+{
+  struct type *type;
+
+  gdb_assert (opt == USE_FLAGS || opt == NO_FLAGS);
+
+  type = arch_type (gdbarch, TYPE_CODE_STRUCT, 4, name);
+  TYPE_TAG_NAME (type) = name;
+  INIT_CPLUS_SPECIFIC (type);
+
+  if (opt == USE_FLAGS)
+    {
+      int i;
+      struct type *flags_type =
+	arch_flags_type (TYPE_OWNER (type).gdbarch, "nds32_dummy_flags_type",
+			 TYPE_LENGTH (type));
+      append_composite_type_field_raw (type, "", flags_type);
+
+      /* Hide all the flags from users. Only explicitly appended flags
+	 are shown to users.  For example,
+	   {[ #1 #3 #16 #17 #18 ], INTL = Lv1, POM = Superuser}
+	 We don't want users to see this, INTL and POM should not be
+	 displayed in the flags field.  */
+      for (i = 0; i < (int) TYPE_LENGTH (type) * TARGET_CHAR_BIT; i++)
+	append_flags_type_flag (flags_type, i, NULL);
+    }
+
+  return type;
+}
+
+/* Append a flags bit.  */
+
+static void
+nds32_append_flag (struct type *type, int bitpos, char *name)
+{
+  int nfields;
+
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT);
+
+  nfields = TYPE_NFIELDS (type);
+
+  if (nfields == 0
+      || TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) != TYPE_CODE_FLAGS)
+    {
+      internal_error (__FILE__, __LINE__,
+		      _("Pseudo field for flags must be the first one."));
+    }
+
+  /* Append flag in the first field.  */
+  append_flags_type_flag (TYPE_FIELD_TYPE (type, 0), bitpos, name);
+}
+
+/* Append a bit-field.  */
+
+static void
+nds32_append_bitfield (struct type *type, struct type *field_type,
+		       int bitpos_from, int bitpos_to, char *name)
+{
+  struct field *f;
+
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT);
+  gdb_assert (bitpos_to >= bitpos_from);
+  gdb_assert (TYPE_NFIELDS (type) != 0 || strcmp (name, "") != 0);
+
+  f = append_composite_type_field_raw (type, xstrdup (name), field_type);
+  SET_FIELD_BITPOS (f[0], bitpos_from);
+  FIELD_BITSIZE (f[0]) = bitpos_to - bitpos_from + 1;
+}
+
+/* Allocate an enumeration type.  The only reason to call this function
+   is that we want it to be UNSIGNED instead.  This is only useful for
+   enum-type bit-field.  */
+
+static struct type *
+nds32_init_enum (struct gdbarch *gdbarch, char *name)
+{
+  struct type *type;
+
+  type = arch_type (gdbarch, TYPE_CODE_ENUM, 4, name);
+  TYPE_UNSIGNED (type) = 1;
+  return type;
+}
+
+static void
+nds32_append_enum (struct type *type, int enumval, char *name)
+{
+  struct field *f;
+
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_ENUM);
+  f = append_composite_type_field_raw (type, name, NULL);
+  SET_FIELD_ENUMVAL (f[0], enumval);
+}
+
+/* Register name and its type.  */
+
+struct type_entry
+{
+  const char *name;
+  struct type *type;
+};
+
+/* Hash code function.  Simply a wrapper for htab_hash_string.
+   This function should only be called by htab_expand,
+   so PTR is the pointer to inserted entry.  */
+
+static hashval_t
+type_hash_string (const PTR ptr)
+{
+  struct type_entry *pe = (struct type_entry *) ptr;
+
+  return htab_hash_string (pe->name);
+}
+
+/* Equal function for hash.  Simply a wrapper for strcmp.
+   This function should only be called by htab_find[_slot]_with_hash,
+   so P2 the ELEMENT argument to it.  */
+
+static int
+type_name_eq (const PTR p1, const PTR p2)
+{
+  struct type_entry *pe = (struct type_entry *) p1;
+  const char *name = (const char *) p2;
+
+  return strcmp (pe->name, name) == 0;
+}
+
+/* Allocate a hash table for register/type pair.  */
+
+static htab_t
+nds32_alloc_type_tab (int size)
+{
+  return htab_create_alloc (size, type_hash_string, type_name_eq,
+			    NULL /* htab_del */ ,
+			    xcalloc, xfree);
+}
+
+/* Look up a register by name.  */
+
+static struct type *
+nds32_type_lookup (htab_t htab, const char *name)
+{
+  struct type_entry *pe;
+  hashval_t hash;
+
+  hash = htab_hash_string (name);
+  pe = (struct type_entry *) htab_find_with_hash (htab, name, hash);
+
+  if (pe == NULL)
+    return NULL;
+  return pe->type;
+}
+
+/* Insert a type for a specific register name.  */
+
+static void
+nds32_type_insert (htab_t htab, const char *name, struct type *type)
+{
+  struct type_entry ent;
+  struct type_entry **pe;
+  hashval_t hash;
+
+  hash = htab_hash_string (name);
+  pe = (struct type_entry **)
+    htab_find_slot_with_hash (htab, name, hash, INSERT);
+
+  /* If the entry already exists, there must be a bug in nds32_alloc_types.  */
+  gdb_assert (pe != NULL && *pe == NULL);
+
+  *pe = xmalloc (sizeof (**pe));
+  (*pe)->name = xstrdup (name);
+  (*pe)->type = type;
+}
+
+/* Create types for registers and insert them to type table by name.  */
+
+static void
+nds32_alloc_types (struct gdbarch *gdbarch)
+{
+  const struct builtin_type *bt = builtin_type (gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct type *type, *stype1, *stype2;
+
+  tdep->type_tab = nds32_alloc_type_tab (24);
+
+  /* fucpr */
+  type = arch_flags_type (gdbarch, "builtin_type_nds32_fucpr", 4);
+  append_flags_type_flag (type, 0, "CP0EN");
+  append_flags_type_flag (type, 1, "CP1EN");
+  append_flags_type_flag (type, 2, "CP2EN");
+  append_flags_type_flag (type, 3, "CP3EN");
+  append_flags_type_flag (type, 31, "AUEN");
+  nds32_type_insert (tdep->type_tab, "fucpr", type);
+
+  /* fpcfg */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_fpcfg");
+  nds32_append_enum (type, 0, "8SP_4DP");
+  nds32_append_enum (type, 1, "16SP_8DP");
+  nds32_append_enum (type, 2, "32SP_16DP");
+  nds32_append_enum (type, 3, "32SP_32DP");
+  stype1 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_fpcfg_type", USE_FLAGS);
+  nds32_append_flag (type, 0, "SP");
+  nds32_append_flag (type, 1, "DP");
+  nds32_append_bitfield (type, stype1, 2, 3, "FREG");
+  nds32_append_flag (type, 4, "FMA");
+  nds32_append_bitfield (type, bt->builtin_uint8, 22, 26, "IMVER");
+  nds32_append_bitfield (type, bt->builtin_uint8, 27, 31, "AVER");
+  nds32_type_insert (tdep->type_tab, "fpcfg", type);
+
+  /* fpcsr */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_fpcsr_rm");
+  nds32_append_enum (type, 0, "RTNE");
+  nds32_append_enum (type, 1, "RTPI");
+  nds32_append_enum (type, 2, "RTMI");
+  nds32_append_enum (type, 3, "RTZ");
+  stype1 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_fpcsr", USE_FLAGS);
+  nds32_append_bitfield (type, stype1, 0, 1, "RM");
+  nds32_append_flag (type, 2, "IVO");
+  nds32_append_flag (type, 3, "DBZ");
+  nds32_append_flag (type, 4, "OVF");
+  nds32_append_flag (type, 5, "UDF");
+  nds32_append_flag (type, 6, "IEX");
+  nds32_append_flag (type, 7, "IVOE");
+  nds32_append_flag (type, 8, "DBZE");
+  nds32_append_flag (type, 9, "OVFE");
+  nds32_append_flag (type, 10, "UDFE");
+  nds32_append_flag (type, 11, "IEXE");
+  nds32_append_flag (type, 12, "DNZ");
+  nds32_append_flag (type, 13, "IVOT");
+  nds32_append_flag (type, 14, "DBZT");
+  nds32_append_flag (type, 15, "OVFT");
+  nds32_append_flag (type, 16, "UDFT");
+  nds32_append_flag (type, 17, "IEXT");
+  nds32_append_flag (type, 18, "DNIT");
+  nds32_append_flag (type, 19, "RIT");
+  nds32_type_insert (tdep->type_tab, "fpcsr", type);
+
+  /* ir0 - processor status word register
+     ir1 - interruption PSW register
+     ir2 - previous IPSW register */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_psw_intl");
+  nds32_append_enum (type, 0, "NO");
+  nds32_append_enum (type, 1, "Lv1");
+  nds32_append_enum (type, 2, "Lv2");
+  nds32_append_enum (type, 3, "Lv3");
+  stype1 = type;
+
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_psw_pow");
+  nds32_append_enum (type, 0, "User");
+  nds32_append_enum (type, 1, "Superuser");
+  nds32_append_enum (type, 2, "Reserved(2)");
+  nds32_append_enum (type, 3, "Reserved(3)");
+  stype2 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_psw", USE_FLAGS);
+  nds32_append_flag (type, 0, "GIE");
+  nds32_append_bitfield (type, stype1, 1, 2, "INTL");
+  nds32_append_bitfield (type, stype2, 3, 4, "POM");
+  nds32_append_flag (type, 5, "BE");
+  nds32_append_flag (type, 6, "IT");
+  nds32_append_flag (type, 7, "DT");
+  nds32_append_flag (type, 8, "IME");
+  nds32_append_flag (type, 9, "DME");
+  nds32_append_flag (type, 10, "DEX");
+  nds32_append_flag (type, 11, "HSS");
+  nds32_append_flag (type, 12, "DRBE");
+  nds32_append_flag (type, 13, "AEN");
+  nds32_append_flag (type, 14, "WBNA");
+  nds32_append_flag (type, 15, "IFCON");
+  nds32_append_flag (type, 20, "OV");
+  nds32_type_insert (tdep->type_tab, "ir0", type);
+  nds32_type_insert (tdep->type_tab, "ir1", type);
+  nds32_type_insert (tdep->type_tab, "ir2", type);
+
+  /* ir3 - Interrupt Vector Base Register */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_ivb_esz");
+  nds32_append_enum (type, 0, "4_byte");
+  nds32_append_enum (type, 1, "16_byte");
+  nds32_append_enum (type, 2, "64_byte");
+  nds32_append_enum (type, 3, "256_byte");
+  stype1 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_ivb", USE_FLAGS);
+  nds32_append_flag (type, 13, "EVIC");
+  nds32_append_bitfield (type, stype1, 14, 15, "ESZ");
+  nds32_append_bitfield (type, bt->builtin_uint16, 16, 31, "IVBASE");
+  nds32_type_insert (tdep->type_tab, "ir3", type);
+
+  /* ir6 - Interruption Type Register
+     ir7 - Previous ITYPE */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_itype", USE_FLAGS);
+  nds32_append_bitfield (type, bt->builtin_uint8, 0, 3, "ETYPE");
+  nds32_append_flag (type, 4, "INST");
+  nds32_append_bitfield (type, bt->builtin_uint16, 16, 30, "SWID");
+  nds32_type_insert (tdep->type_tab, "ir6", type);
+  nds32_type_insert (tdep->type_tab, "ir7", type);
+
+  /* ir14 - Interruption Masking Register */
+  type = arch_flags_type (gdbarch, "builtin_type_nds32_int_mask", 4);
+  append_flags_type_flag (type, 0, "H0IM");
+  append_flags_type_flag (type, 1, "H1IM");
+  append_flags_type_flag (type, 2, "H2IM");
+  append_flags_type_flag (type, 3, "H3IM");
+  append_flags_type_flag (type, 4, "H4IM");
+  append_flags_type_flag (type, 5, "H5IM");
+  append_flags_type_flag (type, 16, "SIM");
+  append_flags_type_flag (type, 29, "ALZ");
+  append_flags_type_flag (type, 30, "IDIVZE");
+  append_flags_type_flag (type, 31, "DSSIM");
+  nds32_type_insert (tdep->type_tab, "ir14", type);
+
+  /* ir18 - Interruption Prioirty Register */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_int_pri", NO_FLAGS);
+  nds32_append_bitfield (type, bt->builtin_uint8, 0, 1, "H0PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 2, 3, "H1PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 4, 5, "H2PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 6, 7, "H3PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 8, 9, "H4PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 10, 11, "H5PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 12, 13, "H6PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 14, 15, "H7PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 16, 17, "H8PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 18, 19, "H9PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 20, 21, "H10PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 22, 23, "H11PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 24, 25, "H12PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 26, 27, "H13PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 28, 29, "H14PRI");
+  nds32_append_bitfield (type, bt->builtin_uint8, 30, 31, "H15PRI");
+  nds32_type_insert (tdep->type_tab, "ir18", type);
+
+  /* mr0 - MMU Control Register */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_mmuctl_ntc");
+  nds32_append_enum (type, 0, "NCA_NCO");
+  nds32_append_enum (type, 1, "NCA_CO");
+  nds32_append_enum (type, 2, "CA_WB");
+  nds32_append_enum (type, 3, "CA_WT");
+  stype1 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_mmu_ctl", USE_FLAGS);
+  nds32_append_flag (type, 0, "D");
+  nds32_append_bitfield (type, stype1, 1, 2, "NTC0");
+  nds32_append_bitfield (type, stype1, 3, 4, "NTC1");
+  nds32_append_bitfield (type, stype1, 5, 6, "NTC2");
+  nds32_append_bitfield (type, stype1, 7, 8, "NTC3");
+  nds32_append_flag (type, 9, "TBALCK");
+  nds32_append_flag (type, 10, "MPZIU");
+  nds32_append_bitfield (type, bt->builtin_uint8, 11, 12, "NTM0");
+  nds32_append_bitfield (type, bt->builtin_uint8, 13, 14, "NTM1");
+  nds32_append_bitfield (type, bt->builtin_uint8, 15, 16, "NTM2");
+  nds32_append_bitfield (type, bt->builtin_uint8, 17, 18, "NTM3");
+  nds32_append_flag (type, 19, "DREE");
+  nds32_type_insert (tdep->type_tab, "mr0", type);
+
+  /* mr1 */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_l1_pptb", USE_FLAGS);
+  nds32_append_flag (type, 0, "NV");
+  nds32_append_bitfield (type, bt->builtin_uint32, 12, 31, "L1_PPT_BASE");
+  nds32_type_insert (tdep->type_tab, "mr1", type);
+
+  /* mr2 */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_tlb_vpn", NO_FLAGS);
+  nds32_append_bitfield (type, bt->builtin_uint32, 12, 31, "VPN");
+  nds32_type_insert (tdep->type_tab, "mr2", type);
+
+  /* mr3 */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_tlb_data", USE_FLAGS);
+  nds32_append_flag (type, 0, "V");
+  nds32_append_bitfield (type, bt->builtin_uint8, 1, 3, "M");
+  nds32_append_flag (type, 4, "D");
+  nds32_append_flag (type, 5, "X");
+  nds32_append_flag (type, 6, "A");
+  nds32_append_flag (type, 7, "G");
+  nds32_append_bitfield (type, bt->builtin_uint8, 8, 10, "C");
+  nds32_append_bitfield (type, bt->builtin_uint32, 12, 31, "PPN");
+  nds32_type_insert (tdep->type_tab, "mr3", type);
+
+  /* mr4 - TLB Access Misc Register */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_tlb_misc_acc_psz");
+  nds32_append_enum (type, 0, "4KB");
+  nds32_append_enum (type, 1, "8KB");
+  nds32_append_enum (type, 2, "16KB");
+  nds32_append_enum (type, 3, "64KB");
+  nds32_append_enum (type, 4, "256KB");
+  nds32_append_enum (type, 5, "1MB");
+  nds32_append_enum (type, 6, "4MB");
+  nds32_append_enum (type, 7, "16MB");
+  nds32_append_enum (type, 8, "64MB");
+  nds32_append_enum (type, 9, "256MB");
+  stype1 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_tlb_misc", NO_FLAGS);
+  nds32_append_bitfield (type, stype1, 0, 3, "ACC_PSZ");
+  nds32_append_bitfield (type, bt->builtin_uint32, 4, 12, "CID");
+  nds32_type_insert (tdep->type_tab, "mr4", type);
+
+  /* mr6 */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_ilm_size");
+  nds32_append_enum (type, 0, "4KB");
+  nds32_append_enum (type, 1, "8KB");
+  nds32_append_enum (type, 2, "16KB");
+  nds32_append_enum (type, 3, "32KB");
+  nds32_append_enum (type, 4, "64KB");
+  nds32_append_enum (type, 5, "128KB");
+  nds32_append_enum (type, 6, "256KB");
+  nds32_append_enum (type, 7, "512KB");
+  nds32_append_enum (type, 8, "1024KB");
+  nds32_append_enum (type, 9, "1KB");
+  nds32_append_enum (type, 10, "2KB");
+  nds32_append_enum (type, 15, "0KB");
+  stype1 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_ilmb", NO_FLAGS);
+  nds32_append_bitfield (type, bt->builtin_uint8, 0, 0, "IEN");
+  nds32_append_bitfield (type, stype1, 1, 4, "ILMSZ");
+  nds32_append_bitfield (type, bt->builtin_data_ptr, 0, 31, "(raw)");
+  nds32_type_insert (tdep->type_tab, "mr6", type);
+
+  /* mr7 */
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_dlm_size");
+  nds32_append_enum (type, 0, "4KB");
+  nds32_append_enum (type, 1, "8KB");
+  nds32_append_enum (type, 2, "16KB");
+  nds32_append_enum (type, 3, "32KB");
+  nds32_append_enum (type, 4, "64KB");
+  nds32_append_enum (type, 5, "128KB");
+  nds32_append_enum (type, 6, "256KB");
+  nds32_append_enum (type, 7, "512KB");
+  nds32_append_enum (type, 8, "1024KB");
+  nds32_append_enum (type, 9, "1KB");
+  nds32_append_enum (type, 10, "2KB");
+  nds32_append_enum (type, 15, "0KB");
+  stype1 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_dlmb", NO_FLAGS);
+  nds32_append_bitfield (type, bt->builtin_uint8, 0, 0, "DEN");
+  nds32_append_bitfield (type, stype1, 1, 4, "DLMSZ");
+  nds32_append_bitfield (type, bt->builtin_uint8, 5, 5, "DBM");
+  nds32_append_bitfield (type, bt->builtin_uint8, 6, 6, "DBB");
+  nds32_append_bitfield (type, bt->builtin_data_ptr, 0, 31, "(raw)");
+  nds32_type_insert (tdep->type_tab, "mr7", type);
+
+  /* mr8 - Cache Control Register */
+  type = arch_flags_type (gdbarch, "builtin_type_nds32_cache_ctl", 4);
+  append_flags_type_flag (type, 0, "IC_EN");
+  append_flags_type_flag (type, 1, "DC_EN");
+  append_flags_type_flag (type, 2, "ICALCK");
+  append_flags_type_flag (type, 3, "DCALCK");
+  append_flags_type_flag (type, 4, "DCCWF");
+  append_flags_type_flag (type, 5, "DCPMW");
+  nds32_type_insert (tdep->type_tab, "mr8", type);
+
+  /* dr40 - EDM Configuration Register */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_edm_cfg", USE_FLAGS);
+  nds32_append_bitfield (type, bt->builtin_uint8, 0, 2, "BC");
+  nds32_append_flag (type, 3, "DIMU");
+  nds32_append_flag (type, 4, "DALM");
+  nds32_append_bitfield (type, bt->builtin_uint16, 16, 31, "VER");
+  nds32_type_insert (tdep->type_tab, "dr40", type);
+
+  /* dmar0 - DMA Configuration Register */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_dma_cfg", USE_FLAGS);
+  nds32_append_bitfield (type, bt->builtin_uint8, 0, 1, "NCHN");
+  nds32_append_flag (type, 2, "UNEA");
+  nds32_append_flag (type, 3, "2DET");
+  nds32_append_bitfield (type, bt->builtin_uint16, 16, 31, "VER");
+  nds32_type_insert (tdep->type_tab, "dmar0", type);
+
+  /* cr0 - CPU Version Register */
+  type = arch_flags_type (gdbarch, "builtin_type_nds32_cpuver_cfgid", 2);
+  append_flags_type_flag (type, 0, "PERF_EXT");
+  append_flags_type_flag (type, 1, "16_EXT");
+  append_flags_type_flag (type, 2, "PERF_EXT2");
+  append_flags_type_flag (type, 3, "COP_EXT");
+  append_flags_type_flag (type, 4, "STR_EXT");
+  stype1 = type;
+
+  type = nds32_init_enum (gdbarch, "builtin_type_nds32_cpuver_cpuid");
+  nds32_append_enum (type, 0x8, "N8");
+  nds32_append_enum (type, 0x9, "N9");
+  nds32_append_enum (type, 0xA, "N10");
+  nds32_append_enum (type, 0xC, "N12");
+  nds32_append_enum (type, 0xD, "N13");
+  nds32_append_enum (type, 0xE, "N14");
+  stype2 = type;
+
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_cpuver", NO_FLAGS);
+  nds32_append_bitfield (type, stype1, 0, 15, "CFGID");
+  nds32_append_bitfield (type, bt->builtin_uint8, 16, 23, "REV");
+  nds32_append_bitfield (type, stype2, 24, 31, "CPUID");
+  nds32_type_insert (tdep->type_tab, "cr0", type);
+
+  /* cr4 - Misc Configuration Register */
+  type = nds32_init_type (gdbarch, "builtin_type_nds32_msc_cfg", USE_FLAGS);
+  nds32_append_flag (type, 0, "EDM");
+  nds32_append_flag (type, 1, "LMDMA");
+  nds32_append_flag (type, 2, "PFM");
+  nds32_append_flag (type, 3, "HSMP");
+  nds32_append_flag (type, 4, "TRACE");
+  nds32_append_flag (type, 5, "DIV");
+  nds32_append_flag (type, 6, "MAC");
+  nds32_append_bitfield (type, bt->builtin_uint8, 7, 8, "AUDIO");
+  nds32_append_flag (type, 9, "L2c");
+  nds32_append_flag (type, 10, "RDREG");
+  nds32_append_flag (type, 11, "ADR24");
+  nds32_append_flag (type, 12, "INTLC");
+  nds32_append_bitfield (type, bt->builtin_uint8, 13, 15, "BASEV");
+  nds32_append_flag (type, 16, "NOD");
+  nds32_append_flag (type, 17, "IMV");
+  nds32_append_flag (type, 18, "IMR");
+  nds32_append_flag (type, 19, "IFC");
+  nds32_append_flag (type, 20, "MCU");
+  nds32_type_insert (tdep->type_tab, "cr4", type);
+
+  /* cr6 - FPU and Coprocessor Existence Configuration Register */
+  type = arch_flags_type (gdbarch, "builtin_type_nds32_fucop_exist", 4);
+  append_flags_type_flag (type, 0, "CP0EX");
+  append_flags_type_flag (type, 1, "CP1EX");
+  append_flags_type_flag (type, 2, "CP2EX");
+  append_flags_type_flag (type, 3, "CP3EX");
+  append_flags_type_flag (type, 31, "AUEX");
+  nds32_type_insert (tdep->type_tab, "cr6", type);
+}
+
+/* Implement gdbarch_register_type method.
+
+   Return the GDB type object for the "standard" data type of data in
+   register REGNUM.  It get pretty messy here.  I want to specify a type
+   on a bit-field for better representation, but they cannot be done by
+   tdesc-xml.  */
+
+static struct type *
+nds32_register_type (struct gdbarch *gdbarch, int regnum)
+{
+  int num_regs = gdbarch_num_regs (gdbarch);
+  const struct builtin_type *bt = builtin_type (gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct type *type;
+  const char *reg_name;
+
+  /* Currently, only FSR are supported.  */
+  if (regnum >= num_regs && regnum < num_regs + 32)
+    return builtin_type (gdbarch)->builtin_float;
+  else if (regnum >= num_regs)
+    return NULL;
+
+  /* NDS32 predefined types for specific registers.  */
+  if (tdep->type_tab == NULL)
+    nds32_alloc_types (gdbarch);
+
+  reg_name = user_reg_map_regnum_to_name (gdbarch, regnum);
+  if (reg_name == NULL)
+    reg_name = "";
+  type = nds32_type_lookup (tdep->type_tab, reg_name);
+  if (type != NULL)
+    return type;
+
+  /* Type provided by target-description.  */
+  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+    {
+      type = tdesc_register_type (gdbarch, regnum);
+      if (type != NULL)
+	return type;
+    }
+
+  /* Floating pointer registers. e.g., fs0 or fd0.  */
+  if (strlen (reg_name) >= 3 && reg_name[0] == 'f' && reg_name[2] >= '0'
+      && reg_name[2] <= '9')
+    {
+      if (reg_name[1] == 's')
+	return bt->builtin_float;
+      else if (reg_name[1] == 'd')
+	return bt->builtin_double;
+    }
+
+  /* GPRs.  */
+  if (regnum == NDS32_PC_REGNUM || regnum == NDS32_LP_REGNUM)
+    return bt->builtin_func_ptr;
+  else if (regnum == NDS32_SP_REGNUM || regnum == NDS32_FP_REGNUM
+	   || regnum == NDS32_GP_REGNUM)
+    return bt->builtin_data_ptr;
+  else if (regnum < 32)
+    return bt->builtin_int32;
+
+  /* We don't know.  Display it in hex-form.  */
+  return bt->builtin_data_ptr;
+}
+\f
+
+/* nds32 register groups.  */
+static struct reggroup *nds32_cr_reggroup;
+static struct reggroup *nds32_ir_reggroup;
+static struct reggroup *nds32_mr_reggroup;
+static struct reggroup *nds32_dr_reggroup;
+static struct reggroup *nds32_pfr_reggroup;
+static struct reggroup *nds32_dmar_reggroup;
+static struct reggroup *nds32_racr_reggroup;
+static struct reggroup *nds32_idr_reggroup;
+static struct reggroup *nds32_audio_reggroup;
+
+static void
+nds32_init_reggroups (void)
+{
+  /* gpr usr sr */
+  nds32_cr_reggroup = reggroup_new ("cr", USER_REGGROUP);
+  nds32_ir_reggroup = reggroup_new ("ir", USER_REGGROUP);
+  nds32_mr_reggroup = reggroup_new ("mr", USER_REGGROUP);
+  nds32_dr_reggroup = reggroup_new ("dr", USER_REGGROUP);
+  nds32_pfr_reggroup = reggroup_new ("pfr", USER_REGGROUP);
+  nds32_dmar_reggroup = reggroup_new ("dmar", USER_REGGROUP);
+  nds32_racr_reggroup = reggroup_new ("racr", USER_REGGROUP);
+  nds32_idr_reggroup = reggroup_new ("idr", USER_REGGROUP);
+
+  nds32_audio_reggroup = reggroup_new ("audio", USER_REGGROUP);
+}
+
+static void
+nds32_add_reggroups (struct gdbarch *gdbarch)
+{
+  /* Target-independent groups.  */
+  reggroup_add (gdbarch, general_reggroup);
+  reggroup_add (gdbarch, float_reggroup);
+  reggroup_add (gdbarch, all_reggroup);
+  reggroup_add (gdbarch, system_reggroup);
+
+  /* System register groups.  */
+  reggroup_add (gdbarch, nds32_cr_reggroup);
+  reggroup_add (gdbarch, nds32_ir_reggroup);
+  reggroup_add (gdbarch, nds32_mr_reggroup);
+  reggroup_add (gdbarch, nds32_dr_reggroup);
+  reggroup_add (gdbarch, nds32_pfr_reggroup);
+  reggroup_add (gdbarch, nds32_dmar_reggroup);
+  reggroup_add (gdbarch, nds32_racr_reggroup);
+  reggroup_add (gdbarch, nds32_idr_reggroup);
+}
+
+/* Implement the gdbarch_register_reggroup_p method.  */
+
+static int
+nds32_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+			   struct reggroup *group)
+{
+  int i;
+  struct reggroup *groups[] =
+  {
+      nds32_cr_reggroup, nds32_ir_reggroup, nds32_mr_reggroup,
+      nds32_dr_reggroup, nds32_pfr_reggroup, nds32_dmar_reggroup,
+      nds32_racr_reggroup, nds32_idr_reggroup
+  };
+  static const char *prefix[] =
+  {
+      "cr", "ir", "mr", "dr", "pfr", "dmar", "racr", "idr"
+  };
+
+  gdb_assert (ARRAY_SIZE (groups) == ARRAY_SIZE (prefix));
+
+  /* GPRs. */
+  if (group == general_reggroup)
+    return regnum <= NDS32_PC_REGNUM;
+
+  /* System Registers are grouped by prefix.  */
+  else if (group == system_reggroup)
+    return (regnum > NDS32_PC_REGNUM)
+	   && TYPE_CODE (register_type (gdbarch, regnum)) != TYPE_CODE_FLT;
+
+  for (i = 0; i < (int) ARRAY_SIZE (groups); i++)
+    {
+      if (group == groups[i])
+	{
+	  const char *regname = tdesc_register_name (gdbarch, regnum);
+
+	  if (!regname)
+	    return 0;
+	  return strstr (regname, prefix[i]) == regname;
+	}
+    }
+
+  return default_register_reggroup_p (gdbarch, regnum, group);
+}
+
+/* Implement the tdesc_pseudo_register_name method.
+
+   This function is called when
+   1. Target-description is used, and the register is pseudo.
+   2. Target-description is NOT used, because
+       i. the target is simulator,
+      ii. or the target is legacy target, so tdesc is not supported.  */
+
+static const char *
+nds32_register_name (struct gdbarch *gdbarch, int regnum)
+{
+  static const char *fpu_pseudo_names[] =
+  {
+    "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
+    "fs8", "fs9", "fs10", "fs11", "fs12", "fs13", "fs14", "fs15",
+    "fs16", "fs17", "fs18", "fs19", "fs20", "fs21", "fs22", "fs23",
+    "fs24", "fs25", "fs26", "fs27", "fs28", "fs29", "fs30", "fs31"
+  };
+  static const char *sim_names[] =
+  {
+    "fd0", "fd1", "fd2", "fd3", "fd4", "fd5", "fd6", "fd7",
+    "fd8", "fd9", "fd10", "fd11", "fd12", "fd13", "fd14", "fd15",
+    "fd16", "fd17", "fd18", "fd19", "fd20", "fd21", "fd22", "fd23",
+    "fd24", "fd25", "fd26", "fd27", "fd28", "fd29", "fd30", "fd31",
+    "ifclp", "itb", "ir0"
+  };
+  int num_regs = gdbarch_num_regs (gdbarch);
+
+  /* Currently, only pseudo FSR are supported.  */
+  if (regnum >= num_regs && regnum < num_regs + 32)
+    return fpu_pseudo_names[regnum - num_regs];
+
+  /* GPRs.  */
+  if (regnum < (int) ARRAY_SIZE (nds32_regnames))
+    return nds32_regnames[regnum];
+
+  /* Registers between NUM_REGS and SMI_NUM_REGS are
+     simulator registers.  */
+  if (regnum >= NDS32_NUM_REGS && regnum < NDS32_SIM_NUM_REGS)
+    return sim_names[regnum - NDS32_NUM_REGS];
+
+  warning (_("Unknown nds32 pseudo register %d."), regnum);
+  return NULL;
+}
+
+/* Implement the gdbarch_pseudo_register_read method.
+
+   For legacy target, target-description and FPRs are not support.
+   Use Rcmd to access FPU registers.  */
+
+static enum register_status
+nds32_pseudo_register_read (struct gdbarch *gdbarch,
+			    struct regcache *regcache, int regnum,
+			    gdb_byte *buf)
+{
+  char name_buf[8];
+  gdb_byte reg_buf[8];
+  int offset;
+  enum register_status status = REG_UNKNOWN;
+
+  /* Sanity check.  */
+  regnum -= gdbarch_num_regs (gdbarch);
+  if (regnum > gdbarch_num_pseudo_regs (gdbarch))
+    return status;
+
+  /* Currently, only FSR are supported.  */
+  if (regnum < 32)
+    {
+      int fd_regnum;
+
+      /* fs0 is always the high-part of fd0.  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	offset = (regnum & 1) ? 4 : 0;
+      else
+	offset = (regnum & 1) ? 0 : 4;
+
+      xsnprintf (name_buf, sizeof (name_buf), "fd%d", regnum >> 1);
+      fd_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+					       strlen (name_buf));
+      status = regcache_raw_read (regcache, fd_regnum, reg_buf);
+      if (status == REG_VALID)
+	memcpy (buf, reg_buf + offset, 4);
+    }
+
+  return status;
+}
+
+/* Implement the gdbarch_pseudo_register_write method.  */
+
+static void
+nds32_pseudo_register_write (struct gdbarch *gdbarch,
+			     struct regcache *regcache, int regnum,
+			     const gdb_byte *buf)
+{
+  char name_buf[8];
+  gdb_byte reg_buf[8];
+  int offset;
+
+  /* Sanity check.  */
+  regnum -= gdbarch_num_regs (gdbarch);
+  if (regnum > gdbarch_num_pseudo_regs (gdbarch))
+    return;
+
+  /* Currently, only FSR are supported.  */
+  if (regnum < 32)
+    {
+      int fd_regnum;
+
+      /* fs0 is always the high-part of fd0.  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	offset = (regnum & 1) ? 4 : 0;
+      else
+	offset = (regnum & 1) ? 0 : 4;
+
+      xsnprintf (name_buf, sizeof (name_buf), "fd%d", regnum >> 1);
+      fd_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+					       strlen (name_buf));
+      regcache_raw_read (regcache, fd_regnum, reg_buf);
+      memcpy (reg_buf + offset, buf, 4);
+      regcache_raw_write (regcache, fd_regnum, reg_buf);
+    }
+
+  return;
+}
+
+/* Skip prologue should be conservative, and frame-unwind should be
+   relative-aggressive.*/
+
+static int
+nds32_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
+			CORE_ADDR scan_limit, CORE_ADDR *pl_endptr)
+{
+  uint32_t insn;
+  CORE_ADDR cpc = -1;		/* Candidate PC if no suitable PC is found.  */
+
+  /* If there is no buffer to store result, ignore this prologue decoding.  */
+  if (pl_endptr == NULL)
+    return 0;
+
+  /* Look up end of prologue.  */
+  for (; pc < scan_limit; )
+    {
+      insn = read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG);
+
+      if ((insn & 0x80000000) == 0)
+	{
+	  /* 32-bit instruction.  */
+
+	  pc += 4;
+	  if (insn == N32_ALU1 (ADD, REG_GP, REG_TA, REG_GP))
+	    {
+	      /* add $gp, $ta, $gp */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ADDI, REG_SP, REG_SP, 0))
+	    {
+	      /* addi $sp, $sp, imm15 */
+	      cpc = pc;
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ADDI, REG_FP, REG_FP, 0))
+	    {
+	      /* addi $fp, $sp, imm15 */
+	      cpc = pc;
+	      continue;
+	    }
+	  else if (insn == N32_ALU2 (MFUSR, REG_TA, 31, 0))
+	    {
+	      /* mfusr $ta, PC  ; group=0, sub=0x20=mfusr */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 20) == N32_TYPE1 (MOVI, REG_TA, 0))
+	    {
+	      /* movi $ta, imm20s */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 20) == N32_TYPE1 (SETHI, REG_GP, 0))
+	    {
+	      /* sethi $gp, imm20 */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ORI, REG_GP, REG_GP, 0))
+	    {
+	      /* ori $gp, $gp, imm15 */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI, REG_LP, REG_FP, 0))
+	    {
+	      /* Unlike swi, we should stop when lwi.  */
+	      /* swi $lp, [$sp + (imm15s<<2)] */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI_BI, REG_LP, REG_FP, 0))
+	    {
+	      /* swi.bi $rt, [$sp], (imm15s<<2) */
+	      continue;
+	    }
+	  else if (N32_OP6 (insn) == N32_OP6_LSMW && (insn & __BIT (5)))
+	    {
+	      /* bit-5 for SMW */
+
+	      /* smwa?.(a|b)(d|i)m? rb,[ra],re,enable4 */
+	      int ra;
+
+	      ra = N32_RA5 (insn);
+
+	      switch (ra)
+		{
+		case NDS32_FP_REGNUM:
+		case NDS32_SP_REGNUM:
+		  cpc = pc;
+		  continue; /* found and continue */
+		default:
+		  break;
+		}
+	    }
+
+	  if (N32_OP6 (insn) == N32_OP6_COP && N32_COP_CP (insn) == 0
+	      && (N32_COP_SUB (insn) == N32_FPU_FSS
+		  || N32_COP_SUB (insn) == N32_FPU_FSD)
+	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
+	    {
+	      /* CP shoud be CP0 */
+	      /* fs[sd][.bi] $fst, [$sp + ($r0 << sv)] */
+	      continue;
+	    }
+
+	  /* fssi    $fst, [$ra + (imm12s << 2)]
+	     fssi.bi $fst, [$ra], (imm12s << 2)
+	     fsdi    $fdt, [$ra + (imm12s << 2)]
+	     fsdi.bi $fdt, [$ra], (imm12s << 2) */
+	  if ((N32_OP6 (insn) == N32_OP6_SWC || N32_OP6 (insn) == N32_OP6_SDC)
+	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
+	    {
+	      /* BI bit is dont-care.  */
+	      continue;
+	    }
+
+	  pc -= 4;
+	  break;
+	}
+      else
+	{
+	  /* 16-bit instruction */
+	  pc += 2;
+	  insn >>= 16;
+
+	  /* 1. If the instruction is j/b, then we stop
+		i.e., OP starts with 10, and beqzs8, bnezs8.
+	     2. If the operations will change sp/fp or based on sp/fp,
+		then we are in the prologue.
+	     3. If we don't know what's it, then stop.  */
+
+	  if (CHOP_BITS (insn, 10) == N16_TYPE10 (ADDI10S, 0))
+	    {
+	      /* addi10s */
+	      continue;
+	    }
+	  else if (__GF (insn, 7, 8) == N16_T25_PUSH25)
+	    {
+	      /* push25 */
+	      continue;
+	    }
+	  else if (insn == N16_TYPE55 (MOV55, REG_FP, REG_SP))
+	    {
+	      /* mov55 fp, sp */
+	      continue;
+	    }
+
+	  /* swi450 */
+	  switch (insn & ~__MF (-1, 5, 4))
+	    {
+	      case N16_TYPE45 (SWI450, 0, REG_SP):
+	      case N16_TYPE45 (SWI450, 0, REG_FP):
+		break;
+	    }
+	  /* swi37 - implied fp */
+	  if (__GF (insn, 11, 4) == N16_T37_XWI37
+	      && (insn & __BIT (7)))
+	    continue;
+
+	  /* swi37sp - implied */
+	  if (__GF (insn, 11, 4) == N16_T37_XWI37SP
+	      && (insn & __BIT (7)))
+	    continue;
+
+	  /* If the a instruction is not accepted,
+	     don't go futher.  */
+	  pc -= 2;
+	  break;
+	}
+    }
+
+  if (pc >= scan_limit)
+    {
+      /* If we can not find end of prologue before scan_limit,
+	 we assume that end of prologue is on pc_after_stack_adject. */
+      if (cpc != -1)
+	pc = cpc;
+    }
+
+  *pl_endptr = pc;
+
+  return 0;
+}
+
+/* Implement the gdbarch_skip_prologue method.
+
+   Find the end of function prologue.  */
+
+static CORE_ADDR
+nds32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR func_addr, func_end;
+  struct symtab_and_line sal = { 0 };
+  LONGEST return_value;
+  const char *func_name;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  const int search_limit = 128;
+
+  /* See what the symbol table says */
+  if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
+    {
+      sal = find_pc_line (func_addr, 0);
+
+      if (sal.line != 0 && sal.end <= func_end)
+	func_end = sal.end;
+      else
+	{
+	  /* Either there's no line info, or the line after the prologue
+	     is after the end of the function.  In this case, there probably
+	     isn't a prologue.  */
+	  func_end = min (func_end, func_addr + search_limit);
+	}
+    }
+  else
+    func_end = pc + search_limit;
+
+  /* If current instruction is not readable, just quit.  */
+  if (!safe_read_memory_integer (pc, 4, byte_order, &return_value))
+    return pc;
+
+  /* Find the end of prologue.  */
+  if (nds32_analyze_prologue (gdbarch, pc, func_end, &sal.end) < 0)
+    return pc;
+
+  return sal.end;
+}
+
+struct nds32_unwind_cache
+{
+  /* The previous frame's inner most stack address.
+     Used as this frame ID's stack_addr.  */
+  CORE_ADDR prev_sp;
+
+  /* The frame's base, optionally used by the high-level debug info.  */
+  CORE_ADDR base;
+  int size;
+
+  /* How far the SP and FP have been offset from the start of
+     the stack frame (as defined by the previous frame's stack
+     pointer).  */
+  LONGEST sp_offset;
+  LONGEST fp_offset;
+  int use_frame;
+
+  /* Table indicating the location of each and every register.  */
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+static struct nds32_unwind_cache *
+nds32_alloc_frame_cache (struct frame_info *this_frame)
+{
+  struct nds32_unwind_cache *cache;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct nds32_unwind_cache);
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+  cache->size = 0;
+  cache->sp_offset = 0;
+  cache->fp_offset = 0;
+  cache->use_frame = 0;
+  cache->base = 0;
+
+  return cache;
+}
+
+/* Implement the gdbarch_in_function_epilogue_p method.  */
+
+static int
+nds32_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  uint32_t insn;
+  int r = 0;
+
+  insn = read_memory_unsigned_integer (addr, 4, BFD_ENDIAN_BIG);
+  if ((insn & 0x80000000) == 0)
+    {
+      /* 32-bit instruction */
+
+      /* ret */
+      if (insn == N32_JREG (JR, 0, REG_LP, 0, 1))
+	r = 1;
+      /* iret */
+      else if (insn == N32_TYPE0 (MISC, N32_MISC_IRET))
+	r = 2;
+    }
+  else
+    {
+      if (insn == N16_TYPE5 (RET5, REG_LP))
+	r = 3;
+    }
+  return r > 0;
+}
+
+/* Put here the code to store, into fi->saved_regs, the addresses of
+   the saved registers of frame described by FRAME_INFO.  This
+   includes special registers such as pc and fp saved in special ways
+   in the stack frame.  sp is even more special: the address we return
+   for it IS the sp for the next frame.  */
+
+static struct nds32_unwind_cache *
+nds32_frame_unwind_cache (struct frame_info *this_frame,
+			  void **this_prologue_cache)
+{
+  CORE_ADDR pc, scan_limit;
+  ULONGEST prev_sp;
+  ULONGEST next_base;
+  ULONGEST fp_base;
+  int i;
+  uint32_t insn;
+  struct nds32_unwind_cache *info;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
+  if ((*this_prologue_cache))
+    return (*this_prologue_cache);
+
+  info = nds32_alloc_frame_cache (this_frame);
+
+  info->base = get_frame_register_unsigned (this_frame, NDS32_FP_REGNUM);
+  (*this_prologue_cache) = info;
+
+  if (info->base == 0)
+    return info;
+
+  pc = get_frame_func (this_frame);
+  scan_limit = get_frame_pc (this_frame);
+
+  for (; pc > 0 && pc < scan_limit; )
+    {
+      insn = read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG);
+
+      if ((insn & 0x80000000) == 0)
+	{
+	  /* 32-bit instruction */
+
+	  pc += 4;
+	  if (insn == N32_ALU1 (ADD, REG_GP, REG_TA, REG_GP))
+	    {
+	      /* add $gp, $ta, $gp */
+	      continue;
+	    }
+	  if (N32_OP6 (insn) == N32_OP6_ADDI)
+	    {
+	      int rt = N32_RT5 (insn);
+	      int ra = N32_RA5 (insn);
+	      int imm15s = N32_IMM15S (insn);
+
+	      if (rt == ra && rt == NDS32_SP_REGNUM)
+		{
+		  info->sp_offset += imm15s;
+		  continue;
+		}
+	      else if (rt == NDS32_FP_REGNUM && ra == NDS32_SP_REGNUM)
+		{
+		  info->fp_offset = info->sp_offset + imm15s;
+		  info->use_frame = 1;
+		  continue;
+		}
+	      else if (rt == ra)
+		/* Prevent stop analyzing form iframe.  */
+		continue;
+	    }
+
+	  if (insn == N32_ALU2 (MFUSR, REG_TA, 31, 0))
+	    {
+	      /* mfusr $ta, PC  ; group=0, sub=0x20=mfusr */
+	      continue;
+	    }
+	  if (CHOP_BITS (insn, 20) == N32_TYPE1 (MOVI, REG_TA, 0))
+	    {
+	      /* movi $ta, imm20s */
+	      continue;
+	    }
+	  if (CHOP_BITS (insn, 20) == N32_TYPE1 (SETHI, REG_GP, 0))
+	    {
+	      /* sethi $gp, imm20 */
+	      continue;
+	    }
+	  if (CHOP_BITS (insn, 15) == N32_TYPE2 (ORI, REG_GP, REG_GP, 0))
+	    {
+	      /* ori $gp, $gp, imm15 */
+	      continue;
+	    }
+	  if (N32_OP6 (insn) == N32_OP6_LSMW && (insn & __BIT (5)))
+	    {
+	      /* smwa?.(a|b)(d|i)m? rb,[ra],re,enable4 */
+
+	      int rb, re, ra, enable4, i;
+	      int aligned;
+	      int m = 0;
+	      int di;	   /* dec=-1 or inc=1 */
+	      int rn;	   /* number of registers.  */
+	      char enb4map[2][4] = {
+		  {0, 1, 2, 3} /* smw */,
+		  {3, 1, 2, 0} /* smwa */ };
+	      /* `base' is the highest/last address for access memory.
+		 e.g., [ lp ] ___ base shoule be here.
+		       [ fp ]
+		       [ r6 ] */
+	      ULONGEST base = -1;
+
+	      rb = N32_RT5 (insn);
+	      ra = N32_RA5 (insn);
+	      re = N32_RB5 (insn);
+	      enable4 = (insn >> 6) & 0x0F;
+	      aligned = (insn & 3) ? 1 : 0;
+	      di = (insn & (1 << 3)) ? -1 : 1;
+
+	      rn = 0;
+	      rn += (enable4 & 0x1) ? 1 : 0;
+	      rn += (enable4 & 0x2) ? 1 : 0;
+	      rn += (enable4 & 0x4) ? 1 : 0;
+	      rn += (enable4 & 0x8) ? 1 : 0;
+	      if (rb < NDS32_FP_REGNUM && re < NDS32_FP_REGNUM)
+		{
+		  /* reg-list should not include fp,gp,lp,sp
+		     ie, the rb==re==sp case, anyway... */
+		  rn += (re - rb) + 1;
+		}
+
+	      /* Let's consider how Ra should update.  */
+	      if (insn & (1 << 0x2))    /* m-bit is set */
+		{
+		  m = rn * 4;			/* 4*TNReg */
+		}
+	      else
+		m = 0;	  /* don't update Ra */
+
+	      switch (ra)
+		{
+		case NDS32_FP_REGNUM:
+		  base = info->fp_offset;
+		  info->fp_offset += m * di;
+		  break;
+		case NDS32_SP_REGNUM:
+		  base = info->sp_offset;
+		  info->sp_offset += m * di;
+		  break;
+		default:
+		  /* Only RA is FP or SP is handled.  */
+		  base = -1;
+		  break;
+		}
+	      if (base == -1)
+		break;	  /* Exit the loop.  */
+
+	      if (insn & (1 << 0x4))	/* b:0, a:1 */
+		base += 4 * di;		/* a: use Ra+4 (for i),
+					      or Ra-4 (for d) */
+	      /* else base = base;	b use Ra */
+
+	      /* We should consider both increasing and decreasing case.
+
+		 Either case stores registers in the same order.
+		 To simplify the code (yes, the loops),
+		 I used the same pushing order, but from different side.  */
+
+	      if (di == 1)		/* Increasing.  */
+		base += (rn * 4 - 4);
+	      /* else, in des case, we already are on the top */
+
+	      for (i = 0; i < 4; i++)
+		{
+		  if (enable4 & (1 << enb4map[aligned][i]))
+		    {
+		      info->saved_regs[NDS32_SP_REGNUM -
+				       (enb4map[aligned][i])].addr = base;
+		      base -= 4;
+		    }
+		}
+
+	      /* Skip re == rb == sp > fp.  */
+	      for (i = re; i >= rb && rb < NDS32_FP_REGNUM; i--)
+		{
+		  info->saved_regs[i].addr = base;
+		  base -= 4;
+		}
+
+	      continue;
+	    }
+	  /* swi $lp, [$sp + (imm15s << 2)] */
+	  /* We must check if $rt is $lp to determine it is
+	     in prologue or not.  */
+	  if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI, REG_LP, REG_FP, 0))
+	    {
+	      int imm15s;
+
+	      /* swi $lp, [$sp + (imm15s<<2)] */
+	      imm15s = N32_IMM15S (insn);
+	      info->saved_regs[NDS32_LP_REGNUM].addr = info->sp_offset
+						       + (imm15s << 2);
+	      continue;
+	    }
+	  /* swi.bi $rt, [$sp], (imm15s << 2) */
+	  if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI_BI, REG_LP, REG_FP, 0))
+	    {
+	      unsigned int rt5 = 0;
+	      unsigned int ra5 = 0;
+	      int imm15s = 0;
+	      rt5 = N32_RT5 (insn);
+	      ra5 = N32_RA5 (insn);
+	      imm15s = N32_IMM15S (insn);
+
+	      if (ra5 == NDS32_SP_REGNUM)
+		{
+		  info->saved_regs[rt5].addr = info->sp_offset;
+		  info->sp_offset += (imm15s << 2);
+		}
+	      else if (ra5 == NDS32_FP_REGNUM)
+		{
+		  info->saved_regs[rt5].addr = info->fp_offset;
+		  info->fp_offset += (imm15s << 2);
+		}
+	      continue;
+	    }
+
+	  if (N32_OP6 (insn) == N32_OP6_COP && N32_COP_CP (insn) == 0
+	      && (N32_COP_SUB (insn) == N32_FPU_FSS
+		  || N32_COP_SUB (insn) == N32_FPU_FSD)
+	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
+	    {
+	      /* CP shoud be CP0 */
+	      /* fs[sd][.bi] $fst, [$sp + ($r0 << sv)] */
+	      continue;
+	    }
+
+	  /* fssi $fst, [$ra + (imm12s << 2)]
+	     fssi.bi $fst, [$ra], (imm12s << 2)
+	     fsdi $fdt, [$ra + (imm12s << 2)]
+	     fsdi.bi $fdt, [$ra], (imm12s << 2) */
+	  if ((N32_OP6 (insn) == N32_OP6_SWC || N32_OP6 (insn) == N32_OP6_SDC)
+	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
+	    {
+	      /* fssi and fsdi have the same form.  */
+	      /* Only .bi form should be handled to adjust reg.  */
+	      unsigned int ra5 = 0;
+	      int imm12s = 0;
+
+	      ra5 = N32_RA5 (insn);
+	      imm12s = N32_IMM12S (insn);
+
+	      if (imm12s & 0x800)
+		imm12s = (imm12s - (0x800 << 1));
+
+	      switch (ra5)
+		{
+		case NDS32_FP_REGNUM:
+		  info->fp_offset += (imm12s << 2);
+		  break;
+		case NDS32_SP_REGNUM:
+		  info->sp_offset += (imm12s << 2);
+		  break;
+		}
+
+	      continue;
+	    }
+
+	  break;
+	}
+      else
+	{
+	  /* 16-bit instruction */
+	  pc += 2;
+	  insn >>= 16;
+
+	  /* 1. If the instruction is j/b, then we stop
+		i.e., OP starts with 10, and beqzs8, bnezs8.
+	     2. If the operations will change sp/fp or based on sp/fp,
+		then we are in the prologue.
+	     3. If we don't know what's it, then stop.  */
+
+	  if (__GF (insn, 13, 2) == 2)
+	    {
+	      /* These are all branch instructions.  */
+	      pc -= 2;
+	      break;
+	    }
+	  else if (__GF (insn, 9, 6) == 0x34)
+	    {
+	      /* beqzs8, bnezs8 */
+	      pc -= 2;
+	      break;
+	    }
+
+	  if (CHOP_BITS (insn, 10) == N16_TYPE10 (ADDI10S, 0))
+	    {
+	      /* addi10s */
+	      info->sp_offset += N16_IMM10S (insn);
+	      continue;
+	    }
+
+	  if (__GF (insn, 7, 8) == N16_T25_PUSH25)
+	    {
+	      /* push25 */
+	      int imm8u = (insn & 0x1f) << 3;
+	      int re = ((insn & 0x60) >> 5) & 0x3;
+	      int m[] = {4, 6, 8, 12};
+
+	      /* Operation 1 - smw.adm R6, [sp], Re, #0xe */
+	      info->saved_regs[NDS32_LP_REGNUM].addr = info->sp_offset - 0x4;
+	      info->saved_regs[NDS32_GP_REGNUM].addr = info->sp_offset - 0x8;
+	      info->saved_regs[NDS32_FP_REGNUM].addr = info->sp_offset - 0xC;
+	      info->sp_offset -= m[re] * 4;
+
+	      switch (re)
+		{
+		  case 3:
+		    info->saved_regs[14].addr = info->sp_offset + 0x20;
+		    info->saved_regs[13].addr = info->sp_offset + 0x1C;
+		    info->saved_regs[12].addr = info->sp_offset + 0x18;
+		    info->saved_regs[11].addr = info->sp_offset + 0x14;
+		  case 2:
+		    info->saved_regs[10].addr = info->sp_offset + 0x10;
+		    info->saved_regs[9].addr = info->sp_offset + 0xC;
+		  case 1:
+		    info->saved_regs[8].addr = info->sp_offset + 0x8;
+		    info->saved_regs[7].addr = info->sp_offset + 0x4;
+		  case 0:
+		    info->saved_regs[6].addr = info->sp_offset;
+		}
+
+	      /* Operation 2 - sp = sp - imm5u<<3 */
+	      info->sp_offset -= imm8u;
+
+	      /* Operation 3 - if (Re >= 1) R8 = concat (PC(31,2), 2`b0) */
+	      continue;
+	    }
+
+	  /* mov55 fp, sp */
+	  if (insn == N16_TYPE55 (MOV55, REG_FP, REG_SP))
+	    {
+		info->fp_offset = info->sp_offset;
+		info->use_frame = 1;
+		continue;
+	    }
+	  /* swi450 */
+	  switch (insn & ~__MF (-1, 5, 4))
+	    {
+	      case N16_TYPE45 (SWI450, 0, REG_SP):
+	      case N16_TYPE45 (SWI450, 0, REG_FP):
+		break;
+	    }
+	  /* swi37 - implied fp */
+	  if (__GF (insn, 11, 4) == N16_T37_XWI37
+	      && (insn & __BIT (7)))
+	    continue;
+
+	  /* swi37sp - implied */
+	  if (__GF (insn, 11, 4) == N16_T37_XWI37SP
+	      && (insn & __BIT (7)))
+	    continue;
+
+	  break;
+	  }
+    }
+
+  info->size = -info->sp_offset;
+  /* Compute the previous frame's stack pointer (which is also the
+     frame's ID's stack address), and this frame's base pointer.
+
+     Assume that the FP is this frame's SP but with that pushed
+     stack space added back.  */
+  next_base = get_frame_register_unsigned (this_frame, NDS32_SP_REGNUM);
+  prev_sp = next_base + info->size;
+  fp_base = get_frame_register_unsigned (this_frame, NDS32_FP_REGNUM);
+  if (info->use_frame && fp_base > 0)
+    {
+      /* Try to use FP if possible. */
+      prev_sp = fp_base - info->fp_offset;
+    }
+
+  /* Convert that SP/BASE into real addresses.  */
+  info->prev_sp = prev_sp;
+  info->base = next_base;
+
+  /* Adjust all the saved registers so that they contain addresses and
+     not offsets.  */
+  for (i = 0; i < gdbarch_num_regs (gdbarch) - 1; i++)
+    {
+      if (trad_frame_addr_p (info->saved_regs, i))
+	{
+	  info->saved_regs[i].addr = info->prev_sp + info->saved_regs[i].addr;
+	}
+    }
+
+  /* The previous frame's SP needed to be computed.
+     Save the computed value.  */
+  trad_frame_set_value (info->saved_regs, NDS32_SP_REGNUM, prev_sp);
+
+  return info;
+}
+
+/* Implement the gdbarch_skip_permanent_breakpoint method.  */
+
+static void
+nds32_skip_permanent_breakpoint (struct regcache *regcache)
+{
+  gdb_byte insn[2];
+  CORE_ADDR current_pc = regcache_read_pc (regcache);
+
+  target_read_memory (current_pc, insn, sizeof (insn));
+
+  if (memcmp (insn, NDS32_BREAK16, sizeof (insn)) != 0)
+    return;
+
+  current_pc += 2;
+  regcache_write_pc (regcache, current_pc);
+}
+
+/* Implement the gdbarch_read_pc method.  */
+
+static CORE_ADDR
+nds32_read_pc (struct regcache *regcache)
+{
+  ULONGEST pc;
+  regcache_cooked_read_unsigned (regcache, NDS32_PC_REGNUM, &pc);
+  return pc;
+}
+
+/* Implement the gdbarch_write_pc method.  */
+
+static void
+nds32_write_pc (struct regcache *regcache, CORE_ADDR val)
+{
+  regcache_cooked_write_unsigned (regcache, NDS32_PC_REGNUM, val);
+}
+
+/* Implement the gdbarch_unwind_pc method.  */
+
+static CORE_ADDR
+nds32_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  /* This snippet code is a mess.
+
+     In most case, LP is the actually register being saved.
+     Hence when unwinding pc for backtrace, LP should be the one.
+     That is, for frames (level > 0), unwinding the PC means
+     unwinding LP from the this_frame.
+
+     However, for a top frame (level==0), unwinding PC means
+     the current program counter (PC).
+     Besides, for dummy frame, PC stored in dummy_frame is the one
+     we want.
+
+     We have to have these cases to make backtrace work properly.  */
+
+  CORE_ADDR pc;
+  pc = frame_unwind_register_unsigned (this_frame, NDS32_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the gdbarch_unwind_sp method.  */
+
+static CORE_ADDR
+nds32_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return frame_unwind_register_unsigned (this_frame, NDS32_SP_REGNUM);
+}
+
+/* If these is exactly one float point type field in the struct,
+   the alignment of the struct is the size of the float pointer type.  */
+
+static int
+nds32_float_in_struct (struct type *type)
+{
+  struct type *actual_type;
+
+  type = check_typedef (type);
+  if (TYPE_CODE (type) != TYPE_CODE_STRUCT || TYPE_NFIELDS (type) != 1)
+    return 0;
+
+  actual_type = check_typedef (TYPE_FIELD_TYPE (type, 0));
+  if (TYPE_CODE (actual_type) == TYPE_CODE_FLT)
+    {
+      gdb_assert (TYPE_LENGTH (type) == 8 || TYPE_LENGTH (type) == 4);
+      return TYPE_LENGTH (type);
+    }
+  return 0;
+}
+
+/* Get the alignment of the type.
+
+   The alignment requirement of a structure is the largest alignment
+   requirement of its member, so we should traverse every member to
+   find the largest alignment.
+
+   For example,
+     struct { int a; int b; char c } is 4-byte aligned,
+   and
+     struct {long long a; char c} is 8-byte aligned.  */
+
+static int
+nds32_type_align (struct type *type)
+{
+  int align = 0;		/* Current max alignment.  */
+  int i;
+
+  gdb_assert (type != NULL);
+  if (type == NULL)
+    return 0;
+
+  if (type->main_type->nfields == 0)
+    return type->length;
+
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_ARRAY:
+      return nds32_type_align (TYPE_TARGET_TYPE (type));
+    case TYPE_CODE_ENUM:
+      return TYPE_LENGTH (type);
+    }
+
+  /* For structs with only one float/double are treated as float/double.  */
+  align = nds32_float_in_struct (type);
+  if (align != 0)
+    return align;
+
+  for (i = 0; i < TYPE_NFIELDS (type); i++)
+    {
+      int r = nds32_type_align (TYPE_FIELD_TYPE (type, i));
+
+      if (r > align)
+	align = r;
+    }
+
+  return align;
+}
+
+/* Implement the gdbarch_push_dummy_call method.  */
+
+static CORE_ADDR
+nds32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+		       struct regcache *regcache, CORE_ADDR bp_addr,
+		       int nargs, struct value **args, CORE_ADDR sp,
+		       int struct_return, CORE_ADDR struct_addr)
+{
+  const int REND = 6;		/* Max arguments number.  */
+  int goff = 0;			/* Current gpr for argument.  */
+  int foff = 0;			/* Currnet gpr for argument.  */
+  int soff = 0;			/* Current stack offset.  */
+  int i;
+  enum type_code typecode;
+  CORE_ADDR regval;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int fs0_regnum = -1, fd0_regnum = -1;
+
+  if (tdep->abi_use_fpr)
+    {
+      /* Use FP registers to pass arguments.  */
+      fs0_regnum = user_reg_map_name_to_regnum (gdbarch, "fs0", -1);
+      fd0_regnum = user_reg_map_name_to_regnum (gdbarch, "fd0", -1);
+    }
+
+  /* Set the return address.  For the nds32, the return breakpoint is
+     always at BP_ADDR.  */
+  regcache_cooked_write_unsigned (regcache, NDS32_LP_REGNUM, bp_addr);
+
+  /* If STRUCT_RETURN is true, then the struct return address (in
+     STRUCT_ADDR) will consume the first argument-passing register.
+     Both adjust the register count and store that value.  */
+  if (struct_return)
+    {
+      regcache_cooked_write_unsigned (regcache, NDS32_R0_REGNUM, struct_addr);
+      goff++;
+    }
+
+  /* Now make sure there's space on the stack */
+  for (i = 0; i < nargs; i++)
+    {
+      struct type *type = value_type (args[i]);
+      int align = nds32_type_align (type);
+
+      /* If align is zero, it may be an empty struct.
+	 Just ignore the argument of empty struct.  */
+      if (align == 0)
+	continue;
+
+      sp -= align_up (TYPE_LENGTH (type), 4);
+      sp = align_down (sp, align);
+    }
+
+  /* Allocate 24-byte for ABI V1.  */
+  sp -= 24;
+  /* Stack must be 8-byte aligned.  */
+  sp = align_down (sp, 8);
+
+  soff = 0;
+  for (i = 0; i < nargs; i++)
+    {
+      const gdb_byte *val;
+      int align, len;
+      struct type *type;
+
+      type = value_type (args[i]);
+      typecode = TYPE_CODE (type);
+      align = nds32_float_in_struct (type);
+      if (align)
+	typecode = TYPE_CODE_FLT;
+      else
+	align = nds32_type_align (type);
+      len = TYPE_LENGTH (type);
+
+      /* For current ABI, the caller pushes arguments in registers,
+	 callee stores unnamed arguments in stack,
+	 and then va_arg fetch arguments in stack.
+	 Therefore, we don't have to handle variadic function specially.  */
+
+      val = value_contents (args[i]);
+
+      /* Once we start using stack, all arguments should go to stack
+	 When use_fpr, all flt must go to fs/fd; otherwise go to stack.  */
+      if (tdep->abi_use_fpr && typecode == TYPE_CODE_FLT)
+	{
+	  /* Adjust alignment.  */
+	  if ((align >> 2) > 0)
+	    foff = align_up (foff, align >> 2);
+
+	  if (foff < REND && !soff)
+	    {
+	      if (tdep->abi_use_fpr && fs0_regnum == -1)
+		goto error_no_fpr;
+
+	      switch (len)
+		{
+		case 4:
+		  regcache_cooked_write (regcache, fs0_regnum + foff, val);
+		  foff++;
+		  continue;
+		case 8:
+		  regcache_cooked_write (regcache, fd0_regnum + foff / 2, val);
+		  foff += 2;
+		  continue;
+		default:
+		  /* Long double? */
+		  internal_error (__FILE__, __LINE__,
+				  "Do not know how to handle %d-byte double.\n",
+				  len);
+		  break;
+		}
+	    }
+	}
+      else if (!soff)
+	{
+	  /* Adjust alignment, and only adjust one time for one argument.  */
+	  if ((align >> 2) > 0)
+	    goff = align_up (goff, align >> 2);
+	  if (!tdep->abi_split && len > (REND - goff) * 4)
+	    goff = REND;
+	}
+
+      /*
+	When passing arguments,
+
+	* A composite type not larger than 4 bytes is passed
+	  in $rN. The format is as if the value is loaded with
+	  load instruction of corresponding size. (i.g., LB, LH, LW)
+
+	   For example,
+
+		  r0
+		  31      0
+	  little: [x x b a]
+	     BIG: [x x a b]
+
+	 * Otherwise, a composite type is passed in consective registers.
+	   The size is rounded up to the nearest multiple of 4.
+	   The successive registers hold the parts of the argument as if
+	   were loaded using lmw instructions.
+
+	  For example,
+
+		  r0	     r1
+		  31      0 31	     0
+	  little: [d c b a] [x x x e]
+	     BIG: [a b c d] [e x x x]
+
+
+	When push an argument in stack,
+
+	* A composite type not larger than 4 bytes is copied
+	  to memory at the next free space, in little-endian.
+	  In big-endian, the last byte of the argument is aligned
+	  at the next word address.  For example,
+
+	  sp [ - ]  [ b ] hi
+	     [ - ]  [ a ]
+	     [ b ]  [ - ]
+	     [ a ]  [ - ] lo
+	    little   BIG
+       */
+
+      if (len > 4)
+	len = align_up (len, 4);
+
+      while (len > 0)
+	{
+	  if (soff
+	      || (typecode == TYPE_CODE_FLT && tdep->abi_use_fpr && foff == REND)
+	      || goff == REND)
+	    {
+	      int rlen = (len > 4) ? 4 : len;
+
+	      if (byte_order == BFD_ENDIAN_BIG)
+		write_memory (sp + soff + 4 - rlen, val, rlen);
+	      else
+		write_memory (sp + soff, val, rlen);
+	      soff += 4;
+	    }
+	  else
+	    {
+	      regval = extract_unsigned_integer (val, (len > 4) ? 4 : len,
+						 byte_order);
+	      regcache_cooked_write_unsigned (regcache,
+					      goff + NDS32_R0_REGNUM, regval);
+	      goff++;
+	    }
+
+	  len -= register_size (gdbarch, goff);
+	  val += register_size (gdbarch, goff);
+	}
+    }
+
+  /* Finally, update the SP register.  */
+  regcache_cooked_write_unsigned (regcache, NDS32_SP_REGNUM, sp);
+
+  return sp;
+
+error_no_fpr:
+  /* If use_fpr, but no floating-point register exists,
+     then it is an error.  */
+  error (_("Fail to call. FS0-FS5 is required."));
+}
+
+/* Extract the value to be returned from REGCACHE and copy it into
+   REGBUF.  */
+
+static void
+nds32_extract_return_value (struct type *type, struct regcache *regcache,
+			    gdb_byte *readbuf)
+{
+  int len = TYPE_LENGTH (type);
+  int typecode = TYPE_CODE (type);
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int fs0_regnum, fd0_regnum;
+
+  /* Although struct are returned in r0/r1 registers, but struct have
+     only one single/double floating-point member are returned in FS/FD
+     registers.  */
+  gdb_assert (TYPE_LENGTH (type) <= 8);
+  if (nds32_float_in_struct (type))
+    typecode = TYPE_CODE_FLT;
+
+  if (typecode == TYPE_CODE_FLT && tdep->abi_use_fpr)
+    {
+      fs0_regnum = user_reg_map_name_to_regnum (gdbarch, "fs0", -1);
+      fd0_regnum = user_reg_map_name_to_regnum (gdbarch, "fd0", -1);
+
+      if (len == 4)
+	regcache_cooked_read (regcache, fs0_regnum, readbuf);
+      else if (len == 8)
+	regcache_cooked_read (regcache, fd0_regnum, readbuf);
+      else
+	internal_error (__FILE__, __LINE__,
+			_("Cannot extract return value of %d bytes "
+			  "long floating point."),
+			len);
+    }
+  else
+    {
+      /* When returning result,
+
+	* A composite type not larger than 4 bytes is returned
+	  in $r0. The format is as if the result is loaded with
+	  load instruction of corresponding size. (i.g., LB, LH, LW)
+
+	  For example,
+
+		  r0
+		  31      0
+	  little: [x x b a]
+	     BIG: [x x a b]
+
+	* Otherwise, a composite type not larger than 8 bytes
+	  is returned in $r0 and $r1. In little-endian, the first
+	  word is loaded in $r0. In big-endian, the last word
+	  is loaded in $r1.
+
+	  For example,
+
+		  r0	    r1
+		  31      0 31      0
+	  little: [d c b a] [x x x e]
+	     BIG: [x x x a] [b c d e]
+       */
+
+      if (len <= 4)
+	{
+	  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	    regcache_raw_read_part (regcache, NDS32_R0_REGNUM, 4 - len, len,
+				    readbuf);
+	  else
+	    regcache_raw_read_part (regcache, NDS32_R0_REGNUM, 0, len,
+				    readbuf);
+	}
+      else if (len <= 8)
+	{
+	  int partial = len - 4;
+
+	  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	    {
+	      regcache_raw_read_part (regcache, NDS32_R0_REGNUM, 4 - partial,
+				      partial, readbuf);
+	      regcache_raw_read (regcache, NDS32_R0_REGNUM + 1,
+				 readbuf + partial);
+
+	    }
+	  else
+	    {
+	      regcache_raw_read (regcache, NDS32_R0_REGNUM, readbuf);
+	      regcache_raw_read_part (regcache, NDS32_R0_REGNUM + 1, 0,
+				      partial, readbuf + 4);
+	    }
+	}
+      else
+	internal_error (__FILE__, __LINE__,
+			_("Cannot extract return value of %d bytes long."),
+			len);
+    }
+}
+
+/* Store the return value of TYPE in WRITEBUF into REGCACHE.  */
+
+static void
+nds32_store_return_value (struct type *type, struct regcache *regcache,
+			  const gdb_byte *writebuf)
+{
+  int len = TYPE_LENGTH (type);
+  int typecode = TYPE_CODE (type);
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int fs0_regnum, fd0_regnum;
+
+  /* Although struct are returned in r0/r1 registers, but struct have
+     only one single/double floating-point member are returned in FS/FD
+     registers.  */
+  gdb_assert (TYPE_LENGTH (type) <= 8);
+  if (nds32_float_in_struct (type))
+    typecode = TYPE_CODE_FLT;
+
+  if (typecode == TYPE_CODE_FLT && tdep->abi_use_fpr)
+    {
+      fs0_regnum = user_reg_map_name_to_regnum (gdbarch, "fs0", -1);
+      fd0_regnum = user_reg_map_name_to_regnum (gdbarch, "fd0", -1);
+
+      if (len == 4)
+	regcache_cooked_write (regcache, fs0_regnum, writebuf);
+      else if (len == 8)
+	regcache_cooked_write (regcache, fd0_regnum, writebuf);
+      else
+	internal_error (__FILE__, __LINE__,
+			_("Cannot store return value of %d bytes long "
+			  "floating point."),
+			len);
+    }
+  else
+    {
+      if (len <= 4)
+	{
+	  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	    regcache_raw_write_part (regcache, NDS32_R0_REGNUM, 4 - len, len,
+				     writebuf);
+	  else
+	    regcache_raw_write_part (regcache, NDS32_R0_REGNUM, 0, len,
+				     writebuf);
+	}
+      else if (len <= 8)
+	{
+	  int partial = len - 4;
+
+	  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	    {
+	      regcache_raw_write_part (regcache, NDS32_R0_REGNUM, 4 - partial,
+				       partial, writebuf);
+	      regcache_raw_write (regcache, NDS32_R0_REGNUM + 1,
+				  writebuf + partial);
+
+	    }
+	  else
+	    {
+	      regcache_raw_write (regcache, NDS32_R0_REGNUM, writebuf);
+	      regcache_raw_write_part (regcache, NDS32_R0_REGNUM + 1, 0,
+				       partial, writebuf + 4);
+	    }
+	}
+      else
+	internal_error (__FILE__, __LINE__,
+			_("Cannot store return value of %d bytes long."),
+			len);
+    }
+}
+
+/* Implement the gdbarch_return_value method.  */
+
+static enum return_value_convention
+nds32_return_value (struct gdbarch *gdbarch, struct value *func_type,
+		    struct type *type, struct regcache *regcache,
+		    gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+  if (TYPE_LENGTH (type) > 8)
+    {
+      return RETURN_VALUE_STRUCT_CONVENTION;
+    }
+  else
+    {
+      /* `readbuf' is used for 'call' to get the return value.
+	 `writebuf' is used for 'return' to set the return value.  */
+      if (readbuf != NULL)
+	nds32_extract_return_value (type, regcache, readbuf);
+      if (writebuf != NULL)
+	nds32_store_return_value (type, regcache, writebuf);
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+}
+
+/* Assuming NEXT_FRAME->prev 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
+nds32_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp, pc;
+
+  sp = get_frame_register_unsigned (this_frame, NDS32_SP_REGNUM);
+  pc = get_frame_pc (this_frame);
+  return frame_id_build (sp, pc);
+}
+
+/* Given a GDB frame, determine the address of the calling function's
+   frame.  This will be used to create a new GDB frame struct.  */
+
+static void
+nds32_frame_this_id (struct frame_info *this_frame,
+		     void **this_prologue_cache, struct frame_id *this_id)
+{
+  struct nds32_unwind_cache *info;
+  CORE_ADDR base;
+  CORE_ADDR func;
+  struct frame_id id;
+
+  info = nds32_frame_unwind_cache (this_frame, this_prologue_cache);
+
+  /* Get function entry address */
+  func = get_frame_func (this_frame);
+
+  /* Hopefully the prologue analysis either correctly determined the
+     frame's base (which is the SP from the previous frame), or set
+     that base to "NULL".  */
+  base = info->prev_sp;
+  if (base == 0)
+    return;
+
+  id = frame_id_build (base, func);
+  (*this_id) = id;
+}
+
+/* Get the value of register REGNUM in previous frame.  */
+
+static struct value *
+nds32_frame_prev_register (struct frame_info *this_frame,
+			   void **this_prologue_cache, int regnum)
+{
+  struct nds32_unwind_cache *cache;
+  cache = nds32_frame_unwind_cache (this_frame, this_prologue_cache);
+
+  if (regnum == NDS32_PC_REGNUM)
+    {
+      CORE_ADDR lr;
+
+      lr = frame_unwind_register_unsigned (this_frame, NDS32_LP_REGNUM);
+      return frame_unwind_got_constant (this_frame, regnum, lr);
+    }
+
+  return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+}
+
+/* The register in previous frame.  For example, the previous PC is
+   current LP.  */
+
+static struct value *
+nds32_dwarf2_prev_register (struct frame_info *this_frame,
+			    void **this_cache, int regnum)
+{
+  CORE_ADDR lp;
+
+  switch (regnum)
+    {
+    case NDS32_PC_REGNUM:
+      lp = frame_unwind_register_unsigned (this_frame, NDS32_LP_REGNUM);
+      return frame_unwind_got_constant (this_frame, regnum, lp);
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unexpected register %d"), regnum);
+    }
+
+   return NULL;
+}
+
+/* Callback of dwarf2_frame_set_init_reg.  */
+
+static void
+nds32_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+			     struct dwarf2_frame_state_reg *reg,
+			     struct frame_info *this_frame)
+{
+  switch (regnum)
+    {
+    case NDS32_PC_REGNUM:
+      reg->how = DWARF2_FRAME_REG_FN;
+      reg->loc.fn = nds32_dwarf2_prev_register;
+      break;
+    case NDS32_SP_REGNUM:
+      reg->how = DWARF2_FRAME_REG_CFA;
+      break;
+    }
+}
+
+/* Implement the gdbarch_get_longjmp_target method.  */
+
+static int
+nds32_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
+{
+  gdb_byte buf[4];
+  CORE_ADDR jmp_buf_p;
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  jmp_buf_p = get_frame_register_unsigned (frame, 0);
+
+  /* Key is in setjmp():
+     lmw.bim   r6, [r0], r14
+     lmw.bim  r16, [r0], r19, 0xf */
+
+  if (target_read_memory (jmp_buf_p + 15 * 4, buf, 4))
+    return 0;
+
+  *pc = extract_unsigned_integer (buf, 4, byte_order);
+
+  return 1;
+}
+
+static const struct frame_unwind nds32_frame_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  nds32_frame_this_id,
+  nds32_frame_prev_register,
+  NULL /* unwind_data */,
+  default_frame_sniffer,
+  NULL /* dealloc_cache */,
+  NULL /* prev_arch */
+};
+
+static CORE_ADDR
+nds32_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+  struct nds32_unwind_cache *info;
+
+  info = nds32_frame_unwind_cache (this_frame, this_cache);
+
+  return info->base;
+}
+
+static const struct frame_base nds32_frame_base =
+{
+  &nds32_frame_unwind,
+  nds32_frame_base_address,
+  nds32_frame_base_address,
+  nds32_frame_base_address
+};
+
+/* Implement the gdbarch_overlay_update method.  */
+
+static void
+nds32_simple_overlay_update (struct obj_section *osect)
+{
+  struct minimal_symbol *minsym = NULL;
+
+  minsym = lookup_minimal_symbol (".nds32.fixed.size", NULL, NULL);
+  if (minsym != NULL && osect != NULL)
+    {
+      bfd *obfd = osect->objfile->obfd;
+      asection *bsect = osect->the_bfd_section;
+      if (bfd_section_vma (obfd, bsect) < SYMBOL_VALUE_ADDRESS (minsym))
+	{
+	  osect->ovly_mapped = 1;
+	  return;
+	}
+    }
+
+  simple_overlay_update (osect);
+}
+
+/* Implement gdbarch_print_insn method.  */
+
+static int
+gdb_print_insn_nds32 (bfd_vma memaddr, disassemble_info *info)
+{
+  struct obj_section * s = find_pc_section (memaddr);
+
+  /* When disassembling ex9 instructions, they are annotated with
+     the original instructions at the end of line.  For example,
+
+	0x00500122 <+82>:    ex9.it #4		! movi $r13, 10
+
+     Dissembler needs the symbol table to extract the original instruction
+     in _ITB_BASE_ table.  If the object file is changed, reload symbol
+     table.  */
+
+  if (s == NULL || info->section != s->the_bfd_section)
+    {
+      xfree (info->symtab);
+      info->symtab = NULL;
+      info->symtab_size = 0;
+    }
+
+  if (info->symtab == NULL && s && s->the_bfd_section)
+    {
+      long storage = bfd_get_symtab_upper_bound (s->objfile->obfd);
+
+      if (storage <= 0)
+	goto done;
+
+      info->section = s->the_bfd_section;
+      info->symtab = xmalloc (storage);
+      info->symtab_size =
+	bfd_canonicalize_symtab (s->the_bfd_section->owner, info->symtab);
+    }
+
+done:
+  return print_insn_nds32 (memaddr, info);
+}
+
+/* Callback for gdbarch_init.  */
+
+static struct gdbarch *
+nds32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  struct gdbarch_list *best_arch;
+  const struct target_desc *tdesc = NULL;
+  struct tdesc_arch_data *tdesc_data = NULL;
+  int i;
+
+  /* Allocate space for the new architecture.  */
+  tdep = XCALLOC (1, struct gdbarch_tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  if (tdesc_has_registers (info.target_desc))
+    {
+      int valid_p;
+      int fpregs = -1;
+      static const char *const nds32_fp_names[] = { "r28", "fp", NULL };
+      static const char *const nds32_lp_names[] = { "r30", "lp", NULL };
+      static const char *const nds32_sp_names[] = { "r31", "sp", NULL };
+      const struct tdesc_feature *feature;
+
+      /* Validate and initialize target-description here.  */
+      tdesc = info.target_desc;
+      tdesc_data = tdesc_data_alloc ();
+
+      info.tdep_info = (void *) tdesc_data;
+
+      feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nds32.core");
+      if (!feature)
+	return 0;
+
+      /* Validate  for FP, LP, GP, PC.  */
+      valid_p = 1;
+      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+						  NDS32_FP_REGNUM,
+						  nds32_fp_names);
+      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+						  NDS32_LP_REGNUM,
+						  nds32_lp_names);
+      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+						  NDS32_SP_REGNUM,
+						  nds32_sp_names);
+      valid_p &= tdesc_numbered_register (feature, tdesc_data,
+					  NDS32_PC_REGNUM, "pc");
+
+      if (!valid_p)
+	{
+	  tdesc_data_cleanup (tdesc_data);
+	  xfree (tdep);
+	  gdbarch_free (gdbarch);
+	  return NULL;
+	}
+
+      /* Number R0-R27.  */
+      for (i = NDS32_R0_REGNUM; i < NDS32_FP_REGNUM; i++)
+	tdesc_numbered_register (feature, tdesc_data, i, nds32_regnames[i]);
+
+      /* Number D0 and D1.  */
+      for (i = NDS32_D0LO_REGNUM; i <= NDS32_D1HI_REGNUM; i++)
+	tdesc_numbered_register (feature, tdesc_data, i, nds32_regnames[i]);
+
+      /* Find register configuration of FPU.  */
+      feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nds32.fpu");
+      if (feature != NULL)
+	{
+	  if (tdesc_unnumbered_register (feature, "fd31"))
+	    fpregs = 3;
+	  else if (tdesc_unnumbered_register (feature, "fd15"))
+	    fpregs = 2;
+	  else if (tdesc_unnumbered_register (feature, "fd7"))
+	    fpregs = 1;
+	  else if (tdesc_unnumbered_register (feature, "fd3"))
+	    fpregs = 0;
+	}
+      tdep->fpu_freg = fpregs;
+
+      /* If FS registers do not exist, make them pseudo registers
+	 of FD registers.  */
+      if (fpregs != -1 && tdesc_unnumbered_register (feature, "fs0") == 0)
+	{
+	  int fsregs = (fpregs + 1) * 8;
+
+	  if (fsregs > 32)
+	    fsregs = 32;
+
+	  set_gdbarch_num_pseudo_regs (gdbarch, fsregs);
+	  set_gdbarch_pseudo_register_read (gdbarch, nds32_pseudo_register_read);
+	  set_gdbarch_pseudo_register_write (gdbarch, nds32_pseudo_register_write);
+	  set_tdesc_pseudo_register_name (gdbarch, nds32_register_name);
+	}
+
+      set_gdbarch_num_regs (gdbarch, NDS32_NUM_REGS);
+      tdesc_use_registers (gdbarch, tdesc, tdesc_data);
+    }
+  else
+    {
+      /* Simulator or legacy target.  */
+
+      /* Physical 32 FD registers.  */
+      set_gdbarch_num_regs (gdbarch, NDS32_SIM_NUM_REGS);
+      set_gdbarch_register_name (gdbarch, nds32_register_name);
+
+      /* Pseudo 32 FS registers.  */
+      set_gdbarch_num_pseudo_regs (gdbarch, 32);
+      set_gdbarch_pseudo_register_read (gdbarch, nds32_pseudo_register_read);
+      set_gdbarch_pseudo_register_write (gdbarch, nds32_pseudo_register_write);
+    }
+
+  /* Extract the elf_flags, if available.  */
+  if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    {
+      int eflags = elf_elfheader (info.abfd)->e_flags;
+      int nds32_abi = eflags & EF_NDS_ABI;
+
+      /* Split large arguments by default.  */
+      tdep->abi_split = TRUE;
+      /* Do not use FPRs by default.  */
+      tdep->abi_use_fpr = FALSE;
+      switch (nds32_abi)
+	{
+	case E_NDS_ABI_V2FP:
+	  tdep->abi_use_fpr = TRUE;
+	  /* Fall-through.  */
+	case E_NDS_ABI_V2:
+	  tdep->abi_split = FALSE;
+	}
+    }
+
+  /* If there is already a candidate, use it.  */
+  for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
+       best_arch != NULL;
+       best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
+    {
+      struct gdbarch_tdep *idep = gdbarch_tdep (best_arch->gdbarch);
+
+      if (tdep->abi_split != idep->abi_split)
+	continue;
+      if (tdep->abi_use_fpr != idep->abi_use_fpr)
+	continue;
+
+      /* Check FPU registers.  */
+      if (idep->fpu_freg != tdep->fpu_freg)
+	continue;
+
+      /* Found a match.  */
+      break;
+    }
+
+  if (best_arch != NULL)
+    {
+      xfree (tdep);
+      gdbarch_free (gdbarch);
+      return best_arch->gdbarch;
+    }
+
+  nds32_add_reggroups (gdbarch);
+
+  gdbarch_init_osabi (info, gdbarch);
+
+  /* Override tdesc_register callbacks for system registers.  */
+  set_gdbarch_register_reggroup_p (gdbarch, nds32_register_reggroup_p);
+  set_gdbarch_register_type (gdbarch, nds32_register_type);
+
+  set_gdbarch_sp_regnum (gdbarch, NDS32_SP_REGNUM);
+  set_gdbarch_pc_regnum (gdbarch, NDS32_PC_REGNUM);
+  set_gdbarch_read_pc (gdbarch, nds32_read_pc);
+  set_gdbarch_write_pc (gdbarch, nds32_write_pc);
+  set_gdbarch_unwind_sp (gdbarch, nds32_unwind_sp);
+  set_gdbarch_unwind_pc (gdbarch, nds32_unwind_pc);
+  set_gdbarch_in_function_epilogue_p (gdbarch, nds32_in_function_epilogue_p);
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, nds32_dwarf_dwarf2_reg_to_regnum);
+  set_gdbarch_register_sim_regno (gdbarch, nds32_register_sim_regno);
+  set_gdbarch_push_dummy_call (gdbarch, nds32_push_dummy_call);
+  set_gdbarch_return_value (gdbarch, nds32_return_value);
+  set_gdbarch_skip_prologue (gdbarch, nds32_skip_prologue);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_breakpoint_from_pc (gdbarch, nds32_breakpoint_from_pc);
+  set_gdbarch_remote_breakpoint_from_pc (gdbarch,
+					 nds32_remote_breakpoint_from_pc);
+
+  set_gdbarch_frame_align (gdbarch, nds32_frame_align);
+  frame_base_set_default (gdbarch, &nds32_frame_base);
+
+  /* Methods for saving / extracting a dummy frame's ID.
+     The ID's stack address must match the SP value returned by
+     PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos.  */
+  set_gdbarch_dummy_id (gdbarch, nds32_dummy_id);
+  set_gdbarch_print_insn (gdbarch, gdb_print_insn_nds32);
+  set_gdbarch_skip_permanent_breakpoint (gdbarch,
+					 nds32_skip_permanent_breakpoint);
+  /* Support simple overlay manager.  */
+  set_gdbarch_overlay_update (gdbarch, nds32_simple_overlay_update);
+
+  /* Handle longjmp.  */
+  set_gdbarch_get_longjmp_target (gdbarch, nds32_get_longjmp_target);
+
+  /* The order of appending is the order it check frame.  */
+  dwarf2_frame_set_init_reg (gdbarch, nds32_dwarf2_frame_init_reg);
+  dwarf2_append_unwinders (gdbarch);
+  frame_unwind_append_unwinder (gdbarch, &nds32_frame_unwind);
+
+  /* Add nds32 register aliases.  */
+  /* FIXME: This is a simple workaround to force user-reg being
+	    initialized before gdbarch initialized.
+	    Without this, calling user_reg_map_name_to_regnum ()
+	    will crash.  */
+  user_reg_add (gdbarch, "r0", nds32_value_of_reg, "r0");
+  for (i = 0; i < (int) ARRAY_SIZE (nds32_register_aliases); i++)
+    {
+      int regnum;
+
+      regnum = user_reg_map_name_to_regnum
+	(gdbarch, nds32_register_aliases[i].name, -1);
+
+      if (regnum == -1)
+	continue;
+
+      user_reg_add (gdbarch, nds32_register_aliases[i].alias,
+		    nds32_value_of_reg, nds32_register_aliases[i].name);
+    }
+
+  return gdbarch;
+}
+
+void
+_initialize_nds32_tdep (void)
+{
+  /* Initialize gdbarch.  */
+  register_gdbarch_init (bfd_arch_nds32, nds32_gdbarch_init);
+
+  nds32_init_reggroups ();
+
+  register_remote_support_xml ("nds32");
+}
diff --git a/gdb/nds32-tdep.h b/gdb/nds32-tdep.h
new file mode 100644
index 0000000..a5767f4
--- /dev/null
+++ b/gdb/nds32-tdep.h
@@ -0,0 +1,72 @@
+/* Target-dependent header for NDS32 architecture, for GDB.
+
+   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   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 __NDS32_TDEP_H__
+#define __NDS32_TDEP_H__
+
+/* NDS32 virtual registers layout for GDB.  */
+enum nds32_regnum
+{
+  /* General purpose registers.  */
+  NDS32_R0_REGNUM = 0,
+  NDS32_R5_REGNUM = 5,
+  NDS32_TA_REGNUM = 15,		/* Temp for assembler.  */
+  NDS32_FP_REGNUM = 28,		/* Frame register.  */
+  NDS32_GP_REGNUM = 29,		/* Global register.  */
+  NDS32_LP_REGNUM = 30,		/* Link pointer.  */
+  NDS32_SP_REGNUM = 31,		/* Address of stack top.  */
+
+  /* Pseudo PC.  */
+  NDS32_PC_REGNUM = 32,
+
+  /* D0/D1 User Registers.  */
+  NDS32_D0LO_REGNUM = 33,
+  NDS32_D0HI_REGNUM = 34,
+  NDS32_D1LO_REGNUM = 35,
+  NDS32_D1HI_REGNUM = 36,
+
+  /* If target-description is not supported, only assume above
+     registers are supported.  */
+  NDS32_NUM_REGS,
+
+  /* These are only used by simulator.  */
+  NDS32_SIM_FD0_REGNUM = NDS32_NUM_REGS,
+  NDS32_SIM_IFCLP_REGNUM = NDS32_SIM_FD0_REGNUM + 32,
+  NDS32_SIM_ITB_REGNUM,
+  NDS32_SIM_PSW_REGNUM,
+
+  NDS32_SIM_NUM_REGS,
+};
+
+struct htab;
+struct gdbarch_tdep
+{
+  /* The configuration of FPU FREG.  */
+  int fpu_freg;
+
+  /* Large arguments are split between registers and stack.  */
+  int abi_split;
+  /* Set if fs0-fs5 are used to pass arguments.  */
+  int abi_use_fpr;
+
+  /* Type table for registers.  */
+  struct htab *type_tab;
+};
+#endif


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

* Re: [PATCH 1/5] Code for nds32 target
  2013-07-10  5:38 ` Yao Qi
  2013-07-11 14:06   ` Wei-cheng Wang
@ 2013-07-11 14:26   ` Wei-cheng Wang
  1 sibling, 0 replies; 9+ messages in thread
From: Wei-cheng Wang @ 2013-07-11 14:26 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On Wed, Jul 10, 2013 at 1:37 PM, Yao Qi <yao@codesourcery.com> wrote:
> On 07/08/2013 05:27 PM, Wei-cheng Wang wrote:
> Here is the 2nd half.
>> +  struct cleanup *back_to;
>> +
>> +  /* Reload symtab if abfd changed.
> I am sorry that I can't get the points of doing this.  Can you elaborate
> please?

  I've revised the comment as such.

  /* When disassembling ex9 instructions, they are annotated with
     the original instructions at the end of line.  For example,

        0x00500122 <+82>:    ex9.it #4          ! movi $r13, 10

     Dissembler needs the symbol table to extract the original instruction
     in _ITB_BASE_ table.  If the object file is changed, reload symbol
     table.  */

>> +
>> +/* Callback for "nds32 dump" command.
>> +
>> +   Dump current register and stack for debug gdb.  */
>> +
> Do we really need this command?  You can examine registers via command 'info
> registers', and examine stack as a piece of memory via command 'x'.

  This was used to dump registers and stack and create a gdbinit script,
  so I can use the script to debug backtrace porting issues.
  Anyway, I've removed this command in revised patch.  I think I don't need
  it anymore.

> The last but not least, the binutils patch hasn't go in yet, so it is pity
> that I can't build GDB with you patches for nds32 target.
  It still needs more work :p
> You also need a news entry in gdb/NEWS about this new port.  Open gdb/NEWS,
> and then you will know how to add one entry for nds32 port :)
  Just add our target and send a separate patch for it?

Wei-cheng


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

* Re: [PATCH 1/5] Code for nds32 target
  2013-07-09 18:23   ` Wei-cheng Wang
@ 2013-07-25  2:35     ` Yao Qi
  0 siblings, 0 replies; 9+ messages in thread
From: Yao Qi @ 2013-07-25  2:35 UTC (permalink / raw)
  To: Wei-cheng Wang; +Cc: gdb-patches

On 07/10/2013 02:23 AM, Wei-cheng Wang wrote:
>     Target description can not describe a enum-typed bit-field.
>
>     If bit-field struct is used, I could not specify the type for
>     a bit-field.
>
>       <struct id="id" size="size">
>         <field name="name" start="start" end="end"/>
>         ...
>       </struct>
>
>     If I want to specify field type, I couldn't specify size of a field.
>
>       <struct id="id">
>         <field name="name" type="type"/>
>         ...
>       </struct>
>

FAOD, this works in general.  See testsuite/gdb.xml/extra-regs.xml. 
However, TYPE can't be flags.  For example, I hack 'i386_eflags' in 
i386/32bit-core.xml, which splits eflags registers into three groups (or 
types),

   <flags id="i386_eflags_1" size="1">
     <field name="CF" start="0" end="0"/>
     <field name="" start="1" end="1"/>
     <field name="PF" start="2" end="2"/>
     <field name="AF" start="4" end="4"/>
     <field name="ZF" start="6" end="6"/>
     <field name="SF" start="7" end="7"/>
   </flags>

   <flags id="i386_eflags_2" size="1">
     <field name="TF" start="0" end="0"/>
     <field name="IF" start="1" end="1"/>
     <field name="DF" start="2" end="2"/>
     <field name="OF" start="3" end="3"/>
     <field name="NT" start="4" end="4"/>
   </flags>

   <flags id="i386_eflags_3" size="1">
     <field name="RF" start="0" end="0"/>
     <field name="VM" start="1" end="1"/>
     <field name="AC" start="2" end="2"/>
     <field name="VIF" start="3" end="3"/>
     <field name="VIP" start="4" end="4"/>
     <field name="ID" start="5" end="5"/>
   </flags>

   <struct id="i386_eflags" size="4">
     <field name="a" type="i386_eflags_1"/>
     <field name="b" type="i386_eflags_2"/>
     <field name="c" type="i386_eflags_3"/>
   </struct>

Then I get an error:

   Explicitly sized type can not contain non-bitfield "a"

It is a limitation of <struct> and <flags>, which was mentioned in the 
patch submission.

   [patch] Add support for <struct> and <flags> in target descriptions
   http://sourceware.org/ml/gdb-patches/2010-02/msg00542.html

I can't evaluate how much efforts are needed to fix this limitation.

>     All I want is to display a register in such format.
>
>       (gdb) p $cr0
>       $1 = {CFGID = [ PERF_EXT 16_EXT PERF_EXT2 COP_EXT STR_EXT ],
>       REV = 16, CPUID = N13}
>
>     (cr0 consist of config flags, revision number and CPU ID.)

With some hack (comment out the code which throws error) in 
xml-tdesc.c:tdesc_start_field, I can get something similar to yours,

(gdb) p $eflags
$1 = {a = [ SF ], b = [ IF ], c = [ ]}

Probably, it is what you want.  Looks target description is quite 
'friendly' to be extended, but I don't know what to start with or how 
much work is needed.

-- 
Yao (齐尧)


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

end of thread, other threads:[~2013-07-25  2:35 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-08  9:28 [PATCH 1/5] Code for nds32 target Wei-cheng Wang
2013-07-08 23:58 ` Joseph S. Myers
2013-07-09 16:18   ` Wei-cheng Wang
2013-07-09  4:10 ` Yao Qi
2013-07-09 18:23   ` Wei-cheng Wang
2013-07-25  2:35     ` Yao Qi
2013-07-10  5:38 ` Yao Qi
2013-07-11 14:06   ` Wei-cheng Wang
2013-07-11 14:26   ` Wei-cheng Wang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox