public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [RFC] gdb/riscv: Add target description support
@ 2018-11-08 16:08 Andrew Burgess
  2018-11-08 18:33 ` John Baldwin
                   ` (3 more replies)
  0 siblings, 4 replies; 27+ messages in thread
From: Andrew Burgess @ 2018-11-08 16:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: jimw, palmer, jhb, Andrew Burgess

This commit adds target description support for riscv.

I've used the split feature approach for specifying the architectural
features, and the CSR feature is auto-generated from the riscv-opc.h
header file.

If the target doesn't provide a suitable target description then GDB
will build one by looking at the bfd headers.

This commit does not implement target description creation for the
Linux or FreeBSD native targets, both of these will need to add
read_description methods into their respective target classes, which
probe the target features, and then call
riscv_create_target_description to build a suitable target
description.  Until this is done Linux and FreeBSD will get the same
default target description based on the bfd that bare-metal targets
get.

I've only added feature descriptions for 32 and 64 bit registers, 128
bit registers (for RISC-V) are not supported in the reset of GDB yet.

This commit removes the special reading of the MISA register in order
to establish the target features, this was only used for figuring out
the f-register size, and even that wasn't done consistently.  We now
rely on the target to tell us what size of registers it has (or look
in the BFD as a last resort).  The result of this is that we should
now support RV64 targets with 32-bit float, though I have not
extensively tested this combination yet.

gdb/ChangeLog:

	* Makefile.in (ALL_TARGET_OBS): Add arch/riscv.o.
	(HFILES_NO_SRCDIR): Add arch/riscv.h.
	* arch/riscv.c: New file.
	* arch/riscv.h: New file.
	* configure.tgt: Add cpu_obs list of riscv, move riscv-tdep.o into
	this list, and add arch/riscv.o.
	* features/Makefile: Add riscv features.
	* features/riscv/32bit-cpu.c: New file.
	* features/riscv/32bit-cpu.xml: New file.
	* features/riscv/32bit-csr.c: New file.
	* features/riscv/32bit-csr.xml: New file.
	* features/riscv/32bit-fpu.c: New file.
	* features/riscv/32bit-fpu.xml: New file.
	* features/riscv/64bit-cpu.c: New file.
	* features/riscv/64bit-cpu.xml: New file.
	* features/riscv/64bit-csr.c: New file.
	* features/riscv/64bit-csr.xml: New file.
	* features/riscv/64bit-fpu.c: New file.
	* features/riscv/64bit-fpu.xml: New file.
	* features/riscv/rebuild-csr-xml.sh: New file.
	* riscv-tdep.c: Add 'arch/riscv.h' include.
	(riscv_gdb_reg_names): Delete.
	(csr_reggroup): New global.
	(struct riscv_register_alias): Delete.
	(struct riscv_register_feature): New structure.
	(riscv_register_aliases): Delete.
	(riscv_xreg_feature): New global.
	(riscv_freg_feature): New global.
	(riscv_virtual_feature): New global.
	(riscv_csr_feature): New global.
	(riscv_create_csr_aliases): New function.
	(riscv_read_misa_reg): Delete.
	(riscv_has_feature): Delete.
	(riscv_isa_xlen): Simplify, just return cached xlen.
	(riscv_isa_flen): Simplify, just return cached flen.
	(riscv_has_fp_abi): Update for changes in struct gdbarch_tdep.
	(riscv_register_name): Update to make use of tdesc_register_name.
	Look up xreg and freg names in the new globals riscv_xreg_feature
	and riscv_freg_feature.  Don't supply csr aliases here.
	(riscv_register_type): Use riscv_isa_flen to establish the size of
	f-registers.  Restructure to use tdesc_register_type if the type
	is otherwise not found.
	(riscv_print_one_register_info): Handle errors reading registers.
	(riscv_register_reggroup_p): Use tdesc_register_in_reggroup_p for
	registers that are otherwise unknown to GDB.  Also check the
	csr_reggroup.
	(riscv_print_registers_info): Remove assert about upper register
	number, and use gdbarch_register_reggroup_p instead of
	short-cutting.
	(riscv_find_default_target_description): New function.
	(riscv_check_tdesc_feature): New function.
	(riscv_add_reggroups): New function.
	(riscv_setup_register_aliases): New function.
	(riscv_init_reggroups): New function.
	(_initialize_riscv_tdep): Add calls to setup CSR aliases, and
	setup register groups.  Register new riscv debug variable.
	* riscv-tdep.h: Add 'arch/riscv.h' include.
	(struct gdbarch_tdep): Remove abi union, and add
	riscv_gdbarch_features field.  Provide initialisation values for
	floating point types.
	* target-descriptions.c (maint_print_c_tdesc_cmd): Add riscv to
	the list of targets using the feature based target descriptions.
---
 gdb/ChangeLog                         |  65 +++
 gdb/Makefile.in                       |   2 +
 gdb/arch/riscv.c                      |  69 +++
 gdb/arch/riscv.h                      |  64 +++
 gdb/configure.tgt                     |   9 +-
 gdb/features/Makefile                 |  11 +
 gdb/features/riscv/32bit-cpu.c        |  46 ++
 gdb/features/riscv/32bit-cpu.xml      |  43 ++
 gdb/features/riscv/32bit-csr.c        |  13 +
 gdb/features/riscv/32bit-csr.xml      | 250 +++++++++++
 gdb/features/riscv/32bit-fpu.c        |  48 +++
 gdb/features/riscv/32bit-fpu.xml      |  46 ++
 gdb/features/riscv/64bit-cpu.c        |  46 ++
 gdb/features/riscv/64bit-cpu.xml      |  43 ++
 gdb/features/riscv/64bit-csr.c        |  13 +
 gdb/features/riscv/64bit-csr.xml      | 250 +++++++++++
 gdb/features/riscv/64bit-fpu.c        |  48 +++
 gdb/features/riscv/64bit-fpu.xml      |  46 ++
 gdb/features/riscv/rebuild-csr-xml.sh |  29 ++
 gdb/riscv-tdep.c                      | 765 ++++++++++++++++++++++------------
 gdb/riscv-tdep.h                      |  30 +-
 gdb/target-descriptions.c             |   1 +
 22 files changed, 1651 insertions(+), 286 deletions(-)
 create mode 100644 gdb/arch/riscv.c
 create mode 100644 gdb/arch/riscv.h
 create mode 100644 gdb/features/riscv/32bit-cpu.c
 create mode 100644 gdb/features/riscv/32bit-cpu.xml
 create mode 100644 gdb/features/riscv/32bit-csr.c
 create mode 100644 gdb/features/riscv/32bit-csr.xml
 create mode 100644 gdb/features/riscv/32bit-fpu.c
 create mode 100644 gdb/features/riscv/32bit-fpu.xml
 create mode 100644 gdb/features/riscv/64bit-cpu.c
 create mode 100644 gdb/features/riscv/64bit-cpu.xml
 create mode 100644 gdb/features/riscv/64bit-csr.c
 create mode 100644 gdb/features/riscv/64bit-csr.xml
 create mode 100644 gdb/features/riscv/64bit-fpu.c
 create mode 100644 gdb/features/riscv/64bit-fpu.xml
 create mode 100755 gdb/features/riscv/rebuild-csr-xml.sh

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6f74911a775..0b8c13905be 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -666,6 +666,7 @@ ALL_TARGET_OBS = \
 	arch/arm-linux.o \
 	arch/i386.o \
 	arch/ppc-linux-common.o \
+	arch/riscv.o \
 	arm-bsd-tdep.o \
 	arm-fbsd-tdep.o \
 	arm-linux-tdep.o \
@@ -1417,6 +1418,7 @@ HFILES_NO_SRCDIR = \
 	arch/i386.h \
 	arch/ppc-linux-common.h \
 	arch/ppc-linux-tdesc.h \
+	arch/riscv.h \
 	cli/cli-cmds.h \
 	cli/cli-decode.h \
 	cli/cli-script.h \
diff --git a/gdb/arch/riscv.c b/gdb/arch/riscv.c
new file mode 100644
index 00000000000..ca2238d5d70
--- /dev/null
+++ b/gdb/arch/riscv.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+#include "riscv.h"
+#include <stdlib.h>
+
+#include "../features/riscv/32bit-cpu.c"
+#include "../features/riscv/64bit-cpu.c"
+#include "../features/riscv/32bit-fpu.c"
+#include "../features/riscv/64bit-fpu.c"
+
+/* See arch/riscv.h.  */
+
+target_desc *
+riscv_create_target_description (struct riscv_gdbarch_features features)
+{
+  target_desc *tdesc = allocate_target_description ();
+
+#ifndef IN_PROCESS_AGENT
+  std::string arch_name = "riscv";
+
+  if (features.xlen == 4)
+    arch_name.append (":rv32i");
+  else if (features.xlen == 8)
+    arch_name.append (":rv64i");
+  else if (features.xlen == 16)
+    arch_name.append (":rv128i");
+
+  if (features.flen == 4)
+    arch_name.append ("f");
+  else if (features.flen == 8)
+    arch_name.append ("d");
+  else if (features.flen == 16)
+    arch_name.append ("q");
+
+  set_tdesc_architecture (tdesc, arch_name.c_str ());
+#endif
+
+  long regnum = 0;
+
+  /* For now we only support creating 32-bit or 64-bit x-registers.  */
+  if (features.xlen == 4)
+    regnum = create_feature_riscv_32bit_cpu (tdesc, regnum);
+  else if (features.xlen == 8)
+    regnum = create_feature_riscv_64bit_cpu (tdesc, regnum);
+
+  /* For now we only support creating 32-bit or 64-bit f-registers.  */
+  if (features.flen == 4)
+    regnum = create_feature_riscv_32bit_fpu (tdesc, regnum);
+  else if (features.flen == 8)
+    regnum = create_feature_riscv_64bit_fpu (tdesc, regnum);
+
+  return tdesc;
+}
diff --git a/gdb/arch/riscv.h b/gdb/arch/riscv.h
new file mode 100644
index 00000000000..007944019a9
--- /dev/null
+++ b/gdb/arch/riscv.h
@@ -0,0 +1,64 @@
+/* Common target-dependent functionality for RISC-V
+
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef ARCH_RISCV_H
+#define ARCH_RISCV_H
+
+#include "common/tdesc.h"
+
+/* The set of RISC-V architectural features that we track that impact how
+   we configure the actual gdbarch instance.  We hold one of these in the
+   gdbarch_tdep structure, and use it to distinguish between different
+   RISC-V gdbarch instances.
+
+   The information in here ideally comes from the target description,
+   however, if the target doesn't provide a target description then we will
+   create a default target description by first populating one of these
+   based on what we know about the binary being executed, and using that to
+   drive default target description creation.  */
+
+struct riscv_gdbarch_features
+{
+  /* The size of the x-registers in bytes.  This is either 4 (RV32), 8
+     (RV64), or 16 (RV128).  No other value is valid.  Initialise to the
+     invalid 0 value so we can spot if one of these is used
+     uninitialised.  */
+  int xlen = 0;
+
+  /* The size of the f-registers in bytes.  This is either 4 (RV32), 8
+     (RV64), or 16 (RV128).  This can also hold the value 0 to indicate
+     that there are no f-registers.  No other value is valid.  */
+  int flen = 0;
+
+  /* This indicates if hardware floating point abi is in use.  If the FLEN
+     field is 0 then this value _must_ be false.  If the FLEN field is
+     non-zero and this field is false then this indicates the target has
+     floating point registers, but is still using the soft-float abi.  If
+     this field is true then the hardware floating point abi is in use, and
+     values are passed in f-registers matching the size of FLEN.  */
+  bool hw_float_abi = false;
+};
+
+/* Create and return a target description that is compatible with
+   FEATURES.  */
+
+target_desc *riscv_create_target_description
+	(struct riscv_gdbarch_features features);
+
+#endif /* ARCH_RISCV_H */
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index e1f5e31f547..1fa8efef29a 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -81,6 +81,9 @@ ia64*-*-*)
 	cpu_obs="ia64-tdep.o"
 	;;
 
+riscv*-*-*)
+	cpu_obs="riscv-tdep.o arch/riscv.o";;
+
 x86_64-*-*)
 	cpu_obs="${i386_tobjs} ${amd64_tobjs}";;
 
@@ -532,18 +535,18 @@ s390*-*-linux*)
 
 riscv*-*-freebsd*)
 	# Target: FreeBSD/riscv
-	gdb_target_obs="riscv-fbsd-tdep.o riscv-tdep.o"
+	gdb_target_obs="riscv-fbsd-tdep.o"
 	;;
 
 riscv*-*-linux*)
 	# Target: Linux/RISC-V
-	gdb_target_obs="riscv-linux-tdep.o riscv-tdep.o glibc-tdep.o \
+	gdb_target_obs="riscv-linux-tdep.oglibc-tdep.o \
  			linux-tdep.o solib-svr4.o symfile-mem.o linux-record.o"
 	;;
 
 riscv*-*-*)
 	# Target: RISC-V architecture
-	gdb_target_obs="riscv-tdep.o"
+	gdb_target_obs=""
 	;;
 
 rl78-*-elf)
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 150fef23f0b..ff2e57c65fd 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -207,6 +207,7 @@ GDB = false
 #Targets which use feature based target descriptions.
 aarch64-feature = 1
 i386-feature = 1
+riscv-feature = 1
 tic6x-feature = 1
 
 all: $(OUTPUTS)
@@ -242,6 +243,12 @@ FEATURE_XMLFILES = aarch64-core.xml \
 	i386/64bit-pkeys.xml \
 	i386/64bit-sse.xml \
 	i386/x32-core.xml \
+	riscv/32bit-cpu.xml \
+	riscv/32bit-csr.xml \
+	riscv/32bit-fpu.xml \
+	riscv/64bit-cpu.xml \
+	riscv/64bit-csr.xml \
+	riscv/64bit-fpu.xml \
 	tic6x-c6xp.xml \
 	tic6x-core.xml \
 	tic6x-gp.xml
@@ -339,6 +346,10 @@ $(outdir)/i386/x32-avx-avx512-linux.dat: i386/x32-core.xml i386/64bit-avx.xml \
 			       i386/64bit-avx512.xml i386/64bit-linux.xml \
 			       i386/64bit-segments.xml
 
+# Regenerate RISC-V CSR feature lists.
+riscv/32bit-csr.xml riscv/64bit-csr.xml: ../../include/opcode/riscv-opc.h
+	./riscv/rebuild-csr-xml.sh ../../include/opcode/riscv-opc.h ./riscv
+
 # 'all' doesn't build the C files, so don't delete them in 'clean'
 # either.
 clean-cfiles:
diff --git a/gdb/features/riscv/32bit-cpu.c b/gdb/features/riscv/32bit-cpu.c
new file mode 100644
index 00000000000..c8b27a3f01b
--- /dev/null
+++ b/gdb/features/riscv/32bit-cpu.c
@@ -0,0 +1,46 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 32bit-cpu.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_32bit_cpu (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.cpu");
+  tdesc_create_reg (feature, "zero", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "ra", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sp", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "gp", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "tp", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t0", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fp", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a0", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a7", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s7", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s8", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s9", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s10", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s11", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pc", regnum++, 1, NULL, 32, "int");
+  return regnum;
+}
diff --git a/gdb/features/riscv/32bit-cpu.xml b/gdb/features/riscv/32bit-cpu.xml
new file mode 100644
index 00000000000..d81a59db24a
--- /dev/null
+++ b/gdb/features/riscv/32bit-cpu.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.cpu">
+  <reg name="zero" bitsize="32" />
+  <reg name="ra" bitsize="32" />
+  <reg name="sp" bitsize="32" />
+  <reg name="gp" bitsize="32" />
+  <reg name="tp" bitsize="32" />
+  <reg name="t0" bitsize="32" />
+  <reg name="t1" bitsize="32" />
+  <reg name="t2" bitsize="32" />
+  <reg name="fp" bitsize="32" />
+  <reg name="s1" bitsize="32" />
+  <reg name="a0" bitsize="32" />
+  <reg name="a1" bitsize="32" />
+  <reg name="a2" bitsize="32" />
+  <reg name="a3" bitsize="32" />
+  <reg name="a4" bitsize="32" />
+  <reg name="a5" bitsize="32" />
+  <reg name="a6" bitsize="32" />
+  <reg name="a7" bitsize="32" />
+  <reg name="s2" bitsize="32" />
+  <reg name="s3" bitsize="32" />
+  <reg name="s4" bitsize="32" />
+  <reg name="s5" bitsize="32" />
+  <reg name="s6" bitsize="32" />
+  <reg name="s7" bitsize="32" />
+  <reg name="s8" bitsize="32" />
+  <reg name="s9" bitsize="32" />
+  <reg name="s10" bitsize="32" />
+  <reg name="s11" bitsize="32" />
+  <reg name="t3" bitsize="32" />
+  <reg name="t4" bitsize="32" />
+  <reg name="t5" bitsize="32" />
+  <reg name="t6" bitsize="32" />
+  <reg name="pc" bitsize="32" />
+</feature>
diff --git a/gdb/features/riscv/32bit-csr.c b/gdb/features/riscv/32bit-csr.c
new file mode 100644
index 00000000000..b19c4ecf65a
--- /dev/null
+++ b/gdb/features/riscv/32bit-csr.c
@@ -0,0 +1,13 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 32bit-csr.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_32bit_csr (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.csr");
+  return regnum;
+}
diff --git a/gdb/features/riscv/32bit-csr.xml b/gdb/features/riscv/32bit-csr.xml
new file mode 100644
index 00000000000..4aea9e657b9
--- /dev/null
+++ b/gdb/features/riscv/32bit-csr.xml
@@ -0,0 +1,250 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.csr">
+  <reg name="ustatus" bitsize="32"/>
+  <reg name="uie" bitsize="32"/>
+  <reg name="utvec" bitsize="32"/>
+  <reg name="uscratch" bitsize="32"/>
+  <reg name="uepc" bitsize="32"/>
+  <reg name="ucause" bitsize="32"/>
+  <reg name="utval" bitsize="32"/>
+  <reg name="uip" bitsize="32"/>
+  <reg name="fflags" bitsize="32"/>
+  <reg name="frm" bitsize="32"/>
+  <reg name="fcsr" bitsize="32"/>
+  <reg name="cycle" bitsize="32"/>
+  <reg name="time" bitsize="32"/>
+  <reg name="instret" bitsize="32"/>
+  <reg name="hpmcounter3" bitsize="32"/>
+  <reg name="hpmcounter4" bitsize="32"/>
+  <reg name="hpmcounter5" bitsize="32"/>
+  <reg name="hpmcounter6" bitsize="32"/>
+  <reg name="hpmcounter7" bitsize="32"/>
+  <reg name="hpmcounter8" bitsize="32"/>
+  <reg name="hpmcounter9" bitsize="32"/>
+  <reg name="hpmcounter10" bitsize="32"/>
+  <reg name="hpmcounter11" bitsize="32"/>
+  <reg name="hpmcounter12" bitsize="32"/>
+  <reg name="hpmcounter13" bitsize="32"/>
+  <reg name="hpmcounter14" bitsize="32"/>
+  <reg name="hpmcounter15" bitsize="32"/>
+  <reg name="hpmcounter16" bitsize="32"/>
+  <reg name="hpmcounter17" bitsize="32"/>
+  <reg name="hpmcounter18" bitsize="32"/>
+  <reg name="hpmcounter19" bitsize="32"/>
+  <reg name="hpmcounter20" bitsize="32"/>
+  <reg name="hpmcounter21" bitsize="32"/>
+  <reg name="hpmcounter22" bitsize="32"/>
+  <reg name="hpmcounter23" bitsize="32"/>
+  <reg name="hpmcounter24" bitsize="32"/>
+  <reg name="hpmcounter25" bitsize="32"/>
+  <reg name="hpmcounter26" bitsize="32"/>
+  <reg name="hpmcounter27" bitsize="32"/>
+  <reg name="hpmcounter28" bitsize="32"/>
+  <reg name="hpmcounter29" bitsize="32"/>
+  <reg name="hpmcounter30" bitsize="32"/>
+  <reg name="hpmcounter31" bitsize="32"/>
+  <reg name="cycleh" bitsize="32"/>
+  <reg name="timeh" bitsize="32"/>
+  <reg name="instreth" bitsize="32"/>
+  <reg name="hpmcounter3h" bitsize="32"/>
+  <reg name="hpmcounter4h" bitsize="32"/>
+  <reg name="hpmcounter5h" bitsize="32"/>
+  <reg name="hpmcounter6h" bitsize="32"/>
+  <reg name="hpmcounter7h" bitsize="32"/>
+  <reg name="hpmcounter8h" bitsize="32"/>
+  <reg name="hpmcounter9h" bitsize="32"/>
+  <reg name="hpmcounter10h" bitsize="32"/>
+  <reg name="hpmcounter11h" bitsize="32"/>
+  <reg name="hpmcounter12h" bitsize="32"/>
+  <reg name="hpmcounter13h" bitsize="32"/>
+  <reg name="hpmcounter14h" bitsize="32"/>
+  <reg name="hpmcounter15h" bitsize="32"/>
+  <reg name="hpmcounter16h" bitsize="32"/>
+  <reg name="hpmcounter17h" bitsize="32"/>
+  <reg name="hpmcounter18h" bitsize="32"/>
+  <reg name="hpmcounter19h" bitsize="32"/>
+  <reg name="hpmcounter20h" bitsize="32"/>
+  <reg name="hpmcounter21h" bitsize="32"/>
+  <reg name="hpmcounter22h" bitsize="32"/>
+  <reg name="hpmcounter23h" bitsize="32"/>
+  <reg name="hpmcounter24h" bitsize="32"/>
+  <reg name="hpmcounter25h" bitsize="32"/>
+  <reg name="hpmcounter26h" bitsize="32"/>
+  <reg name="hpmcounter27h" bitsize="32"/>
+  <reg name="hpmcounter28h" bitsize="32"/>
+  <reg name="hpmcounter29h" bitsize="32"/>
+  <reg name="hpmcounter30h" bitsize="32"/>
+  <reg name="hpmcounter31h" bitsize="32"/>
+  <reg name="sstatus" bitsize="32"/>
+  <reg name="sedeleg" bitsize="32"/>
+  <reg name="sideleg" bitsize="32"/>
+  <reg name="sie" bitsize="32"/>
+  <reg name="stvec" bitsize="32"/>
+  <reg name="scounteren" bitsize="32"/>
+  <reg name="sscratch" bitsize="32"/>
+  <reg name="sepc" bitsize="32"/>
+  <reg name="scause" bitsize="32"/>
+  <reg name="stval" bitsize="32"/>
+  <reg name="sip" bitsize="32"/>
+  <reg name="satp" bitsize="32"/>
+  <reg name="mvendorid" bitsize="32"/>
+  <reg name="marchid" bitsize="32"/>
+  <reg name="mimpid" bitsize="32"/>
+  <reg name="mhartid" bitsize="32"/>
+  <reg name="mstatus" bitsize="32"/>
+  <reg name="misa" bitsize="32"/>
+  <reg name="medeleg" bitsize="32"/>
+  <reg name="mideleg" bitsize="32"/>
+  <reg name="mie" bitsize="32"/>
+  <reg name="mtvec" bitsize="32"/>
+  <reg name="mcounteren" bitsize="32"/>
+  <reg name="mscratch" bitsize="32"/>
+  <reg name="mepc" bitsize="32"/>
+  <reg name="mcause" bitsize="32"/>
+  <reg name="mtval" bitsize="32"/>
+  <reg name="mip" bitsize="32"/>
+  <reg name="pmpcfg0" bitsize="32"/>
+  <reg name="pmpcfg1" bitsize="32"/>
+  <reg name="pmpcfg2" bitsize="32"/>
+  <reg name="pmpcfg3" bitsize="32"/>
+  <reg name="pmpaddr0" bitsize="32"/>
+  <reg name="pmpaddr1" bitsize="32"/>
+  <reg name="pmpaddr2" bitsize="32"/>
+  <reg name="pmpaddr3" bitsize="32"/>
+  <reg name="pmpaddr4" bitsize="32"/>
+  <reg name="pmpaddr5" bitsize="32"/>
+  <reg name="pmpaddr6" bitsize="32"/>
+  <reg name="pmpaddr7" bitsize="32"/>
+  <reg name="pmpaddr8" bitsize="32"/>
+  <reg name="pmpaddr9" bitsize="32"/>
+  <reg name="pmpaddr10" bitsize="32"/>
+  <reg name="pmpaddr11" bitsize="32"/>
+  <reg name="pmpaddr12" bitsize="32"/>
+  <reg name="pmpaddr13" bitsize="32"/>
+  <reg name="pmpaddr14" bitsize="32"/>
+  <reg name="pmpaddr15" bitsize="32"/>
+  <reg name="mcycle" bitsize="32"/>
+  <reg name="minstret" bitsize="32"/>
+  <reg name="mhpmcounter3" bitsize="32"/>
+  <reg name="mhpmcounter4" bitsize="32"/>
+  <reg name="mhpmcounter5" bitsize="32"/>
+  <reg name="mhpmcounter6" bitsize="32"/>
+  <reg name="mhpmcounter7" bitsize="32"/>
+  <reg name="mhpmcounter8" bitsize="32"/>
+  <reg name="mhpmcounter9" bitsize="32"/>
+  <reg name="mhpmcounter10" bitsize="32"/>
+  <reg name="mhpmcounter11" bitsize="32"/>
+  <reg name="mhpmcounter12" bitsize="32"/>
+  <reg name="mhpmcounter13" bitsize="32"/>
+  <reg name="mhpmcounter14" bitsize="32"/>
+  <reg name="mhpmcounter15" bitsize="32"/>
+  <reg name="mhpmcounter16" bitsize="32"/>
+  <reg name="mhpmcounter17" bitsize="32"/>
+  <reg name="mhpmcounter18" bitsize="32"/>
+  <reg name="mhpmcounter19" bitsize="32"/>
+  <reg name="mhpmcounter20" bitsize="32"/>
+  <reg name="mhpmcounter21" bitsize="32"/>
+  <reg name="mhpmcounter22" bitsize="32"/>
+  <reg name="mhpmcounter23" bitsize="32"/>
+  <reg name="mhpmcounter24" bitsize="32"/>
+  <reg name="mhpmcounter25" bitsize="32"/>
+  <reg name="mhpmcounter26" bitsize="32"/>
+  <reg name="mhpmcounter27" bitsize="32"/>
+  <reg name="mhpmcounter28" bitsize="32"/>
+  <reg name="mhpmcounter29" bitsize="32"/>
+  <reg name="mhpmcounter30" bitsize="32"/>
+  <reg name="mhpmcounter31" bitsize="32"/>
+  <reg name="mcycleh" bitsize="32"/>
+  <reg name="minstreth" bitsize="32"/>
+  <reg name="mhpmcounter3h" bitsize="32"/>
+  <reg name="mhpmcounter4h" bitsize="32"/>
+  <reg name="mhpmcounter5h" bitsize="32"/>
+  <reg name="mhpmcounter6h" bitsize="32"/>
+  <reg name="mhpmcounter7h" bitsize="32"/>
+  <reg name="mhpmcounter8h" bitsize="32"/>
+  <reg name="mhpmcounter9h" bitsize="32"/>
+  <reg name="mhpmcounter10h" bitsize="32"/>
+  <reg name="mhpmcounter11h" bitsize="32"/>
+  <reg name="mhpmcounter12h" bitsize="32"/>
+  <reg name="mhpmcounter13h" bitsize="32"/>
+  <reg name="mhpmcounter14h" bitsize="32"/>
+  <reg name="mhpmcounter15h" bitsize="32"/>
+  <reg name="mhpmcounter16h" bitsize="32"/>
+  <reg name="mhpmcounter17h" bitsize="32"/>
+  <reg name="mhpmcounter18h" bitsize="32"/>
+  <reg name="mhpmcounter19h" bitsize="32"/>
+  <reg name="mhpmcounter20h" bitsize="32"/>
+  <reg name="mhpmcounter21h" bitsize="32"/>
+  <reg name="mhpmcounter22h" bitsize="32"/>
+  <reg name="mhpmcounter23h" bitsize="32"/>
+  <reg name="mhpmcounter24h" bitsize="32"/>
+  <reg name="mhpmcounter25h" bitsize="32"/>
+  <reg name="mhpmcounter26h" bitsize="32"/>
+  <reg name="mhpmcounter27h" bitsize="32"/>
+  <reg name="mhpmcounter28h" bitsize="32"/>
+  <reg name="mhpmcounter29h" bitsize="32"/>
+  <reg name="mhpmcounter30h" bitsize="32"/>
+  <reg name="mhpmcounter31h" bitsize="32"/>
+  <reg name="mhpmevent3" bitsize="32"/>
+  <reg name="mhpmevent4" bitsize="32"/>
+  <reg name="mhpmevent5" bitsize="32"/>
+  <reg name="mhpmevent6" bitsize="32"/>
+  <reg name="mhpmevent7" bitsize="32"/>
+  <reg name="mhpmevent8" bitsize="32"/>
+  <reg name="mhpmevent9" bitsize="32"/>
+  <reg name="mhpmevent10" bitsize="32"/>
+  <reg name="mhpmevent11" bitsize="32"/>
+  <reg name="mhpmevent12" bitsize="32"/>
+  <reg name="mhpmevent13" bitsize="32"/>
+  <reg name="mhpmevent14" bitsize="32"/>
+  <reg name="mhpmevent15" bitsize="32"/>
+  <reg name="mhpmevent16" bitsize="32"/>
+  <reg name="mhpmevent17" bitsize="32"/>
+  <reg name="mhpmevent18" bitsize="32"/>
+  <reg name="mhpmevent19" bitsize="32"/>
+  <reg name="mhpmevent20" bitsize="32"/>
+  <reg name="mhpmevent21" bitsize="32"/>
+  <reg name="mhpmevent22" bitsize="32"/>
+  <reg name="mhpmevent23" bitsize="32"/>
+  <reg name="mhpmevent24" bitsize="32"/>
+  <reg name="mhpmevent25" bitsize="32"/>
+  <reg name="mhpmevent26" bitsize="32"/>
+  <reg name="mhpmevent27" bitsize="32"/>
+  <reg name="mhpmevent28" bitsize="32"/>
+  <reg name="mhpmevent29" bitsize="32"/>
+  <reg name="mhpmevent30" bitsize="32"/>
+  <reg name="mhpmevent31" bitsize="32"/>
+  <reg name="tselect" bitsize="32"/>
+  <reg name="tdata1" bitsize="32"/>
+  <reg name="tdata2" bitsize="32"/>
+  <reg name="tdata3" bitsize="32"/>
+  <reg name="dcsr" bitsize="32"/>
+  <reg name="dpc" bitsize="32"/>
+  <reg name="dscratch" bitsize="32"/>
+  <reg name="hstatus" bitsize="32"/>
+  <reg name="hedeleg" bitsize="32"/>
+  <reg name="hideleg" bitsize="32"/>
+  <reg name="hie" bitsize="32"/>
+  <reg name="htvec" bitsize="32"/>
+  <reg name="hscratch" bitsize="32"/>
+  <reg name="hepc" bitsize="32"/>
+  <reg name="hcause" bitsize="32"/>
+  <reg name="hbadaddr" bitsize="32"/>
+  <reg name="hip" bitsize="32"/>
+  <reg name="mbase" bitsize="32"/>
+  <reg name="mbound" bitsize="32"/>
+  <reg name="mibase" bitsize="32"/>
+  <reg name="mibound" bitsize="32"/>
+  <reg name="mdbase" bitsize="32"/>
+  <reg name="mdbound" bitsize="32"/>
+  <reg name="mucounteren" bitsize="32"/>
+  <reg name="mscounteren" bitsize="32"/>
+  <reg name="mhcounteren" bitsize="32"/>
+</feature>
diff --git a/gdb/features/riscv/32bit-fpu.c b/gdb/features/riscv/32bit-fpu.c
new file mode 100644
index 00000000000..22e80d640e5
--- /dev/null
+++ b/gdb/features/riscv/32bit-fpu.c
@@ -0,0 +1,48 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 32bit-fpu.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_32bit_fpu (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.fpu");
+  tdesc_create_reg (feature, "ft0", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft1", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft2", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft3", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft4", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft5", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft6", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft7", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs0", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs1", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa0", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa1", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa2", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa3", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa4", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa5", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa6", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa7", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs2", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs3", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs4", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs5", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs6", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs7", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs8", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs9", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs10", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs11", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft8", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft9", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft10", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft11", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "frm", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fcsr", regnum++, 1, NULL, 32, "int");
+  return regnum;
+}
diff --git a/gdb/features/riscv/32bit-fpu.xml b/gdb/features/riscv/32bit-fpu.xml
new file mode 100644
index 00000000000..783287d9362
--- /dev/null
+++ b/gdb/features/riscv/32bit-fpu.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.fpu">
+  <reg name="ft0" bitsize="32" type="ieee_single"/>
+  <reg name="ft1" bitsize="32" type="ieee_single"/>
+  <reg name="ft2" bitsize="32" type="ieee_single"/>
+  <reg name="ft3" bitsize="32" type="ieee_single"/>
+  <reg name="ft4" bitsize="32" type="ieee_single"/>
+  <reg name="ft5" bitsize="32" type="ieee_single"/>
+  <reg name="ft6" bitsize="32" type="ieee_single"/>
+  <reg name="ft7" bitsize="32" type="ieee_single"/>
+  <reg name="fs0" bitsize="32" type="ieee_single"/>
+  <reg name="fs1" bitsize="32" type="ieee_single"/>
+  <reg name="fa0" bitsize="32" type="ieee_single"/>
+  <reg name="fa1" bitsize="32" type="ieee_single"/>
+  <reg name="fa2" bitsize="32" type="ieee_single"/>
+  <reg name="fa3" bitsize="32" type="ieee_single"/>
+  <reg name="fa4" bitsize="32" type="ieee_single"/>
+  <reg name="fa5" bitsize="32" type="ieee_single"/>
+  <reg name="fa6" bitsize="32" type="ieee_single"/>
+  <reg name="fa7" bitsize="32" type="ieee_single"/>
+  <reg name="fs2" bitsize="32" type="ieee_single"/>
+  <reg name="fs3" bitsize="32" type="ieee_single"/>
+  <reg name="fs4" bitsize="32" type="ieee_single"/>
+  <reg name="fs5" bitsize="32" type="ieee_single"/>
+  <reg name="fs6" bitsize="32" type="ieee_single"/>
+  <reg name="fs7" bitsize="32" type="ieee_single"/>
+  <reg name="fs8" bitsize="32" type="ieee_single"/>
+  <reg name="fs9" bitsize="32" type="ieee_single"/>
+  <reg name="fs10" bitsize="32" type="ieee_single"/>
+  <reg name="fs11" bitsize="32" type="ieee_single"/>
+  <reg name="ft8" bitsize="32" type="ieee_single"/>
+  <reg name="ft9" bitsize="32" type="ieee_single"/>
+  <reg name="ft10" bitsize="32" type="ieee_single"/>
+  <reg name="ft11" bitsize="32" type="ieee_single"/>
+
+  <reg name="fflags" bitsize="32" type="int"/>
+  <reg name="frm" bitsize="32" type="int"/>
+  <reg name="fcsr" bitsize="32" type="int"/>
+</feature>
diff --git a/gdb/features/riscv/64bit-cpu.c b/gdb/features/riscv/64bit-cpu.c
new file mode 100644
index 00000000000..4efdc7392a8
--- /dev/null
+++ b/gdb/features/riscv/64bit-cpu.c
@@ -0,0 +1,46 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 64bit-cpu.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_64bit_cpu (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.cpu");
+  tdesc_create_reg (feature, "zero", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "ra", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sp", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "gp", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "tp", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t0", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "fp", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a0", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a7", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s7", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s8", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s9", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s10", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s11", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pc", regnum++, 1, NULL, 64, "int");
+  return regnum;
+}
diff --git a/gdb/features/riscv/64bit-cpu.xml b/gdb/features/riscv/64bit-cpu.xml
new file mode 100644
index 00000000000..7247b99143a
--- /dev/null
+++ b/gdb/features/riscv/64bit-cpu.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.cpu">
+  <reg name="zero" bitsize="64" />
+  <reg name="ra" bitsize="64" />
+  <reg name="sp" bitsize="64" />
+  <reg name="gp" bitsize="64" />
+  <reg name="tp" bitsize="64" />
+  <reg name="t0" bitsize="64" />
+  <reg name="t1" bitsize="64" />
+  <reg name="t2" bitsize="64" />
+  <reg name="fp" bitsize="64" />
+  <reg name="s1" bitsize="64" />
+  <reg name="a0" bitsize="64" />
+  <reg name="a1" bitsize="64" />
+  <reg name="a2" bitsize="64" />
+  <reg name="a3" bitsize="64" />
+  <reg name="a4" bitsize="64" />
+  <reg name="a5" bitsize="64" />
+  <reg name="a6" bitsize="64" />
+  <reg name="a7" bitsize="64" />
+  <reg name="s2" bitsize="64" />
+  <reg name="s3" bitsize="64" />
+  <reg name="s4" bitsize="64" />
+  <reg name="s5" bitsize="64" />
+  <reg name="s6" bitsize="64" />
+  <reg name="s7" bitsize="64" />
+  <reg name="s8" bitsize="64" />
+  <reg name="s9" bitsize="64" />
+  <reg name="s10" bitsize="64" />
+  <reg name="s11" bitsize="64" />
+  <reg name="t3" bitsize="64" />
+  <reg name="t4" bitsize="64" />
+  <reg name="t5" bitsize="64" />
+  <reg name="t6" bitsize="64" />
+  <reg name="pc" bitsize="64" />
+</feature>
diff --git a/gdb/features/riscv/64bit-csr.c b/gdb/features/riscv/64bit-csr.c
new file mode 100644
index 00000000000..2de1327efbe
--- /dev/null
+++ b/gdb/features/riscv/64bit-csr.c
@@ -0,0 +1,13 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 64bit-csr.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_64bit_csr (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.csr");
+  return regnum;
+}
diff --git a/gdb/features/riscv/64bit-csr.xml b/gdb/features/riscv/64bit-csr.xml
new file mode 100644
index 00000000000..a3de83443a5
--- /dev/null
+++ b/gdb/features/riscv/64bit-csr.xml
@@ -0,0 +1,250 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.csr">
+  <reg name="ustatus" bitsize="64"/>
+  <reg name="uie" bitsize="64"/>
+  <reg name="utvec" bitsize="64"/>
+  <reg name="uscratch" bitsize="64"/>
+  <reg name="uepc" bitsize="64"/>
+  <reg name="ucause" bitsize="64"/>
+  <reg name="utval" bitsize="64"/>
+  <reg name="uip" bitsize="64"/>
+  <reg name="fflags" bitsize="64"/>
+  <reg name="frm" bitsize="64"/>
+  <reg name="fcsr" bitsize="64"/>
+  <reg name="cycle" bitsize="64"/>
+  <reg name="time" bitsize="64"/>
+  <reg name="instret" bitsize="64"/>
+  <reg name="hpmcounter3" bitsize="64"/>
+  <reg name="hpmcounter4" bitsize="64"/>
+  <reg name="hpmcounter5" bitsize="64"/>
+  <reg name="hpmcounter6" bitsize="64"/>
+  <reg name="hpmcounter7" bitsize="64"/>
+  <reg name="hpmcounter8" bitsize="64"/>
+  <reg name="hpmcounter9" bitsize="64"/>
+  <reg name="hpmcounter10" bitsize="64"/>
+  <reg name="hpmcounter11" bitsize="64"/>
+  <reg name="hpmcounter12" bitsize="64"/>
+  <reg name="hpmcounter13" bitsize="64"/>
+  <reg name="hpmcounter14" bitsize="64"/>
+  <reg name="hpmcounter15" bitsize="64"/>
+  <reg name="hpmcounter16" bitsize="64"/>
+  <reg name="hpmcounter17" bitsize="64"/>
+  <reg name="hpmcounter18" bitsize="64"/>
+  <reg name="hpmcounter19" bitsize="64"/>
+  <reg name="hpmcounter20" bitsize="64"/>
+  <reg name="hpmcounter21" bitsize="64"/>
+  <reg name="hpmcounter22" bitsize="64"/>
+  <reg name="hpmcounter23" bitsize="64"/>
+  <reg name="hpmcounter24" bitsize="64"/>
+  <reg name="hpmcounter25" bitsize="64"/>
+  <reg name="hpmcounter26" bitsize="64"/>
+  <reg name="hpmcounter27" bitsize="64"/>
+  <reg name="hpmcounter28" bitsize="64"/>
+  <reg name="hpmcounter29" bitsize="64"/>
+  <reg name="hpmcounter30" bitsize="64"/>
+  <reg name="hpmcounter31" bitsize="64"/>
+  <reg name="cycleh" bitsize="64"/>
+  <reg name="timeh" bitsize="64"/>
+  <reg name="instreth" bitsize="64"/>
+  <reg name="hpmcounter3h" bitsize="64"/>
+  <reg name="hpmcounter4h" bitsize="64"/>
+  <reg name="hpmcounter5h" bitsize="64"/>
+  <reg name="hpmcounter6h" bitsize="64"/>
+  <reg name="hpmcounter7h" bitsize="64"/>
+  <reg name="hpmcounter8h" bitsize="64"/>
+  <reg name="hpmcounter9h" bitsize="64"/>
+  <reg name="hpmcounter10h" bitsize="64"/>
+  <reg name="hpmcounter11h" bitsize="64"/>
+  <reg name="hpmcounter12h" bitsize="64"/>
+  <reg name="hpmcounter13h" bitsize="64"/>
+  <reg name="hpmcounter14h" bitsize="64"/>
+  <reg name="hpmcounter15h" bitsize="64"/>
+  <reg name="hpmcounter16h" bitsize="64"/>
+  <reg name="hpmcounter17h" bitsize="64"/>
+  <reg name="hpmcounter18h" bitsize="64"/>
+  <reg name="hpmcounter19h" bitsize="64"/>
+  <reg name="hpmcounter20h" bitsize="64"/>
+  <reg name="hpmcounter21h" bitsize="64"/>
+  <reg name="hpmcounter22h" bitsize="64"/>
+  <reg name="hpmcounter23h" bitsize="64"/>
+  <reg name="hpmcounter24h" bitsize="64"/>
+  <reg name="hpmcounter25h" bitsize="64"/>
+  <reg name="hpmcounter26h" bitsize="64"/>
+  <reg name="hpmcounter27h" bitsize="64"/>
+  <reg name="hpmcounter28h" bitsize="64"/>
+  <reg name="hpmcounter29h" bitsize="64"/>
+  <reg name="hpmcounter30h" bitsize="64"/>
+  <reg name="hpmcounter31h" bitsize="64"/>
+  <reg name="sstatus" bitsize="64"/>
+  <reg name="sedeleg" bitsize="64"/>
+  <reg name="sideleg" bitsize="64"/>
+  <reg name="sie" bitsize="64"/>
+  <reg name="stvec" bitsize="64"/>
+  <reg name="scounteren" bitsize="64"/>
+  <reg name="sscratch" bitsize="64"/>
+  <reg name="sepc" bitsize="64"/>
+  <reg name="scause" bitsize="64"/>
+  <reg name="stval" bitsize="64"/>
+  <reg name="sip" bitsize="64"/>
+  <reg name="satp" bitsize="64"/>
+  <reg name="mvendorid" bitsize="64"/>
+  <reg name="marchid" bitsize="64"/>
+  <reg name="mimpid" bitsize="64"/>
+  <reg name="mhartid" bitsize="64"/>
+  <reg name="mstatus" bitsize="64"/>
+  <reg name="misa" bitsize="64"/>
+  <reg name="medeleg" bitsize="64"/>
+  <reg name="mideleg" bitsize="64"/>
+  <reg name="mie" bitsize="64"/>
+  <reg name="mtvec" bitsize="64"/>
+  <reg name="mcounteren" bitsize="64"/>
+  <reg name="mscratch" bitsize="64"/>
+  <reg name="mepc" bitsize="64"/>
+  <reg name="mcause" bitsize="64"/>
+  <reg name="mtval" bitsize="64"/>
+  <reg name="mip" bitsize="64"/>
+  <reg name="pmpcfg0" bitsize="64"/>
+  <reg name="pmpcfg1" bitsize="64"/>
+  <reg name="pmpcfg2" bitsize="64"/>
+  <reg name="pmpcfg3" bitsize="64"/>
+  <reg name="pmpaddr0" bitsize="64"/>
+  <reg name="pmpaddr1" bitsize="64"/>
+  <reg name="pmpaddr2" bitsize="64"/>
+  <reg name="pmpaddr3" bitsize="64"/>
+  <reg name="pmpaddr4" bitsize="64"/>
+  <reg name="pmpaddr5" bitsize="64"/>
+  <reg name="pmpaddr6" bitsize="64"/>
+  <reg name="pmpaddr7" bitsize="64"/>
+  <reg name="pmpaddr8" bitsize="64"/>
+  <reg name="pmpaddr9" bitsize="64"/>
+  <reg name="pmpaddr10" bitsize="64"/>
+  <reg name="pmpaddr11" bitsize="64"/>
+  <reg name="pmpaddr12" bitsize="64"/>
+  <reg name="pmpaddr13" bitsize="64"/>
+  <reg name="pmpaddr14" bitsize="64"/>
+  <reg name="pmpaddr15" bitsize="64"/>
+  <reg name="mcycle" bitsize="64"/>
+  <reg name="minstret" bitsize="64"/>
+  <reg name="mhpmcounter3" bitsize="64"/>
+  <reg name="mhpmcounter4" bitsize="64"/>
+  <reg name="mhpmcounter5" bitsize="64"/>
+  <reg name="mhpmcounter6" bitsize="64"/>
+  <reg name="mhpmcounter7" bitsize="64"/>
+  <reg name="mhpmcounter8" bitsize="64"/>
+  <reg name="mhpmcounter9" bitsize="64"/>
+  <reg name="mhpmcounter10" bitsize="64"/>
+  <reg name="mhpmcounter11" bitsize="64"/>
+  <reg name="mhpmcounter12" bitsize="64"/>
+  <reg name="mhpmcounter13" bitsize="64"/>
+  <reg name="mhpmcounter14" bitsize="64"/>
+  <reg name="mhpmcounter15" bitsize="64"/>
+  <reg name="mhpmcounter16" bitsize="64"/>
+  <reg name="mhpmcounter17" bitsize="64"/>
+  <reg name="mhpmcounter18" bitsize="64"/>
+  <reg name="mhpmcounter19" bitsize="64"/>
+  <reg name="mhpmcounter20" bitsize="64"/>
+  <reg name="mhpmcounter21" bitsize="64"/>
+  <reg name="mhpmcounter22" bitsize="64"/>
+  <reg name="mhpmcounter23" bitsize="64"/>
+  <reg name="mhpmcounter24" bitsize="64"/>
+  <reg name="mhpmcounter25" bitsize="64"/>
+  <reg name="mhpmcounter26" bitsize="64"/>
+  <reg name="mhpmcounter27" bitsize="64"/>
+  <reg name="mhpmcounter28" bitsize="64"/>
+  <reg name="mhpmcounter29" bitsize="64"/>
+  <reg name="mhpmcounter30" bitsize="64"/>
+  <reg name="mhpmcounter31" bitsize="64"/>
+  <reg name="mcycleh" bitsize="64"/>
+  <reg name="minstreth" bitsize="64"/>
+  <reg name="mhpmcounter3h" bitsize="64"/>
+  <reg name="mhpmcounter4h" bitsize="64"/>
+  <reg name="mhpmcounter5h" bitsize="64"/>
+  <reg name="mhpmcounter6h" bitsize="64"/>
+  <reg name="mhpmcounter7h" bitsize="64"/>
+  <reg name="mhpmcounter8h" bitsize="64"/>
+  <reg name="mhpmcounter9h" bitsize="64"/>
+  <reg name="mhpmcounter10h" bitsize="64"/>
+  <reg name="mhpmcounter11h" bitsize="64"/>
+  <reg name="mhpmcounter12h" bitsize="64"/>
+  <reg name="mhpmcounter13h" bitsize="64"/>
+  <reg name="mhpmcounter14h" bitsize="64"/>
+  <reg name="mhpmcounter15h" bitsize="64"/>
+  <reg name="mhpmcounter16h" bitsize="64"/>
+  <reg name="mhpmcounter17h" bitsize="64"/>
+  <reg name="mhpmcounter18h" bitsize="64"/>
+  <reg name="mhpmcounter19h" bitsize="64"/>
+  <reg name="mhpmcounter20h" bitsize="64"/>
+  <reg name="mhpmcounter21h" bitsize="64"/>
+  <reg name="mhpmcounter22h" bitsize="64"/>
+  <reg name="mhpmcounter23h" bitsize="64"/>
+  <reg name="mhpmcounter24h" bitsize="64"/>
+  <reg name="mhpmcounter25h" bitsize="64"/>
+  <reg name="mhpmcounter26h" bitsize="64"/>
+  <reg name="mhpmcounter27h" bitsize="64"/>
+  <reg name="mhpmcounter28h" bitsize="64"/>
+  <reg name="mhpmcounter29h" bitsize="64"/>
+  <reg name="mhpmcounter30h" bitsize="64"/>
+  <reg name="mhpmcounter31h" bitsize="64"/>
+  <reg name="mhpmevent3" bitsize="64"/>
+  <reg name="mhpmevent4" bitsize="64"/>
+  <reg name="mhpmevent5" bitsize="64"/>
+  <reg name="mhpmevent6" bitsize="64"/>
+  <reg name="mhpmevent7" bitsize="64"/>
+  <reg name="mhpmevent8" bitsize="64"/>
+  <reg name="mhpmevent9" bitsize="64"/>
+  <reg name="mhpmevent10" bitsize="64"/>
+  <reg name="mhpmevent11" bitsize="64"/>
+  <reg name="mhpmevent12" bitsize="64"/>
+  <reg name="mhpmevent13" bitsize="64"/>
+  <reg name="mhpmevent14" bitsize="64"/>
+  <reg name="mhpmevent15" bitsize="64"/>
+  <reg name="mhpmevent16" bitsize="64"/>
+  <reg name="mhpmevent17" bitsize="64"/>
+  <reg name="mhpmevent18" bitsize="64"/>
+  <reg name="mhpmevent19" bitsize="64"/>
+  <reg name="mhpmevent20" bitsize="64"/>
+  <reg name="mhpmevent21" bitsize="64"/>
+  <reg name="mhpmevent22" bitsize="64"/>
+  <reg name="mhpmevent23" bitsize="64"/>
+  <reg name="mhpmevent24" bitsize="64"/>
+  <reg name="mhpmevent25" bitsize="64"/>
+  <reg name="mhpmevent26" bitsize="64"/>
+  <reg name="mhpmevent27" bitsize="64"/>
+  <reg name="mhpmevent28" bitsize="64"/>
+  <reg name="mhpmevent29" bitsize="64"/>
+  <reg name="mhpmevent30" bitsize="64"/>
+  <reg name="mhpmevent31" bitsize="64"/>
+  <reg name="tselect" bitsize="64"/>
+  <reg name="tdata1" bitsize="64"/>
+  <reg name="tdata2" bitsize="64"/>
+  <reg name="tdata3" bitsize="64"/>
+  <reg name="dcsr" bitsize="64"/>
+  <reg name="dpc" bitsize="64"/>
+  <reg name="dscratch" bitsize="64"/>
+  <reg name="hstatus" bitsize="64"/>
+  <reg name="hedeleg" bitsize="64"/>
+  <reg name="hideleg" bitsize="64"/>
+  <reg name="hie" bitsize="64"/>
+  <reg name="htvec" bitsize="64"/>
+  <reg name="hscratch" bitsize="64"/>
+  <reg name="hepc" bitsize="64"/>
+  <reg name="hcause" bitsize="64"/>
+  <reg name="hbadaddr" bitsize="64"/>
+  <reg name="hip" bitsize="64"/>
+  <reg name="mbase" bitsize="64"/>
+  <reg name="mbound" bitsize="64"/>
+  <reg name="mibase" bitsize="64"/>
+  <reg name="mibound" bitsize="64"/>
+  <reg name="mdbase" bitsize="64"/>
+  <reg name="mdbound" bitsize="64"/>
+  <reg name="mucounteren" bitsize="64"/>
+  <reg name="mscounteren" bitsize="64"/>
+  <reg name="mhcounteren" bitsize="64"/>
+</feature>
diff --git a/gdb/features/riscv/64bit-fpu.c b/gdb/features/riscv/64bit-fpu.c
new file mode 100644
index 00000000000..f1bfde124ee
--- /dev/null
+++ b/gdb/features/riscv/64bit-fpu.c
@@ -0,0 +1,48 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 64bit-fpu.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_64bit_fpu (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.fpu");
+  tdesc_create_reg (feature, "ft0", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "ft1", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "ft2", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "ft3", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "ft4", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "ft5", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "ft6", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "ft7", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fs0", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fs1", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fa0", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fa1", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fa2", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fa3", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fa4", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fa5", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fa6", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fa7", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fs2", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fs3", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fs4", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fs5", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fs6", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fs7", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fs8", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fs9", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fs10", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fs11", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "ft8", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "ft9", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "ft10", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "ft11", regnum++, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "frm", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fcsr", regnum++, 1, NULL, 32, "int");
+  return regnum;
+}
diff --git a/gdb/features/riscv/64bit-fpu.xml b/gdb/features/riscv/64bit-fpu.xml
new file mode 100644
index 00000000000..e7c2ba34485
--- /dev/null
+++ b/gdb/features/riscv/64bit-fpu.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.fpu">
+  <reg name="ft0" bitsize="64" type="ieee_double"/>
+  <reg name="ft1" bitsize="64" type="ieee_double"/>
+  <reg name="ft2" bitsize="64" type="ieee_double"/>
+  <reg name="ft3" bitsize="64" type="ieee_double"/>
+  <reg name="ft4" bitsize="64" type="ieee_double"/>
+  <reg name="ft5" bitsize="64" type="ieee_double"/>
+  <reg name="ft6" bitsize="64" type="ieee_double"/>
+  <reg name="ft7" bitsize="64" type="ieee_double"/>
+  <reg name="fs0" bitsize="64" type="ieee_double"/>
+  <reg name="fs1" bitsize="64" type="ieee_double"/>
+  <reg name="fa0" bitsize="64" type="ieee_double"/>
+  <reg name="fa1" bitsize="64" type="ieee_double"/>
+  <reg name="fa2" bitsize="64" type="ieee_double"/>
+  <reg name="fa3" bitsize="64" type="ieee_double"/>
+  <reg name="fa4" bitsize="64" type="ieee_double"/>
+  <reg name="fa5" bitsize="64" type="ieee_double"/>
+  <reg name="fa6" bitsize="64" type="ieee_double"/>
+  <reg name="fa7" bitsize="64" type="ieee_double"/>
+  <reg name="fs2" bitsize="64" type="ieee_double"/>
+  <reg name="fs3" bitsize="64" type="ieee_double"/>
+  <reg name="fs4" bitsize="64" type="ieee_double"/>
+  <reg name="fs5" bitsize="64" type="ieee_double"/>
+  <reg name="fs6" bitsize="64" type="ieee_double"/>
+  <reg name="fs7" bitsize="64" type="ieee_double"/>
+  <reg name="fs8" bitsize="64" type="ieee_double"/>
+  <reg name="fs9" bitsize="64" type="ieee_double"/>
+  <reg name="fs10" bitsize="64" type="ieee_double"/>
+  <reg name="fs11" bitsize="64" type="ieee_double"/>
+  <reg name="ft8" bitsize="64" type="ieee_double"/>
+  <reg name="ft9" bitsize="64" type="ieee_double"/>
+  <reg name="ft10" bitsize="64" type="ieee_double"/>
+  <reg name="ft11" bitsize="64" type="ieee_double"/>
+
+  <reg name="fflags" bitsize="32" type="int"/>
+  <reg name="frm" bitsize="32" type="int"/>
+  <reg name="fcsr" bitsize="32" type="int"/>
+</feature>
diff --git a/gdb/features/riscv/rebuild-csr-xml.sh b/gdb/features/riscv/rebuild-csr-xml.sh
new file mode 100755
index 00000000000..6971b8dbb2a
--- /dev/null
+++ b/gdb/features/riscv/rebuild-csr-xml.sh
@@ -0,0 +1,29 @@
+#! /bin/bash
+
+RISCV_OPC_FILE=$1
+RISCV_FEATURE_DIR=$2
+
+function gen_csr_xml ()
+{
+    bitsize=$1
+
+    cat <<EOF
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.csr">
+EOF
+
+    grep "^DECLARE_CSR(" ${RISCV_OPC_FILE} \
+        | sed -e "s!DECLARE_CSR(\(.*\), .*!  <reg name=\"\1\" bitsize=\"$bitsize\"/>!"
+
+    echo "</feature>"
+}
+
+gen_csr_xml 32 > ${RISCV_FEATURE_DIR}/32bit-csr.xml
+gen_csr_xml 64 > ${RISCV_FEATURE_DIR}/64bit-csr.xml
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index 7a92fc7fae5..a0b2d1f5d76 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -55,13 +55,11 @@
 #include "cli/cli-decode.h"
 #include "observable.h"
 #include "prologue-value.h"
+#include "arch/riscv.h"
 
 /* The stack must be 16-byte aligned.  */
 #define SP_ALIGNMENT 16
 
-/* Forward declarations.  */
-static bool riscv_has_feature (struct gdbarch *gdbarch, char feature);
-
 /* Define a series of is_XXX_insn functions to check if the value INSN
    is an instance of instruction XXX.  */
 #define DECLARE_INSN(INSN_NAME, INSN_MATCH, INSN_MASK) \
@@ -95,110 +93,170 @@ struct riscv_unwind_cache
   CORE_ADDR frame_base;
 };
 
-/* The preferred register names for all the general purpose and floating
-   point registers.  These are what GDB will use when referencing a
-   register.  */
+/* RISC-V specific register group for CSRs.  */
 
-static const char * const riscv_gdb_reg_names[RISCV_LAST_FP_REGNUM + 1] =
-{
- "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1",
- "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4",
- "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6",
- "pc",
- "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", "fs0", "fs1",
- "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa7", "fs2", "fs3",
- "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", "fs10", "fs11", "ft8", "ft9",
- "ft10", "ft11",
-};
+static reggroup *csr_reggroup = NULL;
 
-/* Map alternative register names onto their GDB register number.  */
+/* A set of registers that we expect to find in a tdesc_feature.  These
+   are use in RISCV_GDBARCH_INIT when processing the target description.  */
 
-struct riscv_register_alias
+struct riscv_register_feature
 {
-  /* The register alias.  Usually more descriptive than the
-     architectural name of the register.  */
+  /* Information for a single register.  */
+  struct register_info
+  {
+    /* The GDB register number for this register.  */
+    int regnum;
+
+    /* List of names for this register.  The first name in this list is the
+       preferred name, the name GDB should use when describing this
+       register.  */
+    std::vector <const char *> names;
+
+    /* When true this register is required in this feature set.  */
+    bool required_p;
+  };
+
+  /* The name for this feature.  This is the name used to find this feature
+     within the target description.  */
   const char *name;
 
-  /* The GDB register number.  */
-  int regnum;
+  /* List of all the registers that we expect that we might find in this
+     register set.  */
+  std::vector <struct register_info> registers;
+};
+
+/* The general x-registers feature set.  */
+
+static const struct riscv_register_feature riscv_xreg_feature =
+{
+ "org.gnu.gdb.riscv.cpu",
+ {
+   { RISCV_ZERO_REGNUM + 0, { "zero", "x0" }, true },
+   { RISCV_ZERO_REGNUM + 1, { "ra", "x1" }, true },
+   { RISCV_ZERO_REGNUM + 2, { "sp", "x2" }, true },
+   { RISCV_ZERO_REGNUM + 3, { "gp", "x3" }, true },
+   { RISCV_ZERO_REGNUM + 4, { "tp", "x4" }, true },
+   { RISCV_ZERO_REGNUM + 5, { "t0", "x5" }, true },
+   { RISCV_ZERO_REGNUM + 6, { "t1", "x6" }, true },
+   { RISCV_ZERO_REGNUM + 7, { "t2", "x7" }, true },
+   { RISCV_ZERO_REGNUM + 8, { "fp", "x8", "s0" }, true },
+   { RISCV_ZERO_REGNUM + 9, { "s1", "x9" }, true },
+   { RISCV_ZERO_REGNUM + 10, { "a0", "x10" }, true },
+   { RISCV_ZERO_REGNUM + 11, { "a1", "x11" }, true },
+   { RISCV_ZERO_REGNUM + 12, { "a2", "x12" }, true },
+   { RISCV_ZERO_REGNUM + 13, { "a3", "x13" }, true },
+   { RISCV_ZERO_REGNUM + 14, { "a4", "x14" }, true },
+   { RISCV_ZERO_REGNUM + 15, { "a5", "x15" }, true },
+   { RISCV_ZERO_REGNUM + 16, { "a6", "x16" }, true },
+   { RISCV_ZERO_REGNUM + 17, { "a7", "x17" }, true },
+   { RISCV_ZERO_REGNUM + 18, { "s2", "x18" }, true },
+   { RISCV_ZERO_REGNUM + 19, { "s3", "x19" }, true },
+   { RISCV_ZERO_REGNUM + 20, { "s4", "x20" }, true },
+   { RISCV_ZERO_REGNUM + 21, { "s5", "x21" }, true },
+   { RISCV_ZERO_REGNUM + 22, { "s6", "x22" }, true },
+   { RISCV_ZERO_REGNUM + 23, { "s7", "x23" }, true },
+   { RISCV_ZERO_REGNUM + 24, { "s8", "x24" }, true },
+   { RISCV_ZERO_REGNUM + 25, { "s9", "x25" }, true },
+   { RISCV_ZERO_REGNUM + 26, { "s10", "x26" }, true },
+   { RISCV_ZERO_REGNUM + 27, { "s11", "x27" }, true },
+   { RISCV_ZERO_REGNUM + 28, { "t3", "x28" }, true },
+   { RISCV_ZERO_REGNUM + 29, { "t4", "x29" }, true },
+   { RISCV_ZERO_REGNUM + 30, { "t5", "x30" }, true },
+   { RISCV_ZERO_REGNUM + 31, { "t6", "x31" }, true },
+   { RISCV_ZERO_REGNUM + 32, { "pc" }, true }
+ }
+};
+
+/* The f-registers feature set.  */
+
+static const struct riscv_register_feature riscv_freg_feature =
+{
+ "org.gnu.gdb.riscv.fpu",
+ {
+   { RISCV_FIRST_FP_REGNUM + 0, { "ft0", "f0" }, true },
+   { RISCV_FIRST_FP_REGNUM + 1, { "ft1", "f1" }, true },
+   { RISCV_FIRST_FP_REGNUM + 2, { "ft2", "f2" }, true },
+   { RISCV_FIRST_FP_REGNUM + 3, { "ft3", "f3" }, true },
+   { RISCV_FIRST_FP_REGNUM + 4, { "ft4", "f4" }, true },
+   { RISCV_FIRST_FP_REGNUM + 5, { "ft5", "f5" }, true },
+   { RISCV_FIRST_FP_REGNUM + 6, { "ft6", "f6" }, true },
+   { RISCV_FIRST_FP_REGNUM + 7, { "ft7", "f7" }, true },
+   { RISCV_FIRST_FP_REGNUM + 8, { "fs0", "f8", "s0" }, true },
+   { RISCV_FIRST_FP_REGNUM + 9, { "fs1", "f9" }, true },
+   { RISCV_FIRST_FP_REGNUM + 10, { "fa0", "f10" }, true },
+   { RISCV_FIRST_FP_REGNUM + 11, { "fa1", "f11" }, true },
+   { RISCV_FIRST_FP_REGNUM + 12, { "fa2", "f12" }, true },
+   { RISCV_FIRST_FP_REGNUM + 13, { "fa3", "f13" }, true },
+   { RISCV_FIRST_FP_REGNUM + 14, { "fa4", "f14" }, true },
+   { RISCV_FIRST_FP_REGNUM + 15, { "fa5", "f15" }, true },
+   { RISCV_FIRST_FP_REGNUM + 16, { "fa6", "f16" }, true },
+   { RISCV_FIRST_FP_REGNUM + 17, { "fa7", "f17" }, true },
+   { RISCV_FIRST_FP_REGNUM + 18, { "fs2", "f18" }, true },
+   { RISCV_FIRST_FP_REGNUM + 19, { "fs3", "f19" }, true },
+   { RISCV_FIRST_FP_REGNUM + 20, { "fs4", "f20" }, true },
+   { RISCV_FIRST_FP_REGNUM + 21, { "fs5", "f21" }, true },
+   { RISCV_FIRST_FP_REGNUM + 22, { "fs6", "f22" }, true },
+   { RISCV_FIRST_FP_REGNUM + 23, { "fs7", "f23" }, true },
+   { RISCV_FIRST_FP_REGNUM + 24, { "fs8", "f24" }, true },
+   { RISCV_FIRST_FP_REGNUM + 25, { "fs9", "f25" }, true },
+   { RISCV_FIRST_FP_REGNUM + 26, { "fs10", "f26" }, true },
+   { RISCV_FIRST_FP_REGNUM + 27, { "fs11", "f27" }, true },
+   { RISCV_FIRST_FP_REGNUM + 28, { "ft8", "f28" }, true },
+   { RISCV_FIRST_FP_REGNUM + 29, { "ft9", "f29" }, true },
+   { RISCV_FIRST_FP_REGNUM + 30, { "ft10", "f30" }, true },
+   { RISCV_FIRST_FP_REGNUM + 31, { "ft11", "f31" }, true },
+
+   { RISCV_CSR_FFLAGS_REGNUM, { "fflags" }, true },
+   { RISCV_CSR_FRM_REGNUM, { "frm" }, true },
+   { RISCV_CSR_FCSR_REGNUM, { "fcsr" }, true },
+
+ }
+};
+
+/* Set of virtual registers.  These are not physical registers on the
+   hardware, but might be available from the target.  These are not pseudo
+   registers, reading these really does result in a register read from the
+   target, it is just that there might not be a physical register backing
+   the result.  */
+
+static const struct riscv_register_feature riscv_virtual_feature =
+{
+ "org.gnu.gdb.riscv.virtual",
+ {
+   { RISCV_PRIV_REGNUM, { "priv" }, false }
+ }
 };
 
-/* Table of register aliases.  */
-
-static const struct riscv_register_alias riscv_register_aliases[] =
-{
- /* Aliases for general purpose registers.  These are the architectural
-    names, as GDB uses the more user friendly names by default.  */
- { "x0", (RISCV_ZERO_REGNUM + 0) },
- { "x1", (RISCV_ZERO_REGNUM + 1) },
- { "x2", (RISCV_ZERO_REGNUM + 2) },
- { "x3", (RISCV_ZERO_REGNUM + 3) },
- { "x4", (RISCV_ZERO_REGNUM + 4) },
- { "x5", (RISCV_ZERO_REGNUM + 5) },
- { "x6", (RISCV_ZERO_REGNUM + 6) },
- { "x7", (RISCV_ZERO_REGNUM + 7) },
- { "x8", (RISCV_ZERO_REGNUM + 8) },
- { "s0", (RISCV_ZERO_REGNUM + 8) },	/* fp, s0, and x8 are all aliases.  */
- { "x9", (RISCV_ZERO_REGNUM + 9) },
- { "x10", (RISCV_ZERO_REGNUM + 10) },
- { "x11", (RISCV_ZERO_REGNUM + 11) },
- { "x12", (RISCV_ZERO_REGNUM + 12) },
- { "x13", (RISCV_ZERO_REGNUM + 13) },
- { "x14", (RISCV_ZERO_REGNUM + 14) },
- { "x15", (RISCV_ZERO_REGNUM + 15) },
- { "x16", (RISCV_ZERO_REGNUM + 16) },
- { "x17", (RISCV_ZERO_REGNUM + 17) },
- { "x18", (RISCV_ZERO_REGNUM + 18) },
- { "x19", (RISCV_ZERO_REGNUM + 19) },
- { "x20", (RISCV_ZERO_REGNUM + 20) },
- { "x21", (RISCV_ZERO_REGNUM + 21) },
- { "x22", (RISCV_ZERO_REGNUM + 22) },
- { "x23", (RISCV_ZERO_REGNUM + 23) },
- { "x24", (RISCV_ZERO_REGNUM + 24) },
- { "x25", (RISCV_ZERO_REGNUM + 25) },
- { "x26", (RISCV_ZERO_REGNUM + 26) },
- { "x27", (RISCV_ZERO_REGNUM + 27) },
- { "x28", (RISCV_ZERO_REGNUM + 28) },
- { "x29", (RISCV_ZERO_REGNUM + 29) },
- { "x30", (RISCV_ZERO_REGNUM + 30) },
- { "x31", (RISCV_ZERO_REGNUM + 31) },
-
- /* Aliases for the floating-point registers.  These are the architectural
-    names as GDB uses the more user friendly names by default.  */
- { "f0", (RISCV_FIRST_FP_REGNUM + 0) },
- { "f1", (RISCV_FIRST_FP_REGNUM + 1) },
- { "f2", (RISCV_FIRST_FP_REGNUM + 2) },
- { "f3", (RISCV_FIRST_FP_REGNUM + 3) },
- { "f4", (RISCV_FIRST_FP_REGNUM + 4) },
- { "f5", (RISCV_FIRST_FP_REGNUM + 5) },
- { "f6", (RISCV_FIRST_FP_REGNUM + 6) },
- { "f7", (RISCV_FIRST_FP_REGNUM + 7) },
- { "f8", (RISCV_FIRST_FP_REGNUM + 8) },
- { "f9", (RISCV_FIRST_FP_REGNUM + 9) },
- { "f10", (RISCV_FIRST_FP_REGNUM + 10) },
- { "f11", (RISCV_FIRST_FP_REGNUM + 11) },
- { "f12", (RISCV_FIRST_FP_REGNUM + 12) },
- { "f13", (RISCV_FIRST_FP_REGNUM + 13) },
- { "f14", (RISCV_FIRST_FP_REGNUM + 14) },
- { "f15", (RISCV_FIRST_FP_REGNUM + 15) },
- { "f16", (RISCV_FIRST_FP_REGNUM + 16) },
- { "f17", (RISCV_FIRST_FP_REGNUM + 17) },
- { "f18", (RISCV_FIRST_FP_REGNUM + 18) },
- { "f19", (RISCV_FIRST_FP_REGNUM + 19) },
- { "f20", (RISCV_FIRST_FP_REGNUM + 20) },
- { "f21", (RISCV_FIRST_FP_REGNUM + 21) },
- { "f22", (RISCV_FIRST_FP_REGNUM + 22) },
- { "f23", (RISCV_FIRST_FP_REGNUM + 23) },
- { "f24", (RISCV_FIRST_FP_REGNUM + 24) },
- { "f25", (RISCV_FIRST_FP_REGNUM + 25) },
- { "f26", (RISCV_FIRST_FP_REGNUM + 26) },
- { "f27", (RISCV_FIRST_FP_REGNUM + 27) },
- { "f28", (RISCV_FIRST_FP_REGNUM + 28) },
- { "f29", (RISCV_FIRST_FP_REGNUM + 29) },
- { "f30", (RISCV_FIRST_FP_REGNUM + 30) },
- { "f31", (RISCV_FIRST_FP_REGNUM + 31) },
+/* Feature set for CSRs.  This set is NOT constant as the register names
+   list for each register is not complete.  The aliases are computed
+   during RISCV_CREATE_CSR_ALIASES.  */
+
+static struct riscv_register_feature riscv_csr_feature =
+{
+ "org.gnu.gdb.riscv.csr",
+ {
+#define DECLARE_CSR(NAME,VALUE) \
+  { RISCV_ ## VALUE ## _REGNUM, { # NAME }, false },
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+ }
 };
 
+/* Complete RISCV_CSR_FEATURE, building the CSR alias names and adding them
+   to the name list for each register.  */
+
+static void
+riscv_create_csr_aliases ()
+{
+  for (auto &reg : riscv_csr_feature.registers)
+    {
+      int csr_num = reg.regnum - RISCV_FIRST_CSR_REGNUM;
+      const char *alias = xstrprintf ("csr%d", csr_num);
+      reg.names.push_back (alias);
+    }
+}
+
 /* Controls whether we place compressed breakpoints or not.  When in auto
    mode GDB tries to determine if the target supports compressed
    breakpoints, and uses them if it does.  */
@@ -290,82 +348,17 @@ static unsigned int riscv_debug_infcall = 0;
 
 static unsigned int riscv_debug_unwinder = 0;
 
-/* Read the MISA register from the target.  There are a couple of locations
-   that the register might be found, these are all tried.  If the MISA
-   register can't be found at all then the default value of 0 is returned,
-   this is inline with the RISC-V specification.  */
-
-static uint32_t
-riscv_read_misa_reg ()
-{
-  uint32_t value = 0;
-
-  if (target_has_registers)
-    {
-      /* Old cores might have MISA located at a different offset.  */
-      static int misa_regs[] =
-	{ RISCV_CSR_MISA_REGNUM, RISCV_CSR_LEGACY_MISA_REGNUM };
-
-      struct frame_info *frame = get_current_frame ();
-
-      for (int i = 0; i < ARRAY_SIZE (misa_regs); ++i)
-	{
-	  bool success = false;
-
-	  TRY
-	    {
-	      value = get_frame_register_unsigned (frame, misa_regs[i]);
-	      success = true;
-	    }
-	  CATCH (ex, RETURN_MASK_ERROR)
-	    {
-	      /* Ignore errors, it is acceptable for a target to not
-		 provide a MISA register, in which case the default value
-		 of 0 should be used.  */
-	    }
-	  END_CATCH
+/* When this is set to non-zero debugging information about gdbarch
+   initialisation will be printed.  */
 
-	  if (success)
-	    break;
-	}
-    }
-
-  return value;
-}
-
-/* Return true if FEATURE is available for the architecture GDBARCH.  The
-   FEATURE should be one of the single character feature codes described in
-   the RiscV ISA manual, these are between 'A' and 'Z'.  */
-
-static bool
-riscv_has_feature (struct gdbarch *gdbarch, char feature)
-{
-  gdb_assert (feature >= 'A' && feature <= 'Z');
-
-  uint32_t misa = riscv_read_misa_reg ();
-  if (misa == 0)
-    misa = gdbarch_tdep (gdbarch)->core_features;
-
-  return (misa & (1 << (feature - 'A'))) != 0;
-}
+static unsigned int riscv_debug_gdbarch = 0;
 
 /* See riscv-tdep.h.  */
 
 int
 riscv_isa_xlen (struct gdbarch *gdbarch)
 {
-  switch (gdbarch_tdep (gdbarch)->abi.fields.base_len)
-    {
-    default:
-      warning (_("unknown xlen size, assuming 4 bytes"));
-      /* Fall through.  */
-    case 1:
-      return 4;
-    case 2:
-      return 8;
-    case 3:
-      return 16;
-    }
+  return gdbarch_tdep (gdbarch)->features.xlen;
 }
 
 /* See riscv-tdep.h.  */
@@ -373,14 +366,7 @@ riscv_isa_xlen (struct gdbarch *gdbarch)
 int
 riscv_isa_flen (struct gdbarch *gdbarch)
 {
-  if (riscv_has_feature (gdbarch, 'Q'))
-    return 16;
-  else if (riscv_has_feature (gdbarch, 'D'))
-    return 8;
-  else if (riscv_has_feature (gdbarch, 'F'))
-    return 4;
-
-  return 0;
+  return gdbarch_tdep (gdbarch)->features.flen;
 }
 
 /* Return true if the target for GDBARCH has floating point hardware.  */
@@ -396,7 +382,7 @@ riscv_has_fp_regs (struct gdbarch *gdbarch)
 static bool
 riscv_has_fp_abi (struct gdbarch *gdbarch)
 {
-  return (gdbarch_tdep (gdbarch)->abi.fields.float_abi != 0);
+  return gdbarch_tdep (gdbarch)->features.hw_float_abi;
 }
 
 /* Return true if REGNO is a floating pointer register.  */
@@ -482,16 +468,36 @@ value_of_riscv_user_reg (struct frame_info *frame, const void *baton)
   return value_of_register (*reg_p, frame);
 }
 
-/* Implement the register_name gdbarch method.  */
+/* Implement the register_name gdbarch method.  This is used instead of
+   the function supplied by calling TDESC_USE_REGISTERS so that we can
+   ensure the preferred names are offered.  */
 
 static const char *
 riscv_register_name (struct gdbarch *gdbarch, int regnum)
 {
-  /* Prefer to use the alias. */
-  if (regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
+  /* Lookup the name through the target description.  If we get back NULL
+     then this is an unknown register.  If we do get a name back then we
+     look up the registers preferred name below.  */
+  const char *name = tdesc_register_name (gdbarch, regnum);
+  if (name == NULL || name[0] == '\0')
+    return NULL;
+
+  if (regnum >= RISCV_ZERO_REGNUM && regnum < RISCV_FIRST_FP_REGNUM)
     {
-      gdb_assert (regnum < ARRAY_SIZE (riscv_gdb_reg_names));
-      return riscv_gdb_reg_names[regnum];
+      gdb_assert (regnum < riscv_xreg_feature.registers.size ());
+      return riscv_xreg_feature.registers[regnum].names[0];
+    }
+
+  if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
+    {
+      if (riscv_has_fp_regs (gdbarch))
+        {
+          regnum -= RISCV_FIRST_FP_REGNUM;
+          gdb_assert (regnum < riscv_freg_feature.registers.size ());
+          return riscv_freg_feature.registers[regnum].names[0];
+        }
+      else
+        return NULL;
     }
 
   /* Check that there's no gap between the set of registers handled above,
@@ -506,14 +512,6 @@ riscv_register_name (struct gdbarch *gdbarch, int regnum)
       switch (regnum)
 	{
 	  #include "opcode/riscv-opc.h"
-	default:
-          {
-            static char buf[20];
-
-            xsnprintf (buf, sizeof (buf), "csr%d",
-                       regnum - RISCV_FIRST_CSR_REGNUM);
-            return buf;
-          }
 	}
 #undef DECLARE_CSR
     }
@@ -521,7 +519,10 @@ riscv_register_name (struct gdbarch *gdbarch, int regnum)
   if (regnum == RISCV_PRIV_REGNUM)
     return "priv";
 
-  return NULL;
+  /* It is possible that that the target provides some registers that GDB
+     is unaware of, in that case just return the NAME from the target
+     description.  */
+  return name;
 }
 
 /* Construct a type for 64-bit FP registers.  */
@@ -630,7 +631,7 @@ riscv_register_type (struct gdbarch *gdbarch, int regnum)
     }
   else if (regnum <= RISCV_LAST_FP_REGNUM)
     {
-      regsize = riscv_isa_xlen (gdbarch);
+      regsize = riscv_isa_flen (gdbarch);
       switch (regsize)
 	{
 	case 4:
@@ -639,6 +640,8 @@ riscv_register_type (struct gdbarch *gdbarch, int regnum)
 	  return riscv_fpreg_d_type (gdbarch);
 	case 16:
 	  return riscv_fpreg_q_type (gdbarch);
+	case 0:
+	  return builtin_type (gdbarch)->builtin_int0;
 	default:
 	  internal_error (__FILE__, __LINE__,
 			  _("unknown isa regsize %i"), regsize);
@@ -646,13 +649,12 @@ riscv_register_type (struct gdbarch *gdbarch, int regnum)
     }
   else if (regnum == RISCV_PRIV_REGNUM)
     return builtin_type (gdbarch)->builtin_int8;
-  else
+  else if (regnum == RISCV_CSR_FFLAGS_REGNUM
+           || regnum == RISCV_CSR_FRM_REGNUM
+           || regnum == RISCV_CSR_FCSR_REGNUM)
+    return builtin_type (gdbarch)->builtin_int32;
+  else if (regnum < RISCV_LAST_REGNUM)
     {
-      if (regnum == RISCV_CSR_FFLAGS_REGNUM
-	  || regnum == RISCV_CSR_FRM_REGNUM
-	  || regnum == RISCV_CSR_FCSR_REGNUM)
-	return builtin_type (gdbarch)->builtin_int32;
-
       regsize = riscv_isa_xlen (gdbarch);
       switch (regsize)
 	{
@@ -667,6 +669,8 @@ riscv_register_type (struct gdbarch *gdbarch, int regnum)
 			  _("unknown isa regsize %i"), regsize);
 	}
     }
+  else
+    return tdesc_register_type (gdbarch, regnum);
 }
 
 /* Helper for riscv_print_registers_info, prints info for a single register
@@ -679,14 +683,28 @@ riscv_print_one_register_info (struct gdbarch *gdbarch,
 			       int regnum)
 {
   const char *name = gdbarch_register_name (gdbarch, regnum);
-  struct value *val = value_of_register (regnum, frame);
-  struct type *regtype = value_type (val);
+  struct value *val;
+  struct type *regtype;
   int print_raw_format;
   enum tab_stops { value_column_1 = 15 };
 
   fputs_filtered (name, file);
   print_spaces_filtered (value_column_1 - strlen (name), file);
 
+  TRY
+    {
+      val = value_of_register (regnum, frame);
+      regtype = value_type (val);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      /* Handle failure to read a register without interrupting the entire
+         'info registers' flow.  */
+      fprintf_filtered (file, "%s\n", ex.message);
+      return;
+    }
+  END_CATCH
+
   print_raw_format = (value_entirely_available (val)
 		      && !value_optimized_out (val));
 
@@ -901,6 +919,15 @@ riscv_register_reggroup_p (struct gdbarch  *gdbarch, int regnum,
       || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
     return 0;
 
+  if (regnum > RISCV_LAST_REGNUM)
+    {
+      int ret = tdesc_register_in_reggroup_p (gdbarch, regnum, reggroup);
+      if (ret != -1)
+        return ret;
+
+      return default_register_reggroup_p (gdbarch, regnum, reggroup);
+    }
+
   if (reggroup == all_reggroup)
     {
       if (regnum < RISCV_FIRST_CSR_REGNUM || regnum == RISCV_PRIV_REGNUM)
@@ -923,7 +950,7 @@ riscv_register_reggroup_p (struct gdbarch  *gdbarch, int regnum,
       else
 	return regnum < RISCV_FIRST_FP_REGNUM;
     }
-  else if (reggroup == system_reggroup)
+  else if (reggroup == system_reggroup || reggroup == csr_reggroup)
     {
       if (regnum == RISCV_PRIV_REGNUM)
 	return 1;
@@ -951,7 +978,6 @@ riscv_print_registers_info (struct gdbarch *gdbarch,
   if (regnum != -1)
     {
       /* Print one specified register.  */
-      gdb_assert (regnum <= RISCV_LAST_REGNUM);
       if (gdbarch_register_name (gdbarch, regnum) == NULL
 	  || *(gdbarch_register_name (gdbarch, regnum)) == '\0')
         error (_("Not a valid register for the current processor type"));
@@ -978,7 +1004,7 @@ riscv_print_registers_info (struct gdbarch *gdbarch,
 	    continue;
 
 	  /* Is the register in the group we're interested in?  */
-	  if (!riscv_register_reggroup_p (gdbarch, regnum, reggroup))
+	  if (!gdbarch_register_reggroup_p (gdbarch, regnum, reggroup))
 	    continue;
 
 	  riscv_print_one_register_info (gdbarch, file, frame, regnum);
@@ -2796,36 +2822,26 @@ static const struct frame_unwind riscv_frame_unwind =
   /*.prev_arch     =*/ NULL,
 };
 
-/* Initialize the current architecture based on INFO.  If possible,
-   re-use an architecture from ARCHES, which is a list of
-   architectures already created during this debugging session.
-
-   Called e.g. at program startup, when reading a core file, and when
-   reading a binary file.  */
+/* Find a suitable default target description.  Use the contents of INFO,
+   specifically the bfd object being executed, to guide the selection of a
+   suitable default target description.  */
 
-static struct gdbarch *
-riscv_gdbarch_init (struct gdbarch_info info,
-		    struct gdbarch_list *arches)
+static struct target_desc *
+riscv_find_default_target_description (const struct gdbarch_info info)
 {
-  struct gdbarch *gdbarch;
-  struct gdbarch_tdep *tdep;
-  struct gdbarch_tdep tmp_tdep;
-  int i;
-
-  /* Ideally, we'd like to get as much information from the target for
-     things like register size, and whether the target has floating point
-     hardware.  However, there are some things that the target can't tell
-     us, like, what ABI is being used.
+  struct riscv_gdbarch_features features;
 
-     So, for now, we take as much information as possible from the ELF,
-     including things like register size, and FP hardware support, along
-     with information about the ABI.
-
-     Information about this target is built up in TMP_TDEP, and then we
-     look for an existing gdbarch in ARCHES that matches TMP_TDEP.  If no
-     match is found we'll create a new gdbarch and copy TMP_TDEP over.  */
-  memset (&tmp_tdep, 0, sizeof (tmp_tdep));
+  /* Setup some arbitrary defaults.  */
+  features.xlen = 8;
+  features.flen = 0;
+  features.hw_float_abi = false;
 
+  /* Now try to improve on the defaults by looking at the binary we are
+     going to execute.  We assume the user knows what they are doing and
+     that the target will match the binary.  Remember, this code path is
+     only used at all if the target hasn't given us a description, so this
+     is really a last ditched effort to do something sane before giving
+     up.  */
   if (info.abfd != NULL
       && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
     {
@@ -2833,26 +2849,22 @@ riscv_gdbarch_init (struct gdbarch_info info,
       int e_flags = elf_elfheader (info.abfd)->e_flags;
 
       if (eclass == ELFCLASS32)
-	tmp_tdep.abi.fields.base_len = 1;
+	features.xlen = 4;
       else if (eclass == ELFCLASS64)
-	tmp_tdep.abi.fields.base_len = 2;
+	features.xlen = 8;
       else
-        internal_error (__FILE__, __LINE__,
+	internal_error (__FILE__, __LINE__,
 			_("unknown ELF header class %d"), eclass);
 
-      if (e_flags & EF_RISCV_RVC)
-	tmp_tdep.core_features |= (1 << ('C' - 'A'));
-
       if (e_flags & EF_RISCV_FLOAT_ABI_DOUBLE)
 	{
-	  tmp_tdep.abi.fields.float_abi = 2;
-	  tmp_tdep.core_features |= (1 << ('D' - 'A'));
-	  tmp_tdep.core_features |= (1 << ('F' - 'A'));
+	  features.flen = 8;
+	  features.hw_float_abi = true;
 	}
       else if (e_flags & EF_RISCV_FLOAT_ABI_SINGLE)
 	{
-	  tmp_tdep.abi.fields.float_abi = 1;
-	  tmp_tdep.core_features |= (1 << ('F' - 'A'));
+	  features.flen = 4;
+	  features.hw_float_abi = true;
 	}
     }
   else
@@ -2860,25 +2872,210 @@ riscv_gdbarch_init (struct gdbarch_info info,
       const struct bfd_arch_info *binfo = info.bfd_arch_info;
 
       if (binfo->bits_per_word == 32)
-	tmp_tdep.abi.fields.base_len = 1;
+	features.xlen = 4;
       else if (binfo->bits_per_word == 64)
-	tmp_tdep.abi.fields.base_len = 2;
+	features.xlen = 8;
       else
-        internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"),
+	internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"),
 			binfo->bits_per_word);
     }
 
+  /* Now build a target description based on the feature set.  */
+  return riscv_create_target_description (features);
+}
+
+/* All of the registers in REG_SET are checked for in FEATURE, TDESC_DATA
+   is updated with the register numbers for each register as listed in
+   REG_SET.  If any register marked as required in REG_SET is not found in
+   FEATURE then this function returns false, otherwise, it returns true.  */
+
+static bool
+riscv_check_tdesc_feature (struct tdesc_arch_data *tdesc_data,
+                           const struct tdesc_feature *feature,
+                           const struct riscv_register_feature *reg_set)
+{
+  for (const auto &reg : reg_set->registers)
+    {
+      bool found = false;
+
+      for (const char *name : reg.names)
+	{
+	  found =
+	    tdesc_numbered_register (feature, tdesc_data, reg.regnum, name);
+
+	  if (found)
+	    break;
+	}
+
+      if (!found && reg.required_p)
+	return false;
+    }
+
+  return true;
+}
+
+/* Add all the expected register sets into GDBARCH.  */
+
+static void
+riscv_add_reggroups (struct gdbarch *gdbarch)
+{
+  /* Add predefined register groups.  */
+  reggroup_add (gdbarch, all_reggroup);
+  reggroup_add (gdbarch, save_reggroup);
+  reggroup_add (gdbarch, restore_reggroup);
+  reggroup_add (gdbarch, system_reggroup);
+  reggroup_add (gdbarch, vector_reggroup);
+  reggroup_add (gdbarch, general_reggroup);
+  reggroup_add (gdbarch, float_reggroup);
+
+  /* Add RISC-V specific register groups.  */
+  reggroup_add (gdbarch, csr_reggroup);
+}
+
+/* Create register aliases for all the alternative names that exist for
+   registers in REG_SET.  */
+
+static void
+riscv_setup_register_aliases (struct gdbarch *gdbarch,
+                              const struct riscv_register_feature *reg_set)
+{
+  for (auto &reg : reg_set->registers)
+    {
+      /* The first item in the names list is the preferred name for the
+         register, this is what RISCV_REGISTER_NAME returns, and so we
+         don't need to create an alias with that name here.  */
+      for (int i = 1; i < reg.names.size (); ++i)
+        user_reg_add (gdbarch, reg.names[i], value_of_riscv_user_reg,
+                      &reg.regnum);
+    }
+}
+
+/* Initialize the current architecture based on INFO.  If possible,
+   re-use an architecture from ARCHES, which is a list of
+   architectures already created during this debugging session.
+
+   Called e.g. at program startup, when reading a core file, and when
+   reading a binary file.  */
+
+static struct gdbarch *
+riscv_gdbarch_init (struct gdbarch_info info,
+		    struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  struct riscv_gdbarch_features features;
+  const struct target_desc *tdesc = info.target_desc;
+
+  /* Ensure we always have a target description.  */
+  if (!tdesc_has_registers (tdesc))
+    tdesc = riscv_find_default_target_description (info);
+  gdb_assert (tdesc);
+
+  if (riscv_debug_gdbarch)
+    fprintf_unfiltered (gdb_stdlog, "Have got a target description\n");
+
+  const struct tdesc_feature *feature_cpu
+    = tdesc_find_feature (tdesc, riscv_xreg_feature.name);
+  const struct tdesc_feature *feature_fpu
+    = tdesc_find_feature (tdesc, riscv_freg_feature.name);
+  const struct tdesc_feature *feature_virtual
+    = tdesc_find_feature (tdesc, riscv_virtual_feature.name);
+  const struct tdesc_feature *feature_csr
+    = tdesc_find_feature (tdesc, riscv_csr_feature.name);
+
+  if (feature_cpu == NULL)
+    return NULL;
+
+  struct tdesc_arch_data *tdesc_data = tdesc_data_alloc ();
+
+  bool valid_p = riscv_check_tdesc_feature (tdesc_data,
+                                            feature_cpu,
+                                            &riscv_xreg_feature);
+  if (valid_p)
+    {
+      /* Check that all of the core cpu registers have the same bitsize.  */
+      int xlen_bitsize = tdesc_register_bitsize (feature_cpu, "pc");
+
+      for (auto &tdesc_reg : feature_cpu->registers)
+        valid_p &= (tdesc_reg->bitsize == xlen_bitsize);
+
+      if (riscv_debug_gdbarch)
+        fprintf_filtered
+          (gdb_stdlog,
+           "From target-description, xlen = %d\n", xlen_bitsize);
+
+      features.xlen = (xlen_bitsize / 8);
+    }
+
+  if (feature_fpu != NULL)
+    {
+      valid_p &= riscv_check_tdesc_feature (tdesc_data, feature_fpu,
+                                            &riscv_freg_feature);
+
+      int bitsize = tdesc_register_bitsize (feature_fpu, "ft0");
+      features.flen = (bitsize / 8);
+      features.hw_float_abi = true;
+
+      if (riscv_debug_gdbarch)
+        fprintf_filtered
+          (gdb_stdlog,
+           "From target-description, flen = %d\n", bitsize);
+    }
+  else
+    {
+      features.flen = 0;
+      features.hw_float_abi = false;
+
+      if (riscv_debug_gdbarch)
+        fprintf_filtered
+          (gdb_stdlog,
+           "No FPU in target-description, assume soft-float ABI\n");
+    }
+
+  if (feature_virtual)
+    riscv_check_tdesc_feature (tdesc_data, feature_virtual,
+                               &riscv_virtual_feature);
+
+  if (feature_csr)
+    riscv_check_tdesc_feature (tdesc_data, feature_csr,
+                               &riscv_csr_feature);
+
+  if (!valid_p)
+    {
+      if (riscv_debug_gdbarch)
+        fprintf_unfiltered (gdb_stdlog, "Target description is not valid\n");
+      tdesc_data_cleanup (tdesc_data);
+      return NULL;
+    }
+
   /* Find a candidate among the list of pre-declared architectures.  */
   for (arches = gdbarch_list_lookup_by_info (arches, &info);
        arches != NULL;
        arches = gdbarch_list_lookup_by_info (arches->next, &info))
-    if (gdbarch_tdep (arches->gdbarch)->abi.value == tmp_tdep.abi.value)
+    {
+      /* Check that the feature set of the ARCHES matches the feature set
+         we are looking for.  If it doesn't then we can't reuse this
+         gdbarch.  */
+      struct gdbarch_tdep *other_tdep = gdbarch_tdep (arches->gdbarch);
+
+      if (other_tdep->features.hw_float_abi != features.hw_float_abi
+          || other_tdep->features.xlen != features.xlen
+          || other_tdep->features.flen != features.flen)
+        continue;
+
+      break;
+    }
+
+  if (arches != NULL)
+    {
+      tdesc_data_cleanup (tdesc_data);
       return arches->gdbarch;
+    }
 
   /* None found, so create a new architecture from the information provided.  */
-  tdep = (struct gdbarch_tdep *) xmalloc (sizeof *tdep);
+  tdep = new (struct gdbarch_tdep);
   gdbarch = gdbarch_alloc (&info, tdep);
-  memcpy (tdep, &tmp_tdep, sizeof (tmp_tdep));
+  tdep->features = features;
 
   /* Target data types.  */
   set_gdbarch_short_bit (gdbarch, 16);
@@ -2898,19 +3095,6 @@ riscv_gdbarch_init (struct gdbarch_info info,
   set_gdbarch_sw_breakpoint_from_kind (gdbarch, riscv_sw_breakpoint_from_kind);
   set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
 
-  /* Register architecture.  */
-  set_gdbarch_num_regs (gdbarch, RISCV_LAST_REGNUM + 1);
-  set_gdbarch_sp_regnum (gdbarch, RISCV_SP_REGNUM);
-  set_gdbarch_pc_regnum (gdbarch, RISCV_PC_REGNUM);
-  set_gdbarch_ps_regnum (gdbarch, RISCV_FP_REGNUM);
-  set_gdbarch_deprecated_fp_regnum (gdbarch, RISCV_FP_REGNUM);
-
-  /* Functions to supply register information.  */
-  set_gdbarch_register_name (gdbarch, riscv_register_name);
-  set_gdbarch_register_type (gdbarch, riscv_register_type);
-  set_gdbarch_print_registers_info (gdbarch, riscv_print_registers_info);
-  set_gdbarch_register_reggroup_p (gdbarch, riscv_register_reggroup_p);
-
   /* Functions to analyze frames.  */
   set_gdbarch_skip_prologue (gdbarch, riscv_skip_prologue);
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
@@ -2931,9 +3115,49 @@ riscv_gdbarch_init (struct gdbarch_info info,
   dwarf2_append_unwinders (gdbarch);
   frame_unwind_append_unwinder (gdbarch, &riscv_frame_unwind);
 
-  for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i)
-    user_reg_add (gdbarch, riscv_register_aliases[i].name,
-		  value_of_riscv_user_reg, &riscv_register_aliases[i].regnum);
+  /* Register architecture.  */
+  riscv_add_reggroups (gdbarch);
+
+  /* We reserve all possible register numbers for the known registers.
+     This means the target description mechanism will add any target
+     specific registers after this number.  This helps make debugging GDB
+     just a little easier.  */
+  set_gdbarch_num_regs (gdbarch, RISCV_LAST_REGNUM + 1);
+
+  /* We don't have to provide the count of 0 here (its the default) but
+     include this line to make it explicit that, right now, we don't have
+     any pseudo registers on RISC-V.  */
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+
+  /* Some specific register numbers GDB likes to know about.  */
+  set_gdbarch_sp_regnum (gdbarch, RISCV_SP_REGNUM);
+  set_gdbarch_pc_regnum (gdbarch, RISCV_PC_REGNUM);
+
+  set_gdbarch_print_registers_info (gdbarch, riscv_print_registers_info);
+
+  /* Finalise the target description registers.  */
+  tdesc_use_registers (gdbarch, tdesc, tdesc_data);
+
+  /* Override the register type callback setup by the target description
+     mechanism.  This allows us to provide special type for floating point
+     registers.  */
+  set_gdbarch_register_type (gdbarch, riscv_register_type);
+
+  /* Override the register name callback setup by the target description
+     mechanism.  This allows us to force our preferred names for the
+     registers, no matter what the target description called them.  */
+  set_gdbarch_register_name (gdbarch, riscv_register_name);
+
+  /* Override the register group callback setup by the target description
+     mechanism.  This allows us to force registers into the groups we
+     want, ignoring what the target tells us.  */
+  set_gdbarch_register_reggroup_p (gdbarch, riscv_register_reggroup_p);
+
+  /* Create register aliases for alternative register names.  */
+  riscv_setup_register_aliases (gdbarch, &riscv_xreg_feature);
+  if (riscv_has_fp_regs (gdbarch))
+    riscv_setup_register_aliases (gdbarch, &riscv_freg_feature);
+  riscv_setup_register_aliases (gdbarch, &riscv_csr_feature);
 
   /* Hook in OS ABI-specific overrides, if they have been registered.  */
   gdbarch_init_osabi (info, gdbarch);
@@ -3080,9 +3304,20 @@ riscv_software_single_step (struct regcache *regcache)
   return {next_pc};
 }
 
+/* Create RISC-V specific reggroups.  */
+
+static void
+riscv_init_reggroups ()
+{
+  csr_reggroup = reggroup_new ("csr", USER_REGGROUP);
+}
+
 void
 _initialize_riscv_tdep (void)
 {
+  riscv_create_csr_aliases ();
+  riscv_init_reggroups ();
+
   gdbarch_register (bfd_arch_riscv, riscv_gdbarch_init, NULL);
 
   /* Add root prefix command for all "set debug riscv" and "show debug
@@ -3127,6 +3362,16 @@ of the stack unwinding mechanism."),
 			     show_riscv_debug_variable,
 			     &setdebugriscvcmdlist, &showdebugriscvcmdlist);
 
+  add_setshow_zuinteger_cmd ("gdbarch", class_maintenance,
+			     &riscv_debug_gdbarch,  _("\
+Set riscv gdbarch initialisation debugging."), _("\
+Show riscv gdbarch initialisation debugging."), _("\
+When non-zero, print debugging information for the riscv gdbarch\n\
+initialisation process."),
+			     NULL,
+			     show_riscv_debug_variable,
+			     &setdebugriscvcmdlist, &showdebugriscvcmdlist);
+
   /* Add root prefix command for all "set riscv" and "show riscv" commands.  */
   add_prefix_cmd ("riscv", no_class, set_riscv_command,
 		  _("RISC-V specific commands."),
diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
index 2cb51b16c53..e3c5c183dcd 100644
--- a/gdb/riscv-tdep.h
+++ b/gdb/riscv-tdep.h
@@ -21,6 +21,8 @@
 #ifndef RISCV_TDEP_H
 #define RISCV_TDEP_H
 
+#include "arch/riscv.h"
+
 /* RiscV register numbers.  */
 enum
 {
@@ -57,31 +59,13 @@ enum
 /* RISC-V specific per-architecture information.  */
 struct gdbarch_tdep
 {
-  union
-  {
-    /* Provide access to the whole ABI in one value.  */
-    unsigned value;
-
-    struct
-    {
-      /* Encode the base machine length following the same rules as in the
-	 MISA register.  */
-      unsigned base_len : 2;
-
-      /* Encode which floating point ABI is in use following the same rules
-	 as the ELF e_flags field.  */
-      unsigned float_abi : 2;
-    } fields;
-  } abi;
-
-  /* Only the least significant 26 bits are (possibly) valid, and indicate
-     features that are supported on the target.  These could be cached from
-     the target, or read from the executable when available.  */
-  unsigned core_features;
+  /* Features about the target that impact how the gdbarch is configured.
+     Two gdbarch instances are compatible only if this field matches.  */
+  struct riscv_gdbarch_features features;
 
   /* ISA-specific data types.  */
-  struct type *riscv_fpreg_d_type;
-  struct type *riscv_fpreg_q_type;
+  struct type *riscv_fpreg_d_type = nullptr;
+  struct type *riscv_fpreg_q_type = nullptr;
 };
 
 
diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c
index bdd29c0f2b5..20604bb4b96 100644
--- a/gdb/target-descriptions.c
+++ b/gdb/target-descriptions.c
@@ -1716,6 +1716,7 @@ maint_print_c_tdesc_cmd (const char *args, int from_tty)
   if (startswith (filename_after_features.c_str (), "i386/32bit-")
       || startswith (filename_after_features.c_str (), "i386/64bit-")
       || startswith (filename_after_features.c_str (), "i386/x32-core.xml")
+      || startswith (filename_after_features.c_str (), "riscv/")
       || startswith (filename_after_features.c_str (), "tic6x-")
       || startswith (filename_after_features.c_str (), "aarch64"))
     {
-- 
2.14.5

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

* Re: [RFC] gdb/riscv: Add target description support
  2018-11-08 16:08 [RFC] gdb/riscv: Add target description support Andrew Burgess
@ 2018-11-08 18:33 ` John Baldwin
  2018-11-08 19:32   ` Palmer Dabbelt
  2018-11-14 14:29   ` Andrew Burgess
  2018-11-08 21:57 ` Jim Wilson
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 27+ messages in thread
From: John Baldwin @ 2018-11-08 18:33 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches; +Cc: jimw, palmer

On 11/8/18 8:07 AM, Andrew Burgess wrote:
> This commit adds target description support for riscv.
> 
> I've used the split feature approach for specifying the architectural
> features, and the CSR feature is auto-generated from the riscv-opc.h
> header file.

In general this looks fine to me (as far as I am familiar with the
target descriptions).  The only possible question/comment I have is if
you considered describing fields of specific registers such as the FP
status registers or MSTATUS, etc. as fields in the XML to replace the
current special cases in riscv_print_one_register_info().  I think the
XML can't handle enum values as riscv_print_one_register_info() uses for
some cases, but I think it would be able to handle many of the special
cases in that function.

Some related-ish questions (though not about this patch): I wonder if we
can do things with pseudo registers to automatically derive FFLAGS and
FRM if a target provides FCSR.

One more note: AFAIU, 1.10 of the privilege spec removed hypervisor mode
with the intention of implementing virtualization support differently.
We might want to remove the references to hypervisor mode from riscv-tdep.c
as a result?

-- 
John Baldwin

                                                                            

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

* Re: [RFC] gdb/riscv: Add target description support
  2018-11-08 18:33 ` John Baldwin
@ 2018-11-08 19:32   ` Palmer Dabbelt
  2018-11-08 19:41     ` John Baldwin
  2018-11-14 14:29   ` Andrew Burgess
  1 sibling, 1 reply; 27+ messages in thread
From: Palmer Dabbelt @ 2018-11-08 19:32 UTC (permalink / raw)
  To: jhb; +Cc: andrew.burgess, gdb-patches, Jim Wilson

On Thu, 08 Nov 2018 10:32:57 PST (-0800), jhb@FreeBSD.org wrote:
> On 11/8/18 8:07 AM, Andrew Burgess wrote:
>> This commit adds target description support for riscv.
>>
>> I've used the split feature approach for specifying the architectural
>> features, and the CSR feature is auto-generated from the riscv-opc.h
>> header file.
>
> In general this looks fine to me (as far as I am familiar with the
> target descriptions).  The only possible question/comment I have is if
> you considered describing fields of specific registers such as the FP
> status registers or MSTATUS, etc. as fields in the XML to replace the
> current special cases in riscv_print_one_register_info().  I think the
> XML can't handle enum values as riscv_print_one_register_info() uses for
> some cases, but I think it would be able to handle many of the special
> cases in that function.
>
> Some related-ish questions (though not about this patch): I wonder if we
> can do things with pseudo registers to automatically derive FFLAGS and
> FRM if a target provides FCSR.
>
> One more note: AFAIU, 1.10 of the privilege spec removed hypervisor mode
> with the intention of implementing virtualization support differently.
> We might want to remove the references to hypervisor mode from riscv-tdep.c
> as a result?

The only reference I see is in the PRV decoding, which I think is OK: while the 
spec doesn't mention hypervisor mode any more, the bit pattern is still there 
and an upcoming spec will add it back in.  I believe the official name is now 
"hypervisor-extended supervisor mode" but since that's a bit of a mouthfull I 
still call it hypervisor mode :)

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

* Re: [RFC] gdb/riscv: Add target description support
  2018-11-08 19:32   ` Palmer Dabbelt
@ 2018-11-08 19:41     ` John Baldwin
  0 siblings, 0 replies; 27+ messages in thread
From: John Baldwin @ 2018-11-08 19:41 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: andrew.burgess, gdb-patches, Jim Wilson

On 11/8/18 11:32 AM, Palmer Dabbelt wrote:
> On Thu, 08 Nov 2018 10:32:57 PST (-0800), jhb@FreeBSD.org wrote:
>> On 11/8/18 8:07 AM, Andrew Burgess wrote:
>>> This commit adds target description support for riscv.
>>>
>>> I've used the split feature approach for specifying the architectural
>>> features, and the CSR feature is auto-generated from the riscv-opc.h
>>> header file.
>>
>> In general this looks fine to me (as far as I am familiar with the
>> target descriptions).  The only possible question/comment I have is if
>> you considered describing fields of specific registers such as the FP
>> status registers or MSTATUS, etc. as fields in the XML to replace the
>> current special cases in riscv_print_one_register_info().  I think the
>> XML can't handle enum values as riscv_print_one_register_info() uses for
>> some cases, but I think it would be able to handle many of the special
>> cases in that function.
>>
>> Some related-ish questions (though not about this patch): I wonder if we
>> can do things with pseudo registers to automatically derive FFLAGS and
>> FRM if a target provides FCSR.
>>
>> One more note: AFAIU, 1.10 of the privilege spec removed hypervisor mode
>> with the intention of implementing virtualization support differently.
>> We might want to remove the references to hypervisor mode from riscv-tdep.c
>> as a result?
> 
> The only reference I see is in the PRV decoding, which I think is OK: while the 
> spec doesn't mention hypervisor mode any more, the bit pattern is still there 
> and an upcoming spec will add it back in.  I believe the official name is now 
> "hypervisor-extended supervisor mode" but since that's a bit of a mouthfull I 
> still call it hypervisor mode :)

Ah, ok.  There are also HIE, etc. bits in the MSTATUS decoding that would
also be related, but if they are going to be reused then leaving them as-is
is probably fine.

-- 
John Baldwin

                                                                            

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

* Re: [RFC] gdb/riscv: Add target description support
  2018-11-08 16:08 [RFC] gdb/riscv: Add target description support Andrew Burgess
  2018-11-08 18:33 ` John Baldwin
@ 2018-11-08 21:57 ` Jim Wilson
  2018-11-13 15:05   ` Andrew Burgess
  2018-11-13 20:08 ` Pedro Alves
  2018-11-14 14:58 ` [PATCH] " Andrew Burgess
  3 siblings, 1 reply; 27+ messages in thread
From: Jim Wilson @ 2018-11-08 21:57 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, Palmer Dabbelt, John Baldwin

On Thu, Nov 8, 2018 at 8:07 AM Andrew Burgess
<andrew.burgess@embecosm.com> wrote:
>  riscv*-*-linux*)
>         # Target: Linux/RISC-V
> -       gdb_target_obs="riscv-linux-tdep.o riscv-tdep.o glibc-tdep.o \
> +       gdb_target_obs="riscv-linux-tdep.oglibc-tdep.o \
>                         linux-tdep.o solib-svr4.o symfile-mem.o linux-record.o"

There is a typo here, a space is missing between riscv-linux-tdep.o
and glibc-tdep.o.

Otherwise this looks great.  I tested it on riscv64-linux and saw no
new problems.  I also tested with riscv-tests/debug against openocd,
and almost everything that failed before is now passing.  There are
two tests that fail because riscv-tests/debug doesn't know how to
parse the new {float...double...} string output for FP registers.
There are two tests that fail for a 32-bit target with
    (gdb) p/x fox = "This little piggy went to the market."
    p/x fox = "This little piggy went to the market."^M
    /scratch/jimw/openocd/fsf-gdb/riscv-gnu-toolchain/build/../riscv-gdb/gdb/regcac\
    he.c:298: internal-error: void
regcache::restore(readonly_detached_regcache*): \
    Assertion `src != NULL' failed.^M
And the same tests fail for a 64-bit target with a timeout.  That may
only be one problem.  This should not prevent the XML register set
support from going in now, and we can worry about debugging these
problems later.  Even with the failures this is a major improvement
over what we had before.

Jim

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

* Re: [RFC] gdb/riscv: Add target description support
  2018-11-08 21:57 ` Jim Wilson
@ 2018-11-13 15:05   ` Andrew Burgess
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Burgess @ 2018-11-13 15:05 UTC (permalink / raw)
  To: Jim Wilson; +Cc: gdb-patches, Palmer Dabbelt, John Baldwin

* Jim Wilson <jimw@sifive.com> [2018-11-08 13:57:10 -0800]:

> On Thu, Nov 8, 2018 at 8:07 AM Andrew Burgess
> <andrew.burgess@embecosm.com> wrote:
> >  riscv*-*-linux*)
> >         # Target: Linux/RISC-V
> > -       gdb_target_obs="riscv-linux-tdep.o riscv-tdep.o glibc-tdep.o \
> > +       gdb_target_obs="riscv-linux-tdep.oglibc-tdep.o \
> >                         linux-tdep.o solib-svr4.o symfile-mem.o linux-record.o"
> 
> There is a typo here, a space is missing between riscv-linux-tdep.o
> and glibc-tdep.o.

Good spot.  I'll fix this.

> 
> Otherwise this looks great.  I tested it on riscv64-linux and saw no
> new problems.  I also tested with riscv-tests/debug against openocd,
> and almost everything that failed before is now passing.  There are
> two tests that fail because riscv-tests/debug doesn't know how to
> parse the new {float...double...} string output for FP registers.
> There are two tests that fail for a 32-bit target with
>     (gdb) p/x fox = "This little piggy went to the market."
>     p/x fox = "This little piggy went to the market."^M
>     /scratch/jimw/openocd/fsf-gdb/riscv-gnu-toolchain/build/../riscv-gdb/gdb/regcac\
>     he.c:298: internal-error: void
> regcache::restore(readonly_detached_regcache*): \
>     Assertion `src != NULL' failed.^M

I have a fix for this issue, but it's not really related to target
register descriptions.  I hope to get this posted soon.

> And the same tests fail for a 64-bit target with a timeout.  That may
> only be one problem.  This should not prevent the XML register set
> support from going in now, and we can worry about debugging these
> problems later.  Even with the failures this is a major improvement
> over what we had before.

Great.  I just need to review John's feedback and then we can move
this forward.

Thanks again,

Andrew

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

* Re: [RFC] gdb/riscv: Add target description support
  2018-11-08 16:08 [RFC] gdb/riscv: Add target description support Andrew Burgess
  2018-11-08 18:33 ` John Baldwin
  2018-11-08 21:57 ` Jim Wilson
@ 2018-11-13 20:08 ` Pedro Alves
  2018-11-14 14:58 ` [PATCH] " Andrew Burgess
  3 siblings, 0 replies; 27+ messages in thread
From: Pedro Alves @ 2018-11-13 20:08 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches; +Cc: jimw, palmer, jhb

Hi,

Please document the target features in the "Standard Target Features"
node in the manual.  I think a NEWS entry might be good too, for stub
implementors.

Thanks,
Pedro Alves

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

* Re: [RFC] gdb/riscv: Add target description support
  2018-11-08 18:33 ` John Baldwin
  2018-11-08 19:32   ` Palmer Dabbelt
@ 2018-11-14 14:29   ` Andrew Burgess
  2018-11-14 17:42     ` John Baldwin
  1 sibling, 1 reply; 27+ messages in thread
From: Andrew Burgess @ 2018-11-14 14:29 UTC (permalink / raw)
  To: John Baldwin; +Cc: gdb-patches, jimw, palmer

* John Baldwin <jhb@FreeBSD.org> [2018-11-08 10:32:57 -0800]:

> On 11/8/18 8:07 AM, Andrew Burgess wrote:
> > This commit adds target description support for riscv.
> > 
> > I've used the split feature approach for specifying the architectural
> > features, and the CSR feature is auto-generated from the riscv-opc.h
> > header file.
> 
> In general this looks fine to me (as far as I am familiar with the
> target descriptions).  The only possible question/comment I have is if
> you considered describing fields of specific registers such as the FP
> status registers or MSTATUS, etc. as fields in the XML to replace the
> current special cases in riscv_print_one_register_info().

I took a look at switching over to using flag fields in the xml
description, but in the end I decided against this.

The main reason is that there appears to be a bug with registers
described as a flag type, I was unable to assign to the register.
What I saw was an invalid cast error.

I defined the type like this:

    <flags id="riscv_fflags" size="1">
      <field name="NX" start="0" end="0"/>
      <field name="UF" start="1" end="1"/>
      <field name="OF" start="2" end="2"/>
      <field name="DZ" start="3" end="3"/>
      <field name="NV" start="4" end="4"/>
    </flags>

    <reg name="fflags" bitsize="32" type="riscv_fflags"/>

But then, when I try to assign to the register I see this error:

    (gdb) set $fflags=0x3
    Invalid cast

This same assignment works fine when the register is a straight
integer.

Next, I actually prefer the current 'info register $fflags' output,
with all of the fields displayed all the time, so taking that away
would feel like a step backward, though I could be convinced if
everyone else feels strongly the other way.

In the end I think that there's some issues that need to be resolved
before we could move to using the <flags> type.  I think this is
something we should consider, but I'd like to kick this down the road
for now.

>                                                            I think the
> XML can't handle enum values as riscv_print_one_register_info() uses for
> some cases, but I think it would be able to handle many of the special
> cases in that function.

I agree, currently we're not going to be able to completely kill the
info registers override, and as a result I'm not that fussed about
having extra cases in here.

> 
> Some related-ish questions (though not about this patch): I wonder if we
> can do things with pseudo registers to automatically derive FFLAGS and
> FRM if a target provides FCSR.

I like this idea a lot, and I definitely plan to implement this, just
because I think it would be a neat feature.  However, my understanding
is that FFLAGS and FRM _are_ real CSRs, at least in the sense that
there's a real CSR offset from which we can read to extract the FFLAGS
or FRM part of FCSR.  So, initially I'd prefer to merge this with
these registers as real registers.

But I think it would be great if for targets that only announce FCSR,
we could automatically emulate FRM and FCSR.

Thank you for your review.  I plan to post a revised patch soon.

Thanks,
Andrew

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

* [PATCH] gdb/riscv: Add target description support
  2018-11-08 16:08 [RFC] gdb/riscv: Add target description support Andrew Burgess
                   ` (2 preceding siblings ...)
  2018-11-13 20:08 ` Pedro Alves
@ 2018-11-14 14:58 ` Andrew Burgess
  2018-11-19  3:51   ` Jim Wilson
  2019-02-22 17:42   ` Tom Tromey
  3 siblings, 2 replies; 27+ messages in thread
From: Andrew Burgess @ 2018-11-14 14:58 UTC (permalink / raw)
  To: gdb-patches; +Cc: jimw, palmer, jhb

This is a slightly revised version of the RISC-V target descriptions
patch.

Changes since the first version:

  - Fixed bug spotted by Jim in gdb/configure.tgt

  - Correctly generated the gdb/features/riscv/{32,64}bit-csr.c files.

  - Greatly simplified riscv_register_types function, we now only
    override a few specific cases, as a result the quad FP union type
    has been removed.  I would expect this to be handled through
    target descriptions as/when we add quad support.

  - Added docs and NEWS entries as suggested by Pedro.

Everything else is unchanged.

I'm proposing to merge this version if everyone is happy with it.

Thanks,
Andrew

--

gdb/riscv: Add target description support

This commit adds target description support for riscv.

I've used the split feature approach for specifying the architectural
features, and the CSR feature is auto-generated from the riscv-opc.h
header file.

If the target doesn't provide a suitable target description then GDB
will build one by looking at the bfd headers.

This commit does not implement target description creation for the
Linux or FreeBSD native targets, both of these will need to add
read_description methods into their respective target classes, which
probe the target features, and then call
riscv_create_target_description to build a suitable target
description.  Until this is done Linux and FreeBSD will get the same
default target description based on the bfd that bare-metal targets
get.

I've only added feature descriptions for 32 and 64 bit registers, 128
bit registers (for RISC-V) are not supported in the reset of GDB yet.

This commit removes the special reading of the MISA register in order
to establish the target features, this was only used for figuring out
the f-register size, and even that wasn't done consistently.  We now
rely on the target to tell us what size of registers it has (or look
in the BFD as a last resort).  The result of this is that we should
now support RV64 targets with 32-bit float, though I have not
extensively tested this combination yet.

	* Makefile.in (ALL_TARGET_OBS): Add arch/riscv.o.
	(HFILES_NO_SRCDIR): Add arch/riscv.h.
	* arch/riscv.c: New file.
	* arch/riscv.h: New file.
	* configure.tgt: Add cpu_obs list of riscv, move riscv-tdep.o into
	this list, and add arch/riscv.o.
	* features/Makefile: Add riscv features.
	* features/riscv/32bit-cpu.c: New file.
	* features/riscv/32bit-cpu.xml: New file.
	* features/riscv/32bit-csr.c: New file.
	* features/riscv/32bit-csr.xml: New file.
	* features/riscv/32bit-fpu.c: New file.
	* features/riscv/32bit-fpu.xml: New file.
	* features/riscv/64bit-cpu.c: New file.
	* features/riscv/64bit-cpu.xml: New file.
	* features/riscv/64bit-csr.c: New file.
	* features/riscv/64bit-csr.xml: New file.
	* features/riscv/64bit-fpu.c: New file.
	* features/riscv/64bit-fpu.xml: New file.
	* features/riscv/rebuild-csr-xml.sh: New file.
	* riscv-tdep.c: Add 'arch/riscv.h' include.
	(riscv_gdb_reg_names): Delete.
	(csr_reggroup): New global.
	(struct riscv_register_alias): Delete.
	(struct riscv_register_feature): New structure.
	(riscv_register_aliases): Delete.
	(riscv_xreg_feature): New global.
	(riscv_freg_feature): New global.
	(riscv_virtual_feature): New global.
	(riscv_csr_feature): New global.
	(riscv_create_csr_aliases): New function.
	(riscv_read_misa_reg): Delete.
	(riscv_has_feature): Delete.
	(riscv_isa_xlen): Simplify, just return cached xlen.
	(riscv_isa_flen): Simplify, just return cached flen.
	(riscv_has_fp_abi): Update for changes in struct gdbarch_tdep.
	(riscv_register_name): Update to make use of tdesc_register_name.
	Look up xreg and freg names in the new globals riscv_xreg_feature
	and riscv_freg_feature.  Don't supply csr aliases here.
	(riscv_fpreg_q_type): Delete.
	(riscv_register_type): Use tdesc_register_type in almost all
	cases, override the returned type in a few specific cases only.
	(riscv_print_one_register_info): Handle errors reading registers.
	(riscv_register_reggroup_p): Use tdesc_register_in_reggroup_p for
	registers that are otherwise unknown to GDB.  Also check the
	csr_reggroup.
	(riscv_print_registers_info): Remove assert about upper register
	number, and use gdbarch_register_reggroup_p instead of
	short-cutting.
	(riscv_find_default_target_description): New function.
	(riscv_check_tdesc_feature): New function.
	(riscv_add_reggroups): New function.
	(riscv_setup_register_aliases): New function.
	(riscv_init_reggroups): New function.
	(_initialize_riscv_tdep): Add calls to setup CSR aliases, and
	setup register groups.  Register new riscv debug variable.
	* riscv-tdep.h: Add 'arch/riscv.h' include.
	(struct gdbarch_tdep): Remove abi union, and add
	riscv_gdbarch_features field.  Remove cached quad floating point
	type, and provide initialisation for double type field.
	* target-descriptions.c (maint_print_c_tdesc_cmd): Add riscv to
	the list of targets using the feature based target descriptions.
	* NEWS: Mention target description support.

gdb/doc/ChangeLog:

	* gdb.texinfo (Standard Target Features): Add RISC-V Features
	sub-section.
---
 gdb/ChangeLog                         |  66 +++
 gdb/Makefile.in                       |   2 +
 gdb/NEWS                              |   2 +
 gdb/arch/riscv.c                      |  69 +++
 gdb/arch/riscv.h                      |  64 +++
 gdb/configure.tgt                     |   9 +-
 gdb/doc/ChangeLog                     |   5 +
 gdb/doc/gdb.texinfo                   |  36 ++
 gdb/features/Makefile                 |  11 +
 gdb/features/riscv/32bit-cpu.c        |  46 ++
 gdb/features/riscv/32bit-cpu.xml      |  43 ++
 gdb/features/riscv/32bit-csr.c        | 253 ++++++++++
 gdb/features/riscv/32bit-csr.xml      | 250 ++++++++++
 gdb/features/riscv/32bit-fpu.c        |  48 ++
 gdb/features/riscv/32bit-fpu.xml      |  46 ++
 gdb/features/riscv/64bit-cpu.c        |  46 ++
 gdb/features/riscv/64bit-cpu.xml      |  43 ++
 gdb/features/riscv/64bit-csr.c        | 253 ++++++++++
 gdb/features/riscv/64bit-csr.xml      | 250 ++++++++++
 gdb/features/riscv/64bit-fpu.c        |  56 +++
 gdb/features/riscv/64bit-fpu.xml      |  52 ++
 gdb/features/riscv/rebuild-csr-xml.sh |  29 ++
 gdb/riscv-tdep.c                      | 888 ++++++++++++++++++++--------------
 gdb/riscv-tdep.h                      |  29 +-
 gdb/target-descriptions.c             |   1 +
 25 files changed, 2220 insertions(+), 377 deletions(-)
 create mode 100644 gdb/arch/riscv.c
 create mode 100644 gdb/arch/riscv.h
 create mode 100644 gdb/features/riscv/32bit-cpu.c
 create mode 100644 gdb/features/riscv/32bit-cpu.xml
 create mode 100644 gdb/features/riscv/32bit-csr.c
 create mode 100644 gdb/features/riscv/32bit-csr.xml
 create mode 100644 gdb/features/riscv/32bit-fpu.c
 create mode 100644 gdb/features/riscv/32bit-fpu.xml
 create mode 100644 gdb/features/riscv/64bit-cpu.c
 create mode 100644 gdb/features/riscv/64bit-cpu.xml
 create mode 100644 gdb/features/riscv/64bit-csr.c
 create mode 100644 gdb/features/riscv/64bit-csr.xml
 create mode 100644 gdb/features/riscv/64bit-fpu.c
 create mode 100644 gdb/features/riscv/64bit-fpu.xml
 create mode 100755 gdb/features/riscv/rebuild-csr-xml.sh

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6f74911a775..0b8c13905be 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -666,6 +666,7 @@ ALL_TARGET_OBS = \
 	arch/arm-linux.o \
 	arch/i386.o \
 	arch/ppc-linux-common.o \
+	arch/riscv.o \
 	arm-bsd-tdep.o \
 	arm-fbsd-tdep.o \
 	arm-linux-tdep.o \
@@ -1417,6 +1418,7 @@ HFILES_NO_SRCDIR = \
 	arch/i386.h \
 	arch/ppc-linux-common.h \
 	arch/ppc-linux-tdesc.h \
+	arch/riscv.h \
 	cli/cli-cmds.h \
 	cli/cli-decode.h \
 	cli/cli-script.h \
diff --git a/gdb/NEWS b/gdb/NEWS
index ff9b192a384..50856239051 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -38,6 +38,8 @@
   requires the use of a keyword.  Selecting a frame by level is
   unchanged.  The MI comment "-stack-select-frame" is unchanged.
 
+* The RISC-V target now supports target descriptions.
+
 * New targets
 
   NXP S12Z		s12z-*-elf
diff --git a/gdb/arch/riscv.c b/gdb/arch/riscv.c
new file mode 100644
index 00000000000..ca2238d5d70
--- /dev/null
+++ b/gdb/arch/riscv.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+#include "riscv.h"
+#include <stdlib.h>
+
+#include "../features/riscv/32bit-cpu.c"
+#include "../features/riscv/64bit-cpu.c"
+#include "../features/riscv/32bit-fpu.c"
+#include "../features/riscv/64bit-fpu.c"
+
+/* See arch/riscv.h.  */
+
+target_desc *
+riscv_create_target_description (struct riscv_gdbarch_features features)
+{
+  target_desc *tdesc = allocate_target_description ();
+
+#ifndef IN_PROCESS_AGENT
+  std::string arch_name = "riscv";
+
+  if (features.xlen == 4)
+    arch_name.append (":rv32i");
+  else if (features.xlen == 8)
+    arch_name.append (":rv64i");
+  else if (features.xlen == 16)
+    arch_name.append (":rv128i");
+
+  if (features.flen == 4)
+    arch_name.append ("f");
+  else if (features.flen == 8)
+    arch_name.append ("d");
+  else if (features.flen == 16)
+    arch_name.append ("q");
+
+  set_tdesc_architecture (tdesc, arch_name.c_str ());
+#endif
+
+  long regnum = 0;
+
+  /* For now we only support creating 32-bit or 64-bit x-registers.  */
+  if (features.xlen == 4)
+    regnum = create_feature_riscv_32bit_cpu (tdesc, regnum);
+  else if (features.xlen == 8)
+    regnum = create_feature_riscv_64bit_cpu (tdesc, regnum);
+
+  /* For now we only support creating 32-bit or 64-bit f-registers.  */
+  if (features.flen == 4)
+    regnum = create_feature_riscv_32bit_fpu (tdesc, regnum);
+  else if (features.flen == 8)
+    regnum = create_feature_riscv_64bit_fpu (tdesc, regnum);
+
+  return tdesc;
+}
diff --git a/gdb/arch/riscv.h b/gdb/arch/riscv.h
new file mode 100644
index 00000000000..007944019a9
--- /dev/null
+++ b/gdb/arch/riscv.h
@@ -0,0 +1,64 @@
+/* Common target-dependent functionality for RISC-V
+
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef ARCH_RISCV_H
+#define ARCH_RISCV_H
+
+#include "common/tdesc.h"
+
+/* The set of RISC-V architectural features that we track that impact how
+   we configure the actual gdbarch instance.  We hold one of these in the
+   gdbarch_tdep structure, and use it to distinguish between different
+   RISC-V gdbarch instances.
+
+   The information in here ideally comes from the target description,
+   however, if the target doesn't provide a target description then we will
+   create a default target description by first populating one of these
+   based on what we know about the binary being executed, and using that to
+   drive default target description creation.  */
+
+struct riscv_gdbarch_features
+{
+  /* The size of the x-registers in bytes.  This is either 4 (RV32), 8
+     (RV64), or 16 (RV128).  No other value is valid.  Initialise to the
+     invalid 0 value so we can spot if one of these is used
+     uninitialised.  */
+  int xlen = 0;
+
+  /* The size of the f-registers in bytes.  This is either 4 (RV32), 8
+     (RV64), or 16 (RV128).  This can also hold the value 0 to indicate
+     that there are no f-registers.  No other value is valid.  */
+  int flen = 0;
+
+  /* This indicates if hardware floating point abi is in use.  If the FLEN
+     field is 0 then this value _must_ be false.  If the FLEN field is
+     non-zero and this field is false then this indicates the target has
+     floating point registers, but is still using the soft-float abi.  If
+     this field is true then the hardware floating point abi is in use, and
+     values are passed in f-registers matching the size of FLEN.  */
+  bool hw_float_abi = false;
+};
+
+/* Create and return a target description that is compatible with
+   FEATURES.  */
+
+target_desc *riscv_create_target_description
+	(struct riscv_gdbarch_features features);
+
+#endif /* ARCH_RISCV_H */
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index e1f5e31f547..9b646fa1a21 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -81,6 +81,9 @@ ia64*-*-*)
 	cpu_obs="ia64-tdep.o"
 	;;
 
+riscv*-*-*)
+	cpu_obs="riscv-tdep.o arch/riscv.o";;
+
 x86_64-*-*)
 	cpu_obs="${i386_tobjs} ${amd64_tobjs}";;
 
@@ -532,18 +535,18 @@ s390*-*-linux*)
 
 riscv*-*-freebsd*)
 	# Target: FreeBSD/riscv
-	gdb_target_obs="riscv-fbsd-tdep.o riscv-tdep.o"
+	gdb_target_obs="riscv-fbsd-tdep.o"
 	;;
 
 riscv*-*-linux*)
 	# Target: Linux/RISC-V
-	gdb_target_obs="riscv-linux-tdep.o riscv-tdep.o glibc-tdep.o \
+	gdb_target_obs="riscv-linux-tdep.o glibc-tdep.o \
  			linux-tdep.o solib-svr4.o symfile-mem.o linux-record.o"
 	;;
 
 riscv*-*-*)
 	# Target: RISC-V architecture
-	gdb_target_obs="riscv-tdep.o"
+	gdb_target_obs=""
 	;;
 
 rl78-*-elf)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 944a2c43837..802ec3f8330 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -42916,6 +42916,7 @@
 * Nios II Features::
 * OpenRISC 1000 Features::
 * PowerPC Features::
+* RISC-V Features::
 * S/390 and System z Features::
 * Sparc Features::
 * TIC6x Features::
@@ -43306,6 +43307,41 @@
 The @samp{org.gnu.gdb.power.htm.tar} feature is optional.  It should
 contain the 64-bit checkpointed register @samp{ctar}.
 
+
+@node RISC-V Features
+@subsection RISC-V Features
+@cindex target descriptions, RISC-V Features
+
+The @samp{org.gnu.gdb.riscv.cpu} feature is required for RISC-V
+targets.  It should contain the registers @samp{x0} through
+@samp{x31}, and @samp{pc}.  Either the architectural names (@samp{x0},
+@samp{x1}, etc) can be used, or the ABI names (@samp{zero}, @samp{ra},
+etc).
+
+The @samp{org.gnu.gdb.riscv.fpu} feature is optional.  If present it
+should contains registers @samp{f0} through @samp{f31}, @samp{fflags},
+@samp{frm}, and @samp{fcsr}.  As with the cpu feature either the
+architectural register names, or the ABI names can be used.
+
+The @samp{org.gnu.gdb.riscv.virtual} feature is optional.  If present
+it should contain registers that are not backed by real registers on
+the target but are instead virtual, where the register value is
+derived from other target state.  In many ways these are like GDBs
+pseudo-registers, except implemented by the target.  Currently the
+only register expected in this set is the one byte @samp{priv}
+register that contains the targets privilege level in the least
+significant two bits.
+
+The @samp{org.gnu.gdb.riscv.csr} feature is optional.  If present it
+should contain all of the targets standard CSRs.  Standard CSRs are
+those defined in the RISC-V specification documents.  There is some
+overlap between this feature and the fpu feature; the @samp{fflags},
+@samp{frm}, and @samp{fcsr} registers could be in either feature.  The
+expectation is that these registers will be in the fpu feature if the
+target has floating point hardware, but can be moved into the csr
+feature if the target has the floating point control registers, but no
+other floating point hardware.
+
 @node S/390 and System z Features
 @subsection S/390 and System z Features
 @cindex target descriptions, S/390 features
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 150fef23f0b..ff2e57c65fd 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -207,6 +207,7 @@ GDB = false
 #Targets which use feature based target descriptions.
 aarch64-feature = 1
 i386-feature = 1
+riscv-feature = 1
 tic6x-feature = 1
 
 all: $(OUTPUTS)
@@ -242,6 +243,12 @@ FEATURE_XMLFILES = aarch64-core.xml \
 	i386/64bit-pkeys.xml \
 	i386/64bit-sse.xml \
 	i386/x32-core.xml \
+	riscv/32bit-cpu.xml \
+	riscv/32bit-csr.xml \
+	riscv/32bit-fpu.xml \
+	riscv/64bit-cpu.xml \
+	riscv/64bit-csr.xml \
+	riscv/64bit-fpu.xml \
 	tic6x-c6xp.xml \
 	tic6x-core.xml \
 	tic6x-gp.xml
@@ -339,6 +346,10 @@ $(outdir)/i386/x32-avx-avx512-linux.dat: i386/x32-core.xml i386/64bit-avx.xml \
 			       i386/64bit-avx512.xml i386/64bit-linux.xml \
 			       i386/64bit-segments.xml
 
+# Regenerate RISC-V CSR feature lists.
+riscv/32bit-csr.xml riscv/64bit-csr.xml: ../../include/opcode/riscv-opc.h
+	./riscv/rebuild-csr-xml.sh ../../include/opcode/riscv-opc.h ./riscv
+
 # 'all' doesn't build the C files, so don't delete them in 'clean'
 # either.
 clean-cfiles:
diff --git a/gdb/features/riscv/32bit-cpu.c b/gdb/features/riscv/32bit-cpu.c
new file mode 100644
index 00000000000..64686db5cdd
--- /dev/null
+++ b/gdb/features/riscv/32bit-cpu.c
@@ -0,0 +1,46 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 32bit-cpu.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_32bit_cpu (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.cpu");
+  tdesc_create_reg (feature, "zero", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "ra", regnum++, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "sp", regnum++, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "gp", regnum++, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "tp", regnum++, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "t0", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fp", regnum++, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "s1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a0", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a7", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s7", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s8", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s9", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s10", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s11", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pc", regnum++, 1, NULL, 32, "code_ptr");
+  return regnum;
+}
diff --git a/gdb/features/riscv/32bit-cpu.xml b/gdb/features/riscv/32bit-cpu.xml
new file mode 100644
index 00000000000..c02f86c0b03
--- /dev/null
+++ b/gdb/features/riscv/32bit-cpu.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.cpu">
+  <reg name="zero" bitsize="32" type="int"/>
+  <reg name="ra" bitsize="32" type="code_ptr"/>
+  <reg name="sp" bitsize="32" type="data_ptr"/>
+  <reg name="gp" bitsize="32" type="data_ptr"/>
+  <reg name="tp" bitsize="32" type="data_ptr"/>
+  <reg name="t0" bitsize="32" type="int"/>
+  <reg name="t1" bitsize="32" type="int"/>
+  <reg name="t2" bitsize="32" type="int"/>
+  <reg name="fp" bitsize="32" type="data_ptr"/>
+  <reg name="s1" bitsize="32" type="int"/>
+  <reg name="a0" bitsize="32" type="int"/>
+  <reg name="a1" bitsize="32" type="int"/>
+  <reg name="a2" bitsize="32" type="int"/>
+  <reg name="a3" bitsize="32" type="int"/>
+  <reg name="a4" bitsize="32" type="int"/>
+  <reg name="a5" bitsize="32" type="int"/>
+  <reg name="a6" bitsize="32" type="int"/>
+  <reg name="a7" bitsize="32" type="int"/>
+  <reg name="s2" bitsize="32" type="int"/>
+  <reg name="s3" bitsize="32" type="int"/>
+  <reg name="s4" bitsize="32" type="int"/>
+  <reg name="s5" bitsize="32" type="int"/>
+  <reg name="s6" bitsize="32" type="int"/>
+  <reg name="s7" bitsize="32" type="int"/>
+  <reg name="s8" bitsize="32" type="int"/>
+  <reg name="s9" bitsize="32" type="int"/>
+  <reg name="s10" bitsize="32" type="int"/>
+  <reg name="s11" bitsize="32" type="int"/>
+  <reg name="t3" bitsize="32" type="int"/>
+  <reg name="t4" bitsize="32" type="int"/>
+  <reg name="t5" bitsize="32" type="int"/>
+  <reg name="t6" bitsize="32" type="int"/>
+  <reg name="pc" bitsize="32" type="code_ptr"/>
+</feature>
diff --git a/gdb/features/riscv/32bit-csr.c b/gdb/features/riscv/32bit-csr.c
new file mode 100644
index 00000000000..711e958ddae
--- /dev/null
+++ b/gdb/features/riscv/32bit-csr.c
@@ -0,0 +1,253 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 32bit-csr.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_32bit_csr (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.csr");
+  tdesc_create_reg (feature, "ustatus", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "uie", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "utvec", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "uscratch", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "uepc", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "ucause", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "utval", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "uip", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "frm", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fcsr", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "cycle", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "time", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "instret", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter7", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter8", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter9", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter10", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter11", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter12", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter13", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter14", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter15", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter16", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter17", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter18", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter19", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter20", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter21", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter22", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter23", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter24", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter25", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter26", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter27", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter28", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter29", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter30", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter31", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "cycleh", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "timeh", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "instreth", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter3h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter4h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter5h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter6h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter7h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter8h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter9h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter10h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter11h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter12h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter13h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter14h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter15h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter16h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter17h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter18h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter19h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter20h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter21h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter22h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter23h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter24h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter25h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter26h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter27h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter28h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter29h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter30h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter31h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sstatus", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sedeleg", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sideleg", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sie", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "stvec", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "scounteren", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sscratch", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sepc", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "scause", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "stval", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sip", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "satp", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mvendorid", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "marchid", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mimpid", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhartid", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mstatus", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "misa", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "medeleg", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mideleg", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mie", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mtvec", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mcounteren", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mscratch", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mepc", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mcause", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mtval", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mip", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpcfg0", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpcfg1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpcfg2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpcfg3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr0", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr7", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr8", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr9", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr10", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr11", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr12", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr13", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr14", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr15", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mcycle", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "minstret", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter7", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter8", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter9", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter10", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter11", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter12", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter13", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter14", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter15", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter16", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter17", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter18", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter19", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter20", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter21", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter22", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter23", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter24", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter25", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter26", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter27", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter28", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter29", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter30", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter31", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mcycleh", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "minstreth", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter3h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter4h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter5h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter6h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter7h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter8h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter9h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter10h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter11h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter12h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter13h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter14h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter15h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter16h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter17h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter18h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter19h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter20h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter21h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter22h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter23h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter24h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter25h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter26h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter27h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter28h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter29h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter30h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter31h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent7", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent8", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent9", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent10", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent11", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent12", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent13", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent14", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent15", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent16", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent17", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent18", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent19", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent20", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent21", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent22", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent23", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent24", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent25", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent26", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent27", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent28", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent29", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent30", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent31", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "tselect", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "tdata1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "tdata2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "tdata3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "dcsr", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "dpc", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "dscratch", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hstatus", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hedeleg", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hideleg", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hie", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "htvec", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hscratch", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hepc", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hcause", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hbadaddr", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hip", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mbase", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mbound", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mibase", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mibound", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mdbase", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mdbound", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mucounteren", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mscounteren", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhcounteren", regnum++, 1, NULL, 32, "int");
+  return regnum;
+}
diff --git a/gdb/features/riscv/32bit-csr.xml b/gdb/features/riscv/32bit-csr.xml
new file mode 100644
index 00000000000..4aea9e657b9
--- /dev/null
+++ b/gdb/features/riscv/32bit-csr.xml
@@ -0,0 +1,250 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.csr">
+  <reg name="ustatus" bitsize="32"/>
+  <reg name="uie" bitsize="32"/>
+  <reg name="utvec" bitsize="32"/>
+  <reg name="uscratch" bitsize="32"/>
+  <reg name="uepc" bitsize="32"/>
+  <reg name="ucause" bitsize="32"/>
+  <reg name="utval" bitsize="32"/>
+  <reg name="uip" bitsize="32"/>
+  <reg name="fflags" bitsize="32"/>
+  <reg name="frm" bitsize="32"/>
+  <reg name="fcsr" bitsize="32"/>
+  <reg name="cycle" bitsize="32"/>
+  <reg name="time" bitsize="32"/>
+  <reg name="instret" bitsize="32"/>
+  <reg name="hpmcounter3" bitsize="32"/>
+  <reg name="hpmcounter4" bitsize="32"/>
+  <reg name="hpmcounter5" bitsize="32"/>
+  <reg name="hpmcounter6" bitsize="32"/>
+  <reg name="hpmcounter7" bitsize="32"/>
+  <reg name="hpmcounter8" bitsize="32"/>
+  <reg name="hpmcounter9" bitsize="32"/>
+  <reg name="hpmcounter10" bitsize="32"/>
+  <reg name="hpmcounter11" bitsize="32"/>
+  <reg name="hpmcounter12" bitsize="32"/>
+  <reg name="hpmcounter13" bitsize="32"/>
+  <reg name="hpmcounter14" bitsize="32"/>
+  <reg name="hpmcounter15" bitsize="32"/>
+  <reg name="hpmcounter16" bitsize="32"/>
+  <reg name="hpmcounter17" bitsize="32"/>
+  <reg name="hpmcounter18" bitsize="32"/>
+  <reg name="hpmcounter19" bitsize="32"/>
+  <reg name="hpmcounter20" bitsize="32"/>
+  <reg name="hpmcounter21" bitsize="32"/>
+  <reg name="hpmcounter22" bitsize="32"/>
+  <reg name="hpmcounter23" bitsize="32"/>
+  <reg name="hpmcounter24" bitsize="32"/>
+  <reg name="hpmcounter25" bitsize="32"/>
+  <reg name="hpmcounter26" bitsize="32"/>
+  <reg name="hpmcounter27" bitsize="32"/>
+  <reg name="hpmcounter28" bitsize="32"/>
+  <reg name="hpmcounter29" bitsize="32"/>
+  <reg name="hpmcounter30" bitsize="32"/>
+  <reg name="hpmcounter31" bitsize="32"/>
+  <reg name="cycleh" bitsize="32"/>
+  <reg name="timeh" bitsize="32"/>
+  <reg name="instreth" bitsize="32"/>
+  <reg name="hpmcounter3h" bitsize="32"/>
+  <reg name="hpmcounter4h" bitsize="32"/>
+  <reg name="hpmcounter5h" bitsize="32"/>
+  <reg name="hpmcounter6h" bitsize="32"/>
+  <reg name="hpmcounter7h" bitsize="32"/>
+  <reg name="hpmcounter8h" bitsize="32"/>
+  <reg name="hpmcounter9h" bitsize="32"/>
+  <reg name="hpmcounter10h" bitsize="32"/>
+  <reg name="hpmcounter11h" bitsize="32"/>
+  <reg name="hpmcounter12h" bitsize="32"/>
+  <reg name="hpmcounter13h" bitsize="32"/>
+  <reg name="hpmcounter14h" bitsize="32"/>
+  <reg name="hpmcounter15h" bitsize="32"/>
+  <reg name="hpmcounter16h" bitsize="32"/>
+  <reg name="hpmcounter17h" bitsize="32"/>
+  <reg name="hpmcounter18h" bitsize="32"/>
+  <reg name="hpmcounter19h" bitsize="32"/>
+  <reg name="hpmcounter20h" bitsize="32"/>
+  <reg name="hpmcounter21h" bitsize="32"/>
+  <reg name="hpmcounter22h" bitsize="32"/>
+  <reg name="hpmcounter23h" bitsize="32"/>
+  <reg name="hpmcounter24h" bitsize="32"/>
+  <reg name="hpmcounter25h" bitsize="32"/>
+  <reg name="hpmcounter26h" bitsize="32"/>
+  <reg name="hpmcounter27h" bitsize="32"/>
+  <reg name="hpmcounter28h" bitsize="32"/>
+  <reg name="hpmcounter29h" bitsize="32"/>
+  <reg name="hpmcounter30h" bitsize="32"/>
+  <reg name="hpmcounter31h" bitsize="32"/>
+  <reg name="sstatus" bitsize="32"/>
+  <reg name="sedeleg" bitsize="32"/>
+  <reg name="sideleg" bitsize="32"/>
+  <reg name="sie" bitsize="32"/>
+  <reg name="stvec" bitsize="32"/>
+  <reg name="scounteren" bitsize="32"/>
+  <reg name="sscratch" bitsize="32"/>
+  <reg name="sepc" bitsize="32"/>
+  <reg name="scause" bitsize="32"/>
+  <reg name="stval" bitsize="32"/>
+  <reg name="sip" bitsize="32"/>
+  <reg name="satp" bitsize="32"/>
+  <reg name="mvendorid" bitsize="32"/>
+  <reg name="marchid" bitsize="32"/>
+  <reg name="mimpid" bitsize="32"/>
+  <reg name="mhartid" bitsize="32"/>
+  <reg name="mstatus" bitsize="32"/>
+  <reg name="misa" bitsize="32"/>
+  <reg name="medeleg" bitsize="32"/>
+  <reg name="mideleg" bitsize="32"/>
+  <reg name="mie" bitsize="32"/>
+  <reg name="mtvec" bitsize="32"/>
+  <reg name="mcounteren" bitsize="32"/>
+  <reg name="mscratch" bitsize="32"/>
+  <reg name="mepc" bitsize="32"/>
+  <reg name="mcause" bitsize="32"/>
+  <reg name="mtval" bitsize="32"/>
+  <reg name="mip" bitsize="32"/>
+  <reg name="pmpcfg0" bitsize="32"/>
+  <reg name="pmpcfg1" bitsize="32"/>
+  <reg name="pmpcfg2" bitsize="32"/>
+  <reg name="pmpcfg3" bitsize="32"/>
+  <reg name="pmpaddr0" bitsize="32"/>
+  <reg name="pmpaddr1" bitsize="32"/>
+  <reg name="pmpaddr2" bitsize="32"/>
+  <reg name="pmpaddr3" bitsize="32"/>
+  <reg name="pmpaddr4" bitsize="32"/>
+  <reg name="pmpaddr5" bitsize="32"/>
+  <reg name="pmpaddr6" bitsize="32"/>
+  <reg name="pmpaddr7" bitsize="32"/>
+  <reg name="pmpaddr8" bitsize="32"/>
+  <reg name="pmpaddr9" bitsize="32"/>
+  <reg name="pmpaddr10" bitsize="32"/>
+  <reg name="pmpaddr11" bitsize="32"/>
+  <reg name="pmpaddr12" bitsize="32"/>
+  <reg name="pmpaddr13" bitsize="32"/>
+  <reg name="pmpaddr14" bitsize="32"/>
+  <reg name="pmpaddr15" bitsize="32"/>
+  <reg name="mcycle" bitsize="32"/>
+  <reg name="minstret" bitsize="32"/>
+  <reg name="mhpmcounter3" bitsize="32"/>
+  <reg name="mhpmcounter4" bitsize="32"/>
+  <reg name="mhpmcounter5" bitsize="32"/>
+  <reg name="mhpmcounter6" bitsize="32"/>
+  <reg name="mhpmcounter7" bitsize="32"/>
+  <reg name="mhpmcounter8" bitsize="32"/>
+  <reg name="mhpmcounter9" bitsize="32"/>
+  <reg name="mhpmcounter10" bitsize="32"/>
+  <reg name="mhpmcounter11" bitsize="32"/>
+  <reg name="mhpmcounter12" bitsize="32"/>
+  <reg name="mhpmcounter13" bitsize="32"/>
+  <reg name="mhpmcounter14" bitsize="32"/>
+  <reg name="mhpmcounter15" bitsize="32"/>
+  <reg name="mhpmcounter16" bitsize="32"/>
+  <reg name="mhpmcounter17" bitsize="32"/>
+  <reg name="mhpmcounter18" bitsize="32"/>
+  <reg name="mhpmcounter19" bitsize="32"/>
+  <reg name="mhpmcounter20" bitsize="32"/>
+  <reg name="mhpmcounter21" bitsize="32"/>
+  <reg name="mhpmcounter22" bitsize="32"/>
+  <reg name="mhpmcounter23" bitsize="32"/>
+  <reg name="mhpmcounter24" bitsize="32"/>
+  <reg name="mhpmcounter25" bitsize="32"/>
+  <reg name="mhpmcounter26" bitsize="32"/>
+  <reg name="mhpmcounter27" bitsize="32"/>
+  <reg name="mhpmcounter28" bitsize="32"/>
+  <reg name="mhpmcounter29" bitsize="32"/>
+  <reg name="mhpmcounter30" bitsize="32"/>
+  <reg name="mhpmcounter31" bitsize="32"/>
+  <reg name="mcycleh" bitsize="32"/>
+  <reg name="minstreth" bitsize="32"/>
+  <reg name="mhpmcounter3h" bitsize="32"/>
+  <reg name="mhpmcounter4h" bitsize="32"/>
+  <reg name="mhpmcounter5h" bitsize="32"/>
+  <reg name="mhpmcounter6h" bitsize="32"/>
+  <reg name="mhpmcounter7h" bitsize="32"/>
+  <reg name="mhpmcounter8h" bitsize="32"/>
+  <reg name="mhpmcounter9h" bitsize="32"/>
+  <reg name="mhpmcounter10h" bitsize="32"/>
+  <reg name="mhpmcounter11h" bitsize="32"/>
+  <reg name="mhpmcounter12h" bitsize="32"/>
+  <reg name="mhpmcounter13h" bitsize="32"/>
+  <reg name="mhpmcounter14h" bitsize="32"/>
+  <reg name="mhpmcounter15h" bitsize="32"/>
+  <reg name="mhpmcounter16h" bitsize="32"/>
+  <reg name="mhpmcounter17h" bitsize="32"/>
+  <reg name="mhpmcounter18h" bitsize="32"/>
+  <reg name="mhpmcounter19h" bitsize="32"/>
+  <reg name="mhpmcounter20h" bitsize="32"/>
+  <reg name="mhpmcounter21h" bitsize="32"/>
+  <reg name="mhpmcounter22h" bitsize="32"/>
+  <reg name="mhpmcounter23h" bitsize="32"/>
+  <reg name="mhpmcounter24h" bitsize="32"/>
+  <reg name="mhpmcounter25h" bitsize="32"/>
+  <reg name="mhpmcounter26h" bitsize="32"/>
+  <reg name="mhpmcounter27h" bitsize="32"/>
+  <reg name="mhpmcounter28h" bitsize="32"/>
+  <reg name="mhpmcounter29h" bitsize="32"/>
+  <reg name="mhpmcounter30h" bitsize="32"/>
+  <reg name="mhpmcounter31h" bitsize="32"/>
+  <reg name="mhpmevent3" bitsize="32"/>
+  <reg name="mhpmevent4" bitsize="32"/>
+  <reg name="mhpmevent5" bitsize="32"/>
+  <reg name="mhpmevent6" bitsize="32"/>
+  <reg name="mhpmevent7" bitsize="32"/>
+  <reg name="mhpmevent8" bitsize="32"/>
+  <reg name="mhpmevent9" bitsize="32"/>
+  <reg name="mhpmevent10" bitsize="32"/>
+  <reg name="mhpmevent11" bitsize="32"/>
+  <reg name="mhpmevent12" bitsize="32"/>
+  <reg name="mhpmevent13" bitsize="32"/>
+  <reg name="mhpmevent14" bitsize="32"/>
+  <reg name="mhpmevent15" bitsize="32"/>
+  <reg name="mhpmevent16" bitsize="32"/>
+  <reg name="mhpmevent17" bitsize="32"/>
+  <reg name="mhpmevent18" bitsize="32"/>
+  <reg name="mhpmevent19" bitsize="32"/>
+  <reg name="mhpmevent20" bitsize="32"/>
+  <reg name="mhpmevent21" bitsize="32"/>
+  <reg name="mhpmevent22" bitsize="32"/>
+  <reg name="mhpmevent23" bitsize="32"/>
+  <reg name="mhpmevent24" bitsize="32"/>
+  <reg name="mhpmevent25" bitsize="32"/>
+  <reg name="mhpmevent26" bitsize="32"/>
+  <reg name="mhpmevent27" bitsize="32"/>
+  <reg name="mhpmevent28" bitsize="32"/>
+  <reg name="mhpmevent29" bitsize="32"/>
+  <reg name="mhpmevent30" bitsize="32"/>
+  <reg name="mhpmevent31" bitsize="32"/>
+  <reg name="tselect" bitsize="32"/>
+  <reg name="tdata1" bitsize="32"/>
+  <reg name="tdata2" bitsize="32"/>
+  <reg name="tdata3" bitsize="32"/>
+  <reg name="dcsr" bitsize="32"/>
+  <reg name="dpc" bitsize="32"/>
+  <reg name="dscratch" bitsize="32"/>
+  <reg name="hstatus" bitsize="32"/>
+  <reg name="hedeleg" bitsize="32"/>
+  <reg name="hideleg" bitsize="32"/>
+  <reg name="hie" bitsize="32"/>
+  <reg name="htvec" bitsize="32"/>
+  <reg name="hscratch" bitsize="32"/>
+  <reg name="hepc" bitsize="32"/>
+  <reg name="hcause" bitsize="32"/>
+  <reg name="hbadaddr" bitsize="32"/>
+  <reg name="hip" bitsize="32"/>
+  <reg name="mbase" bitsize="32"/>
+  <reg name="mbound" bitsize="32"/>
+  <reg name="mibase" bitsize="32"/>
+  <reg name="mibound" bitsize="32"/>
+  <reg name="mdbase" bitsize="32"/>
+  <reg name="mdbound" bitsize="32"/>
+  <reg name="mucounteren" bitsize="32"/>
+  <reg name="mscounteren" bitsize="32"/>
+  <reg name="mhcounteren" bitsize="32"/>
+</feature>
diff --git a/gdb/features/riscv/32bit-fpu.c b/gdb/features/riscv/32bit-fpu.c
new file mode 100644
index 00000000000..22e80d640e5
--- /dev/null
+++ b/gdb/features/riscv/32bit-fpu.c
@@ -0,0 +1,48 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 32bit-fpu.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_32bit_fpu (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.fpu");
+  tdesc_create_reg (feature, "ft0", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft1", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft2", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft3", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft4", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft5", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft6", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft7", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs0", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs1", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa0", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa1", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa2", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa3", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa4", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa5", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa6", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa7", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs2", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs3", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs4", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs5", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs6", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs7", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs8", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs9", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs10", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs11", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft8", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft9", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft10", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft11", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "frm", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fcsr", regnum++, 1, NULL, 32, "int");
+  return regnum;
+}
diff --git a/gdb/features/riscv/32bit-fpu.xml b/gdb/features/riscv/32bit-fpu.xml
new file mode 100644
index 00000000000..783287d9362
--- /dev/null
+++ b/gdb/features/riscv/32bit-fpu.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.fpu">
+  <reg name="ft0" bitsize="32" type="ieee_single"/>
+  <reg name="ft1" bitsize="32" type="ieee_single"/>
+  <reg name="ft2" bitsize="32" type="ieee_single"/>
+  <reg name="ft3" bitsize="32" type="ieee_single"/>
+  <reg name="ft4" bitsize="32" type="ieee_single"/>
+  <reg name="ft5" bitsize="32" type="ieee_single"/>
+  <reg name="ft6" bitsize="32" type="ieee_single"/>
+  <reg name="ft7" bitsize="32" type="ieee_single"/>
+  <reg name="fs0" bitsize="32" type="ieee_single"/>
+  <reg name="fs1" bitsize="32" type="ieee_single"/>
+  <reg name="fa0" bitsize="32" type="ieee_single"/>
+  <reg name="fa1" bitsize="32" type="ieee_single"/>
+  <reg name="fa2" bitsize="32" type="ieee_single"/>
+  <reg name="fa3" bitsize="32" type="ieee_single"/>
+  <reg name="fa4" bitsize="32" type="ieee_single"/>
+  <reg name="fa5" bitsize="32" type="ieee_single"/>
+  <reg name="fa6" bitsize="32" type="ieee_single"/>
+  <reg name="fa7" bitsize="32" type="ieee_single"/>
+  <reg name="fs2" bitsize="32" type="ieee_single"/>
+  <reg name="fs3" bitsize="32" type="ieee_single"/>
+  <reg name="fs4" bitsize="32" type="ieee_single"/>
+  <reg name="fs5" bitsize="32" type="ieee_single"/>
+  <reg name="fs6" bitsize="32" type="ieee_single"/>
+  <reg name="fs7" bitsize="32" type="ieee_single"/>
+  <reg name="fs8" bitsize="32" type="ieee_single"/>
+  <reg name="fs9" bitsize="32" type="ieee_single"/>
+  <reg name="fs10" bitsize="32" type="ieee_single"/>
+  <reg name="fs11" bitsize="32" type="ieee_single"/>
+  <reg name="ft8" bitsize="32" type="ieee_single"/>
+  <reg name="ft9" bitsize="32" type="ieee_single"/>
+  <reg name="ft10" bitsize="32" type="ieee_single"/>
+  <reg name="ft11" bitsize="32" type="ieee_single"/>
+
+  <reg name="fflags" bitsize="32" type="int"/>
+  <reg name="frm" bitsize="32" type="int"/>
+  <reg name="fcsr" bitsize="32" type="int"/>
+</feature>
diff --git a/gdb/features/riscv/64bit-cpu.c b/gdb/features/riscv/64bit-cpu.c
new file mode 100644
index 00000000000..910089805ee
--- /dev/null
+++ b/gdb/features/riscv/64bit-cpu.c
@@ -0,0 +1,46 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 64bit-cpu.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_64bit_cpu (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.cpu");
+  tdesc_create_reg (feature, "zero", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "ra", regnum++, 1, NULL, 64, "code_ptr");
+  tdesc_create_reg (feature, "sp", regnum++, 1, NULL, 64, "data_ptr");
+  tdesc_create_reg (feature, "gp", regnum++, 1, NULL, 64, "data_ptr");
+  tdesc_create_reg (feature, "tp", regnum++, 1, NULL, 64, "data_ptr");
+  tdesc_create_reg (feature, "t0", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "fp", regnum++, 1, NULL, 64, "data_ptr");
+  tdesc_create_reg (feature, "s1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a0", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a7", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s7", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s8", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s9", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s10", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s11", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pc", regnum++, 1, NULL, 64, "code_ptr");
+  return regnum;
+}
diff --git a/gdb/features/riscv/64bit-cpu.xml b/gdb/features/riscv/64bit-cpu.xml
new file mode 100644
index 00000000000..f37d7f3ce36
--- /dev/null
+++ b/gdb/features/riscv/64bit-cpu.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.cpu">
+  <reg name="zero" bitsize="64" type="int"/>
+  <reg name="ra" bitsize="64" type="code_ptr"/>
+  <reg name="sp" bitsize="64" type="data_ptr"/>
+  <reg name="gp" bitsize="64" type="data_ptr"/>
+  <reg name="tp" bitsize="64" type="data_ptr"/>
+  <reg name="t0" bitsize="64" type="int"/>
+  <reg name="t1" bitsize="64" type="int"/>
+  <reg name="t2" bitsize="64" type="int"/>
+  <reg name="fp" bitsize="64" type="data_ptr"/>
+  <reg name="s1" bitsize="64" type="int"/>
+  <reg name="a0" bitsize="64" type="int"/>
+  <reg name="a1" bitsize="64" type="int"/>
+  <reg name="a2" bitsize="64" type="int"/>
+  <reg name="a3" bitsize="64" type="int"/>
+  <reg name="a4" bitsize="64" type="int"/>
+  <reg name="a5" bitsize="64" type="int"/>
+  <reg name="a6" bitsize="64" type="int"/>
+  <reg name="a7" bitsize="64" type="int"/>
+  <reg name="s2" bitsize="64" type="int"/>
+  <reg name="s3" bitsize="64" type="int"/>
+  <reg name="s4" bitsize="64" type="int"/>
+  <reg name="s5" bitsize="64" type="int"/>
+  <reg name="s6" bitsize="64" type="int"/>
+  <reg name="s7" bitsize="64" type="int"/>
+  <reg name="s8" bitsize="64" type="int"/>
+  <reg name="s9" bitsize="64" type="int"/>
+  <reg name="s10" bitsize="64" type="int"/>
+  <reg name="s11" bitsize="64" type="int"/>
+  <reg name="t3" bitsize="64" type="int"/>
+  <reg name="t4" bitsize="64" type="int"/>
+  <reg name="t5" bitsize="64" type="int"/>
+  <reg name="t6" bitsize="64" type="int"/>
+  <reg name="pc" bitsize="64" type="code_ptr"/>
+</feature>
diff --git a/gdb/features/riscv/64bit-csr.c b/gdb/features/riscv/64bit-csr.c
new file mode 100644
index 00000000000..7c777406254
--- /dev/null
+++ b/gdb/features/riscv/64bit-csr.c
@@ -0,0 +1,253 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 64bit-csr.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_64bit_csr (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.csr");
+  tdesc_create_reg (feature, "ustatus", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "uie", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "utvec", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "uscratch", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "uepc", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "ucause", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "utval", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "uip", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "frm", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "fcsr", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "cycle", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "time", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "instret", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter7", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter8", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter9", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter10", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter11", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter12", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter13", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter14", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter15", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter16", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter17", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter18", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter19", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter20", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter21", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter22", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter23", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter24", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter25", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter26", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter27", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter28", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter29", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter30", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter31", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "cycleh", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "timeh", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "instreth", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter3h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter4h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter5h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter6h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter7h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter8h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter9h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter10h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter11h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter12h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter13h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter14h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter15h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter16h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter17h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter18h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter19h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter20h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter21h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter22h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter23h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter24h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter25h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter26h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter27h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter28h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter29h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter30h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter31h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sstatus", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sedeleg", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sideleg", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sie", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "stvec", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "scounteren", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sscratch", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sepc", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "scause", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "stval", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sip", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "satp", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mvendorid", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "marchid", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mimpid", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhartid", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mstatus", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "misa", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "medeleg", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mideleg", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mie", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mtvec", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mcounteren", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mscratch", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mepc", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mcause", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mtval", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mip", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpcfg0", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpcfg1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpcfg2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpcfg3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr0", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr7", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr8", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr9", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr10", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr11", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr12", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr13", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr14", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr15", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mcycle", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "minstret", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter7", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter8", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter9", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter10", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter11", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter12", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter13", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter14", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter15", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter16", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter17", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter18", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter19", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter20", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter21", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter22", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter23", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter24", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter25", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter26", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter27", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter28", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter29", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter30", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter31", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mcycleh", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "minstreth", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter3h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter4h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter5h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter6h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter7h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter8h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter9h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter10h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter11h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter12h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter13h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter14h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter15h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter16h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter17h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter18h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter19h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter20h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter21h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter22h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter23h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter24h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter25h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter26h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter27h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter28h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter29h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter30h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter31h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent7", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent8", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent9", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent10", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent11", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent12", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent13", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent14", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent15", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent16", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent17", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent18", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent19", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent20", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent21", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent22", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent23", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent24", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent25", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent26", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent27", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent28", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent29", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent30", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent31", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "tselect", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "tdata1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "tdata2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "tdata3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "dcsr", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "dpc", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "dscratch", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hstatus", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hedeleg", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hideleg", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hie", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "htvec", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hscratch", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hepc", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hcause", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hbadaddr", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hip", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mbase", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mbound", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mibase", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mibound", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mdbase", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mdbound", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mucounteren", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mscounteren", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhcounteren", regnum++, 1, NULL, 64, "int");
+  return regnum;
+}
diff --git a/gdb/features/riscv/64bit-csr.xml b/gdb/features/riscv/64bit-csr.xml
new file mode 100644
index 00000000000..a3de83443a5
--- /dev/null
+++ b/gdb/features/riscv/64bit-csr.xml
@@ -0,0 +1,250 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.csr">
+  <reg name="ustatus" bitsize="64"/>
+  <reg name="uie" bitsize="64"/>
+  <reg name="utvec" bitsize="64"/>
+  <reg name="uscratch" bitsize="64"/>
+  <reg name="uepc" bitsize="64"/>
+  <reg name="ucause" bitsize="64"/>
+  <reg name="utval" bitsize="64"/>
+  <reg name="uip" bitsize="64"/>
+  <reg name="fflags" bitsize="64"/>
+  <reg name="frm" bitsize="64"/>
+  <reg name="fcsr" bitsize="64"/>
+  <reg name="cycle" bitsize="64"/>
+  <reg name="time" bitsize="64"/>
+  <reg name="instret" bitsize="64"/>
+  <reg name="hpmcounter3" bitsize="64"/>
+  <reg name="hpmcounter4" bitsize="64"/>
+  <reg name="hpmcounter5" bitsize="64"/>
+  <reg name="hpmcounter6" bitsize="64"/>
+  <reg name="hpmcounter7" bitsize="64"/>
+  <reg name="hpmcounter8" bitsize="64"/>
+  <reg name="hpmcounter9" bitsize="64"/>
+  <reg name="hpmcounter10" bitsize="64"/>
+  <reg name="hpmcounter11" bitsize="64"/>
+  <reg name="hpmcounter12" bitsize="64"/>
+  <reg name="hpmcounter13" bitsize="64"/>
+  <reg name="hpmcounter14" bitsize="64"/>
+  <reg name="hpmcounter15" bitsize="64"/>
+  <reg name="hpmcounter16" bitsize="64"/>
+  <reg name="hpmcounter17" bitsize="64"/>
+  <reg name="hpmcounter18" bitsize="64"/>
+  <reg name="hpmcounter19" bitsize="64"/>
+  <reg name="hpmcounter20" bitsize="64"/>
+  <reg name="hpmcounter21" bitsize="64"/>
+  <reg name="hpmcounter22" bitsize="64"/>
+  <reg name="hpmcounter23" bitsize="64"/>
+  <reg name="hpmcounter24" bitsize="64"/>
+  <reg name="hpmcounter25" bitsize="64"/>
+  <reg name="hpmcounter26" bitsize="64"/>
+  <reg name="hpmcounter27" bitsize="64"/>
+  <reg name="hpmcounter28" bitsize="64"/>
+  <reg name="hpmcounter29" bitsize="64"/>
+  <reg name="hpmcounter30" bitsize="64"/>
+  <reg name="hpmcounter31" bitsize="64"/>
+  <reg name="cycleh" bitsize="64"/>
+  <reg name="timeh" bitsize="64"/>
+  <reg name="instreth" bitsize="64"/>
+  <reg name="hpmcounter3h" bitsize="64"/>
+  <reg name="hpmcounter4h" bitsize="64"/>
+  <reg name="hpmcounter5h" bitsize="64"/>
+  <reg name="hpmcounter6h" bitsize="64"/>
+  <reg name="hpmcounter7h" bitsize="64"/>
+  <reg name="hpmcounter8h" bitsize="64"/>
+  <reg name="hpmcounter9h" bitsize="64"/>
+  <reg name="hpmcounter10h" bitsize="64"/>
+  <reg name="hpmcounter11h" bitsize="64"/>
+  <reg name="hpmcounter12h" bitsize="64"/>
+  <reg name="hpmcounter13h" bitsize="64"/>
+  <reg name="hpmcounter14h" bitsize="64"/>
+  <reg name="hpmcounter15h" bitsize="64"/>
+  <reg name="hpmcounter16h" bitsize="64"/>
+  <reg name="hpmcounter17h" bitsize="64"/>
+  <reg name="hpmcounter18h" bitsize="64"/>
+  <reg name="hpmcounter19h" bitsize="64"/>
+  <reg name="hpmcounter20h" bitsize="64"/>
+  <reg name="hpmcounter21h" bitsize="64"/>
+  <reg name="hpmcounter22h" bitsize="64"/>
+  <reg name="hpmcounter23h" bitsize="64"/>
+  <reg name="hpmcounter24h" bitsize="64"/>
+  <reg name="hpmcounter25h" bitsize="64"/>
+  <reg name="hpmcounter26h" bitsize="64"/>
+  <reg name="hpmcounter27h" bitsize="64"/>
+  <reg name="hpmcounter28h" bitsize="64"/>
+  <reg name="hpmcounter29h" bitsize="64"/>
+  <reg name="hpmcounter30h" bitsize="64"/>
+  <reg name="hpmcounter31h" bitsize="64"/>
+  <reg name="sstatus" bitsize="64"/>
+  <reg name="sedeleg" bitsize="64"/>
+  <reg name="sideleg" bitsize="64"/>
+  <reg name="sie" bitsize="64"/>
+  <reg name="stvec" bitsize="64"/>
+  <reg name="scounteren" bitsize="64"/>
+  <reg name="sscratch" bitsize="64"/>
+  <reg name="sepc" bitsize="64"/>
+  <reg name="scause" bitsize="64"/>
+  <reg name="stval" bitsize="64"/>
+  <reg name="sip" bitsize="64"/>
+  <reg name="satp" bitsize="64"/>
+  <reg name="mvendorid" bitsize="64"/>
+  <reg name="marchid" bitsize="64"/>
+  <reg name="mimpid" bitsize="64"/>
+  <reg name="mhartid" bitsize="64"/>
+  <reg name="mstatus" bitsize="64"/>
+  <reg name="misa" bitsize="64"/>
+  <reg name="medeleg" bitsize="64"/>
+  <reg name="mideleg" bitsize="64"/>
+  <reg name="mie" bitsize="64"/>
+  <reg name="mtvec" bitsize="64"/>
+  <reg name="mcounteren" bitsize="64"/>
+  <reg name="mscratch" bitsize="64"/>
+  <reg name="mepc" bitsize="64"/>
+  <reg name="mcause" bitsize="64"/>
+  <reg name="mtval" bitsize="64"/>
+  <reg name="mip" bitsize="64"/>
+  <reg name="pmpcfg0" bitsize="64"/>
+  <reg name="pmpcfg1" bitsize="64"/>
+  <reg name="pmpcfg2" bitsize="64"/>
+  <reg name="pmpcfg3" bitsize="64"/>
+  <reg name="pmpaddr0" bitsize="64"/>
+  <reg name="pmpaddr1" bitsize="64"/>
+  <reg name="pmpaddr2" bitsize="64"/>
+  <reg name="pmpaddr3" bitsize="64"/>
+  <reg name="pmpaddr4" bitsize="64"/>
+  <reg name="pmpaddr5" bitsize="64"/>
+  <reg name="pmpaddr6" bitsize="64"/>
+  <reg name="pmpaddr7" bitsize="64"/>
+  <reg name="pmpaddr8" bitsize="64"/>
+  <reg name="pmpaddr9" bitsize="64"/>
+  <reg name="pmpaddr10" bitsize="64"/>
+  <reg name="pmpaddr11" bitsize="64"/>
+  <reg name="pmpaddr12" bitsize="64"/>
+  <reg name="pmpaddr13" bitsize="64"/>
+  <reg name="pmpaddr14" bitsize="64"/>
+  <reg name="pmpaddr15" bitsize="64"/>
+  <reg name="mcycle" bitsize="64"/>
+  <reg name="minstret" bitsize="64"/>
+  <reg name="mhpmcounter3" bitsize="64"/>
+  <reg name="mhpmcounter4" bitsize="64"/>
+  <reg name="mhpmcounter5" bitsize="64"/>
+  <reg name="mhpmcounter6" bitsize="64"/>
+  <reg name="mhpmcounter7" bitsize="64"/>
+  <reg name="mhpmcounter8" bitsize="64"/>
+  <reg name="mhpmcounter9" bitsize="64"/>
+  <reg name="mhpmcounter10" bitsize="64"/>
+  <reg name="mhpmcounter11" bitsize="64"/>
+  <reg name="mhpmcounter12" bitsize="64"/>
+  <reg name="mhpmcounter13" bitsize="64"/>
+  <reg name="mhpmcounter14" bitsize="64"/>
+  <reg name="mhpmcounter15" bitsize="64"/>
+  <reg name="mhpmcounter16" bitsize="64"/>
+  <reg name="mhpmcounter17" bitsize="64"/>
+  <reg name="mhpmcounter18" bitsize="64"/>
+  <reg name="mhpmcounter19" bitsize="64"/>
+  <reg name="mhpmcounter20" bitsize="64"/>
+  <reg name="mhpmcounter21" bitsize="64"/>
+  <reg name="mhpmcounter22" bitsize="64"/>
+  <reg name="mhpmcounter23" bitsize="64"/>
+  <reg name="mhpmcounter24" bitsize="64"/>
+  <reg name="mhpmcounter25" bitsize="64"/>
+  <reg name="mhpmcounter26" bitsize="64"/>
+  <reg name="mhpmcounter27" bitsize="64"/>
+  <reg name="mhpmcounter28" bitsize="64"/>
+  <reg name="mhpmcounter29" bitsize="64"/>
+  <reg name="mhpmcounter30" bitsize="64"/>
+  <reg name="mhpmcounter31" bitsize="64"/>
+  <reg name="mcycleh" bitsize="64"/>
+  <reg name="minstreth" bitsize="64"/>
+  <reg name="mhpmcounter3h" bitsize="64"/>
+  <reg name="mhpmcounter4h" bitsize="64"/>
+  <reg name="mhpmcounter5h" bitsize="64"/>
+  <reg name="mhpmcounter6h" bitsize="64"/>
+  <reg name="mhpmcounter7h" bitsize="64"/>
+  <reg name="mhpmcounter8h" bitsize="64"/>
+  <reg name="mhpmcounter9h" bitsize="64"/>
+  <reg name="mhpmcounter10h" bitsize="64"/>
+  <reg name="mhpmcounter11h" bitsize="64"/>
+  <reg name="mhpmcounter12h" bitsize="64"/>
+  <reg name="mhpmcounter13h" bitsize="64"/>
+  <reg name="mhpmcounter14h" bitsize="64"/>
+  <reg name="mhpmcounter15h" bitsize="64"/>
+  <reg name="mhpmcounter16h" bitsize="64"/>
+  <reg name="mhpmcounter17h" bitsize="64"/>
+  <reg name="mhpmcounter18h" bitsize="64"/>
+  <reg name="mhpmcounter19h" bitsize="64"/>
+  <reg name="mhpmcounter20h" bitsize="64"/>
+  <reg name="mhpmcounter21h" bitsize="64"/>
+  <reg name="mhpmcounter22h" bitsize="64"/>
+  <reg name="mhpmcounter23h" bitsize="64"/>
+  <reg name="mhpmcounter24h" bitsize="64"/>
+  <reg name="mhpmcounter25h" bitsize="64"/>
+  <reg name="mhpmcounter26h" bitsize="64"/>
+  <reg name="mhpmcounter27h" bitsize="64"/>
+  <reg name="mhpmcounter28h" bitsize="64"/>
+  <reg name="mhpmcounter29h" bitsize="64"/>
+  <reg name="mhpmcounter30h" bitsize="64"/>
+  <reg name="mhpmcounter31h" bitsize="64"/>
+  <reg name="mhpmevent3" bitsize="64"/>
+  <reg name="mhpmevent4" bitsize="64"/>
+  <reg name="mhpmevent5" bitsize="64"/>
+  <reg name="mhpmevent6" bitsize="64"/>
+  <reg name="mhpmevent7" bitsize="64"/>
+  <reg name="mhpmevent8" bitsize="64"/>
+  <reg name="mhpmevent9" bitsize="64"/>
+  <reg name="mhpmevent10" bitsize="64"/>
+  <reg name="mhpmevent11" bitsize="64"/>
+  <reg name="mhpmevent12" bitsize="64"/>
+  <reg name="mhpmevent13" bitsize="64"/>
+  <reg name="mhpmevent14" bitsize="64"/>
+  <reg name="mhpmevent15" bitsize="64"/>
+  <reg name="mhpmevent16" bitsize="64"/>
+  <reg name="mhpmevent17" bitsize="64"/>
+  <reg name="mhpmevent18" bitsize="64"/>
+  <reg name="mhpmevent19" bitsize="64"/>
+  <reg name="mhpmevent20" bitsize="64"/>
+  <reg name="mhpmevent21" bitsize="64"/>
+  <reg name="mhpmevent22" bitsize="64"/>
+  <reg name="mhpmevent23" bitsize="64"/>
+  <reg name="mhpmevent24" bitsize="64"/>
+  <reg name="mhpmevent25" bitsize="64"/>
+  <reg name="mhpmevent26" bitsize="64"/>
+  <reg name="mhpmevent27" bitsize="64"/>
+  <reg name="mhpmevent28" bitsize="64"/>
+  <reg name="mhpmevent29" bitsize="64"/>
+  <reg name="mhpmevent30" bitsize="64"/>
+  <reg name="mhpmevent31" bitsize="64"/>
+  <reg name="tselect" bitsize="64"/>
+  <reg name="tdata1" bitsize="64"/>
+  <reg name="tdata2" bitsize="64"/>
+  <reg name="tdata3" bitsize="64"/>
+  <reg name="dcsr" bitsize="64"/>
+  <reg name="dpc" bitsize="64"/>
+  <reg name="dscratch" bitsize="64"/>
+  <reg name="hstatus" bitsize="64"/>
+  <reg name="hedeleg" bitsize="64"/>
+  <reg name="hideleg" bitsize="64"/>
+  <reg name="hie" bitsize="64"/>
+  <reg name="htvec" bitsize="64"/>
+  <reg name="hscratch" bitsize="64"/>
+  <reg name="hepc" bitsize="64"/>
+  <reg name="hcause" bitsize="64"/>
+  <reg name="hbadaddr" bitsize="64"/>
+  <reg name="hip" bitsize="64"/>
+  <reg name="mbase" bitsize="64"/>
+  <reg name="mbound" bitsize="64"/>
+  <reg name="mibase" bitsize="64"/>
+  <reg name="mibound" bitsize="64"/>
+  <reg name="mdbase" bitsize="64"/>
+  <reg name="mdbound" bitsize="64"/>
+  <reg name="mucounteren" bitsize="64"/>
+  <reg name="mscounteren" bitsize="64"/>
+  <reg name="mhcounteren" bitsize="64"/>
+</feature>
diff --git a/gdb/features/riscv/64bit-fpu.c b/gdb/features/riscv/64bit-fpu.c
new file mode 100644
index 00000000000..8cbd7484ab3
--- /dev/null
+++ b/gdb/features/riscv/64bit-fpu.c
@@ -0,0 +1,56 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 64bit-fpu.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_64bit_fpu (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.fpu");
+  tdesc_type_with_fields *type_with_fields;
+  type_with_fields = tdesc_create_union (feature, "riscv_double");
+  tdesc_type *field_type;
+  field_type = tdesc_named_type (feature, "ieee_single");
+  tdesc_add_field (type_with_fields, "float", field_type);
+  field_type = tdesc_named_type (feature, "ieee_double");
+  tdesc_add_field (type_with_fields, "double", field_type);
+
+  tdesc_create_reg (feature, "ft0", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft1", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft2", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft3", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft4", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft5", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft6", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft7", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs0", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs1", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa0", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa1", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa2", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa3", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa4", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa5", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa6", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa7", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs2", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs3", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs4", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs5", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs6", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs7", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs8", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs9", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs10", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs11", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft8", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft9", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft10", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft11", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "frm", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fcsr", regnum++, 1, NULL, 32, "int");
+  return regnum;
+}
diff --git a/gdb/features/riscv/64bit-fpu.xml b/gdb/features/riscv/64bit-fpu.xml
new file mode 100644
index 00000000000..fb24b72bcaf
--- /dev/null
+++ b/gdb/features/riscv/64bit-fpu.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.fpu">
+
+  <union id="riscv_double">
+    <field name="float" type="ieee_single"/>
+    <field name="double" type="ieee_double"/>
+  </union>
+
+  <reg name="ft0" bitsize="64" type="riscv_double"/>
+  <reg name="ft1" bitsize="64" type="riscv_double"/>
+  <reg name="ft2" bitsize="64" type="riscv_double"/>
+  <reg name="ft3" bitsize="64" type="riscv_double"/>
+  <reg name="ft4" bitsize="64" type="riscv_double"/>
+  <reg name="ft5" bitsize="64" type="riscv_double"/>
+  <reg name="ft6" bitsize="64" type="riscv_double"/>
+  <reg name="ft7" bitsize="64" type="riscv_double"/>
+  <reg name="fs0" bitsize="64" type="riscv_double"/>
+  <reg name="fs1" bitsize="64" type="riscv_double"/>
+  <reg name="fa0" bitsize="64" type="riscv_double"/>
+  <reg name="fa1" bitsize="64" type="riscv_double"/>
+  <reg name="fa2" bitsize="64" type="riscv_double"/>
+  <reg name="fa3" bitsize="64" type="riscv_double"/>
+  <reg name="fa4" bitsize="64" type="riscv_double"/>
+  <reg name="fa5" bitsize="64" type="riscv_double"/>
+  <reg name="fa6" bitsize="64" type="riscv_double"/>
+  <reg name="fa7" bitsize="64" type="riscv_double"/>
+  <reg name="fs2" bitsize="64" type="riscv_double"/>
+  <reg name="fs3" bitsize="64" type="riscv_double"/>
+  <reg name="fs4" bitsize="64" type="riscv_double"/>
+  <reg name="fs5" bitsize="64" type="riscv_double"/>
+  <reg name="fs6" bitsize="64" type="riscv_double"/>
+  <reg name="fs7" bitsize="64" type="riscv_double"/>
+  <reg name="fs8" bitsize="64" type="riscv_double"/>
+  <reg name="fs9" bitsize="64" type="riscv_double"/>
+  <reg name="fs10" bitsize="64" type="riscv_double"/>
+  <reg name="fs11" bitsize="64" type="riscv_double"/>
+  <reg name="ft8" bitsize="64" type="riscv_double"/>
+  <reg name="ft9" bitsize="64" type="riscv_double"/>
+  <reg name="ft10" bitsize="64" type="riscv_double"/>
+  <reg name="ft11" bitsize="64" type="riscv_double"/>
+
+  <reg name="fflags" bitsize="32" type="int"/>
+  <reg name="frm" bitsize="32" type="int"/>
+  <reg name="fcsr" bitsize="32" type="int"/>
+</feature>
diff --git a/gdb/features/riscv/rebuild-csr-xml.sh b/gdb/features/riscv/rebuild-csr-xml.sh
new file mode 100755
index 00000000000..6971b8dbb2a
--- /dev/null
+++ b/gdb/features/riscv/rebuild-csr-xml.sh
@@ -0,0 +1,29 @@
+#! /bin/bash
+
+RISCV_OPC_FILE=$1
+RISCV_FEATURE_DIR=$2
+
+function gen_csr_xml ()
+{
+    bitsize=$1
+
+    cat <<EOF
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.csr">
+EOF
+
+    grep "^DECLARE_CSR(" ${RISCV_OPC_FILE} \
+        | sed -e "s!DECLARE_CSR(\(.*\), .*!  <reg name=\"\1\" bitsize=\"$bitsize\"/>!"
+
+    echo "</feature>"
+}
+
+gen_csr_xml 32 > ${RISCV_FEATURE_DIR}/32bit-csr.xml
+gen_csr_xml 64 > ${RISCV_FEATURE_DIR}/64bit-csr.xml
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index 7a92fc7fae5..25682a47546 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -55,13 +55,11 @@
 #include "cli/cli-decode.h"
 #include "observable.h"
 #include "prologue-value.h"
+#include "arch/riscv.h"
 
 /* The stack must be 16-byte aligned.  */
 #define SP_ALIGNMENT 16
 
-/* Forward declarations.  */
-static bool riscv_has_feature (struct gdbarch *gdbarch, char feature);
-
 /* Define a series of is_XXX_insn functions to check if the value INSN
    is an instance of instruction XXX.  */
 #define DECLARE_INSN(INSN_NAME, INSN_MATCH, INSN_MASK) \
@@ -95,110 +93,170 @@ struct riscv_unwind_cache
   CORE_ADDR frame_base;
 };
 
-/* The preferred register names for all the general purpose and floating
-   point registers.  These are what GDB will use when referencing a
-   register.  */
+/* RISC-V specific register group for CSRs.  */
 
-static const char * const riscv_gdb_reg_names[RISCV_LAST_FP_REGNUM + 1] =
-{
- "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1",
- "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4",
- "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6",
- "pc",
- "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", "fs0", "fs1",
- "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa7", "fs2", "fs3",
- "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", "fs10", "fs11", "ft8", "ft9",
- "ft10", "ft11",
-};
+static reggroup *csr_reggroup = NULL;
 
-/* Map alternative register names onto their GDB register number.  */
+/* A set of registers that we expect to find in a tdesc_feature.  These
+   are use in RISCV_GDBARCH_INIT when processing the target description.  */
 
-struct riscv_register_alias
+struct riscv_register_feature
 {
-  /* The register alias.  Usually more descriptive than the
-     architectural name of the register.  */
+  /* Information for a single register.  */
+  struct register_info
+  {
+    /* The GDB register number for this register.  */
+    int regnum;
+
+    /* List of names for this register.  The first name in this list is the
+       preferred name, the name GDB should use when describing this
+       register.  */
+    std::vector <const char *> names;
+
+    /* When true this register is required in this feature set.  */
+    bool required_p;
+  };
+
+  /* The name for this feature.  This is the name used to find this feature
+     within the target description.  */
   const char *name;
 
-  /* The GDB register number.  */
-  int regnum;
+  /* List of all the registers that we expect that we might find in this
+     register set.  */
+  std::vector <struct register_info> registers;
+};
+
+/* The general x-registers feature set.  */
+
+static const struct riscv_register_feature riscv_xreg_feature =
+{
+ "org.gnu.gdb.riscv.cpu",
+ {
+   { RISCV_ZERO_REGNUM + 0, { "zero", "x0" }, true },
+   { RISCV_ZERO_REGNUM + 1, { "ra", "x1" }, true },
+   { RISCV_ZERO_REGNUM + 2, { "sp", "x2" }, true },
+   { RISCV_ZERO_REGNUM + 3, { "gp", "x3" }, true },
+   { RISCV_ZERO_REGNUM + 4, { "tp", "x4" }, true },
+   { RISCV_ZERO_REGNUM + 5, { "t0", "x5" }, true },
+   { RISCV_ZERO_REGNUM + 6, { "t1", "x6" }, true },
+   { RISCV_ZERO_REGNUM + 7, { "t2", "x7" }, true },
+   { RISCV_ZERO_REGNUM + 8, { "fp", "x8", "s0" }, true },
+   { RISCV_ZERO_REGNUM + 9, { "s1", "x9" }, true },
+   { RISCV_ZERO_REGNUM + 10, { "a0", "x10" }, true },
+   { RISCV_ZERO_REGNUM + 11, { "a1", "x11" }, true },
+   { RISCV_ZERO_REGNUM + 12, { "a2", "x12" }, true },
+   { RISCV_ZERO_REGNUM + 13, { "a3", "x13" }, true },
+   { RISCV_ZERO_REGNUM + 14, { "a4", "x14" }, true },
+   { RISCV_ZERO_REGNUM + 15, { "a5", "x15" }, true },
+   { RISCV_ZERO_REGNUM + 16, { "a6", "x16" }, true },
+   { RISCV_ZERO_REGNUM + 17, { "a7", "x17" }, true },
+   { RISCV_ZERO_REGNUM + 18, { "s2", "x18" }, true },
+   { RISCV_ZERO_REGNUM + 19, { "s3", "x19" }, true },
+   { RISCV_ZERO_REGNUM + 20, { "s4", "x20" }, true },
+   { RISCV_ZERO_REGNUM + 21, { "s5", "x21" }, true },
+   { RISCV_ZERO_REGNUM + 22, { "s6", "x22" }, true },
+   { RISCV_ZERO_REGNUM + 23, { "s7", "x23" }, true },
+   { RISCV_ZERO_REGNUM + 24, { "s8", "x24" }, true },
+   { RISCV_ZERO_REGNUM + 25, { "s9", "x25" }, true },
+   { RISCV_ZERO_REGNUM + 26, { "s10", "x26" }, true },
+   { RISCV_ZERO_REGNUM + 27, { "s11", "x27" }, true },
+   { RISCV_ZERO_REGNUM + 28, { "t3", "x28" }, true },
+   { RISCV_ZERO_REGNUM + 29, { "t4", "x29" }, true },
+   { RISCV_ZERO_REGNUM + 30, { "t5", "x30" }, true },
+   { RISCV_ZERO_REGNUM + 31, { "t6", "x31" }, true },
+   { RISCV_ZERO_REGNUM + 32, { "pc" }, true }
+ }
+};
+
+/* The f-registers feature set.  */
+
+static const struct riscv_register_feature riscv_freg_feature =
+{
+ "org.gnu.gdb.riscv.fpu",
+ {
+   { RISCV_FIRST_FP_REGNUM + 0, { "ft0", "f0" }, true },
+   { RISCV_FIRST_FP_REGNUM + 1, { "ft1", "f1" }, true },
+   { RISCV_FIRST_FP_REGNUM + 2, { "ft2", "f2" }, true },
+   { RISCV_FIRST_FP_REGNUM + 3, { "ft3", "f3" }, true },
+   { RISCV_FIRST_FP_REGNUM + 4, { "ft4", "f4" }, true },
+   { RISCV_FIRST_FP_REGNUM + 5, { "ft5", "f5" }, true },
+   { RISCV_FIRST_FP_REGNUM + 6, { "ft6", "f6" }, true },
+   { RISCV_FIRST_FP_REGNUM + 7, { "ft7", "f7" }, true },
+   { RISCV_FIRST_FP_REGNUM + 8, { "fs0", "f8", "s0" }, true },
+   { RISCV_FIRST_FP_REGNUM + 9, { "fs1", "f9" }, true },
+   { RISCV_FIRST_FP_REGNUM + 10, { "fa0", "f10" }, true },
+   { RISCV_FIRST_FP_REGNUM + 11, { "fa1", "f11" }, true },
+   { RISCV_FIRST_FP_REGNUM + 12, { "fa2", "f12" }, true },
+   { RISCV_FIRST_FP_REGNUM + 13, { "fa3", "f13" }, true },
+   { RISCV_FIRST_FP_REGNUM + 14, { "fa4", "f14" }, true },
+   { RISCV_FIRST_FP_REGNUM + 15, { "fa5", "f15" }, true },
+   { RISCV_FIRST_FP_REGNUM + 16, { "fa6", "f16" }, true },
+   { RISCV_FIRST_FP_REGNUM + 17, { "fa7", "f17" }, true },
+   { RISCV_FIRST_FP_REGNUM + 18, { "fs2", "f18" }, true },
+   { RISCV_FIRST_FP_REGNUM + 19, { "fs3", "f19" }, true },
+   { RISCV_FIRST_FP_REGNUM + 20, { "fs4", "f20" }, true },
+   { RISCV_FIRST_FP_REGNUM + 21, { "fs5", "f21" }, true },
+   { RISCV_FIRST_FP_REGNUM + 22, { "fs6", "f22" }, true },
+   { RISCV_FIRST_FP_REGNUM + 23, { "fs7", "f23" }, true },
+   { RISCV_FIRST_FP_REGNUM + 24, { "fs8", "f24" }, true },
+   { RISCV_FIRST_FP_REGNUM + 25, { "fs9", "f25" }, true },
+   { RISCV_FIRST_FP_REGNUM + 26, { "fs10", "f26" }, true },
+   { RISCV_FIRST_FP_REGNUM + 27, { "fs11", "f27" }, true },
+   { RISCV_FIRST_FP_REGNUM + 28, { "ft8", "f28" }, true },
+   { RISCV_FIRST_FP_REGNUM + 29, { "ft9", "f29" }, true },
+   { RISCV_FIRST_FP_REGNUM + 30, { "ft10", "f30" }, true },
+   { RISCV_FIRST_FP_REGNUM + 31, { "ft11", "f31" }, true },
+
+   { RISCV_CSR_FFLAGS_REGNUM, { "fflags" }, true },
+   { RISCV_CSR_FRM_REGNUM, { "frm" }, true },
+   { RISCV_CSR_FCSR_REGNUM, { "fcsr" }, true },
+
+ }
+};
+
+/* Set of virtual registers.  These are not physical registers on the
+   hardware, but might be available from the target.  These are not pseudo
+   registers, reading these really does result in a register read from the
+   target, it is just that there might not be a physical register backing
+   the result.  */
+
+static const struct riscv_register_feature riscv_virtual_feature =
+{
+ "org.gnu.gdb.riscv.virtual",
+ {
+   { RISCV_PRIV_REGNUM, { "priv" }, false }
+ }
 };
 
-/* Table of register aliases.  */
-
-static const struct riscv_register_alias riscv_register_aliases[] =
-{
- /* Aliases for general purpose registers.  These are the architectural
-    names, as GDB uses the more user friendly names by default.  */
- { "x0", (RISCV_ZERO_REGNUM + 0) },
- { "x1", (RISCV_ZERO_REGNUM + 1) },
- { "x2", (RISCV_ZERO_REGNUM + 2) },
- { "x3", (RISCV_ZERO_REGNUM + 3) },
- { "x4", (RISCV_ZERO_REGNUM + 4) },
- { "x5", (RISCV_ZERO_REGNUM + 5) },
- { "x6", (RISCV_ZERO_REGNUM + 6) },
- { "x7", (RISCV_ZERO_REGNUM + 7) },
- { "x8", (RISCV_ZERO_REGNUM + 8) },
- { "s0", (RISCV_ZERO_REGNUM + 8) },	/* fp, s0, and x8 are all aliases.  */
- { "x9", (RISCV_ZERO_REGNUM + 9) },
- { "x10", (RISCV_ZERO_REGNUM + 10) },
- { "x11", (RISCV_ZERO_REGNUM + 11) },
- { "x12", (RISCV_ZERO_REGNUM + 12) },
- { "x13", (RISCV_ZERO_REGNUM + 13) },
- { "x14", (RISCV_ZERO_REGNUM + 14) },
- { "x15", (RISCV_ZERO_REGNUM + 15) },
- { "x16", (RISCV_ZERO_REGNUM + 16) },
- { "x17", (RISCV_ZERO_REGNUM + 17) },
- { "x18", (RISCV_ZERO_REGNUM + 18) },
- { "x19", (RISCV_ZERO_REGNUM + 19) },
- { "x20", (RISCV_ZERO_REGNUM + 20) },
- { "x21", (RISCV_ZERO_REGNUM + 21) },
- { "x22", (RISCV_ZERO_REGNUM + 22) },
- { "x23", (RISCV_ZERO_REGNUM + 23) },
- { "x24", (RISCV_ZERO_REGNUM + 24) },
- { "x25", (RISCV_ZERO_REGNUM + 25) },
- { "x26", (RISCV_ZERO_REGNUM + 26) },
- { "x27", (RISCV_ZERO_REGNUM + 27) },
- { "x28", (RISCV_ZERO_REGNUM + 28) },
- { "x29", (RISCV_ZERO_REGNUM + 29) },
- { "x30", (RISCV_ZERO_REGNUM + 30) },
- { "x31", (RISCV_ZERO_REGNUM + 31) },
-
- /* Aliases for the floating-point registers.  These are the architectural
-    names as GDB uses the more user friendly names by default.  */
- { "f0", (RISCV_FIRST_FP_REGNUM + 0) },
- { "f1", (RISCV_FIRST_FP_REGNUM + 1) },
- { "f2", (RISCV_FIRST_FP_REGNUM + 2) },
- { "f3", (RISCV_FIRST_FP_REGNUM + 3) },
- { "f4", (RISCV_FIRST_FP_REGNUM + 4) },
- { "f5", (RISCV_FIRST_FP_REGNUM + 5) },
- { "f6", (RISCV_FIRST_FP_REGNUM + 6) },
- { "f7", (RISCV_FIRST_FP_REGNUM + 7) },
- { "f8", (RISCV_FIRST_FP_REGNUM + 8) },
- { "f9", (RISCV_FIRST_FP_REGNUM + 9) },
- { "f10", (RISCV_FIRST_FP_REGNUM + 10) },
- { "f11", (RISCV_FIRST_FP_REGNUM + 11) },
- { "f12", (RISCV_FIRST_FP_REGNUM + 12) },
- { "f13", (RISCV_FIRST_FP_REGNUM + 13) },
- { "f14", (RISCV_FIRST_FP_REGNUM + 14) },
- { "f15", (RISCV_FIRST_FP_REGNUM + 15) },
- { "f16", (RISCV_FIRST_FP_REGNUM + 16) },
- { "f17", (RISCV_FIRST_FP_REGNUM + 17) },
- { "f18", (RISCV_FIRST_FP_REGNUM + 18) },
- { "f19", (RISCV_FIRST_FP_REGNUM + 19) },
- { "f20", (RISCV_FIRST_FP_REGNUM + 20) },
- { "f21", (RISCV_FIRST_FP_REGNUM + 21) },
- { "f22", (RISCV_FIRST_FP_REGNUM + 22) },
- { "f23", (RISCV_FIRST_FP_REGNUM + 23) },
- { "f24", (RISCV_FIRST_FP_REGNUM + 24) },
- { "f25", (RISCV_FIRST_FP_REGNUM + 25) },
- { "f26", (RISCV_FIRST_FP_REGNUM + 26) },
- { "f27", (RISCV_FIRST_FP_REGNUM + 27) },
- { "f28", (RISCV_FIRST_FP_REGNUM + 28) },
- { "f29", (RISCV_FIRST_FP_REGNUM + 29) },
- { "f30", (RISCV_FIRST_FP_REGNUM + 30) },
- { "f31", (RISCV_FIRST_FP_REGNUM + 31) },
+/* Feature set for CSRs.  This set is NOT constant as the register names
+   list for each register is not complete.  The aliases are computed
+   during RISCV_CREATE_CSR_ALIASES.  */
+
+static struct riscv_register_feature riscv_csr_feature =
+{
+ "org.gnu.gdb.riscv.csr",
+ {
+#define DECLARE_CSR(NAME,VALUE) \
+  { RISCV_ ## VALUE ## _REGNUM, { # NAME }, false },
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+ }
 };
 
+/* Complete RISCV_CSR_FEATURE, building the CSR alias names and adding them
+   to the name list for each register.  */
+
+static void
+riscv_create_csr_aliases ()
+{
+  for (auto &reg : riscv_csr_feature.registers)
+    {
+      int csr_num = reg.regnum - RISCV_FIRST_CSR_REGNUM;
+      const char *alias = xstrprintf ("csr%d", csr_num);
+      reg.names.push_back (alias);
+    }
+}
+
 /* Controls whether we place compressed breakpoints or not.  When in auto
    mode GDB tries to determine if the target supports compressed
    breakpoints, and uses them if it does.  */
@@ -290,82 +348,17 @@ static unsigned int riscv_debug_infcall = 0;
 
 static unsigned int riscv_debug_unwinder = 0;
 
-/* Read the MISA register from the target.  There are a couple of locations
-   that the register might be found, these are all tried.  If the MISA
-   register can't be found at all then the default value of 0 is returned,
-   this is inline with the RISC-V specification.  */
-
-static uint32_t
-riscv_read_misa_reg ()
-{
-  uint32_t value = 0;
-
-  if (target_has_registers)
-    {
-      /* Old cores might have MISA located at a different offset.  */
-      static int misa_regs[] =
-	{ RISCV_CSR_MISA_REGNUM, RISCV_CSR_LEGACY_MISA_REGNUM };
-
-      struct frame_info *frame = get_current_frame ();
-
-      for (int i = 0; i < ARRAY_SIZE (misa_regs); ++i)
-	{
-	  bool success = false;
-
-	  TRY
-	    {
-	      value = get_frame_register_unsigned (frame, misa_regs[i]);
-	      success = true;
-	    }
-	  CATCH (ex, RETURN_MASK_ERROR)
-	    {
-	      /* Ignore errors, it is acceptable for a target to not
-		 provide a MISA register, in which case the default value
-		 of 0 should be used.  */
-	    }
-	  END_CATCH
-
-	  if (success)
-	    break;
-	}
-    }
-
-  return value;
-}
+/* When this is set to non-zero debugging information about gdbarch
+   initialisation will be printed.  */
 
-/* Return true if FEATURE is available for the architecture GDBARCH.  The
-   FEATURE should be one of the single character feature codes described in
-   the RiscV ISA manual, these are between 'A' and 'Z'.  */
-
-static bool
-riscv_has_feature (struct gdbarch *gdbarch, char feature)
-{
-  gdb_assert (feature >= 'A' && feature <= 'Z');
-
-  uint32_t misa = riscv_read_misa_reg ();
-  if (misa == 0)
-    misa = gdbarch_tdep (gdbarch)->core_features;
-
-  return (misa & (1 << (feature - 'A'))) != 0;
-}
+static unsigned int riscv_debug_gdbarch = 0;
 
 /* See riscv-tdep.h.  */
 
 int
 riscv_isa_xlen (struct gdbarch *gdbarch)
 {
-  switch (gdbarch_tdep (gdbarch)->abi.fields.base_len)
-    {
-    default:
-      warning (_("unknown xlen size, assuming 4 bytes"));
-      /* Fall through.  */
-    case 1:
-      return 4;
-    case 2:
-      return 8;
-    case 3:
-      return 16;
-    }
+  return gdbarch_tdep (gdbarch)->features.xlen;
 }
 
 /* See riscv-tdep.h.  */
@@ -373,14 +366,7 @@ riscv_isa_xlen (struct gdbarch *gdbarch)
 int
 riscv_isa_flen (struct gdbarch *gdbarch)
 {
-  if (riscv_has_feature (gdbarch, 'Q'))
-    return 16;
-  else if (riscv_has_feature (gdbarch, 'D'))
-    return 8;
-  else if (riscv_has_feature (gdbarch, 'F'))
-    return 4;
-
-  return 0;
+  return gdbarch_tdep (gdbarch)->features.flen;
 }
 
 /* Return true if the target for GDBARCH has floating point hardware.  */
@@ -396,7 +382,7 @@ riscv_has_fp_regs (struct gdbarch *gdbarch)
 static bool
 riscv_has_fp_abi (struct gdbarch *gdbarch)
 {
-  return (gdbarch_tdep (gdbarch)->abi.fields.float_abi != 0);
+  return gdbarch_tdep (gdbarch)->features.hw_float_abi;
 }
 
 /* Return true if REGNO is a floating pointer register.  */
@@ -482,16 +468,36 @@ value_of_riscv_user_reg (struct frame_info *frame, const void *baton)
   return value_of_register (*reg_p, frame);
 }
 
-/* Implement the register_name gdbarch method.  */
+/* Implement the register_name gdbarch method.  This is used instead of
+   the function supplied by calling TDESC_USE_REGISTERS so that we can
+   ensure the preferred names are offered.  */
 
 static const char *
 riscv_register_name (struct gdbarch *gdbarch, int regnum)
 {
-  /* Prefer to use the alias. */
-  if (regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
+  /* Lookup the name through the target description.  If we get back NULL
+     then this is an unknown register.  If we do get a name back then we
+     look up the registers preferred name below.  */
+  const char *name = tdesc_register_name (gdbarch, regnum);
+  if (name == NULL || name[0] == '\0')
+    return NULL;
+
+  if (regnum >= RISCV_ZERO_REGNUM && regnum < RISCV_FIRST_FP_REGNUM)
+    {
+      gdb_assert (regnum < riscv_xreg_feature.registers.size ());
+      return riscv_xreg_feature.registers[regnum].names[0];
+    }
+
+  if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
     {
-      gdb_assert (regnum < ARRAY_SIZE (riscv_gdb_reg_names));
-      return riscv_gdb_reg_names[regnum];
+      if (riscv_has_fp_regs (gdbarch))
+        {
+          regnum -= RISCV_FIRST_FP_REGNUM;
+          gdb_assert (regnum < riscv_freg_feature.registers.size ());
+          return riscv_freg_feature.registers[regnum].names[0];
+        }
+      else
+        return NULL;
     }
 
   /* Check that there's no gap between the set of registers handled above,
@@ -506,14 +512,6 @@ riscv_register_name (struct gdbarch *gdbarch, int regnum)
       switch (regnum)
 	{
 	  #include "opcode/riscv-opc.h"
-	default:
-          {
-            static char buf[20];
-
-            xsnprintf (buf, sizeof (buf), "csr%d",
-                       regnum - RISCV_FIRST_CSR_REGNUM);
-            return buf;
-          }
 	}
 #undef DECLARE_CSR
     }
@@ -521,7 +519,10 @@ riscv_register_name (struct gdbarch *gdbarch, int regnum)
   if (regnum == RISCV_PRIV_REGNUM)
     return "priv";
 
-  return NULL;
+  /* It is possible that that the target provides some registers that GDB
+     is unaware of, in that case just return the NAME from the target
+     description.  */
+  return name;
 }
 
 /* Construct a type for 64-bit FP registers.  */
@@ -558,115 +559,59 @@ riscv_fpreg_d_type (struct gdbarch *gdbarch)
   return tdep->riscv_fpreg_d_type;
 }
 
-/* Construct a type for 128-bit FP registers.  */
+/* Implement the register_type gdbarch method.  This is installed as an
+   for the override setup by TDESC_USE_REGISTERS, for most registers we
+   delegate the type choice to the target description, but for a few
+   registers we try to improve the types if the target description has
+   taken a simplistic approach.  */
 
 static struct type *
-riscv_fpreg_q_type (struct gdbarch *gdbarch)
+riscv_register_type (struct gdbarch *gdbarch, int regnum)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct type *type = tdesc_register_type (gdbarch, regnum);
+  int xlen = riscv_isa_xlen (gdbarch);
 
-  if (tdep->riscv_fpreg_q_type == nullptr)
+  /* We want to perform some specific type "fixes" in cases where we feel
+     that we really can do better than the target description.  For all
+     other cases we just return what the target description says.  */
+  if (riscv_is_fp_regno_p (regnum))
     {
-      const struct builtin_type *bt = builtin_type (gdbarch);
-
-      /* The type we're building is this: */
-#if 0
-      union __gdb_builtin_type_fpreg_d
-      {
-	float f;
-	double d;
-	long double ld;
-      };
-#endif
-
-      struct type *t;
-
-      t = arch_composite_type (gdbarch,
-			       "__gdb_builtin_type_fpreg_q", TYPE_CODE_UNION);
-      append_composite_type_field (t, "float", bt->builtin_float);
-      append_composite_type_field (t, "double", bt->builtin_double);
-      append_composite_type_field (t, "long double", bt->builtin_long_double);
-      TYPE_VECTOR (t) = 1;
-      TYPE_NAME (t) = "builtin_type_fpreg_q";
-      tdep->riscv_fpreg_q_type = t;
+      /* This spots the case for RV64 where the double is defined as
+         either 'ieee_double' or 'float' (which is the generic name that
+         converts to 'double' on 64-bit).  In these cases its better to
+         present the registers using a union type.  */
+      int flen = riscv_isa_flen (gdbarch);
+      if (flen == 8
+          && TYPE_CODE (type) == TYPE_CODE_FLT
+          && TYPE_LENGTH (type) == flen
+          && (strcmp (TYPE_NAME (type), "builtin_type_ieee_double") == 0
+              || strcmp (TYPE_NAME (type), "double") == 0))
+        type = riscv_fpreg_d_type (gdbarch);
     }
 
-  return tdep->riscv_fpreg_q_type;
-}
-
-/* Implement the register_type gdbarch method.  */
-
-static struct type *
-riscv_register_type (struct gdbarch *gdbarch, int regnum)
-{
-  int regsize;
-
-  if (regnum < RISCV_FIRST_FP_REGNUM)
+  if ((regnum == gdbarch_pc_regnum (gdbarch)
+       || regnum == RISCV_RA_REGNUM
+       || regnum == RISCV_FP_REGNUM
+       || regnum == RISCV_SP_REGNUM
+       || regnum == RISCV_GP_REGNUM
+       || regnum == RISCV_TP_REGNUM)
+      && TYPE_CODE (type) == TYPE_CODE_INT
+      && TYPE_LENGTH (type) == xlen)
     {
+      /* This spots the case where some interesting registers are defined
+         as simple integers of the expected size, we force these registers
+         to be pointers as we believe that is more useful.  */
       if (regnum == gdbarch_pc_regnum (gdbarch)
-	  || regnum == RISCV_RA_REGNUM)
-	return builtin_type (gdbarch)->builtin_func_ptr;
-
-      if (regnum == RISCV_FP_REGNUM
-	  || regnum == RISCV_SP_REGNUM
-	  || regnum == RISCV_GP_REGNUM
-	  || regnum == RISCV_TP_REGNUM)
-	return builtin_type (gdbarch)->builtin_data_ptr;
-
-      /* Remaining GPRs vary in size based on the current ISA.  */
-      regsize = riscv_isa_xlen (gdbarch);
-      switch (regsize)
-	{
-	case 4:
-	  return builtin_type (gdbarch)->builtin_uint32;
-	case 8:
-	  return builtin_type (gdbarch)->builtin_uint64;
-	case 16:
-	  return builtin_type (gdbarch)->builtin_uint128;
-	default:
-	  internal_error (__FILE__, __LINE__,
-			  _("unknown isa regsize %i"), regsize);
-	}
+          || regnum == RISCV_RA_REGNUM)
+        type = builtin_type (gdbarch)->builtin_func_ptr;
+      else if (regnum == RISCV_FP_REGNUM
+               || regnum == RISCV_SP_REGNUM
+               || regnum == RISCV_GP_REGNUM
+               || regnum == RISCV_TP_REGNUM)
+	type = builtin_type (gdbarch)->builtin_data_ptr;
     }
-  else if (regnum <= RISCV_LAST_FP_REGNUM)
-    {
-      regsize = riscv_isa_xlen (gdbarch);
-      switch (regsize)
-	{
-	case 4:
-	  return builtin_type (gdbarch)->builtin_float;
-	case 8:
-	  return riscv_fpreg_d_type (gdbarch);
-	case 16:
-	  return riscv_fpreg_q_type (gdbarch);
-	default:
-	  internal_error (__FILE__, __LINE__,
-			  _("unknown isa regsize %i"), regsize);
-	}
-    }
-  else if (regnum == RISCV_PRIV_REGNUM)
-    return builtin_type (gdbarch)->builtin_int8;
-  else
-    {
-      if (regnum == RISCV_CSR_FFLAGS_REGNUM
-	  || regnum == RISCV_CSR_FRM_REGNUM
-	  || regnum == RISCV_CSR_FCSR_REGNUM)
-	return builtin_type (gdbarch)->builtin_int32;
 
-      regsize = riscv_isa_xlen (gdbarch);
-      switch (regsize)
-	{
-	case 4:
-	  return builtin_type (gdbarch)->builtin_int32;
-	case 8:
-	  return builtin_type (gdbarch)->builtin_int64;
-	case 16:
-	  return builtin_type (gdbarch)->builtin_int128;
-	default:
-	  internal_error (__FILE__, __LINE__,
-			  _("unknown isa regsize %i"), regsize);
-	}
-    }
+  return type;
 }
 
 /* Helper for riscv_print_registers_info, prints info for a single register
@@ -679,14 +624,28 @@ riscv_print_one_register_info (struct gdbarch *gdbarch,
 			       int regnum)
 {
   const char *name = gdbarch_register_name (gdbarch, regnum);
-  struct value *val = value_of_register (regnum, frame);
-  struct type *regtype = value_type (val);
+  struct value *val;
+  struct type *regtype;
   int print_raw_format;
   enum tab_stops { value_column_1 = 15 };
 
   fputs_filtered (name, file);
   print_spaces_filtered (value_column_1 - strlen (name), file);
 
+  TRY
+    {
+      val = value_of_register (regnum, frame);
+      regtype = value_type (val);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      /* Handle failure to read a register without interrupting the entire
+         'info registers' flow.  */
+      fprintf_filtered (file, "%s\n", ex.message);
+      return;
+    }
+  END_CATCH
+
   print_raw_format = (value_entirely_available (val)
 		      && !value_optimized_out (val));
 
@@ -901,6 +860,15 @@ riscv_register_reggroup_p (struct gdbarch  *gdbarch, int regnum,
       || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
     return 0;
 
+  if (regnum > RISCV_LAST_REGNUM)
+    {
+      int ret = tdesc_register_in_reggroup_p (gdbarch, regnum, reggroup);
+      if (ret != -1)
+        return ret;
+
+      return default_register_reggroup_p (gdbarch, regnum, reggroup);
+    }
+
   if (reggroup == all_reggroup)
     {
       if (regnum < RISCV_FIRST_CSR_REGNUM || regnum == RISCV_PRIV_REGNUM)
@@ -923,7 +891,7 @@ riscv_register_reggroup_p (struct gdbarch  *gdbarch, int regnum,
       else
 	return regnum < RISCV_FIRST_FP_REGNUM;
     }
-  else if (reggroup == system_reggroup)
+  else if (reggroup == system_reggroup || reggroup == csr_reggroup)
     {
       if (regnum == RISCV_PRIV_REGNUM)
 	return 1;
@@ -951,7 +919,6 @@ riscv_print_registers_info (struct gdbarch *gdbarch,
   if (regnum != -1)
     {
       /* Print one specified register.  */
-      gdb_assert (regnum <= RISCV_LAST_REGNUM);
       if (gdbarch_register_name (gdbarch, regnum) == NULL
 	  || *(gdbarch_register_name (gdbarch, regnum)) == '\0')
         error (_("Not a valid register for the current processor type"));
@@ -978,7 +945,7 @@ riscv_print_registers_info (struct gdbarch *gdbarch,
 	    continue;
 
 	  /* Is the register in the group we're interested in?  */
-	  if (!riscv_register_reggroup_p (gdbarch, regnum, reggroup))
+	  if (!gdbarch_register_reggroup_p (gdbarch, regnum, reggroup))
 	    continue;
 
 	  riscv_print_one_register_info (gdbarch, file, frame, regnum);
@@ -2796,36 +2763,26 @@ static const struct frame_unwind riscv_frame_unwind =
   /*.prev_arch     =*/ NULL,
 };
 
-/* Initialize the current architecture based on INFO.  If possible,
-   re-use an architecture from ARCHES, which is a list of
-   architectures already created during this debugging session.
-
-   Called e.g. at program startup, when reading a core file, and when
-   reading a binary file.  */
+/* Find a suitable default target description.  Use the contents of INFO,
+   specifically the bfd object being executed, to guide the selection of a
+   suitable default target description.  */
 
-static struct gdbarch *
-riscv_gdbarch_init (struct gdbarch_info info,
-		    struct gdbarch_list *arches)
+static struct target_desc *
+riscv_find_default_target_description (const struct gdbarch_info info)
 {
-  struct gdbarch *gdbarch;
-  struct gdbarch_tdep *tdep;
-  struct gdbarch_tdep tmp_tdep;
-  int i;
-
-  /* Ideally, we'd like to get as much information from the target for
-     things like register size, and whether the target has floating point
-     hardware.  However, there are some things that the target can't tell
-     us, like, what ABI is being used.
+  struct riscv_gdbarch_features features;
 
-     So, for now, we take as much information as possible from the ELF,
-     including things like register size, and FP hardware support, along
-     with information about the ABI.
-
-     Information about this target is built up in TMP_TDEP, and then we
-     look for an existing gdbarch in ARCHES that matches TMP_TDEP.  If no
-     match is found we'll create a new gdbarch and copy TMP_TDEP over.  */
-  memset (&tmp_tdep, 0, sizeof (tmp_tdep));
+  /* Setup some arbitrary defaults.  */
+  features.xlen = 8;
+  features.flen = 0;
+  features.hw_float_abi = false;
 
+  /* Now try to improve on the defaults by looking at the binary we are
+     going to execute.  We assume the user knows what they are doing and
+     that the target will match the binary.  Remember, this code path is
+     only used at all if the target hasn't given us a description, so this
+     is really a last ditched effort to do something sane before giving
+     up.  */
   if (info.abfd != NULL
       && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
     {
@@ -2833,26 +2790,22 @@ riscv_gdbarch_init (struct gdbarch_info info,
       int e_flags = elf_elfheader (info.abfd)->e_flags;
 
       if (eclass == ELFCLASS32)
-	tmp_tdep.abi.fields.base_len = 1;
+	features.xlen = 4;
       else if (eclass == ELFCLASS64)
-	tmp_tdep.abi.fields.base_len = 2;
+	features.xlen = 8;
       else
-        internal_error (__FILE__, __LINE__,
+	internal_error (__FILE__, __LINE__,
 			_("unknown ELF header class %d"), eclass);
 
-      if (e_flags & EF_RISCV_RVC)
-	tmp_tdep.core_features |= (1 << ('C' - 'A'));
-
       if (e_flags & EF_RISCV_FLOAT_ABI_DOUBLE)
 	{
-	  tmp_tdep.abi.fields.float_abi = 2;
-	  tmp_tdep.core_features |= (1 << ('D' - 'A'));
-	  tmp_tdep.core_features |= (1 << ('F' - 'A'));
+	  features.flen = 8;
+	  features.hw_float_abi = true;
 	}
       else if (e_flags & EF_RISCV_FLOAT_ABI_SINGLE)
 	{
-	  tmp_tdep.abi.fields.float_abi = 1;
-	  tmp_tdep.core_features |= (1 << ('F' - 'A'));
+	  features.flen = 4;
+	  features.hw_float_abi = true;
 	}
     }
   else
@@ -2860,25 +2813,210 @@ riscv_gdbarch_init (struct gdbarch_info info,
       const struct bfd_arch_info *binfo = info.bfd_arch_info;
 
       if (binfo->bits_per_word == 32)
-	tmp_tdep.abi.fields.base_len = 1;
+	features.xlen = 4;
       else if (binfo->bits_per_word == 64)
-	tmp_tdep.abi.fields.base_len = 2;
+	features.xlen = 8;
       else
-        internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"),
+	internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"),
 			binfo->bits_per_word);
     }
 
+  /* Now build a target description based on the feature set.  */
+  return riscv_create_target_description (features);
+}
+
+/* All of the registers in REG_SET are checked for in FEATURE, TDESC_DATA
+   is updated with the register numbers for each register as listed in
+   REG_SET.  If any register marked as required in REG_SET is not found in
+   FEATURE then this function returns false, otherwise, it returns true.  */
+
+static bool
+riscv_check_tdesc_feature (struct tdesc_arch_data *tdesc_data,
+                           const struct tdesc_feature *feature,
+                           const struct riscv_register_feature *reg_set)
+{
+  for (const auto &reg : reg_set->registers)
+    {
+      bool found = false;
+
+      for (const char *name : reg.names)
+	{
+	  found =
+	    tdesc_numbered_register (feature, tdesc_data, reg.regnum, name);
+
+	  if (found)
+	    break;
+	}
+
+      if (!found && reg.required_p)
+	return false;
+    }
+
+  return true;
+}
+
+/* Add all the expected register sets into GDBARCH.  */
+
+static void
+riscv_add_reggroups (struct gdbarch *gdbarch)
+{
+  /* Add predefined register groups.  */
+  reggroup_add (gdbarch, all_reggroup);
+  reggroup_add (gdbarch, save_reggroup);
+  reggroup_add (gdbarch, restore_reggroup);
+  reggroup_add (gdbarch, system_reggroup);
+  reggroup_add (gdbarch, vector_reggroup);
+  reggroup_add (gdbarch, general_reggroup);
+  reggroup_add (gdbarch, float_reggroup);
+
+  /* Add RISC-V specific register groups.  */
+  reggroup_add (gdbarch, csr_reggroup);
+}
+
+/* Create register aliases for all the alternative names that exist for
+   registers in REG_SET.  */
+
+static void
+riscv_setup_register_aliases (struct gdbarch *gdbarch,
+                              const struct riscv_register_feature *reg_set)
+{
+  for (auto &reg : reg_set->registers)
+    {
+      /* The first item in the names list is the preferred name for the
+         register, this is what RISCV_REGISTER_NAME returns, and so we
+         don't need to create an alias with that name here.  */
+      for (int i = 1; i < reg.names.size (); ++i)
+        user_reg_add (gdbarch, reg.names[i], value_of_riscv_user_reg,
+                      &reg.regnum);
+    }
+}
+
+/* Initialize the current architecture based on INFO.  If possible,
+   re-use an architecture from ARCHES, which is a list of
+   architectures already created during this debugging session.
+
+   Called e.g. at program startup, when reading a core file, and when
+   reading a binary file.  */
+
+static struct gdbarch *
+riscv_gdbarch_init (struct gdbarch_info info,
+		    struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  struct riscv_gdbarch_features features;
+  const struct target_desc *tdesc = info.target_desc;
+
+  /* Ensure we always have a target description.  */
+  if (!tdesc_has_registers (tdesc))
+    tdesc = riscv_find_default_target_description (info);
+  gdb_assert (tdesc);
+
+  if (riscv_debug_gdbarch)
+    fprintf_unfiltered (gdb_stdlog, "Have got a target description\n");
+
+  const struct tdesc_feature *feature_cpu
+    = tdesc_find_feature (tdesc, riscv_xreg_feature.name);
+  const struct tdesc_feature *feature_fpu
+    = tdesc_find_feature (tdesc, riscv_freg_feature.name);
+  const struct tdesc_feature *feature_virtual
+    = tdesc_find_feature (tdesc, riscv_virtual_feature.name);
+  const struct tdesc_feature *feature_csr
+    = tdesc_find_feature (tdesc, riscv_csr_feature.name);
+
+  if (feature_cpu == NULL)
+    return NULL;
+
+  struct tdesc_arch_data *tdesc_data = tdesc_data_alloc ();
+
+  bool valid_p = riscv_check_tdesc_feature (tdesc_data,
+                                            feature_cpu,
+                                            &riscv_xreg_feature);
+  if (valid_p)
+    {
+      /* Check that all of the core cpu registers have the same bitsize.  */
+      int xlen_bitsize = tdesc_register_bitsize (feature_cpu, "pc");
+
+      for (auto &tdesc_reg : feature_cpu->registers)
+        valid_p &= (tdesc_reg->bitsize == xlen_bitsize);
+
+      if (riscv_debug_gdbarch)
+        fprintf_filtered
+          (gdb_stdlog,
+           "From target-description, xlen = %d\n", xlen_bitsize);
+
+      features.xlen = (xlen_bitsize / 8);
+    }
+
+  if (feature_fpu != NULL)
+    {
+      valid_p &= riscv_check_tdesc_feature (tdesc_data, feature_fpu,
+                                            &riscv_freg_feature);
+
+      int bitsize = tdesc_register_bitsize (feature_fpu, "ft0");
+      features.flen = (bitsize / 8);
+      features.hw_float_abi = true;
+
+      if (riscv_debug_gdbarch)
+        fprintf_filtered
+          (gdb_stdlog,
+           "From target-description, flen = %d\n", bitsize);
+    }
+  else
+    {
+      features.flen = 0;
+      features.hw_float_abi = false;
+
+      if (riscv_debug_gdbarch)
+        fprintf_filtered
+          (gdb_stdlog,
+           "No FPU in target-description, assume soft-float ABI\n");
+    }
+
+  if (feature_virtual)
+    riscv_check_tdesc_feature (tdesc_data, feature_virtual,
+                               &riscv_virtual_feature);
+
+  if (feature_csr)
+    riscv_check_tdesc_feature (tdesc_data, feature_csr,
+                               &riscv_csr_feature);
+
+  if (!valid_p)
+    {
+      if (riscv_debug_gdbarch)
+        fprintf_unfiltered (gdb_stdlog, "Target description is not valid\n");
+      tdesc_data_cleanup (tdesc_data);
+      return NULL;
+    }
+
   /* Find a candidate among the list of pre-declared architectures.  */
   for (arches = gdbarch_list_lookup_by_info (arches, &info);
        arches != NULL;
        arches = gdbarch_list_lookup_by_info (arches->next, &info))
-    if (gdbarch_tdep (arches->gdbarch)->abi.value == tmp_tdep.abi.value)
+    {
+      /* Check that the feature set of the ARCHES matches the feature set
+         we are looking for.  If it doesn't then we can't reuse this
+         gdbarch.  */
+      struct gdbarch_tdep *other_tdep = gdbarch_tdep (arches->gdbarch);
+
+      if (other_tdep->features.hw_float_abi != features.hw_float_abi
+          || other_tdep->features.xlen != features.xlen
+          || other_tdep->features.flen != features.flen)
+        continue;
+
+      break;
+    }
+
+  if (arches != NULL)
+    {
+      tdesc_data_cleanup (tdesc_data);
       return arches->gdbarch;
+    }
 
   /* None found, so create a new architecture from the information provided.  */
-  tdep = (struct gdbarch_tdep *) xmalloc (sizeof *tdep);
+  tdep = new (struct gdbarch_tdep);
   gdbarch = gdbarch_alloc (&info, tdep);
-  memcpy (tdep, &tmp_tdep, sizeof (tmp_tdep));
+  tdep->features = features;
 
   /* Target data types.  */
   set_gdbarch_short_bit (gdbarch, 16);
@@ -2898,19 +3036,6 @@ riscv_gdbarch_init (struct gdbarch_info info,
   set_gdbarch_sw_breakpoint_from_kind (gdbarch, riscv_sw_breakpoint_from_kind);
   set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
 
-  /* Register architecture.  */
-  set_gdbarch_num_regs (gdbarch, RISCV_LAST_REGNUM + 1);
-  set_gdbarch_sp_regnum (gdbarch, RISCV_SP_REGNUM);
-  set_gdbarch_pc_regnum (gdbarch, RISCV_PC_REGNUM);
-  set_gdbarch_ps_regnum (gdbarch, RISCV_FP_REGNUM);
-  set_gdbarch_deprecated_fp_regnum (gdbarch, RISCV_FP_REGNUM);
-
-  /* Functions to supply register information.  */
-  set_gdbarch_register_name (gdbarch, riscv_register_name);
-  set_gdbarch_register_type (gdbarch, riscv_register_type);
-  set_gdbarch_print_registers_info (gdbarch, riscv_print_registers_info);
-  set_gdbarch_register_reggroup_p (gdbarch, riscv_register_reggroup_p);
-
   /* Functions to analyze frames.  */
   set_gdbarch_skip_prologue (gdbarch, riscv_skip_prologue);
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
@@ -2931,9 +3056,49 @@ riscv_gdbarch_init (struct gdbarch_info info,
   dwarf2_append_unwinders (gdbarch);
   frame_unwind_append_unwinder (gdbarch, &riscv_frame_unwind);
 
-  for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i)
-    user_reg_add (gdbarch, riscv_register_aliases[i].name,
-		  value_of_riscv_user_reg, &riscv_register_aliases[i].regnum);
+  /* Register architecture.  */
+  riscv_add_reggroups (gdbarch);
+
+  /* We reserve all possible register numbers for the known registers.
+     This means the target description mechanism will add any target
+     specific registers after this number.  This helps make debugging GDB
+     just a little easier.  */
+  set_gdbarch_num_regs (gdbarch, RISCV_LAST_REGNUM + 1);
+
+  /* We don't have to provide the count of 0 here (its the default) but
+     include this line to make it explicit that, right now, we don't have
+     any pseudo registers on RISC-V.  */
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+
+  /* Some specific register numbers GDB likes to know about.  */
+  set_gdbarch_sp_regnum (gdbarch, RISCV_SP_REGNUM);
+  set_gdbarch_pc_regnum (gdbarch, RISCV_PC_REGNUM);
+
+  set_gdbarch_print_registers_info (gdbarch, riscv_print_registers_info);
+
+  /* Finalise the target description registers.  */
+  tdesc_use_registers (gdbarch, tdesc, tdesc_data);
+
+  /* Override the register type callback setup by the target description
+     mechanism.  This allows us to provide special type for floating point
+     registers.  */
+  set_gdbarch_register_type (gdbarch, riscv_register_type);
+
+  /* Override the register name callback setup by the target description
+     mechanism.  This allows us to force our preferred names for the
+     registers, no matter what the target description called them.  */
+  set_gdbarch_register_name (gdbarch, riscv_register_name);
+
+  /* Override the register group callback setup by the target description
+     mechanism.  This allows us to force registers into the groups we
+     want, ignoring what the target tells us.  */
+  set_gdbarch_register_reggroup_p (gdbarch, riscv_register_reggroup_p);
+
+  /* Create register aliases for alternative register names.  */
+  riscv_setup_register_aliases (gdbarch, &riscv_xreg_feature);
+  if (riscv_has_fp_regs (gdbarch))
+    riscv_setup_register_aliases (gdbarch, &riscv_freg_feature);
+  riscv_setup_register_aliases (gdbarch, &riscv_csr_feature);
 
   /* Hook in OS ABI-specific overrides, if they have been registered.  */
   gdbarch_init_osabi (info, gdbarch);
@@ -3080,9 +3245,20 @@ riscv_software_single_step (struct regcache *regcache)
   return {next_pc};
 }
 
+/* Create RISC-V specific reggroups.  */
+
+static void
+riscv_init_reggroups ()
+{
+  csr_reggroup = reggroup_new ("csr", USER_REGGROUP);
+}
+
 void
 _initialize_riscv_tdep (void)
 {
+  riscv_create_csr_aliases ();
+  riscv_init_reggroups ();
+
   gdbarch_register (bfd_arch_riscv, riscv_gdbarch_init, NULL);
 
   /* Add root prefix command for all "set debug riscv" and "show debug
@@ -3127,6 +3303,16 @@ of the stack unwinding mechanism."),
 			     show_riscv_debug_variable,
 			     &setdebugriscvcmdlist, &showdebugriscvcmdlist);
 
+  add_setshow_zuinteger_cmd ("gdbarch", class_maintenance,
+			     &riscv_debug_gdbarch,  _("\
+Set riscv gdbarch initialisation debugging."), _("\
+Show riscv gdbarch initialisation debugging."), _("\
+When non-zero, print debugging information for the riscv gdbarch\n\
+initialisation process."),
+			     NULL,
+			     show_riscv_debug_variable,
+			     &setdebugriscvcmdlist, &showdebugriscvcmdlist);
+
   /* Add root prefix command for all "set riscv" and "show riscv" commands.  */
   add_prefix_cmd ("riscv", no_class, set_riscv_command,
 		  _("RISC-V specific commands."),
diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
index 2cb51b16c53..59ad37df6ce 100644
--- a/gdb/riscv-tdep.h
+++ b/gdb/riscv-tdep.h
@@ -21,6 +21,8 @@
 #ifndef RISCV_TDEP_H
 #define RISCV_TDEP_H
 
+#include "arch/riscv.h"
+
 /* RiscV register numbers.  */
 enum
 {
@@ -57,31 +59,12 @@ enum
 /* RISC-V specific per-architecture information.  */
 struct gdbarch_tdep
 {
-  union
-  {
-    /* Provide access to the whole ABI in one value.  */
-    unsigned value;
-
-    struct
-    {
-      /* Encode the base machine length following the same rules as in the
-	 MISA register.  */
-      unsigned base_len : 2;
-
-      /* Encode which floating point ABI is in use following the same rules
-	 as the ELF e_flags field.  */
-      unsigned float_abi : 2;
-    } fields;
-  } abi;
-
-  /* Only the least significant 26 bits are (possibly) valid, and indicate
-     features that are supported on the target.  These could be cached from
-     the target, or read from the executable when available.  */
-  unsigned core_features;
+  /* Features about the target that impact how the gdbarch is configured.
+     Two gdbarch instances are compatible only if this field matches.  */
+  struct riscv_gdbarch_features features;
 
   /* ISA-specific data types.  */
-  struct type *riscv_fpreg_d_type;
-  struct type *riscv_fpreg_q_type;
+  struct type *riscv_fpreg_d_type = nullptr;
 };
 
 
diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c
index bdd29c0f2b5..20604bb4b96 100644
--- a/gdb/target-descriptions.c
+++ b/gdb/target-descriptions.c
@@ -1716,6 +1716,7 @@ maint_print_c_tdesc_cmd (const char *args, int from_tty)
   if (startswith (filename_after_features.c_str (), "i386/32bit-")
       || startswith (filename_after_features.c_str (), "i386/64bit-")
       || startswith (filename_after_features.c_str (), "i386/x32-core.xml")
+      || startswith (filename_after_features.c_str (), "riscv/")
       || startswith (filename_after_features.c_str (), "tic6x-")
       || startswith (filename_after_features.c_str (), "aarch64"))
     {
-- 
2.14.5

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

* Re: [RFC] gdb/riscv: Add target description support
  2018-11-14 14:29   ` Andrew Burgess
@ 2018-11-14 17:42     ` John Baldwin
  0 siblings, 0 replies; 27+ messages in thread
From: John Baldwin @ 2018-11-14 17:42 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, jimw, palmer

On 11/14/18 6:29 AM, Andrew Burgess wrote:
> * John Baldwin <jhb@FreeBSD.org> [2018-11-08 10:32:57 -0800]:
> 
>> On 11/8/18 8:07 AM, Andrew Burgess wrote:
>>> This commit adds target description support for riscv.
>>>
>>> I've used the split feature approach for specifying the architectural
>>> features, and the CSR feature is auto-generated from the riscv-opc.h
>>> header file.
>>
>> In general this looks fine to me (as far as I am familiar with the
>> target descriptions).  The only possible question/comment I have is if
>> you considered describing fields of specific registers such as the FP
>> status registers or MSTATUS, etc. as fields in the XML to replace the
>> current special cases in riscv_print_one_register_info().
> 
> I took a look at switching over to using flag fields in the xml
> description, but in the end I decided against this.
> 
> The main reason is that there appears to be a bug with registers
> described as a flag type, I was unable to assign to the register.
> What I saw was an invalid cast error.
> 
> I defined the type like this:
> 
>     <flags id="riscv_fflags" size="1">
>       <field name="NX" start="0" end="0"/>
>       <field name="UF" start="1" end="1"/>
>       <field name="OF" start="2" end="2"/>
>       <field name="DZ" start="3" end="3"/>
>       <field name="NV" start="4" end="4"/>
>     </flags>
> 
>     <reg name="fflags" bitsize="32" type="riscv_fflags"/>
> 
> But then, when I try to assign to the register I see this error:
> 
>     (gdb) set $fflags=0x3
>     Invalid cast

Weird, on x86 you can assign raw values to $eflags which is also described
as a flags field:

  <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"/>
    ...

(gdb) p $eflags
$1 = [ PF IF ]
(gdb) p/x $eflags
$2 = 0x206
(gdb) set $eflags = $eflags | 1
(gdb) p $eflags
$3 = [ CF PF IF ]

However, if it doesn't work I think it's fine to not use it.  I just wanted
to make sure you weren't duplicating work you wouldn't need.

>> Some related-ish questions (though not about this patch): I wonder if we
>> can do things with pseudo registers to automatically derive FFLAGS and
>> FRM if a target provides FCSR.
> 
> I like this idea a lot, and I definitely plan to implement this, just
> because I think it would be a neat feature.  However, my understanding
> is that FFLAGS and FRM _are_ real CSRs, at least in the sense that
> there's a real CSR offset from which we can read to extract the FFLAGS
> or FRM part of FCSR.  So, initially I'd prefer to merge this with
> these registers as real registers.
> 
> But I think it would be great if for targets that only announce FCSR,
> we could automatically emulate FRM and FCSR.

Ok.  I had assumed that we would have to use pseudo registers to do this,
but perhaps it can be done another way that allows a target to provide them
explicitly if it chose.

-- 
John Baldwin

                                                                            

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

* Re: [PATCH] gdb/riscv: Add target description support
  2018-11-14 14:58 ` [PATCH] " Andrew Burgess
@ 2018-11-19  3:51   ` Jim Wilson
  2018-11-21 11:23     ` Andrew Burgess
  2019-02-22 17:42   ` Tom Tromey
  1 sibling, 1 reply; 27+ messages in thread
From: Jim Wilson @ 2018-11-19  3:51 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, Palmer Dabbelt, John Baldwin

On Wed, Nov 14, 2018 at 6:58 AM Andrew Burgess
<andrew.burgess@embecosm.com> wrote:
> I'm proposing to merge this version if everyone is happy with it.

Looks like a few minor typos in the new docs, but otherwise it looks
good to me.  I tested this riscv-linux native on a HiFive Unleashed
board, and with riscv-tests/debug using openocd and spike.

> +The @samp{org.gnu.gdb.riscv.fpu} feature is optional.  If present it
> +should contains registers @samp{f0} through @samp{f31}, @samp{fflags},
> +@samp{frm}, and @samp{fcsr}.  As with the cpu feature either the
> +architectural register names, or the ABI names can be used.

"should contains registers" -> "should contain registers"

> +The @samp{org.gnu.gdb.riscv.virtual} feature is optional.  If present
> +it should contain registers that are not backed by real registers on
> +the target but are instead virtual, where the register value is
> +derived from other target state.  In many ways these are like GDBs
> +pseudo-registers, except implemented by the target.  Currently the
> +only register expected in this set is the one byte @samp{priv}
> +register that contains the targets privilege level in the least
> +significant two bits.

"targets privilege level" -> "target's privilege level"

> +The @samp{org.gnu.gdb.riscv.csr} feature is optional.  If present it
> +should contain all of the targets standard CSRs.  Standard CSRs are
> +those defined in the RISC-V specification documents.  There is some
> +overlap between this feature and the fpu feature; the @samp{fflags},
> +@samp{frm}, and @samp{fcsr} registers could be in either feature.  The
> +expectation is that these registers will be in the fpu feature if the
> +target has floating point hardware, but can be moved into the csr
> +feature if the target has the floating point control registers, but no
> +other floating point hardware.

"targets standard CSRs" -> "target's standard CSRs"

Jim

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

* Re: [PATCH] gdb/riscv: Add target description support
  2018-11-19  3:51   ` Jim Wilson
@ 2018-11-21 11:23     ` Andrew Burgess
  2018-11-21 12:37       ` Eli Zaretskii
  0 siblings, 1 reply; 27+ messages in thread
From: Andrew Burgess @ 2018-11-21 11:23 UTC (permalink / raw)
  To: Jim Wilson, Eli Zaretskii; +Cc: gdb-patches, Palmer Dabbelt, John Baldwin

* Jim Wilson <jimw@sifive.com> [2018-11-18 19:51:23 -0800]:

> On Wed, Nov 14, 2018 at 6:58 AM Andrew Burgess
> <andrew.burgess@embecosm.com> wrote:
> > I'm proposing to merge this version if everyone is happy with it.
> 
> Looks like a few minor typos in the new docs, but otherwise it looks
> good to me.  I tested this riscv-linux native on a HiFive Unleashed
> board, and with riscv-tests/debug using openocd and spike.
> 
> > +The @samp{org.gnu.gdb.riscv.fpu} feature is optional.  If present it
> > +should contains registers @samp{f0} through @samp{f31}, @samp{fflags},
> > +@samp{frm}, and @samp{fcsr}.  As with the cpu feature either the
> > +architectural register names, or the ABI names can be used.
> 
> "should contains registers" -> "should contain registers"
> 
> > +The @samp{org.gnu.gdb.riscv.virtual} feature is optional.  If present
> > +it should contain registers that are not backed by real registers on
> > +the target but are instead virtual, where the register value is
> > +derived from other target state.  In many ways these are like GDBs
> > +pseudo-registers, except implemented by the target.  Currently the
> > +only register expected in this set is the one byte @samp{priv}
> > +register that contains the targets privilege level in the least
> > +significant two bits.
> 
> "targets privilege level" -> "target's privilege level"
> 
> > +The @samp{org.gnu.gdb.riscv.csr} feature is optional.  If present it
> > +should contain all of the targets standard CSRs.  Standard CSRs are
> > +those defined in the RISC-V specification documents.  There is some
> > +overlap between this feature and the fpu feature; the @samp{fflags},
> > +@samp{frm}, and @samp{fcsr} registers could be in either feature.  The
> > +expectation is that these registers will be in the fpu feature if the
> > +target has floating point hardware, but can be moved into the csr
> > +feature if the target has the floating point control registers, but no
> > +other floating point hardware.
> 
> "targets standard CSRs" -> "target's standard CSRs"

Jim,

Thanks for the feedback.  Below is an updated revision, rebased onto
current HEAD.

Eli,

I believe I still need a doc review before I can merge this patch.
Could I ask you to take a look please.

Thanks,
Andrew

---

gdb/riscv: Add target description support

This commit adds target description support for riscv.

I've used the split feature approach for specifying the architectural
features, and the CSR feature is auto-generated from the riscv-opc.h
header file.

If the target doesn't provide a suitable target description then GDB
will build one by looking at the bfd headers.

This commit does not implement target description creation for the
Linux or FreeBSD native targets, both of these will need to add
read_description methods into their respective target classes, which
probe the target features, and then call
riscv_create_target_description to build a suitable target
description.  Until this is done Linux and FreeBSD will get the same
default target description based on the bfd that bare-metal targets
get.

I've only added feature descriptions for 32 and 64 bit registers, 128
bit registers (for RISC-V) are not supported in the reset of GDB yet.

This commit removes the special reading of the MISA register in order
to establish the target features, this was only used for figuring out
the f-register size, and even that wasn't done consistently.  We now
rely on the target to tell us what size of registers it has (or look
in the BFD as a last resort).  The result of this is that we should
now support RV64 targets with 32-bit float, though I have not
extensively tested this combination yet.

	* Makefile.in (ALL_TARGET_OBS): Add arch/riscv.o.
	(HFILES_NO_SRCDIR): Add arch/riscv.h.
	* arch/riscv.c: New file.
	* arch/riscv.h: New file.
	* configure.tgt: Add cpu_obs list of riscv, move riscv-tdep.o into
	this list, and add arch/riscv.o.
	* features/Makefile: Add riscv features.
	* features/riscv/32bit-cpu.c: New file.
	* features/riscv/32bit-cpu.xml: New file.
	* features/riscv/32bit-csr.c: New file.
	* features/riscv/32bit-csr.xml: New file.
	* features/riscv/32bit-fpu.c: New file.
	* features/riscv/32bit-fpu.xml: New file.
	* features/riscv/64bit-cpu.c: New file.
	* features/riscv/64bit-cpu.xml: New file.
	* features/riscv/64bit-csr.c: New file.
	* features/riscv/64bit-csr.xml: New file.
	* features/riscv/64bit-fpu.c: New file.
	* features/riscv/64bit-fpu.xml: New file.
	* features/riscv/rebuild-csr-xml.sh: New file.
	* riscv-tdep.c: Add 'arch/riscv.h' include.
	(riscv_gdb_reg_names): Delete.
	(csr_reggroup): New global.
	(struct riscv_register_alias): Delete.
	(struct riscv_register_feature): New structure.
	(riscv_register_aliases): Delete.
	(riscv_xreg_feature): New global.
	(riscv_freg_feature): New global.
	(riscv_virtual_feature): New global.
	(riscv_csr_feature): New global.
	(riscv_create_csr_aliases): New function.
	(riscv_read_misa_reg): Delete.
	(riscv_has_feature): Delete.
	(riscv_isa_xlen): Simplify, just return cached xlen.
	(riscv_isa_flen): Simplify, just return cached flen.
	(riscv_has_fp_abi): Update for changes in struct gdbarch_tdep.
	(riscv_register_name): Update to make use of tdesc_register_name.
	Look up xreg and freg names in the new globals riscv_xreg_feature
	and riscv_freg_feature.  Don't supply csr aliases here.
	(riscv_fpreg_q_type): Delete.
	(riscv_register_type): Use tdesc_register_type in almost all
	cases, override the returned type in a few specific cases only.
	(riscv_print_one_register_info): Handle errors reading registers.
	(riscv_register_reggroup_p): Use tdesc_register_in_reggroup_p for
	registers that are otherwise unknown to GDB.  Also check the
	csr_reggroup.
	(riscv_print_registers_info): Remove assert about upper register
	number, and use gdbarch_register_reggroup_p instead of
	short-cutting.
	(riscv_find_default_target_description): New function.
	(riscv_check_tdesc_feature): New function.
	(riscv_add_reggroups): New function.
	(riscv_setup_register_aliases): New function.
	(riscv_init_reggroups): New function.
	(_initialize_riscv_tdep): Add calls to setup CSR aliases, and
	setup register groups.  Register new riscv debug variable.
	* riscv-tdep.h: Add 'arch/riscv.h' include.
	(struct gdbarch_tdep): Remove abi union, and add
	riscv_gdbarch_features field.  Remove cached quad floating point
	type, and provide initialisation for double type field.
	* target-descriptions.c (maint_print_c_tdesc_cmd): Add riscv to
	the list of targets using the feature based target descriptions.
	* NEWS: Mention target description support.

gdb/doc/ChangeLog:

	* gdb.texinfo (Standard Target Features): Add RISC-V Features
	sub-section.
---
 gdb/ChangeLog                         |  66 +++
 gdb/Makefile.in                       |   2 +
 gdb/NEWS                              |   2 +
 gdb/arch/riscv.c                      |  69 +++
 gdb/arch/riscv.h                      |  64 +++
 gdb/configure.tgt                     |   9 +-
 gdb/doc/ChangeLog                     |   5 +
 gdb/doc/gdb.texinfo                   |  36 ++
 gdb/features/Makefile                 |  11 +
 gdb/features/riscv/32bit-cpu.c        |  46 ++
 gdb/features/riscv/32bit-cpu.xml      |  43 ++
 gdb/features/riscv/32bit-csr.c        | 253 ++++++++++
 gdb/features/riscv/32bit-csr.xml      | 250 ++++++++++
 gdb/features/riscv/32bit-fpu.c        |  48 ++
 gdb/features/riscv/32bit-fpu.xml      |  46 ++
 gdb/features/riscv/64bit-cpu.c        |  46 ++
 gdb/features/riscv/64bit-cpu.xml      |  43 ++
 gdb/features/riscv/64bit-csr.c        | 253 ++++++++++
 gdb/features/riscv/64bit-csr.xml      | 250 ++++++++++
 gdb/features/riscv/64bit-fpu.c        |  56 +++
 gdb/features/riscv/64bit-fpu.xml      |  52 ++
 gdb/features/riscv/rebuild-csr-xml.sh |  29 ++
 gdb/riscv-tdep.c                      | 888 ++++++++++++++++++++--------------
 gdb/riscv-tdep.h                      |  29 +-
 gdb/target-descriptions.c             |   1 +
 25 files changed, 2220 insertions(+), 377 deletions(-)
 create mode 100644 gdb/arch/riscv.c
 create mode 100644 gdb/arch/riscv.h
 create mode 100644 gdb/features/riscv/32bit-cpu.c
 create mode 100644 gdb/features/riscv/32bit-cpu.xml
 create mode 100644 gdb/features/riscv/32bit-csr.c
 create mode 100644 gdb/features/riscv/32bit-csr.xml
 create mode 100644 gdb/features/riscv/32bit-fpu.c
 create mode 100644 gdb/features/riscv/32bit-fpu.xml
 create mode 100644 gdb/features/riscv/64bit-cpu.c
 create mode 100644 gdb/features/riscv/64bit-cpu.xml
 create mode 100644 gdb/features/riscv/64bit-csr.c
 create mode 100644 gdb/features/riscv/64bit-csr.xml
 create mode 100644 gdb/features/riscv/64bit-fpu.c
 create mode 100644 gdb/features/riscv/64bit-fpu.xml
 create mode 100755 gdb/features/riscv/rebuild-csr-xml.sh

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8bd78a6b84a..4001bcbc07c 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -667,6 +667,7 @@ ALL_TARGET_OBS = \
 	arch/arm-linux.o \
 	arch/i386.o \
 	arch/ppc-linux-common.o \
+	arch/riscv.o \
 	arm-bsd-tdep.o \
 	arm-fbsd-tdep.o \
 	arm-linux-tdep.o \
@@ -1418,6 +1419,7 @@ HFILES_NO_SRCDIR = \
 	arch/i386.h \
 	arch/ppc-linux-common.h \
 	arch/ppc-linux-tdesc.h \
+	arch/riscv.h \
 	cli/cli-cmds.h \
 	cli/cli-decode.h \
 	cli/cli-script.h \
diff --git a/gdb/NEWS b/gdb/NEWS
index ef037dee4a2..9ecbb83d99c 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -38,6 +38,8 @@
   requires the use of a keyword.  Selecting a frame by level is
   unchanged.  The MI comment "-stack-select-frame" is unchanged.
 
+* The RISC-V target now supports target descriptions.
+
 * New targets
 
   NXP S12Z		s12z-*-elf
diff --git a/gdb/arch/riscv.c b/gdb/arch/riscv.c
new file mode 100644
index 00000000000..ca2238d5d70
--- /dev/null
+++ b/gdb/arch/riscv.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+#include "riscv.h"
+#include <stdlib.h>
+
+#include "../features/riscv/32bit-cpu.c"
+#include "../features/riscv/64bit-cpu.c"
+#include "../features/riscv/32bit-fpu.c"
+#include "../features/riscv/64bit-fpu.c"
+
+/* See arch/riscv.h.  */
+
+target_desc *
+riscv_create_target_description (struct riscv_gdbarch_features features)
+{
+  target_desc *tdesc = allocate_target_description ();
+
+#ifndef IN_PROCESS_AGENT
+  std::string arch_name = "riscv";
+
+  if (features.xlen == 4)
+    arch_name.append (":rv32i");
+  else if (features.xlen == 8)
+    arch_name.append (":rv64i");
+  else if (features.xlen == 16)
+    arch_name.append (":rv128i");
+
+  if (features.flen == 4)
+    arch_name.append ("f");
+  else if (features.flen == 8)
+    arch_name.append ("d");
+  else if (features.flen == 16)
+    arch_name.append ("q");
+
+  set_tdesc_architecture (tdesc, arch_name.c_str ());
+#endif
+
+  long regnum = 0;
+
+  /* For now we only support creating 32-bit or 64-bit x-registers.  */
+  if (features.xlen == 4)
+    regnum = create_feature_riscv_32bit_cpu (tdesc, regnum);
+  else if (features.xlen == 8)
+    regnum = create_feature_riscv_64bit_cpu (tdesc, regnum);
+
+  /* For now we only support creating 32-bit or 64-bit f-registers.  */
+  if (features.flen == 4)
+    regnum = create_feature_riscv_32bit_fpu (tdesc, regnum);
+  else if (features.flen == 8)
+    regnum = create_feature_riscv_64bit_fpu (tdesc, regnum);
+
+  return tdesc;
+}
diff --git a/gdb/arch/riscv.h b/gdb/arch/riscv.h
new file mode 100644
index 00000000000..007944019a9
--- /dev/null
+++ b/gdb/arch/riscv.h
@@ -0,0 +1,64 @@
+/* Common target-dependent functionality for RISC-V
+
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef ARCH_RISCV_H
+#define ARCH_RISCV_H
+
+#include "common/tdesc.h"
+
+/* The set of RISC-V architectural features that we track that impact how
+   we configure the actual gdbarch instance.  We hold one of these in the
+   gdbarch_tdep structure, and use it to distinguish between different
+   RISC-V gdbarch instances.
+
+   The information in here ideally comes from the target description,
+   however, if the target doesn't provide a target description then we will
+   create a default target description by first populating one of these
+   based on what we know about the binary being executed, and using that to
+   drive default target description creation.  */
+
+struct riscv_gdbarch_features
+{
+  /* The size of the x-registers in bytes.  This is either 4 (RV32), 8
+     (RV64), or 16 (RV128).  No other value is valid.  Initialise to the
+     invalid 0 value so we can spot if one of these is used
+     uninitialised.  */
+  int xlen = 0;
+
+  /* The size of the f-registers in bytes.  This is either 4 (RV32), 8
+     (RV64), or 16 (RV128).  This can also hold the value 0 to indicate
+     that there are no f-registers.  No other value is valid.  */
+  int flen = 0;
+
+  /* This indicates if hardware floating point abi is in use.  If the FLEN
+     field is 0 then this value _must_ be false.  If the FLEN field is
+     non-zero and this field is false then this indicates the target has
+     floating point registers, but is still using the soft-float abi.  If
+     this field is true then the hardware floating point abi is in use, and
+     values are passed in f-registers matching the size of FLEN.  */
+  bool hw_float_abi = false;
+};
+
+/* Create and return a target description that is compatible with
+   FEATURES.  */
+
+target_desc *riscv_create_target_description
+	(struct riscv_gdbarch_features features);
+
+#endif /* ARCH_RISCV_H */
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index e1f5e31f547..9b646fa1a21 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -81,6 +81,9 @@ ia64*-*-*)
 	cpu_obs="ia64-tdep.o"
 	;;
 
+riscv*-*-*)
+	cpu_obs="riscv-tdep.o arch/riscv.o";;
+
 x86_64-*-*)
 	cpu_obs="${i386_tobjs} ${amd64_tobjs}";;
 
@@ -532,18 +535,18 @@ s390*-*-linux*)
 
 riscv*-*-freebsd*)
 	# Target: FreeBSD/riscv
-	gdb_target_obs="riscv-fbsd-tdep.o riscv-tdep.o"
+	gdb_target_obs="riscv-fbsd-tdep.o"
 	;;
 
 riscv*-*-linux*)
 	# Target: Linux/RISC-V
-	gdb_target_obs="riscv-linux-tdep.o riscv-tdep.o glibc-tdep.o \
+	gdb_target_obs="riscv-linux-tdep.o glibc-tdep.o \
  			linux-tdep.o solib-svr4.o symfile-mem.o linux-record.o"
 	;;
 
 riscv*-*-*)
 	# Target: RISC-V architecture
-	gdb_target_obs="riscv-tdep.o"
+	gdb_target_obs=""
 	;;
 
 rl78-*-elf)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 3c3915b332c..def9c5c3469 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -42944,6 +42944,7 @@
 * Nios II Features::
 * OpenRISC 1000 Features::
 * PowerPC Features::
+* RISC-V Features::
 * S/390 and System z Features::
 * Sparc Features::
 * TIC6x Features::
@@ -43334,6 +43335,41 @@
 The @samp{org.gnu.gdb.power.htm.tar} feature is optional.  It should
 contain the 64-bit checkpointed register @samp{ctar}.
 
+
+@node RISC-V Features
+@subsection RISC-V Features
+@cindex target descriptions, RISC-V Features
+
+The @samp{org.gnu.gdb.riscv.cpu} feature is required for RISC-V
+targets.  It should contain the registers @samp{x0} through
+@samp{x31}, and @samp{pc}.  Either the architectural names (@samp{x0},
+@samp{x1}, etc) can be used, or the ABI names (@samp{zero}, @samp{ra},
+etc).
+
+The @samp{org.gnu.gdb.riscv.fpu} feature is optional.  If present it
+should contain registers @samp{f0} through @samp{f31}, @samp{fflags},
+@samp{frm}, and @samp{fcsr}.  As with the cpu feature either the
+architectural register names, or the ABI names can be used.
+
+The @samp{org.gnu.gdb.riscv.virtual} feature is optional.  If present
+it should contain registers that are not backed by real registers on
+the target but are instead virtual, where the register value is
+derived from other target state.  In many ways these are like GDBs
+pseudo-registers, except implemented by the target.  Currently the
+only register expected in this set is the one byte @samp{priv}
+register that contains the target's privilege level in the least
+significant two bits.
+
+The @samp{org.gnu.gdb.riscv.csr} feature is optional.  If present it
+should contain all of the target's standard CSRs.  Standard CSRs are
+those defined in the RISC-V specification documents.  There is some
+overlap between this feature and the fpu feature; the @samp{fflags},
+@samp{frm}, and @samp{fcsr} registers could be in either feature.  The
+expectation is that these registers will be in the fpu feature if the
+target has floating point hardware, but can be moved into the csr
+feature if the target has the floating point control registers, but no
+other floating point hardware.
+
 @node S/390 and System z Features
 @subsection S/390 and System z Features
 @cindex target descriptions, S/390 features
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 150fef23f0b..ff2e57c65fd 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -207,6 +207,7 @@ GDB = false
 #Targets which use feature based target descriptions.
 aarch64-feature = 1
 i386-feature = 1
+riscv-feature = 1
 tic6x-feature = 1
 
 all: $(OUTPUTS)
@@ -242,6 +243,12 @@ FEATURE_XMLFILES = aarch64-core.xml \
 	i386/64bit-pkeys.xml \
 	i386/64bit-sse.xml \
 	i386/x32-core.xml \
+	riscv/32bit-cpu.xml \
+	riscv/32bit-csr.xml \
+	riscv/32bit-fpu.xml \
+	riscv/64bit-cpu.xml \
+	riscv/64bit-csr.xml \
+	riscv/64bit-fpu.xml \
 	tic6x-c6xp.xml \
 	tic6x-core.xml \
 	tic6x-gp.xml
@@ -339,6 +346,10 @@ $(outdir)/i386/x32-avx-avx512-linux.dat: i386/x32-core.xml i386/64bit-avx.xml \
 			       i386/64bit-avx512.xml i386/64bit-linux.xml \
 			       i386/64bit-segments.xml
 
+# Regenerate RISC-V CSR feature lists.
+riscv/32bit-csr.xml riscv/64bit-csr.xml: ../../include/opcode/riscv-opc.h
+	./riscv/rebuild-csr-xml.sh ../../include/opcode/riscv-opc.h ./riscv
+
 # 'all' doesn't build the C files, so don't delete them in 'clean'
 # either.
 clean-cfiles:
diff --git a/gdb/features/riscv/32bit-cpu.c b/gdb/features/riscv/32bit-cpu.c
new file mode 100644
index 00000000000..64686db5cdd
--- /dev/null
+++ b/gdb/features/riscv/32bit-cpu.c
@@ -0,0 +1,46 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 32bit-cpu.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_32bit_cpu (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.cpu");
+  tdesc_create_reg (feature, "zero", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "ra", regnum++, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "sp", regnum++, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "gp", regnum++, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "tp", regnum++, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "t0", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fp", regnum++, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "s1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a0", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "a7", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s7", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s8", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s9", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s10", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "s11", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "t6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pc", regnum++, 1, NULL, 32, "code_ptr");
+  return regnum;
+}
diff --git a/gdb/features/riscv/32bit-cpu.xml b/gdb/features/riscv/32bit-cpu.xml
new file mode 100644
index 00000000000..c02f86c0b03
--- /dev/null
+++ b/gdb/features/riscv/32bit-cpu.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.cpu">
+  <reg name="zero" bitsize="32" type="int"/>
+  <reg name="ra" bitsize="32" type="code_ptr"/>
+  <reg name="sp" bitsize="32" type="data_ptr"/>
+  <reg name="gp" bitsize="32" type="data_ptr"/>
+  <reg name="tp" bitsize="32" type="data_ptr"/>
+  <reg name="t0" bitsize="32" type="int"/>
+  <reg name="t1" bitsize="32" type="int"/>
+  <reg name="t2" bitsize="32" type="int"/>
+  <reg name="fp" bitsize="32" type="data_ptr"/>
+  <reg name="s1" bitsize="32" type="int"/>
+  <reg name="a0" bitsize="32" type="int"/>
+  <reg name="a1" bitsize="32" type="int"/>
+  <reg name="a2" bitsize="32" type="int"/>
+  <reg name="a3" bitsize="32" type="int"/>
+  <reg name="a4" bitsize="32" type="int"/>
+  <reg name="a5" bitsize="32" type="int"/>
+  <reg name="a6" bitsize="32" type="int"/>
+  <reg name="a7" bitsize="32" type="int"/>
+  <reg name="s2" bitsize="32" type="int"/>
+  <reg name="s3" bitsize="32" type="int"/>
+  <reg name="s4" bitsize="32" type="int"/>
+  <reg name="s5" bitsize="32" type="int"/>
+  <reg name="s6" bitsize="32" type="int"/>
+  <reg name="s7" bitsize="32" type="int"/>
+  <reg name="s8" bitsize="32" type="int"/>
+  <reg name="s9" bitsize="32" type="int"/>
+  <reg name="s10" bitsize="32" type="int"/>
+  <reg name="s11" bitsize="32" type="int"/>
+  <reg name="t3" bitsize="32" type="int"/>
+  <reg name="t4" bitsize="32" type="int"/>
+  <reg name="t5" bitsize="32" type="int"/>
+  <reg name="t6" bitsize="32" type="int"/>
+  <reg name="pc" bitsize="32" type="code_ptr"/>
+</feature>
diff --git a/gdb/features/riscv/32bit-csr.c b/gdb/features/riscv/32bit-csr.c
new file mode 100644
index 00000000000..711e958ddae
--- /dev/null
+++ b/gdb/features/riscv/32bit-csr.c
@@ -0,0 +1,253 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 32bit-csr.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_32bit_csr (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.csr");
+  tdesc_create_reg (feature, "ustatus", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "uie", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "utvec", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "uscratch", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "uepc", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "ucause", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "utval", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "uip", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "frm", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fcsr", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "cycle", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "time", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "instret", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter7", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter8", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter9", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter10", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter11", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter12", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter13", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter14", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter15", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter16", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter17", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter18", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter19", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter20", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter21", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter22", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter23", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter24", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter25", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter26", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter27", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter28", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter29", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter30", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter31", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "cycleh", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "timeh", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "instreth", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter3h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter4h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter5h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter6h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter7h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter8h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter9h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter10h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter11h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter12h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter13h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter14h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter15h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter16h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter17h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter18h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter19h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter20h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter21h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter22h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter23h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter24h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter25h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter26h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter27h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter28h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter29h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter30h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hpmcounter31h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sstatus", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sedeleg", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sideleg", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sie", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "stvec", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "scounteren", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sscratch", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sepc", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "scause", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "stval", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "sip", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "satp", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mvendorid", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "marchid", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mimpid", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhartid", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mstatus", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "misa", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "medeleg", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mideleg", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mie", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mtvec", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mcounteren", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mscratch", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mepc", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mcause", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mtval", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mip", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpcfg0", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpcfg1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpcfg2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpcfg3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr0", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr7", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr8", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr9", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr10", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr11", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr12", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr13", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr14", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "pmpaddr15", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mcycle", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "minstret", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter7", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter8", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter9", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter10", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter11", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter12", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter13", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter14", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter15", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter16", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter17", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter18", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter19", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter20", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter21", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter22", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter23", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter24", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter25", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter26", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter27", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter28", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter29", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter30", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter31", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mcycleh", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "minstreth", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter3h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter4h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter5h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter6h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter7h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter8h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter9h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter10h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter11h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter12h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter13h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter14h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter15h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter16h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter17h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter18h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter19h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter20h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter21h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter22h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter23h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter24h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter25h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter26h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter27h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter28h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter29h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter30h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmcounter31h", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent4", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent5", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent6", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent7", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent8", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent9", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent10", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent11", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent12", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent13", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent14", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent15", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent16", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent17", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent18", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent19", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent20", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent21", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent22", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent23", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent24", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent25", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent26", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent27", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent28", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent29", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent30", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhpmevent31", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "tselect", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "tdata1", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "tdata2", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "tdata3", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "dcsr", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "dpc", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "dscratch", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hstatus", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hedeleg", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hideleg", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hie", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "htvec", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hscratch", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hepc", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hcause", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hbadaddr", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "hip", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mbase", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mbound", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mibase", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mibound", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mdbase", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mdbound", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mucounteren", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mscounteren", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "mhcounteren", regnum++, 1, NULL, 32, "int");
+  return regnum;
+}
diff --git a/gdb/features/riscv/32bit-csr.xml b/gdb/features/riscv/32bit-csr.xml
new file mode 100644
index 00000000000..4aea9e657b9
--- /dev/null
+++ b/gdb/features/riscv/32bit-csr.xml
@@ -0,0 +1,250 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.csr">
+  <reg name="ustatus" bitsize="32"/>
+  <reg name="uie" bitsize="32"/>
+  <reg name="utvec" bitsize="32"/>
+  <reg name="uscratch" bitsize="32"/>
+  <reg name="uepc" bitsize="32"/>
+  <reg name="ucause" bitsize="32"/>
+  <reg name="utval" bitsize="32"/>
+  <reg name="uip" bitsize="32"/>
+  <reg name="fflags" bitsize="32"/>
+  <reg name="frm" bitsize="32"/>
+  <reg name="fcsr" bitsize="32"/>
+  <reg name="cycle" bitsize="32"/>
+  <reg name="time" bitsize="32"/>
+  <reg name="instret" bitsize="32"/>
+  <reg name="hpmcounter3" bitsize="32"/>
+  <reg name="hpmcounter4" bitsize="32"/>
+  <reg name="hpmcounter5" bitsize="32"/>
+  <reg name="hpmcounter6" bitsize="32"/>
+  <reg name="hpmcounter7" bitsize="32"/>
+  <reg name="hpmcounter8" bitsize="32"/>
+  <reg name="hpmcounter9" bitsize="32"/>
+  <reg name="hpmcounter10" bitsize="32"/>
+  <reg name="hpmcounter11" bitsize="32"/>
+  <reg name="hpmcounter12" bitsize="32"/>
+  <reg name="hpmcounter13" bitsize="32"/>
+  <reg name="hpmcounter14" bitsize="32"/>
+  <reg name="hpmcounter15" bitsize="32"/>
+  <reg name="hpmcounter16" bitsize="32"/>
+  <reg name="hpmcounter17" bitsize="32"/>
+  <reg name="hpmcounter18" bitsize="32"/>
+  <reg name="hpmcounter19" bitsize="32"/>
+  <reg name="hpmcounter20" bitsize="32"/>
+  <reg name="hpmcounter21" bitsize="32"/>
+  <reg name="hpmcounter22" bitsize="32"/>
+  <reg name="hpmcounter23" bitsize="32"/>
+  <reg name="hpmcounter24" bitsize="32"/>
+  <reg name="hpmcounter25" bitsize="32"/>
+  <reg name="hpmcounter26" bitsize="32"/>
+  <reg name="hpmcounter27" bitsize="32"/>
+  <reg name="hpmcounter28" bitsize="32"/>
+  <reg name="hpmcounter29" bitsize="32"/>
+  <reg name="hpmcounter30" bitsize="32"/>
+  <reg name="hpmcounter31" bitsize="32"/>
+  <reg name="cycleh" bitsize="32"/>
+  <reg name="timeh" bitsize="32"/>
+  <reg name="instreth" bitsize="32"/>
+  <reg name="hpmcounter3h" bitsize="32"/>
+  <reg name="hpmcounter4h" bitsize="32"/>
+  <reg name="hpmcounter5h" bitsize="32"/>
+  <reg name="hpmcounter6h" bitsize="32"/>
+  <reg name="hpmcounter7h" bitsize="32"/>
+  <reg name="hpmcounter8h" bitsize="32"/>
+  <reg name="hpmcounter9h" bitsize="32"/>
+  <reg name="hpmcounter10h" bitsize="32"/>
+  <reg name="hpmcounter11h" bitsize="32"/>
+  <reg name="hpmcounter12h" bitsize="32"/>
+  <reg name="hpmcounter13h" bitsize="32"/>
+  <reg name="hpmcounter14h" bitsize="32"/>
+  <reg name="hpmcounter15h" bitsize="32"/>
+  <reg name="hpmcounter16h" bitsize="32"/>
+  <reg name="hpmcounter17h" bitsize="32"/>
+  <reg name="hpmcounter18h" bitsize="32"/>
+  <reg name="hpmcounter19h" bitsize="32"/>
+  <reg name="hpmcounter20h" bitsize="32"/>
+  <reg name="hpmcounter21h" bitsize="32"/>
+  <reg name="hpmcounter22h" bitsize="32"/>
+  <reg name="hpmcounter23h" bitsize="32"/>
+  <reg name="hpmcounter24h" bitsize="32"/>
+  <reg name="hpmcounter25h" bitsize="32"/>
+  <reg name="hpmcounter26h" bitsize="32"/>
+  <reg name="hpmcounter27h" bitsize="32"/>
+  <reg name="hpmcounter28h" bitsize="32"/>
+  <reg name="hpmcounter29h" bitsize="32"/>
+  <reg name="hpmcounter30h" bitsize="32"/>
+  <reg name="hpmcounter31h" bitsize="32"/>
+  <reg name="sstatus" bitsize="32"/>
+  <reg name="sedeleg" bitsize="32"/>
+  <reg name="sideleg" bitsize="32"/>
+  <reg name="sie" bitsize="32"/>
+  <reg name="stvec" bitsize="32"/>
+  <reg name="scounteren" bitsize="32"/>
+  <reg name="sscratch" bitsize="32"/>
+  <reg name="sepc" bitsize="32"/>
+  <reg name="scause" bitsize="32"/>
+  <reg name="stval" bitsize="32"/>
+  <reg name="sip" bitsize="32"/>
+  <reg name="satp" bitsize="32"/>
+  <reg name="mvendorid" bitsize="32"/>
+  <reg name="marchid" bitsize="32"/>
+  <reg name="mimpid" bitsize="32"/>
+  <reg name="mhartid" bitsize="32"/>
+  <reg name="mstatus" bitsize="32"/>
+  <reg name="misa" bitsize="32"/>
+  <reg name="medeleg" bitsize="32"/>
+  <reg name="mideleg" bitsize="32"/>
+  <reg name="mie" bitsize="32"/>
+  <reg name="mtvec" bitsize="32"/>
+  <reg name="mcounteren" bitsize="32"/>
+  <reg name="mscratch" bitsize="32"/>
+  <reg name="mepc" bitsize="32"/>
+  <reg name="mcause" bitsize="32"/>
+  <reg name="mtval" bitsize="32"/>
+  <reg name="mip" bitsize="32"/>
+  <reg name="pmpcfg0" bitsize="32"/>
+  <reg name="pmpcfg1" bitsize="32"/>
+  <reg name="pmpcfg2" bitsize="32"/>
+  <reg name="pmpcfg3" bitsize="32"/>
+  <reg name="pmpaddr0" bitsize="32"/>
+  <reg name="pmpaddr1" bitsize="32"/>
+  <reg name="pmpaddr2" bitsize="32"/>
+  <reg name="pmpaddr3" bitsize="32"/>
+  <reg name="pmpaddr4" bitsize="32"/>
+  <reg name="pmpaddr5" bitsize="32"/>
+  <reg name="pmpaddr6" bitsize="32"/>
+  <reg name="pmpaddr7" bitsize="32"/>
+  <reg name="pmpaddr8" bitsize="32"/>
+  <reg name="pmpaddr9" bitsize="32"/>
+  <reg name="pmpaddr10" bitsize="32"/>
+  <reg name="pmpaddr11" bitsize="32"/>
+  <reg name="pmpaddr12" bitsize="32"/>
+  <reg name="pmpaddr13" bitsize="32"/>
+  <reg name="pmpaddr14" bitsize="32"/>
+  <reg name="pmpaddr15" bitsize="32"/>
+  <reg name="mcycle" bitsize="32"/>
+  <reg name="minstret" bitsize="32"/>
+  <reg name="mhpmcounter3" bitsize="32"/>
+  <reg name="mhpmcounter4" bitsize="32"/>
+  <reg name="mhpmcounter5" bitsize="32"/>
+  <reg name="mhpmcounter6" bitsize="32"/>
+  <reg name="mhpmcounter7" bitsize="32"/>
+  <reg name="mhpmcounter8" bitsize="32"/>
+  <reg name="mhpmcounter9" bitsize="32"/>
+  <reg name="mhpmcounter10" bitsize="32"/>
+  <reg name="mhpmcounter11" bitsize="32"/>
+  <reg name="mhpmcounter12" bitsize="32"/>
+  <reg name="mhpmcounter13" bitsize="32"/>
+  <reg name="mhpmcounter14" bitsize="32"/>
+  <reg name="mhpmcounter15" bitsize="32"/>
+  <reg name="mhpmcounter16" bitsize="32"/>
+  <reg name="mhpmcounter17" bitsize="32"/>
+  <reg name="mhpmcounter18" bitsize="32"/>
+  <reg name="mhpmcounter19" bitsize="32"/>
+  <reg name="mhpmcounter20" bitsize="32"/>
+  <reg name="mhpmcounter21" bitsize="32"/>
+  <reg name="mhpmcounter22" bitsize="32"/>
+  <reg name="mhpmcounter23" bitsize="32"/>
+  <reg name="mhpmcounter24" bitsize="32"/>
+  <reg name="mhpmcounter25" bitsize="32"/>
+  <reg name="mhpmcounter26" bitsize="32"/>
+  <reg name="mhpmcounter27" bitsize="32"/>
+  <reg name="mhpmcounter28" bitsize="32"/>
+  <reg name="mhpmcounter29" bitsize="32"/>
+  <reg name="mhpmcounter30" bitsize="32"/>
+  <reg name="mhpmcounter31" bitsize="32"/>
+  <reg name="mcycleh" bitsize="32"/>
+  <reg name="minstreth" bitsize="32"/>
+  <reg name="mhpmcounter3h" bitsize="32"/>
+  <reg name="mhpmcounter4h" bitsize="32"/>
+  <reg name="mhpmcounter5h" bitsize="32"/>
+  <reg name="mhpmcounter6h" bitsize="32"/>
+  <reg name="mhpmcounter7h" bitsize="32"/>
+  <reg name="mhpmcounter8h" bitsize="32"/>
+  <reg name="mhpmcounter9h" bitsize="32"/>
+  <reg name="mhpmcounter10h" bitsize="32"/>
+  <reg name="mhpmcounter11h" bitsize="32"/>
+  <reg name="mhpmcounter12h" bitsize="32"/>
+  <reg name="mhpmcounter13h" bitsize="32"/>
+  <reg name="mhpmcounter14h" bitsize="32"/>
+  <reg name="mhpmcounter15h" bitsize="32"/>
+  <reg name="mhpmcounter16h" bitsize="32"/>
+  <reg name="mhpmcounter17h" bitsize="32"/>
+  <reg name="mhpmcounter18h" bitsize="32"/>
+  <reg name="mhpmcounter19h" bitsize="32"/>
+  <reg name="mhpmcounter20h" bitsize="32"/>
+  <reg name="mhpmcounter21h" bitsize="32"/>
+  <reg name="mhpmcounter22h" bitsize="32"/>
+  <reg name="mhpmcounter23h" bitsize="32"/>
+  <reg name="mhpmcounter24h" bitsize="32"/>
+  <reg name="mhpmcounter25h" bitsize="32"/>
+  <reg name="mhpmcounter26h" bitsize="32"/>
+  <reg name="mhpmcounter27h" bitsize="32"/>
+  <reg name="mhpmcounter28h" bitsize="32"/>
+  <reg name="mhpmcounter29h" bitsize="32"/>
+  <reg name="mhpmcounter30h" bitsize="32"/>
+  <reg name="mhpmcounter31h" bitsize="32"/>
+  <reg name="mhpmevent3" bitsize="32"/>
+  <reg name="mhpmevent4" bitsize="32"/>
+  <reg name="mhpmevent5" bitsize="32"/>
+  <reg name="mhpmevent6" bitsize="32"/>
+  <reg name="mhpmevent7" bitsize="32"/>
+  <reg name="mhpmevent8" bitsize="32"/>
+  <reg name="mhpmevent9" bitsize="32"/>
+  <reg name="mhpmevent10" bitsize="32"/>
+  <reg name="mhpmevent11" bitsize="32"/>
+  <reg name="mhpmevent12" bitsize="32"/>
+  <reg name="mhpmevent13" bitsize="32"/>
+  <reg name="mhpmevent14" bitsize="32"/>
+  <reg name="mhpmevent15" bitsize="32"/>
+  <reg name="mhpmevent16" bitsize="32"/>
+  <reg name="mhpmevent17" bitsize="32"/>
+  <reg name="mhpmevent18" bitsize="32"/>
+  <reg name="mhpmevent19" bitsize="32"/>
+  <reg name="mhpmevent20" bitsize="32"/>
+  <reg name="mhpmevent21" bitsize="32"/>
+  <reg name="mhpmevent22" bitsize="32"/>
+  <reg name="mhpmevent23" bitsize="32"/>
+  <reg name="mhpmevent24" bitsize="32"/>
+  <reg name="mhpmevent25" bitsize="32"/>
+  <reg name="mhpmevent26" bitsize="32"/>
+  <reg name="mhpmevent27" bitsize="32"/>
+  <reg name="mhpmevent28" bitsize="32"/>
+  <reg name="mhpmevent29" bitsize="32"/>
+  <reg name="mhpmevent30" bitsize="32"/>
+  <reg name="mhpmevent31" bitsize="32"/>
+  <reg name="tselect" bitsize="32"/>
+  <reg name="tdata1" bitsize="32"/>
+  <reg name="tdata2" bitsize="32"/>
+  <reg name="tdata3" bitsize="32"/>
+  <reg name="dcsr" bitsize="32"/>
+  <reg name="dpc" bitsize="32"/>
+  <reg name="dscratch" bitsize="32"/>
+  <reg name="hstatus" bitsize="32"/>
+  <reg name="hedeleg" bitsize="32"/>
+  <reg name="hideleg" bitsize="32"/>
+  <reg name="hie" bitsize="32"/>
+  <reg name="htvec" bitsize="32"/>
+  <reg name="hscratch" bitsize="32"/>
+  <reg name="hepc" bitsize="32"/>
+  <reg name="hcause" bitsize="32"/>
+  <reg name="hbadaddr" bitsize="32"/>
+  <reg name="hip" bitsize="32"/>
+  <reg name="mbase" bitsize="32"/>
+  <reg name="mbound" bitsize="32"/>
+  <reg name="mibase" bitsize="32"/>
+  <reg name="mibound" bitsize="32"/>
+  <reg name="mdbase" bitsize="32"/>
+  <reg name="mdbound" bitsize="32"/>
+  <reg name="mucounteren" bitsize="32"/>
+  <reg name="mscounteren" bitsize="32"/>
+  <reg name="mhcounteren" bitsize="32"/>
+</feature>
diff --git a/gdb/features/riscv/32bit-fpu.c b/gdb/features/riscv/32bit-fpu.c
new file mode 100644
index 00000000000..22e80d640e5
--- /dev/null
+++ b/gdb/features/riscv/32bit-fpu.c
@@ -0,0 +1,48 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 32bit-fpu.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_32bit_fpu (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.fpu");
+  tdesc_create_reg (feature, "ft0", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft1", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft2", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft3", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft4", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft5", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft6", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft7", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs0", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs1", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa0", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa1", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa2", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa3", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa4", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa5", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa6", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fa7", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs2", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs3", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs4", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs5", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs6", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs7", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs8", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs9", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs10", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fs11", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft8", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft9", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft10", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "ft11", regnum++, 1, NULL, 32, "ieee_single");
+  tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "frm", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fcsr", regnum++, 1, NULL, 32, "int");
+  return regnum;
+}
diff --git a/gdb/features/riscv/32bit-fpu.xml b/gdb/features/riscv/32bit-fpu.xml
new file mode 100644
index 00000000000..783287d9362
--- /dev/null
+++ b/gdb/features/riscv/32bit-fpu.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.fpu">
+  <reg name="ft0" bitsize="32" type="ieee_single"/>
+  <reg name="ft1" bitsize="32" type="ieee_single"/>
+  <reg name="ft2" bitsize="32" type="ieee_single"/>
+  <reg name="ft3" bitsize="32" type="ieee_single"/>
+  <reg name="ft4" bitsize="32" type="ieee_single"/>
+  <reg name="ft5" bitsize="32" type="ieee_single"/>
+  <reg name="ft6" bitsize="32" type="ieee_single"/>
+  <reg name="ft7" bitsize="32" type="ieee_single"/>
+  <reg name="fs0" bitsize="32" type="ieee_single"/>
+  <reg name="fs1" bitsize="32" type="ieee_single"/>
+  <reg name="fa0" bitsize="32" type="ieee_single"/>
+  <reg name="fa1" bitsize="32" type="ieee_single"/>
+  <reg name="fa2" bitsize="32" type="ieee_single"/>
+  <reg name="fa3" bitsize="32" type="ieee_single"/>
+  <reg name="fa4" bitsize="32" type="ieee_single"/>
+  <reg name="fa5" bitsize="32" type="ieee_single"/>
+  <reg name="fa6" bitsize="32" type="ieee_single"/>
+  <reg name="fa7" bitsize="32" type="ieee_single"/>
+  <reg name="fs2" bitsize="32" type="ieee_single"/>
+  <reg name="fs3" bitsize="32" type="ieee_single"/>
+  <reg name="fs4" bitsize="32" type="ieee_single"/>
+  <reg name="fs5" bitsize="32" type="ieee_single"/>
+  <reg name="fs6" bitsize="32" type="ieee_single"/>
+  <reg name="fs7" bitsize="32" type="ieee_single"/>
+  <reg name="fs8" bitsize="32" type="ieee_single"/>
+  <reg name="fs9" bitsize="32" type="ieee_single"/>
+  <reg name="fs10" bitsize="32" type="ieee_single"/>
+  <reg name="fs11" bitsize="32" type="ieee_single"/>
+  <reg name="ft8" bitsize="32" type="ieee_single"/>
+  <reg name="ft9" bitsize="32" type="ieee_single"/>
+  <reg name="ft10" bitsize="32" type="ieee_single"/>
+  <reg name="ft11" bitsize="32" type="ieee_single"/>
+
+  <reg name="fflags" bitsize="32" type="int"/>
+  <reg name="frm" bitsize="32" type="int"/>
+  <reg name="fcsr" bitsize="32" type="int"/>
+</feature>
diff --git a/gdb/features/riscv/64bit-cpu.c b/gdb/features/riscv/64bit-cpu.c
new file mode 100644
index 00000000000..910089805ee
--- /dev/null
+++ b/gdb/features/riscv/64bit-cpu.c
@@ -0,0 +1,46 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 64bit-cpu.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_64bit_cpu (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.cpu");
+  tdesc_create_reg (feature, "zero", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "ra", regnum++, 1, NULL, 64, "code_ptr");
+  tdesc_create_reg (feature, "sp", regnum++, 1, NULL, 64, "data_ptr");
+  tdesc_create_reg (feature, "gp", regnum++, 1, NULL, 64, "data_ptr");
+  tdesc_create_reg (feature, "tp", regnum++, 1, NULL, 64, "data_ptr");
+  tdesc_create_reg (feature, "t0", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "fp", regnum++, 1, NULL, 64, "data_ptr");
+  tdesc_create_reg (feature, "s1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a0", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "a7", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s7", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s8", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s9", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s10", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "s11", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "t6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pc", regnum++, 1, NULL, 64, "code_ptr");
+  return regnum;
+}
diff --git a/gdb/features/riscv/64bit-cpu.xml b/gdb/features/riscv/64bit-cpu.xml
new file mode 100644
index 00000000000..f37d7f3ce36
--- /dev/null
+++ b/gdb/features/riscv/64bit-cpu.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.cpu">
+  <reg name="zero" bitsize="64" type="int"/>
+  <reg name="ra" bitsize="64" type="code_ptr"/>
+  <reg name="sp" bitsize="64" type="data_ptr"/>
+  <reg name="gp" bitsize="64" type="data_ptr"/>
+  <reg name="tp" bitsize="64" type="data_ptr"/>
+  <reg name="t0" bitsize="64" type="int"/>
+  <reg name="t1" bitsize="64" type="int"/>
+  <reg name="t2" bitsize="64" type="int"/>
+  <reg name="fp" bitsize="64" type="data_ptr"/>
+  <reg name="s1" bitsize="64" type="int"/>
+  <reg name="a0" bitsize="64" type="int"/>
+  <reg name="a1" bitsize="64" type="int"/>
+  <reg name="a2" bitsize="64" type="int"/>
+  <reg name="a3" bitsize="64" type="int"/>
+  <reg name="a4" bitsize="64" type="int"/>
+  <reg name="a5" bitsize="64" type="int"/>
+  <reg name="a6" bitsize="64" type="int"/>
+  <reg name="a7" bitsize="64" type="int"/>
+  <reg name="s2" bitsize="64" type="int"/>
+  <reg name="s3" bitsize="64" type="int"/>
+  <reg name="s4" bitsize="64" type="int"/>
+  <reg name="s5" bitsize="64" type="int"/>
+  <reg name="s6" bitsize="64" type="int"/>
+  <reg name="s7" bitsize="64" type="int"/>
+  <reg name="s8" bitsize="64" type="int"/>
+  <reg name="s9" bitsize="64" type="int"/>
+  <reg name="s10" bitsize="64" type="int"/>
+  <reg name="s11" bitsize="64" type="int"/>
+  <reg name="t3" bitsize="64" type="int"/>
+  <reg name="t4" bitsize="64" type="int"/>
+  <reg name="t5" bitsize="64" type="int"/>
+  <reg name="t6" bitsize="64" type="int"/>
+  <reg name="pc" bitsize="64" type="code_ptr"/>
+</feature>
diff --git a/gdb/features/riscv/64bit-csr.c b/gdb/features/riscv/64bit-csr.c
new file mode 100644
index 00000000000..7c777406254
--- /dev/null
+++ b/gdb/features/riscv/64bit-csr.c
@@ -0,0 +1,253 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 64bit-csr.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_64bit_csr (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.csr");
+  tdesc_create_reg (feature, "ustatus", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "uie", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "utvec", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "uscratch", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "uepc", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "ucause", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "utval", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "uip", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "frm", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "fcsr", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "cycle", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "time", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "instret", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter7", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter8", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter9", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter10", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter11", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter12", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter13", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter14", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter15", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter16", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter17", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter18", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter19", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter20", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter21", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter22", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter23", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter24", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter25", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter26", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter27", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter28", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter29", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter30", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter31", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "cycleh", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "timeh", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "instreth", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter3h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter4h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter5h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter6h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter7h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter8h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter9h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter10h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter11h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter12h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter13h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter14h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter15h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter16h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter17h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter18h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter19h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter20h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter21h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter22h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter23h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter24h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter25h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter26h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter27h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter28h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter29h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter30h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hpmcounter31h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sstatus", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sedeleg", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sideleg", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sie", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "stvec", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "scounteren", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sscratch", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sepc", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "scause", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "stval", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sip", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "satp", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mvendorid", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "marchid", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mimpid", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhartid", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mstatus", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "misa", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "medeleg", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mideleg", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mie", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mtvec", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mcounteren", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mscratch", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mepc", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mcause", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mtval", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mip", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpcfg0", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpcfg1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpcfg2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpcfg3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr0", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr7", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr8", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr9", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr10", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr11", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr12", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr13", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr14", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pmpaddr15", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mcycle", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "minstret", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter7", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter8", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter9", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter10", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter11", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter12", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter13", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter14", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter15", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter16", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter17", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter18", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter19", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter20", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter21", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter22", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter23", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter24", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter25", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter26", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter27", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter28", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter29", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter30", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter31", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mcycleh", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "minstreth", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter3h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter4h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter5h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter6h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter7h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter8h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter9h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter10h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter11h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter12h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter13h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter14h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter15h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter16h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter17h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter18h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter19h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter20h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter21h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter22h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter23h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter24h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter25h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter26h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter27h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter28h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter29h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter30h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmcounter31h", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent4", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent5", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent6", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent7", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent8", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent9", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent10", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent11", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent12", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent13", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent14", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent15", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent16", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent17", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent18", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent19", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent20", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent21", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent22", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent23", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent24", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent25", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent26", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent27", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent28", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent29", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent30", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhpmevent31", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "tselect", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "tdata1", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "tdata2", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "tdata3", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "dcsr", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "dpc", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "dscratch", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hstatus", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hedeleg", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hideleg", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hie", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "htvec", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hscratch", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hepc", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hcause", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hbadaddr", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "hip", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mbase", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mbound", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mibase", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mibound", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mdbase", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mdbound", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mucounteren", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mscounteren", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "mhcounteren", regnum++, 1, NULL, 64, "int");
+  return regnum;
+}
diff --git a/gdb/features/riscv/64bit-csr.xml b/gdb/features/riscv/64bit-csr.xml
new file mode 100644
index 00000000000..a3de83443a5
--- /dev/null
+++ b/gdb/features/riscv/64bit-csr.xml
@@ -0,0 +1,250 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.csr">
+  <reg name="ustatus" bitsize="64"/>
+  <reg name="uie" bitsize="64"/>
+  <reg name="utvec" bitsize="64"/>
+  <reg name="uscratch" bitsize="64"/>
+  <reg name="uepc" bitsize="64"/>
+  <reg name="ucause" bitsize="64"/>
+  <reg name="utval" bitsize="64"/>
+  <reg name="uip" bitsize="64"/>
+  <reg name="fflags" bitsize="64"/>
+  <reg name="frm" bitsize="64"/>
+  <reg name="fcsr" bitsize="64"/>
+  <reg name="cycle" bitsize="64"/>
+  <reg name="time" bitsize="64"/>
+  <reg name="instret" bitsize="64"/>
+  <reg name="hpmcounter3" bitsize="64"/>
+  <reg name="hpmcounter4" bitsize="64"/>
+  <reg name="hpmcounter5" bitsize="64"/>
+  <reg name="hpmcounter6" bitsize="64"/>
+  <reg name="hpmcounter7" bitsize="64"/>
+  <reg name="hpmcounter8" bitsize="64"/>
+  <reg name="hpmcounter9" bitsize="64"/>
+  <reg name="hpmcounter10" bitsize="64"/>
+  <reg name="hpmcounter11" bitsize="64"/>
+  <reg name="hpmcounter12" bitsize="64"/>
+  <reg name="hpmcounter13" bitsize="64"/>
+  <reg name="hpmcounter14" bitsize="64"/>
+  <reg name="hpmcounter15" bitsize="64"/>
+  <reg name="hpmcounter16" bitsize="64"/>
+  <reg name="hpmcounter17" bitsize="64"/>
+  <reg name="hpmcounter18" bitsize="64"/>
+  <reg name="hpmcounter19" bitsize="64"/>
+  <reg name="hpmcounter20" bitsize="64"/>
+  <reg name="hpmcounter21" bitsize="64"/>
+  <reg name="hpmcounter22" bitsize="64"/>
+  <reg name="hpmcounter23" bitsize="64"/>
+  <reg name="hpmcounter24" bitsize="64"/>
+  <reg name="hpmcounter25" bitsize="64"/>
+  <reg name="hpmcounter26" bitsize="64"/>
+  <reg name="hpmcounter27" bitsize="64"/>
+  <reg name="hpmcounter28" bitsize="64"/>
+  <reg name="hpmcounter29" bitsize="64"/>
+  <reg name="hpmcounter30" bitsize="64"/>
+  <reg name="hpmcounter31" bitsize="64"/>
+  <reg name="cycleh" bitsize="64"/>
+  <reg name="timeh" bitsize="64"/>
+  <reg name="instreth" bitsize="64"/>
+  <reg name="hpmcounter3h" bitsize="64"/>
+  <reg name="hpmcounter4h" bitsize="64"/>
+  <reg name="hpmcounter5h" bitsize="64"/>
+  <reg name="hpmcounter6h" bitsize="64"/>
+  <reg name="hpmcounter7h" bitsize="64"/>
+  <reg name="hpmcounter8h" bitsize="64"/>
+  <reg name="hpmcounter9h" bitsize="64"/>
+  <reg name="hpmcounter10h" bitsize="64"/>
+  <reg name="hpmcounter11h" bitsize="64"/>
+  <reg name="hpmcounter12h" bitsize="64"/>
+  <reg name="hpmcounter13h" bitsize="64"/>
+  <reg name="hpmcounter14h" bitsize="64"/>
+  <reg name="hpmcounter15h" bitsize="64"/>
+  <reg name="hpmcounter16h" bitsize="64"/>
+  <reg name="hpmcounter17h" bitsize="64"/>
+  <reg name="hpmcounter18h" bitsize="64"/>
+  <reg name="hpmcounter19h" bitsize="64"/>
+  <reg name="hpmcounter20h" bitsize="64"/>
+  <reg name="hpmcounter21h" bitsize="64"/>
+  <reg name="hpmcounter22h" bitsize="64"/>
+  <reg name="hpmcounter23h" bitsize="64"/>
+  <reg name="hpmcounter24h" bitsize="64"/>
+  <reg name="hpmcounter25h" bitsize="64"/>
+  <reg name="hpmcounter26h" bitsize="64"/>
+  <reg name="hpmcounter27h" bitsize="64"/>
+  <reg name="hpmcounter28h" bitsize="64"/>
+  <reg name="hpmcounter29h" bitsize="64"/>
+  <reg name="hpmcounter30h" bitsize="64"/>
+  <reg name="hpmcounter31h" bitsize="64"/>
+  <reg name="sstatus" bitsize="64"/>
+  <reg name="sedeleg" bitsize="64"/>
+  <reg name="sideleg" bitsize="64"/>
+  <reg name="sie" bitsize="64"/>
+  <reg name="stvec" bitsize="64"/>
+  <reg name="scounteren" bitsize="64"/>
+  <reg name="sscratch" bitsize="64"/>
+  <reg name="sepc" bitsize="64"/>
+  <reg name="scause" bitsize="64"/>
+  <reg name="stval" bitsize="64"/>
+  <reg name="sip" bitsize="64"/>
+  <reg name="satp" bitsize="64"/>
+  <reg name="mvendorid" bitsize="64"/>
+  <reg name="marchid" bitsize="64"/>
+  <reg name="mimpid" bitsize="64"/>
+  <reg name="mhartid" bitsize="64"/>
+  <reg name="mstatus" bitsize="64"/>
+  <reg name="misa" bitsize="64"/>
+  <reg name="medeleg" bitsize="64"/>
+  <reg name="mideleg" bitsize="64"/>
+  <reg name="mie" bitsize="64"/>
+  <reg name="mtvec" bitsize="64"/>
+  <reg name="mcounteren" bitsize="64"/>
+  <reg name="mscratch" bitsize="64"/>
+  <reg name="mepc" bitsize="64"/>
+  <reg name="mcause" bitsize="64"/>
+  <reg name="mtval" bitsize="64"/>
+  <reg name="mip" bitsize="64"/>
+  <reg name="pmpcfg0" bitsize="64"/>
+  <reg name="pmpcfg1" bitsize="64"/>
+  <reg name="pmpcfg2" bitsize="64"/>
+  <reg name="pmpcfg3" bitsize="64"/>
+  <reg name="pmpaddr0" bitsize="64"/>
+  <reg name="pmpaddr1" bitsize="64"/>
+  <reg name="pmpaddr2" bitsize="64"/>
+  <reg name="pmpaddr3" bitsize="64"/>
+  <reg name="pmpaddr4" bitsize="64"/>
+  <reg name="pmpaddr5" bitsize="64"/>
+  <reg name="pmpaddr6" bitsize="64"/>
+  <reg name="pmpaddr7" bitsize="64"/>
+  <reg name="pmpaddr8" bitsize="64"/>
+  <reg name="pmpaddr9" bitsize="64"/>
+  <reg name="pmpaddr10" bitsize="64"/>
+  <reg name="pmpaddr11" bitsize="64"/>
+  <reg name="pmpaddr12" bitsize="64"/>
+  <reg name="pmpaddr13" bitsize="64"/>
+  <reg name="pmpaddr14" bitsize="64"/>
+  <reg name="pmpaddr15" bitsize="64"/>
+  <reg name="mcycle" bitsize="64"/>
+  <reg name="minstret" bitsize="64"/>
+  <reg name="mhpmcounter3" bitsize="64"/>
+  <reg name="mhpmcounter4" bitsize="64"/>
+  <reg name="mhpmcounter5" bitsize="64"/>
+  <reg name="mhpmcounter6" bitsize="64"/>
+  <reg name="mhpmcounter7" bitsize="64"/>
+  <reg name="mhpmcounter8" bitsize="64"/>
+  <reg name="mhpmcounter9" bitsize="64"/>
+  <reg name="mhpmcounter10" bitsize="64"/>
+  <reg name="mhpmcounter11" bitsize="64"/>
+  <reg name="mhpmcounter12" bitsize="64"/>
+  <reg name="mhpmcounter13" bitsize="64"/>
+  <reg name="mhpmcounter14" bitsize="64"/>
+  <reg name="mhpmcounter15" bitsize="64"/>
+  <reg name="mhpmcounter16" bitsize="64"/>
+  <reg name="mhpmcounter17" bitsize="64"/>
+  <reg name="mhpmcounter18" bitsize="64"/>
+  <reg name="mhpmcounter19" bitsize="64"/>
+  <reg name="mhpmcounter20" bitsize="64"/>
+  <reg name="mhpmcounter21" bitsize="64"/>
+  <reg name="mhpmcounter22" bitsize="64"/>
+  <reg name="mhpmcounter23" bitsize="64"/>
+  <reg name="mhpmcounter24" bitsize="64"/>
+  <reg name="mhpmcounter25" bitsize="64"/>
+  <reg name="mhpmcounter26" bitsize="64"/>
+  <reg name="mhpmcounter27" bitsize="64"/>
+  <reg name="mhpmcounter28" bitsize="64"/>
+  <reg name="mhpmcounter29" bitsize="64"/>
+  <reg name="mhpmcounter30" bitsize="64"/>
+  <reg name="mhpmcounter31" bitsize="64"/>
+  <reg name="mcycleh" bitsize="64"/>
+  <reg name="minstreth" bitsize="64"/>
+  <reg name="mhpmcounter3h" bitsize="64"/>
+  <reg name="mhpmcounter4h" bitsize="64"/>
+  <reg name="mhpmcounter5h" bitsize="64"/>
+  <reg name="mhpmcounter6h" bitsize="64"/>
+  <reg name="mhpmcounter7h" bitsize="64"/>
+  <reg name="mhpmcounter8h" bitsize="64"/>
+  <reg name="mhpmcounter9h" bitsize="64"/>
+  <reg name="mhpmcounter10h" bitsize="64"/>
+  <reg name="mhpmcounter11h" bitsize="64"/>
+  <reg name="mhpmcounter12h" bitsize="64"/>
+  <reg name="mhpmcounter13h" bitsize="64"/>
+  <reg name="mhpmcounter14h" bitsize="64"/>
+  <reg name="mhpmcounter15h" bitsize="64"/>
+  <reg name="mhpmcounter16h" bitsize="64"/>
+  <reg name="mhpmcounter17h" bitsize="64"/>
+  <reg name="mhpmcounter18h" bitsize="64"/>
+  <reg name="mhpmcounter19h" bitsize="64"/>
+  <reg name="mhpmcounter20h" bitsize="64"/>
+  <reg name="mhpmcounter21h" bitsize="64"/>
+  <reg name="mhpmcounter22h" bitsize="64"/>
+  <reg name="mhpmcounter23h" bitsize="64"/>
+  <reg name="mhpmcounter24h" bitsize="64"/>
+  <reg name="mhpmcounter25h" bitsize="64"/>
+  <reg name="mhpmcounter26h" bitsize="64"/>
+  <reg name="mhpmcounter27h" bitsize="64"/>
+  <reg name="mhpmcounter28h" bitsize="64"/>
+  <reg name="mhpmcounter29h" bitsize="64"/>
+  <reg name="mhpmcounter30h" bitsize="64"/>
+  <reg name="mhpmcounter31h" bitsize="64"/>
+  <reg name="mhpmevent3" bitsize="64"/>
+  <reg name="mhpmevent4" bitsize="64"/>
+  <reg name="mhpmevent5" bitsize="64"/>
+  <reg name="mhpmevent6" bitsize="64"/>
+  <reg name="mhpmevent7" bitsize="64"/>
+  <reg name="mhpmevent8" bitsize="64"/>
+  <reg name="mhpmevent9" bitsize="64"/>
+  <reg name="mhpmevent10" bitsize="64"/>
+  <reg name="mhpmevent11" bitsize="64"/>
+  <reg name="mhpmevent12" bitsize="64"/>
+  <reg name="mhpmevent13" bitsize="64"/>
+  <reg name="mhpmevent14" bitsize="64"/>
+  <reg name="mhpmevent15" bitsize="64"/>
+  <reg name="mhpmevent16" bitsize="64"/>
+  <reg name="mhpmevent17" bitsize="64"/>
+  <reg name="mhpmevent18" bitsize="64"/>
+  <reg name="mhpmevent19" bitsize="64"/>
+  <reg name="mhpmevent20" bitsize="64"/>
+  <reg name="mhpmevent21" bitsize="64"/>
+  <reg name="mhpmevent22" bitsize="64"/>
+  <reg name="mhpmevent23" bitsize="64"/>
+  <reg name="mhpmevent24" bitsize="64"/>
+  <reg name="mhpmevent25" bitsize="64"/>
+  <reg name="mhpmevent26" bitsize="64"/>
+  <reg name="mhpmevent27" bitsize="64"/>
+  <reg name="mhpmevent28" bitsize="64"/>
+  <reg name="mhpmevent29" bitsize="64"/>
+  <reg name="mhpmevent30" bitsize="64"/>
+  <reg name="mhpmevent31" bitsize="64"/>
+  <reg name="tselect" bitsize="64"/>
+  <reg name="tdata1" bitsize="64"/>
+  <reg name="tdata2" bitsize="64"/>
+  <reg name="tdata3" bitsize="64"/>
+  <reg name="dcsr" bitsize="64"/>
+  <reg name="dpc" bitsize="64"/>
+  <reg name="dscratch" bitsize="64"/>
+  <reg name="hstatus" bitsize="64"/>
+  <reg name="hedeleg" bitsize="64"/>
+  <reg name="hideleg" bitsize="64"/>
+  <reg name="hie" bitsize="64"/>
+  <reg name="htvec" bitsize="64"/>
+  <reg name="hscratch" bitsize="64"/>
+  <reg name="hepc" bitsize="64"/>
+  <reg name="hcause" bitsize="64"/>
+  <reg name="hbadaddr" bitsize="64"/>
+  <reg name="hip" bitsize="64"/>
+  <reg name="mbase" bitsize="64"/>
+  <reg name="mbound" bitsize="64"/>
+  <reg name="mibase" bitsize="64"/>
+  <reg name="mibound" bitsize="64"/>
+  <reg name="mdbase" bitsize="64"/>
+  <reg name="mdbound" bitsize="64"/>
+  <reg name="mucounteren" bitsize="64"/>
+  <reg name="mscounteren" bitsize="64"/>
+  <reg name="mhcounteren" bitsize="64"/>
+</feature>
diff --git a/gdb/features/riscv/64bit-fpu.c b/gdb/features/riscv/64bit-fpu.c
new file mode 100644
index 00000000000..8cbd7484ab3
--- /dev/null
+++ b/gdb/features/riscv/64bit-fpu.c
@@ -0,0 +1,56 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 64bit-fpu.xml */
+
+#include "common/tdesc.h"
+
+static int
+create_feature_riscv_64bit_fpu (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.fpu");
+  tdesc_type_with_fields *type_with_fields;
+  type_with_fields = tdesc_create_union (feature, "riscv_double");
+  tdesc_type *field_type;
+  field_type = tdesc_named_type (feature, "ieee_single");
+  tdesc_add_field (type_with_fields, "float", field_type);
+  field_type = tdesc_named_type (feature, "ieee_double");
+  tdesc_add_field (type_with_fields, "double", field_type);
+
+  tdesc_create_reg (feature, "ft0", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft1", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft2", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft3", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft4", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft5", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft6", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft7", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs0", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs1", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa0", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa1", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa2", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa3", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa4", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa5", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa6", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fa7", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs2", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs3", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs4", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs5", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs6", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs7", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs8", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs9", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs10", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fs11", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft8", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft9", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft10", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "ft11", regnum++, 1, NULL, 64, "riscv_double");
+  tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "frm", regnum++, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fcsr", regnum++, 1, NULL, 32, "int");
+  return regnum;
+}
diff --git a/gdb/features/riscv/64bit-fpu.xml b/gdb/features/riscv/64bit-fpu.xml
new file mode 100644
index 00000000000..fb24b72bcaf
--- /dev/null
+++ b/gdb/features/riscv/64bit-fpu.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.fpu">
+
+  <union id="riscv_double">
+    <field name="float" type="ieee_single"/>
+    <field name="double" type="ieee_double"/>
+  </union>
+
+  <reg name="ft0" bitsize="64" type="riscv_double"/>
+  <reg name="ft1" bitsize="64" type="riscv_double"/>
+  <reg name="ft2" bitsize="64" type="riscv_double"/>
+  <reg name="ft3" bitsize="64" type="riscv_double"/>
+  <reg name="ft4" bitsize="64" type="riscv_double"/>
+  <reg name="ft5" bitsize="64" type="riscv_double"/>
+  <reg name="ft6" bitsize="64" type="riscv_double"/>
+  <reg name="ft7" bitsize="64" type="riscv_double"/>
+  <reg name="fs0" bitsize="64" type="riscv_double"/>
+  <reg name="fs1" bitsize="64" type="riscv_double"/>
+  <reg name="fa0" bitsize="64" type="riscv_double"/>
+  <reg name="fa1" bitsize="64" type="riscv_double"/>
+  <reg name="fa2" bitsize="64" type="riscv_double"/>
+  <reg name="fa3" bitsize="64" type="riscv_double"/>
+  <reg name="fa4" bitsize="64" type="riscv_double"/>
+  <reg name="fa5" bitsize="64" type="riscv_double"/>
+  <reg name="fa6" bitsize="64" type="riscv_double"/>
+  <reg name="fa7" bitsize="64" type="riscv_double"/>
+  <reg name="fs2" bitsize="64" type="riscv_double"/>
+  <reg name="fs3" bitsize="64" type="riscv_double"/>
+  <reg name="fs4" bitsize="64" type="riscv_double"/>
+  <reg name="fs5" bitsize="64" type="riscv_double"/>
+  <reg name="fs6" bitsize="64" type="riscv_double"/>
+  <reg name="fs7" bitsize="64" type="riscv_double"/>
+  <reg name="fs8" bitsize="64" type="riscv_double"/>
+  <reg name="fs9" bitsize="64" type="riscv_double"/>
+  <reg name="fs10" bitsize="64" type="riscv_double"/>
+  <reg name="fs11" bitsize="64" type="riscv_double"/>
+  <reg name="ft8" bitsize="64" type="riscv_double"/>
+  <reg name="ft9" bitsize="64" type="riscv_double"/>
+  <reg name="ft10" bitsize="64" type="riscv_double"/>
+  <reg name="ft11" bitsize="64" type="riscv_double"/>
+
+  <reg name="fflags" bitsize="32" type="int"/>
+  <reg name="frm" bitsize="32" type="int"/>
+  <reg name="fcsr" bitsize="32" type="int"/>
+</feature>
diff --git a/gdb/features/riscv/rebuild-csr-xml.sh b/gdb/features/riscv/rebuild-csr-xml.sh
new file mode 100755
index 00000000000..6971b8dbb2a
--- /dev/null
+++ b/gdb/features/riscv/rebuild-csr-xml.sh
@@ -0,0 +1,29 @@
+#! /bin/bash
+
+RISCV_OPC_FILE=$1
+RISCV_FEATURE_DIR=$2
+
+function gen_csr_xml ()
+{
+    bitsize=$1
+
+    cat <<EOF
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018 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.riscv.csr">
+EOF
+
+    grep "^DECLARE_CSR(" ${RISCV_OPC_FILE} \
+        | sed -e "s!DECLARE_CSR(\(.*\), .*!  <reg name=\"\1\" bitsize=\"$bitsize\"/>!"
+
+    echo "</feature>"
+}
+
+gen_csr_xml 32 > ${RISCV_FEATURE_DIR}/32bit-csr.xml
+gen_csr_xml 64 > ${RISCV_FEATURE_DIR}/64bit-csr.xml
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index 408ab0af24b..5965a594440 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -55,6 +55,7 @@
 #include "cli/cli-decode.h"
 #include "observable.h"
 #include "prologue-value.h"
+#include "arch/riscv.h"
 
 /* The stack must be 16-byte aligned.  */
 #define SP_ALIGNMENT 16
@@ -62,9 +63,6 @@
 /* The biggest alignment that the target supports.  */
 #define BIGGEST_ALIGNMENT 16
 
-/* Forward declarations.  */
-static bool riscv_has_feature (struct gdbarch *gdbarch, char feature);
-
 /* Define a series of is_XXX_insn functions to check if the value INSN
    is an instance of instruction XXX.  */
 #define DECLARE_INSN(INSN_NAME, INSN_MATCH, INSN_MASK) \
@@ -98,110 +96,170 @@ struct riscv_unwind_cache
   CORE_ADDR frame_base;
 };
 
-/* The preferred register names for all the general purpose and floating
-   point registers.  These are what GDB will use when referencing a
-   register.  */
+/* RISC-V specific register group for CSRs.  */
 
-static const char * const riscv_gdb_reg_names[RISCV_LAST_FP_REGNUM + 1] =
-{
- "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1",
- "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4",
- "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6",
- "pc",
- "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", "fs0", "fs1",
- "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa7", "fs2", "fs3",
- "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", "fs10", "fs11", "ft8", "ft9",
- "ft10", "ft11",
-};
+static reggroup *csr_reggroup = NULL;
 
-/* Map alternative register names onto their GDB register number.  */
+/* A set of registers that we expect to find in a tdesc_feature.  These
+   are use in RISCV_GDBARCH_INIT when processing the target description.  */
 
-struct riscv_register_alias
+struct riscv_register_feature
 {
-  /* The register alias.  Usually more descriptive than the
-     architectural name of the register.  */
+  /* Information for a single register.  */
+  struct register_info
+  {
+    /* The GDB register number for this register.  */
+    int regnum;
+
+    /* List of names for this register.  The first name in this list is the
+       preferred name, the name GDB should use when describing this
+       register.  */
+    std::vector <const char *> names;
+
+    /* When true this register is required in this feature set.  */
+    bool required_p;
+  };
+
+  /* The name for this feature.  This is the name used to find this feature
+     within the target description.  */
   const char *name;
 
-  /* The GDB register number.  */
-  int regnum;
+  /* List of all the registers that we expect that we might find in this
+     register set.  */
+  std::vector <struct register_info> registers;
+};
+
+/* The general x-registers feature set.  */
+
+static const struct riscv_register_feature riscv_xreg_feature =
+{
+ "org.gnu.gdb.riscv.cpu",
+ {
+   { RISCV_ZERO_REGNUM + 0, { "zero", "x0" }, true },
+   { RISCV_ZERO_REGNUM + 1, { "ra", "x1" }, true },
+   { RISCV_ZERO_REGNUM + 2, { "sp", "x2" }, true },
+   { RISCV_ZERO_REGNUM + 3, { "gp", "x3" }, true },
+   { RISCV_ZERO_REGNUM + 4, { "tp", "x4" }, true },
+   { RISCV_ZERO_REGNUM + 5, { "t0", "x5" }, true },
+   { RISCV_ZERO_REGNUM + 6, { "t1", "x6" }, true },
+   { RISCV_ZERO_REGNUM + 7, { "t2", "x7" }, true },
+   { RISCV_ZERO_REGNUM + 8, { "fp", "x8", "s0" }, true },
+   { RISCV_ZERO_REGNUM + 9, { "s1", "x9" }, true },
+   { RISCV_ZERO_REGNUM + 10, { "a0", "x10" }, true },
+   { RISCV_ZERO_REGNUM + 11, { "a1", "x11" }, true },
+   { RISCV_ZERO_REGNUM + 12, { "a2", "x12" }, true },
+   { RISCV_ZERO_REGNUM + 13, { "a3", "x13" }, true },
+   { RISCV_ZERO_REGNUM + 14, { "a4", "x14" }, true },
+   { RISCV_ZERO_REGNUM + 15, { "a5", "x15" }, true },
+   { RISCV_ZERO_REGNUM + 16, { "a6", "x16" }, true },
+   { RISCV_ZERO_REGNUM + 17, { "a7", "x17" }, true },
+   { RISCV_ZERO_REGNUM + 18, { "s2", "x18" }, true },
+   { RISCV_ZERO_REGNUM + 19, { "s3", "x19" }, true },
+   { RISCV_ZERO_REGNUM + 20, { "s4", "x20" }, true },
+   { RISCV_ZERO_REGNUM + 21, { "s5", "x21" }, true },
+   { RISCV_ZERO_REGNUM + 22, { "s6", "x22" }, true },
+   { RISCV_ZERO_REGNUM + 23, { "s7", "x23" }, true },
+   { RISCV_ZERO_REGNUM + 24, { "s8", "x24" }, true },
+   { RISCV_ZERO_REGNUM + 25, { "s9", "x25" }, true },
+   { RISCV_ZERO_REGNUM + 26, { "s10", "x26" }, true },
+   { RISCV_ZERO_REGNUM + 27, { "s11", "x27" }, true },
+   { RISCV_ZERO_REGNUM + 28, { "t3", "x28" }, true },
+   { RISCV_ZERO_REGNUM + 29, { "t4", "x29" }, true },
+   { RISCV_ZERO_REGNUM + 30, { "t5", "x30" }, true },
+   { RISCV_ZERO_REGNUM + 31, { "t6", "x31" }, true },
+   { RISCV_ZERO_REGNUM + 32, { "pc" }, true }
+ }
+};
+
+/* The f-registers feature set.  */
+
+static const struct riscv_register_feature riscv_freg_feature =
+{
+ "org.gnu.gdb.riscv.fpu",
+ {
+   { RISCV_FIRST_FP_REGNUM + 0, { "ft0", "f0" }, true },
+   { RISCV_FIRST_FP_REGNUM + 1, { "ft1", "f1" }, true },
+   { RISCV_FIRST_FP_REGNUM + 2, { "ft2", "f2" }, true },
+   { RISCV_FIRST_FP_REGNUM + 3, { "ft3", "f3" }, true },
+   { RISCV_FIRST_FP_REGNUM + 4, { "ft4", "f4" }, true },
+   { RISCV_FIRST_FP_REGNUM + 5, { "ft5", "f5" }, true },
+   { RISCV_FIRST_FP_REGNUM + 6, { "ft6", "f6" }, true },
+   { RISCV_FIRST_FP_REGNUM + 7, { "ft7", "f7" }, true },
+   { RISCV_FIRST_FP_REGNUM + 8, { "fs0", "f8", "s0" }, true },
+   { RISCV_FIRST_FP_REGNUM + 9, { "fs1", "f9" }, true },
+   { RISCV_FIRST_FP_REGNUM + 10, { "fa0", "f10" }, true },
+   { RISCV_FIRST_FP_REGNUM + 11, { "fa1", "f11" }, true },
+   { RISCV_FIRST_FP_REGNUM + 12, { "fa2", "f12" }, true },
+   { RISCV_FIRST_FP_REGNUM + 13, { "fa3", "f13" }, true },
+   { RISCV_FIRST_FP_REGNUM + 14, { "fa4", "f14" }, true },
+   { RISCV_FIRST_FP_REGNUM + 15, { "fa5", "f15" }, true },
+   { RISCV_FIRST_FP_REGNUM + 16, { "fa6", "f16" }, true },
+   { RISCV_FIRST_FP_REGNUM + 17, { "fa7", "f17" }, true },
+   { RISCV_FIRST_FP_REGNUM + 18, { "fs2", "f18" }, true },
+   { RISCV_FIRST_FP_REGNUM + 19, { "fs3", "f19" }, true },
+   { RISCV_FIRST_FP_REGNUM + 20, { "fs4", "f20" }, true },
+   { RISCV_FIRST_FP_REGNUM + 21, { "fs5", "f21" }, true },
+   { RISCV_FIRST_FP_REGNUM + 22, { "fs6", "f22" }, true },
+   { RISCV_FIRST_FP_REGNUM + 23, { "fs7", "f23" }, true },
+   { RISCV_FIRST_FP_REGNUM + 24, { "fs8", "f24" }, true },
+   { RISCV_FIRST_FP_REGNUM + 25, { "fs9", "f25" }, true },
+   { RISCV_FIRST_FP_REGNUM + 26, { "fs10", "f26" }, true },
+   { RISCV_FIRST_FP_REGNUM + 27, { "fs11", "f27" }, true },
+   { RISCV_FIRST_FP_REGNUM + 28, { "ft8", "f28" }, true },
+   { RISCV_FIRST_FP_REGNUM + 29, { "ft9", "f29" }, true },
+   { RISCV_FIRST_FP_REGNUM + 30, { "ft10", "f30" }, true },
+   { RISCV_FIRST_FP_REGNUM + 31, { "ft11", "f31" }, true },
+
+   { RISCV_CSR_FFLAGS_REGNUM, { "fflags" }, true },
+   { RISCV_CSR_FRM_REGNUM, { "frm" }, true },
+   { RISCV_CSR_FCSR_REGNUM, { "fcsr" }, true },
+
+ }
+};
+
+/* Set of virtual registers.  These are not physical registers on the
+   hardware, but might be available from the target.  These are not pseudo
+   registers, reading these really does result in a register read from the
+   target, it is just that there might not be a physical register backing
+   the result.  */
+
+static const struct riscv_register_feature riscv_virtual_feature =
+{
+ "org.gnu.gdb.riscv.virtual",
+ {
+   { RISCV_PRIV_REGNUM, { "priv" }, false }
+ }
 };
 
-/* Table of register aliases.  */
-
-static const struct riscv_register_alias riscv_register_aliases[] =
-{
- /* Aliases for general purpose registers.  These are the architectural
-    names, as GDB uses the more user friendly names by default.  */
- { "x0", (RISCV_ZERO_REGNUM + 0) },
- { "x1", (RISCV_ZERO_REGNUM + 1) },
- { "x2", (RISCV_ZERO_REGNUM + 2) },
- { "x3", (RISCV_ZERO_REGNUM + 3) },
- { "x4", (RISCV_ZERO_REGNUM + 4) },
- { "x5", (RISCV_ZERO_REGNUM + 5) },
- { "x6", (RISCV_ZERO_REGNUM + 6) },
- { "x7", (RISCV_ZERO_REGNUM + 7) },
- { "x8", (RISCV_ZERO_REGNUM + 8) },
- { "s0", (RISCV_ZERO_REGNUM + 8) },	/* fp, s0, and x8 are all aliases.  */
- { "x9", (RISCV_ZERO_REGNUM + 9) },
- { "x10", (RISCV_ZERO_REGNUM + 10) },
- { "x11", (RISCV_ZERO_REGNUM + 11) },
- { "x12", (RISCV_ZERO_REGNUM + 12) },
- { "x13", (RISCV_ZERO_REGNUM + 13) },
- { "x14", (RISCV_ZERO_REGNUM + 14) },
- { "x15", (RISCV_ZERO_REGNUM + 15) },
- { "x16", (RISCV_ZERO_REGNUM + 16) },
- { "x17", (RISCV_ZERO_REGNUM + 17) },
- { "x18", (RISCV_ZERO_REGNUM + 18) },
- { "x19", (RISCV_ZERO_REGNUM + 19) },
- { "x20", (RISCV_ZERO_REGNUM + 20) },
- { "x21", (RISCV_ZERO_REGNUM + 21) },
- { "x22", (RISCV_ZERO_REGNUM + 22) },
- { "x23", (RISCV_ZERO_REGNUM + 23) },
- { "x24", (RISCV_ZERO_REGNUM + 24) },
- { "x25", (RISCV_ZERO_REGNUM + 25) },
- { "x26", (RISCV_ZERO_REGNUM + 26) },
- { "x27", (RISCV_ZERO_REGNUM + 27) },
- { "x28", (RISCV_ZERO_REGNUM + 28) },
- { "x29", (RISCV_ZERO_REGNUM + 29) },
- { "x30", (RISCV_ZERO_REGNUM + 30) },
- { "x31", (RISCV_ZERO_REGNUM + 31) },
-
- /* Aliases for the floating-point registers.  These are the architectural
-    names as GDB uses the more user friendly names by default.  */
- { "f0", (RISCV_FIRST_FP_REGNUM + 0) },
- { "f1", (RISCV_FIRST_FP_REGNUM + 1) },
- { "f2", (RISCV_FIRST_FP_REGNUM + 2) },
- { "f3", (RISCV_FIRST_FP_REGNUM + 3) },
- { "f4", (RISCV_FIRST_FP_REGNUM + 4) },
- { "f5", (RISCV_FIRST_FP_REGNUM + 5) },
- { "f6", (RISCV_FIRST_FP_REGNUM + 6) },
- { "f7", (RISCV_FIRST_FP_REGNUM + 7) },
- { "f8", (RISCV_FIRST_FP_REGNUM + 8) },
- { "f9", (RISCV_FIRST_FP_REGNUM + 9) },
- { "f10", (RISCV_FIRST_FP_REGNUM + 10) },
- { "f11", (RISCV_FIRST_FP_REGNUM + 11) },
- { "f12", (RISCV_FIRST_FP_REGNUM + 12) },
- { "f13", (RISCV_FIRST_FP_REGNUM + 13) },
- { "f14", (RISCV_FIRST_FP_REGNUM + 14) },
- { "f15", (RISCV_FIRST_FP_REGNUM + 15) },
- { "f16", (RISCV_FIRST_FP_REGNUM + 16) },
- { "f17", (RISCV_FIRST_FP_REGNUM + 17) },
- { "f18", (RISCV_FIRST_FP_REGNUM + 18) },
- { "f19", (RISCV_FIRST_FP_REGNUM + 19) },
- { "f20", (RISCV_FIRST_FP_REGNUM + 20) },
- { "f21", (RISCV_FIRST_FP_REGNUM + 21) },
- { "f22", (RISCV_FIRST_FP_REGNUM + 22) },
- { "f23", (RISCV_FIRST_FP_REGNUM + 23) },
- { "f24", (RISCV_FIRST_FP_REGNUM + 24) },
- { "f25", (RISCV_FIRST_FP_REGNUM + 25) },
- { "f26", (RISCV_FIRST_FP_REGNUM + 26) },
- { "f27", (RISCV_FIRST_FP_REGNUM + 27) },
- { "f28", (RISCV_FIRST_FP_REGNUM + 28) },
- { "f29", (RISCV_FIRST_FP_REGNUM + 29) },
- { "f30", (RISCV_FIRST_FP_REGNUM + 30) },
- { "f31", (RISCV_FIRST_FP_REGNUM + 31) },
+/* Feature set for CSRs.  This set is NOT constant as the register names
+   list for each register is not complete.  The aliases are computed
+   during RISCV_CREATE_CSR_ALIASES.  */
+
+static struct riscv_register_feature riscv_csr_feature =
+{
+ "org.gnu.gdb.riscv.csr",
+ {
+#define DECLARE_CSR(NAME,VALUE) \
+  { RISCV_ ## VALUE ## _REGNUM, { # NAME }, false },
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+ }
 };
 
+/* Complete RISCV_CSR_FEATURE, building the CSR alias names and adding them
+   to the name list for each register.  */
+
+static void
+riscv_create_csr_aliases ()
+{
+  for (auto &reg : riscv_csr_feature.registers)
+    {
+      int csr_num = reg.regnum - RISCV_FIRST_CSR_REGNUM;
+      const char *alias = xstrprintf ("csr%d", csr_num);
+      reg.names.push_back (alias);
+    }
+}
+
 /* Controls whether we place compressed breakpoints or not.  When in auto
    mode GDB tries to determine if the target supports compressed
    breakpoints, and uses them if it does.  */
@@ -293,82 +351,17 @@ static unsigned int riscv_debug_infcall = 0;
 
 static unsigned int riscv_debug_unwinder = 0;
 
-/* Read the MISA register from the target.  There are a couple of locations
-   that the register might be found, these are all tried.  If the MISA
-   register can't be found at all then the default value of 0 is returned,
-   this is inline with the RISC-V specification.  */
-
-static uint32_t
-riscv_read_misa_reg ()
-{
-  uint32_t value = 0;
-
-  if (target_has_registers)
-    {
-      /* Old cores might have MISA located at a different offset.  */
-      static int misa_regs[] =
-	{ RISCV_CSR_MISA_REGNUM, RISCV_CSR_LEGACY_MISA_REGNUM };
-
-      struct frame_info *frame = get_current_frame ();
-
-      for (int i = 0; i < ARRAY_SIZE (misa_regs); ++i)
-	{
-	  bool success = false;
-
-	  TRY
-	    {
-	      value = get_frame_register_unsigned (frame, misa_regs[i]);
-	      success = true;
-	    }
-	  CATCH (ex, RETURN_MASK_ERROR)
-	    {
-	      /* Ignore errors, it is acceptable for a target to not
-		 provide a MISA register, in which case the default value
-		 of 0 should be used.  */
-	    }
-	  END_CATCH
-
-	  if (success)
-	    break;
-	}
-    }
-
-  return value;
-}
+/* When this is set to non-zero debugging information about gdbarch
+   initialisation will be printed.  */
 
-/* Return true if FEATURE is available for the architecture GDBARCH.  The
-   FEATURE should be one of the single character feature codes described in
-   the RiscV ISA manual, these are between 'A' and 'Z'.  */
-
-static bool
-riscv_has_feature (struct gdbarch *gdbarch, char feature)
-{
-  gdb_assert (feature >= 'A' && feature <= 'Z');
-
-  uint32_t misa = riscv_read_misa_reg ();
-  if (misa == 0)
-    misa = gdbarch_tdep (gdbarch)->core_features;
-
-  return (misa & (1 << (feature - 'A'))) != 0;
-}
+static unsigned int riscv_debug_gdbarch = 0;
 
 /* See riscv-tdep.h.  */
 
 int
 riscv_isa_xlen (struct gdbarch *gdbarch)
 {
-  switch (gdbarch_tdep (gdbarch)->abi.fields.base_len)
-    {
-    default:
-      warning (_("unknown xlen size, assuming 4 bytes"));
-      /* Fall through.  */
-    case 1:
-      return 4;
-    case 2:
-      return 8;
-    case 3:
-      return 16;
-    }
+  return gdbarch_tdep (gdbarch)->features.xlen;
 }
 
 /* See riscv-tdep.h.  */
@@ -376,14 +369,7 @@ riscv_isa_xlen (struct gdbarch *gdbarch)
 int
 riscv_isa_flen (struct gdbarch *gdbarch)
 {
-  if (riscv_has_feature (gdbarch, 'Q'))
-    return 16;
-  else if (riscv_has_feature (gdbarch, 'D'))
-    return 8;
-  else if (riscv_has_feature (gdbarch, 'F'))
-    return 4;
-
-  return 0;
+  return gdbarch_tdep (gdbarch)->features.flen;
 }
 
 /* Return true if the target for GDBARCH has floating point hardware.  */
@@ -399,7 +385,7 @@ riscv_has_fp_regs (struct gdbarch *gdbarch)
 static bool
 riscv_has_fp_abi (struct gdbarch *gdbarch)
 {
-  return (gdbarch_tdep (gdbarch)->abi.fields.float_abi != 0);
+  return gdbarch_tdep (gdbarch)->features.hw_float_abi;
 }
 
 /* Return true if REGNO is a floating pointer register.  */
@@ -485,16 +471,36 @@ value_of_riscv_user_reg (struct frame_info *frame, const void *baton)
   return value_of_register (*reg_p, frame);
 }
 
-/* Implement the register_name gdbarch method.  */
+/* Implement the register_name gdbarch method.  This is used instead of
+   the function supplied by calling TDESC_USE_REGISTERS so that we can
+   ensure the preferred names are offered.  */
 
 static const char *
 riscv_register_name (struct gdbarch *gdbarch, int regnum)
 {
-  /* Prefer to use the alias. */
-  if (regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
+  /* Lookup the name through the target description.  If we get back NULL
+     then this is an unknown register.  If we do get a name back then we
+     look up the registers preferred name below.  */
+  const char *name = tdesc_register_name (gdbarch, regnum);
+  if (name == NULL || name[0] == '\0')
+    return NULL;
+
+  if (regnum >= RISCV_ZERO_REGNUM && regnum < RISCV_FIRST_FP_REGNUM)
+    {
+      gdb_assert (regnum < riscv_xreg_feature.registers.size ());
+      return riscv_xreg_feature.registers[regnum].names[0];
+    }
+
+  if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
     {
-      gdb_assert (regnum < ARRAY_SIZE (riscv_gdb_reg_names));
-      return riscv_gdb_reg_names[regnum];
+      if (riscv_has_fp_regs (gdbarch))
+        {
+          regnum -= RISCV_FIRST_FP_REGNUM;
+          gdb_assert (regnum < riscv_freg_feature.registers.size ());
+          return riscv_freg_feature.registers[regnum].names[0];
+        }
+      else
+        return NULL;
     }
 
   /* Check that there's no gap between the set of registers handled above,
@@ -509,14 +515,6 @@ riscv_register_name (struct gdbarch *gdbarch, int regnum)
       switch (regnum)
 	{
 	  #include "opcode/riscv-opc.h"
-	default:
-          {
-            static char buf[20];
-
-            xsnprintf (buf, sizeof (buf), "csr%d",
-                       regnum - RISCV_FIRST_CSR_REGNUM);
-            return buf;
-          }
 	}
 #undef DECLARE_CSR
     }
@@ -524,7 +522,10 @@ riscv_register_name (struct gdbarch *gdbarch, int regnum)
   if (regnum == RISCV_PRIV_REGNUM)
     return "priv";
 
-  return NULL;
+  /* It is possible that that the target provides some registers that GDB
+     is unaware of, in that case just return the NAME from the target
+     description.  */
+  return name;
 }
 
 /* Construct a type for 64-bit FP registers.  */
@@ -561,115 +562,59 @@ riscv_fpreg_d_type (struct gdbarch *gdbarch)
   return tdep->riscv_fpreg_d_type;
 }
 
-/* Construct a type for 128-bit FP registers.  */
+/* Implement the register_type gdbarch method.  This is installed as an
+   for the override setup by TDESC_USE_REGISTERS, for most registers we
+   delegate the type choice to the target description, but for a few
+   registers we try to improve the types if the target description has
+   taken a simplistic approach.  */
 
 static struct type *
-riscv_fpreg_q_type (struct gdbarch *gdbarch)
+riscv_register_type (struct gdbarch *gdbarch, int regnum)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct type *type = tdesc_register_type (gdbarch, regnum);
+  int xlen = riscv_isa_xlen (gdbarch);
 
-  if (tdep->riscv_fpreg_q_type == nullptr)
+  /* We want to perform some specific type "fixes" in cases where we feel
+     that we really can do better than the target description.  For all
+     other cases we just return what the target description says.  */
+  if (riscv_is_fp_regno_p (regnum))
     {
-      const struct builtin_type *bt = builtin_type (gdbarch);
-
-      /* The type we're building is this: */
-#if 0
-      union __gdb_builtin_type_fpreg_d
-      {
-	float f;
-	double d;
-	long double ld;
-      };
-#endif
-
-      struct type *t;
-
-      t = arch_composite_type (gdbarch,
-			       "__gdb_builtin_type_fpreg_q", TYPE_CODE_UNION);
-      append_composite_type_field (t, "float", bt->builtin_float);
-      append_composite_type_field (t, "double", bt->builtin_double);
-      append_composite_type_field (t, "long double", bt->builtin_long_double);
-      TYPE_VECTOR (t) = 1;
-      TYPE_NAME (t) = "builtin_type_fpreg_q";
-      tdep->riscv_fpreg_q_type = t;
+      /* This spots the case for RV64 where the double is defined as
+         either 'ieee_double' or 'float' (which is the generic name that
+         converts to 'double' on 64-bit).  In these cases its better to
+         present the registers using a union type.  */
+      int flen = riscv_isa_flen (gdbarch);
+      if (flen == 8
+          && TYPE_CODE (type) == TYPE_CODE_FLT
+          && TYPE_LENGTH (type) == flen
+          && (strcmp (TYPE_NAME (type), "builtin_type_ieee_double") == 0
+              || strcmp (TYPE_NAME (type), "double") == 0))
+        type = riscv_fpreg_d_type (gdbarch);
     }
 
-  return tdep->riscv_fpreg_q_type;
-}
-
-/* Implement the register_type gdbarch method.  */
-
-static struct type *
-riscv_register_type (struct gdbarch *gdbarch, int regnum)
-{
-  int regsize;
-
-  if (regnum < RISCV_FIRST_FP_REGNUM)
+  if ((regnum == gdbarch_pc_regnum (gdbarch)
+       || regnum == RISCV_RA_REGNUM
+       || regnum == RISCV_FP_REGNUM
+       || regnum == RISCV_SP_REGNUM
+       || regnum == RISCV_GP_REGNUM
+       || regnum == RISCV_TP_REGNUM)
+      && TYPE_CODE (type) == TYPE_CODE_INT
+      && TYPE_LENGTH (type) == xlen)
     {
+      /* This spots the case where some interesting registers are defined
+         as simple integers of the expected size, we force these registers
+         to be pointers as we believe that is more useful.  */
       if (regnum == gdbarch_pc_regnum (gdbarch)
-	  || regnum == RISCV_RA_REGNUM)
-	return builtin_type (gdbarch)->builtin_func_ptr;
-
-      if (regnum == RISCV_FP_REGNUM
-	  || regnum == RISCV_SP_REGNUM
-	  || regnum == RISCV_GP_REGNUM
-	  || regnum == RISCV_TP_REGNUM)
-	return builtin_type (gdbarch)->builtin_data_ptr;
-
-      /* Remaining GPRs vary in size based on the current ISA.  */
-      regsize = riscv_isa_xlen (gdbarch);
-      switch (regsize)
-	{
-	case 4:
-	  return builtin_type (gdbarch)->builtin_uint32;
-	case 8:
-	  return builtin_type (gdbarch)->builtin_uint64;
-	case 16:
-	  return builtin_type (gdbarch)->builtin_uint128;
-	default:
-	  internal_error (__FILE__, __LINE__,
-			  _("unknown isa regsize %i"), regsize);
-	}
+          || regnum == RISCV_RA_REGNUM)
+        type = builtin_type (gdbarch)->builtin_func_ptr;
+      else if (regnum == RISCV_FP_REGNUM
+               || regnum == RISCV_SP_REGNUM
+               || regnum == RISCV_GP_REGNUM
+               || regnum == RISCV_TP_REGNUM)
+	type = builtin_type (gdbarch)->builtin_data_ptr;
     }
-  else if (regnum <= RISCV_LAST_FP_REGNUM)
-    {
-      regsize = riscv_isa_xlen (gdbarch);
-      switch (regsize)
-	{
-	case 4:
-	  return builtin_type (gdbarch)->builtin_float;
-	case 8:
-	  return riscv_fpreg_d_type (gdbarch);
-	case 16:
-	  return riscv_fpreg_q_type (gdbarch);
-	default:
-	  internal_error (__FILE__, __LINE__,
-			  _("unknown isa regsize %i"), regsize);
-	}
-    }
-  else if (regnum == RISCV_PRIV_REGNUM)
-    return builtin_type (gdbarch)->builtin_int8;
-  else
-    {
-      if (regnum == RISCV_CSR_FFLAGS_REGNUM
-	  || regnum == RISCV_CSR_FRM_REGNUM
-	  || regnum == RISCV_CSR_FCSR_REGNUM)
-	return builtin_type (gdbarch)->builtin_int32;
 
-      regsize = riscv_isa_xlen (gdbarch);
-      switch (regsize)
-	{
-	case 4:
-	  return builtin_type (gdbarch)->builtin_int32;
-	case 8:
-	  return builtin_type (gdbarch)->builtin_int64;
-	case 16:
-	  return builtin_type (gdbarch)->builtin_int128;
-	default:
-	  internal_error (__FILE__, __LINE__,
-			  _("unknown isa regsize %i"), regsize);
-	}
-    }
+  return type;
 }
 
 /* Helper for riscv_print_registers_info, prints info for a single register
@@ -682,14 +627,28 @@ riscv_print_one_register_info (struct gdbarch *gdbarch,
 			       int regnum)
 {
   const char *name = gdbarch_register_name (gdbarch, regnum);
-  struct value *val = value_of_register (regnum, frame);
-  struct type *regtype = value_type (val);
+  struct value *val;
+  struct type *regtype;
   int print_raw_format;
   enum tab_stops { value_column_1 = 15 };
 
   fputs_filtered (name, file);
   print_spaces_filtered (value_column_1 - strlen (name), file);
 
+  TRY
+    {
+      val = value_of_register (regnum, frame);
+      regtype = value_type (val);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      /* Handle failure to read a register without interrupting the entire
+         'info registers' flow.  */
+      fprintf_filtered (file, "%s\n", ex.message);
+      return;
+    }
+  END_CATCH
+
   print_raw_format = (value_entirely_available (val)
 		      && !value_optimized_out (val));
 
@@ -904,6 +863,15 @@ riscv_register_reggroup_p (struct gdbarch  *gdbarch, int regnum,
       || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
     return 0;
 
+  if (regnum > RISCV_LAST_REGNUM)
+    {
+      int ret = tdesc_register_in_reggroup_p (gdbarch, regnum, reggroup);
+      if (ret != -1)
+        return ret;
+
+      return default_register_reggroup_p (gdbarch, regnum, reggroup);
+    }
+
   if (reggroup == all_reggroup)
     {
       if (regnum < RISCV_FIRST_CSR_REGNUM || regnum == RISCV_PRIV_REGNUM)
@@ -926,7 +894,7 @@ riscv_register_reggroup_p (struct gdbarch  *gdbarch, int regnum,
       else
 	return regnum < RISCV_FIRST_FP_REGNUM;
     }
-  else if (reggroup == system_reggroup)
+  else if (reggroup == system_reggroup || reggroup == csr_reggroup)
     {
       if (regnum == RISCV_PRIV_REGNUM)
 	return 1;
@@ -954,7 +922,6 @@ riscv_print_registers_info (struct gdbarch *gdbarch,
   if (regnum != -1)
     {
       /* Print one specified register.  */
-      gdb_assert (regnum <= RISCV_LAST_REGNUM);
       if (gdbarch_register_name (gdbarch, regnum) == NULL
 	  || *(gdbarch_register_name (gdbarch, regnum)) == '\0')
         error (_("Not a valid register for the current processor type"));
@@ -981,7 +948,7 @@ riscv_print_registers_info (struct gdbarch *gdbarch,
 	    continue;
 
 	  /* Is the register in the group we're interested in?  */
-	  if (!riscv_register_reggroup_p (gdbarch, regnum, reggroup))
+	  if (!gdbarch_register_reggroup_p (gdbarch, regnum, reggroup))
 	    continue;
 
 	  riscv_print_one_register_info (gdbarch, file, frame, regnum);
@@ -2822,36 +2789,26 @@ static const struct frame_unwind riscv_frame_unwind =
   /*.prev_arch     =*/ NULL,
 };
 
-/* Initialize the current architecture based on INFO.  If possible,
-   re-use an architecture from ARCHES, which is a list of
-   architectures already created during this debugging session.
-
-   Called e.g. at program startup, when reading a core file, and when
-   reading a binary file.  */
+/* Find a suitable default target description.  Use the contents of INFO,
+   specifically the bfd object being executed, to guide the selection of a
+   suitable default target description.  */
 
-static struct gdbarch *
-riscv_gdbarch_init (struct gdbarch_info info,
-		    struct gdbarch_list *arches)
+static struct target_desc *
+riscv_find_default_target_description (const struct gdbarch_info info)
 {
-  struct gdbarch *gdbarch;
-  struct gdbarch_tdep *tdep;
-  struct gdbarch_tdep tmp_tdep;
-  int i;
-
-  /* Ideally, we'd like to get as much information from the target for
-     things like register size, and whether the target has floating point
-     hardware.  However, there are some things that the target can't tell
-     us, like, what ABI is being used.
+  struct riscv_gdbarch_features features;
 
-     So, for now, we take as much information as possible from the ELF,
-     including things like register size, and FP hardware support, along
-     with information about the ABI.
-
-     Information about this target is built up in TMP_TDEP, and then we
-     look for an existing gdbarch in ARCHES that matches TMP_TDEP.  If no
-     match is found we'll create a new gdbarch and copy TMP_TDEP over.  */
-  memset (&tmp_tdep, 0, sizeof (tmp_tdep));
+  /* Setup some arbitrary defaults.  */
+  features.xlen = 8;
+  features.flen = 0;
+  features.hw_float_abi = false;
 
+  /* Now try to improve on the defaults by looking at the binary we are
+     going to execute.  We assume the user knows what they are doing and
+     that the target will match the binary.  Remember, this code path is
+     only used at all if the target hasn't given us a description, so this
+     is really a last ditched effort to do something sane before giving
+     up.  */
   if (info.abfd != NULL
       && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
     {
@@ -2859,26 +2816,22 @@ riscv_gdbarch_init (struct gdbarch_info info,
       int e_flags = elf_elfheader (info.abfd)->e_flags;
 
       if (eclass == ELFCLASS32)
-	tmp_tdep.abi.fields.base_len = 1;
+	features.xlen = 4;
       else if (eclass == ELFCLASS64)
-	tmp_tdep.abi.fields.base_len = 2;
+	features.xlen = 8;
       else
-        internal_error (__FILE__, __LINE__,
+	internal_error (__FILE__, __LINE__,
 			_("unknown ELF header class %d"), eclass);
 
-      if (e_flags & EF_RISCV_RVC)
-	tmp_tdep.core_features |= (1 << ('C' - 'A'));
-
       if (e_flags & EF_RISCV_FLOAT_ABI_DOUBLE)
 	{
-	  tmp_tdep.abi.fields.float_abi = 2;
-	  tmp_tdep.core_features |= (1 << ('D' - 'A'));
-	  tmp_tdep.core_features |= (1 << ('F' - 'A'));
+	  features.flen = 8;
+	  features.hw_float_abi = true;
 	}
       else if (e_flags & EF_RISCV_FLOAT_ABI_SINGLE)
 	{
-	  tmp_tdep.abi.fields.float_abi = 1;
-	  tmp_tdep.core_features |= (1 << ('F' - 'A'));
+	  features.flen = 4;
+	  features.hw_float_abi = true;
 	}
     }
   else
@@ -2886,25 +2839,210 @@ riscv_gdbarch_init (struct gdbarch_info info,
       const struct bfd_arch_info *binfo = info.bfd_arch_info;
 
       if (binfo->bits_per_word == 32)
-	tmp_tdep.abi.fields.base_len = 1;
+	features.xlen = 4;
       else if (binfo->bits_per_word == 64)
-	tmp_tdep.abi.fields.base_len = 2;
+	features.xlen = 8;
       else
-        internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"),
+	internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"),
 			binfo->bits_per_word);
     }
 
+  /* Now build a target description based on the feature set.  */
+  return riscv_create_target_description (features);
+}
+
+/* All of the registers in REG_SET are checked for in FEATURE, TDESC_DATA
+   is updated with the register numbers for each register as listed in
+   REG_SET.  If any register marked as required in REG_SET is not found in
+   FEATURE then this function returns false, otherwise, it returns true.  */
+
+static bool
+riscv_check_tdesc_feature (struct tdesc_arch_data *tdesc_data,
+                           const struct tdesc_feature *feature,
+                           const struct riscv_register_feature *reg_set)
+{
+  for (const auto &reg : reg_set->registers)
+    {
+      bool found = false;
+
+      for (const char *name : reg.names)
+	{
+	  found =
+	    tdesc_numbered_register (feature, tdesc_data, reg.regnum, name);
+
+	  if (found)
+	    break;
+	}
+
+      if (!found && reg.required_p)
+	return false;
+    }
+
+  return true;
+}
+
+/* Add all the expected register sets into GDBARCH.  */
+
+static void
+riscv_add_reggroups (struct gdbarch *gdbarch)
+{
+  /* Add predefined register groups.  */
+  reggroup_add (gdbarch, all_reggroup);
+  reggroup_add (gdbarch, save_reggroup);
+  reggroup_add (gdbarch, restore_reggroup);
+  reggroup_add (gdbarch, system_reggroup);
+  reggroup_add (gdbarch, vector_reggroup);
+  reggroup_add (gdbarch, general_reggroup);
+  reggroup_add (gdbarch, float_reggroup);
+
+  /* Add RISC-V specific register groups.  */
+  reggroup_add (gdbarch, csr_reggroup);
+}
+
+/* Create register aliases for all the alternative names that exist for
+   registers in REG_SET.  */
+
+static void
+riscv_setup_register_aliases (struct gdbarch *gdbarch,
+                              const struct riscv_register_feature *reg_set)
+{
+  for (auto &reg : reg_set->registers)
+    {
+      /* The first item in the names list is the preferred name for the
+         register, this is what RISCV_REGISTER_NAME returns, and so we
+         don't need to create an alias with that name here.  */
+      for (int i = 1; i < reg.names.size (); ++i)
+        user_reg_add (gdbarch, reg.names[i], value_of_riscv_user_reg,
+                      &reg.regnum);
+    }
+}
+
+/* Initialize the current architecture based on INFO.  If possible,
+   re-use an architecture from ARCHES, which is a list of
+   architectures already created during this debugging session.
+
+   Called e.g. at program startup, when reading a core file, and when
+   reading a binary file.  */
+
+static struct gdbarch *
+riscv_gdbarch_init (struct gdbarch_info info,
+		    struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  struct riscv_gdbarch_features features;
+  const struct target_desc *tdesc = info.target_desc;
+
+  /* Ensure we always have a target description.  */
+  if (!tdesc_has_registers (tdesc))
+    tdesc = riscv_find_default_target_description (info);
+  gdb_assert (tdesc);
+
+  if (riscv_debug_gdbarch)
+    fprintf_unfiltered (gdb_stdlog, "Have got a target description\n");
+
+  const struct tdesc_feature *feature_cpu
+    = tdesc_find_feature (tdesc, riscv_xreg_feature.name);
+  const struct tdesc_feature *feature_fpu
+    = tdesc_find_feature (tdesc, riscv_freg_feature.name);
+  const struct tdesc_feature *feature_virtual
+    = tdesc_find_feature (tdesc, riscv_virtual_feature.name);
+  const struct tdesc_feature *feature_csr
+    = tdesc_find_feature (tdesc, riscv_csr_feature.name);
+
+  if (feature_cpu == NULL)
+    return NULL;
+
+  struct tdesc_arch_data *tdesc_data = tdesc_data_alloc ();
+
+  bool valid_p = riscv_check_tdesc_feature (tdesc_data,
+                                            feature_cpu,
+                                            &riscv_xreg_feature);
+  if (valid_p)
+    {
+      /* Check that all of the core cpu registers have the same bitsize.  */
+      int xlen_bitsize = tdesc_register_bitsize (feature_cpu, "pc");
+
+      for (auto &tdesc_reg : feature_cpu->registers)
+        valid_p &= (tdesc_reg->bitsize == xlen_bitsize);
+
+      if (riscv_debug_gdbarch)
+        fprintf_filtered
+          (gdb_stdlog,
+           "From target-description, xlen = %d\n", xlen_bitsize);
+
+      features.xlen = (xlen_bitsize / 8);
+    }
+
+  if (feature_fpu != NULL)
+    {
+      valid_p &= riscv_check_tdesc_feature (tdesc_data, feature_fpu,
+                                            &riscv_freg_feature);
+
+      int bitsize = tdesc_register_bitsize (feature_fpu, "ft0");
+      features.flen = (bitsize / 8);
+      features.hw_float_abi = true;
+
+      if (riscv_debug_gdbarch)
+        fprintf_filtered
+          (gdb_stdlog,
+           "From target-description, flen = %d\n", bitsize);
+    }
+  else
+    {
+      features.flen = 0;
+      features.hw_float_abi = false;
+
+      if (riscv_debug_gdbarch)
+        fprintf_filtered
+          (gdb_stdlog,
+           "No FPU in target-description, assume soft-float ABI\n");
+    }
+
+  if (feature_virtual)
+    riscv_check_tdesc_feature (tdesc_data, feature_virtual,
+                               &riscv_virtual_feature);
+
+  if (feature_csr)
+    riscv_check_tdesc_feature (tdesc_data, feature_csr,
+                               &riscv_csr_feature);
+
+  if (!valid_p)
+    {
+      if (riscv_debug_gdbarch)
+        fprintf_unfiltered (gdb_stdlog, "Target description is not valid\n");
+      tdesc_data_cleanup (tdesc_data);
+      return NULL;
+    }
+
   /* Find a candidate among the list of pre-declared architectures.  */
   for (arches = gdbarch_list_lookup_by_info (arches, &info);
        arches != NULL;
        arches = gdbarch_list_lookup_by_info (arches->next, &info))
-    if (gdbarch_tdep (arches->gdbarch)->abi.value == tmp_tdep.abi.value)
+    {
+      /* Check that the feature set of the ARCHES matches the feature set
+         we are looking for.  If it doesn't then we can't reuse this
+         gdbarch.  */
+      struct gdbarch_tdep *other_tdep = gdbarch_tdep (arches->gdbarch);
+
+      if (other_tdep->features.hw_float_abi != features.hw_float_abi
+          || other_tdep->features.xlen != features.xlen
+          || other_tdep->features.flen != features.flen)
+        continue;
+
+      break;
+    }
+
+  if (arches != NULL)
+    {
+      tdesc_data_cleanup (tdesc_data);
       return arches->gdbarch;
+    }
 
   /* None found, so create a new architecture from the information provided.  */
-  tdep = (struct gdbarch_tdep *) xmalloc (sizeof *tdep);
+  tdep = new (struct gdbarch_tdep);
   gdbarch = gdbarch_alloc (&info, tdep);
-  memcpy (tdep, &tmp_tdep, sizeof (tmp_tdep));
+  tdep->features = features;
 
   /* Target data types.  */
   set_gdbarch_short_bit (gdbarch, 16);
@@ -2924,19 +3062,6 @@ riscv_gdbarch_init (struct gdbarch_info info,
   set_gdbarch_sw_breakpoint_from_kind (gdbarch, riscv_sw_breakpoint_from_kind);
   set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
 
-  /* Register architecture.  */
-  set_gdbarch_num_regs (gdbarch, RISCV_LAST_REGNUM + 1);
-  set_gdbarch_sp_regnum (gdbarch, RISCV_SP_REGNUM);
-  set_gdbarch_pc_regnum (gdbarch, RISCV_PC_REGNUM);
-  set_gdbarch_ps_regnum (gdbarch, RISCV_FP_REGNUM);
-  set_gdbarch_deprecated_fp_regnum (gdbarch, RISCV_FP_REGNUM);
-
-  /* Functions to supply register information.  */
-  set_gdbarch_register_name (gdbarch, riscv_register_name);
-  set_gdbarch_register_type (gdbarch, riscv_register_type);
-  set_gdbarch_print_registers_info (gdbarch, riscv_print_registers_info);
-  set_gdbarch_register_reggroup_p (gdbarch, riscv_register_reggroup_p);
-
   /* Functions to analyze frames.  */
   set_gdbarch_skip_prologue (gdbarch, riscv_skip_prologue);
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
@@ -2957,9 +3082,49 @@ riscv_gdbarch_init (struct gdbarch_info info,
   dwarf2_append_unwinders (gdbarch);
   frame_unwind_append_unwinder (gdbarch, &riscv_frame_unwind);
 
-  for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i)
-    user_reg_add (gdbarch, riscv_register_aliases[i].name,
-		  value_of_riscv_user_reg, &riscv_register_aliases[i].regnum);
+  /* Register architecture.  */
+  riscv_add_reggroups (gdbarch);
+
+  /* We reserve all possible register numbers for the known registers.
+     This means the target description mechanism will add any target
+     specific registers after this number.  This helps make debugging GDB
+     just a little easier.  */
+  set_gdbarch_num_regs (gdbarch, RISCV_LAST_REGNUM + 1);
+
+  /* We don't have to provide the count of 0 here (its the default) but
+     include this line to make it explicit that, right now, we don't have
+     any pseudo registers on RISC-V.  */
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+
+  /* Some specific register numbers GDB likes to know about.  */
+  set_gdbarch_sp_regnum (gdbarch, RISCV_SP_REGNUM);
+  set_gdbarch_pc_regnum (gdbarch, RISCV_PC_REGNUM);
+
+  set_gdbarch_print_registers_info (gdbarch, riscv_print_registers_info);
+
+  /* Finalise the target description registers.  */
+  tdesc_use_registers (gdbarch, tdesc, tdesc_data);
+
+  /* Override the register type callback setup by the target description
+     mechanism.  This allows us to provide special type for floating point
+     registers.  */
+  set_gdbarch_register_type (gdbarch, riscv_register_type);
+
+  /* Override the register name callback setup by the target description
+     mechanism.  This allows us to force our preferred names for the
+     registers, no matter what the target description called them.  */
+  set_gdbarch_register_name (gdbarch, riscv_register_name);
+
+  /* Override the register group callback setup by the target description
+     mechanism.  This allows us to force registers into the groups we
+     want, ignoring what the target tells us.  */
+  set_gdbarch_register_reggroup_p (gdbarch, riscv_register_reggroup_p);
+
+  /* Create register aliases for alternative register names.  */
+  riscv_setup_register_aliases (gdbarch, &riscv_xreg_feature);
+  if (riscv_has_fp_regs (gdbarch))
+    riscv_setup_register_aliases (gdbarch, &riscv_freg_feature);
+  riscv_setup_register_aliases (gdbarch, &riscv_csr_feature);
 
   /* Hook in OS ABI-specific overrides, if they have been registered.  */
   gdbarch_init_osabi (info, gdbarch);
@@ -3106,9 +3271,20 @@ riscv_software_single_step (struct regcache *regcache)
   return {next_pc};
 }
 
+/* Create RISC-V specific reggroups.  */
+
+static void
+riscv_init_reggroups ()
+{
+  csr_reggroup = reggroup_new ("csr", USER_REGGROUP);
+}
+
 void
 _initialize_riscv_tdep (void)
 {
+  riscv_create_csr_aliases ();
+  riscv_init_reggroups ();
+
   gdbarch_register (bfd_arch_riscv, riscv_gdbarch_init, NULL);
 
   /* Add root prefix command for all "set debug riscv" and "show debug
@@ -3153,6 +3329,16 @@ of the stack unwinding mechanism."),
 			     show_riscv_debug_variable,
 			     &setdebugriscvcmdlist, &showdebugriscvcmdlist);
 
+  add_setshow_zuinteger_cmd ("gdbarch", class_maintenance,
+			     &riscv_debug_gdbarch,  _("\
+Set riscv gdbarch initialisation debugging."), _("\
+Show riscv gdbarch initialisation debugging."), _("\
+When non-zero, print debugging information for the riscv gdbarch\n\
+initialisation process."),
+			     NULL,
+			     show_riscv_debug_variable,
+			     &setdebugriscvcmdlist, &showdebugriscvcmdlist);
+
   /* Add root prefix command for all "set riscv" and "show riscv" commands.  */
   add_prefix_cmd ("riscv", no_class, set_riscv_command,
 		  _("RISC-V specific commands."),
diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
index 2cb51b16c53..59ad37df6ce 100644
--- a/gdb/riscv-tdep.h
+++ b/gdb/riscv-tdep.h
@@ -21,6 +21,8 @@
 #ifndef RISCV_TDEP_H
 #define RISCV_TDEP_H
 
+#include "arch/riscv.h"
+
 /* RiscV register numbers.  */
 enum
 {
@@ -57,31 +59,12 @@ enum
 /* RISC-V specific per-architecture information.  */
 struct gdbarch_tdep
 {
-  union
-  {
-    /* Provide access to the whole ABI in one value.  */
-    unsigned value;
-
-    struct
-    {
-      /* Encode the base machine length following the same rules as in the
-	 MISA register.  */
-      unsigned base_len : 2;
-
-      /* Encode which floating point ABI is in use following the same rules
-	 as the ELF e_flags field.  */
-      unsigned float_abi : 2;
-    } fields;
-  } abi;
-
-  /* Only the least significant 26 bits are (possibly) valid, and indicate
-     features that are supported on the target.  These could be cached from
-     the target, or read from the executable when available.  */
-  unsigned core_features;
+  /* Features about the target that impact how the gdbarch is configured.
+     Two gdbarch instances are compatible only if this field matches.  */
+  struct riscv_gdbarch_features features;
 
   /* ISA-specific data types.  */
-  struct type *riscv_fpreg_d_type;
-  struct type *riscv_fpreg_q_type;
+  struct type *riscv_fpreg_d_type = nullptr;
 };
 
 
diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c
index bdd29c0f2b5..20604bb4b96 100644
--- a/gdb/target-descriptions.c
+++ b/gdb/target-descriptions.c
@@ -1716,6 +1716,7 @@ maint_print_c_tdesc_cmd (const char *args, int from_tty)
   if (startswith (filename_after_features.c_str (), "i386/32bit-")
       || startswith (filename_after_features.c_str (), "i386/64bit-")
       || startswith (filename_after_features.c_str (), "i386/x32-core.xml")
+      || startswith (filename_after_features.c_str (), "riscv/")
       || startswith (filename_after_features.c_str (), "tic6x-")
       || startswith (filename_after_features.c_str (), "aarch64"))
     {
-- 
2.14.5

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

* Re: [PATCH] gdb/riscv: Add target description support
  2018-11-21 11:23     ` Andrew Burgess
@ 2018-11-21 12:37       ` Eli Zaretskii
  2018-11-21 13:19         ` Andrew Burgess
  0 siblings, 1 reply; 27+ messages in thread
From: Eli Zaretskii @ 2018-11-21 12:37 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: jimw, gdb-patches, palmer, jhb

> Date: Wed, 21 Nov 2018 11:23:35 +0000
> From: Andrew Burgess <andrew.burgess@embecosm.com>
> Cc: gdb-patches@sourceware.org, Palmer Dabbelt <palmer@sifive.com>,
> 	John Baldwin <jhb@freebsd.org>
> 
> Eli,
> 
> I believe I still need a doc review before I can merge this patch.
> Could I ask you to take a look please.

Sorry, I thought I already did.  See below.

> +The @samp{org.gnu.gdb.riscv.fpu} feature is optional.  If present it
                                                                    ^
Please insert a comma where shown.

> +should contain registers @samp{f0} through @samp{f31}, @samp{fflags},
> +@samp{frm}, and @samp{fcsr}.  As with the cpu feature either the
                                                        ^
And here.

> +The @samp{org.gnu.gdb.riscv.virtual} feature is optional.  If present
                                                                        ^
And here.

> +it should contain registers that are not backed by real registers on
> +the target but are instead virtual, where the register value is
             ^
And here.

> +derived from other target state.  In many ways these are like GDBs
                                                                 ^^^^
@value{GDBN}s

> +The @samp{org.gnu.gdb.riscv.csr} feature is optional.  If present it
                                                                    ^
Need a comma there.

OK with these nits fixed.

Thanks.

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

* Re: [PATCH] gdb/riscv: Add target description support
  2018-11-21 12:37       ` Eli Zaretskii
@ 2018-11-21 13:19         ` Andrew Burgess
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Burgess @ 2018-11-21 13:19 UTC (permalink / raw)
  To: gdb-patches; +Cc: jimw, palmer, jhb, Eli Zaretskii

* Eli Zaretskii <eliz@gnu.org> [2018-11-21 14:37:20 +0200]:

> > Date: Wed, 21 Nov 2018 11:23:35 +0000
> > From: Andrew Burgess <andrew.burgess@embecosm.com>
> > Cc: gdb-patches@sourceware.org, Palmer Dabbelt <palmer@sifive.com>,
> > 	John Baldwin <jhb@freebsd.org>
> > 
> > Eli,
> > 
> > I believe I still need a doc review before I can merge this patch.
> > Could I ask you to take a look please.
> 
> Sorry, I thought I already did.  See below.

No problem, and thanks for the speedy review.

I've pushed this patch with the fixes suggested by Eli.

Thanks,
Andrew


> 
> > +The @samp{org.gnu.gdb.riscv.fpu} feature is optional.  If present it
>                                                                     ^
> Please insert a comma where shown.
> 
> > +should contain registers @samp{f0} through @samp{f31}, @samp{fflags},
> > +@samp{frm}, and @samp{fcsr}.  As with the cpu feature either the
>                                                         ^
> And here.
> 
> > +The @samp{org.gnu.gdb.riscv.virtual} feature is optional.  If present
>                                                                         ^
> And here.
> 
> > +it should contain registers that are not backed by real registers on
> > +the target but are instead virtual, where the register value is
>              ^
> And here.
> 
> > +derived from other target state.  In many ways these are like GDBs
>                                                                  ^^^^
> @value{GDBN}s
> 
> > +The @samp{org.gnu.gdb.riscv.csr} feature is optional.  If present it
>                                                                     ^
> Need a comma there.
> 
> OK with these nits fixed.
> 
> Thanks.

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

* Re: [PATCH] gdb/riscv: Add target description support
  2018-11-14 14:58 ` [PATCH] " Andrew Burgess
  2018-11-19  3:51   ` Jim Wilson
@ 2019-02-22 17:42   ` Tom Tromey
  2019-02-22 19:24     ` Jim Wilson
  2019-02-23 20:40     ` Andrew Burgess
  1 sibling, 2 replies; 27+ messages in thread
From: Tom Tromey @ 2019-02-22 17:42 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, jimw, palmer, jhb

>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

Andrew> This is a slightly revised version of the RISC-V target descriptions
Andrew> patch.

I'm seeing a difference that I think was introduced by this patch and I
am wondering whether it is intentional and whether something ought to be
done about it.  I'm really not sure, this is my first foray into RISC-V
and into target descriptions.

With an older gdb (8.2), with remote debugging enabled:

    (gdb) p $fflags
    Sending packet: $p42#d6...Ack
    Packet received: 0000000000000000
    $1 = 0

Here you can see that gdb thinks the register number for fflags is 0x42.
And, that is the value of RISCV_CSR_FFLAGS_REGNUM, even in today's gdb
master:

    (top-gdb) p/x RISCV_CSR_FFLAGS_REGNUM
    $1 = 0x42

However with a newer gdb, with an older qemu, I get a failure:

    Sending packet: $p41#d5...Ack
    Packet received: E14
    Could not fetch register "fflags"; remote failure reply 'E14'

Here you can see gdb is sending 0x41.

RISCV_CSR_FFLAGS_REGNUM is computed by:

    RISCV_LAST_FP_REGNUM = 64,	/* Last Floating Point Register */
    RISCV_FIRST_CSR_REGNUM = 65,  /* First CSR */
    [...]
    #define DECLARE_CSR(name, num) \
      RISCV_ ## num ## _REGNUM = RISCV_FIRST_CSR_REGNUM + num,

Then from riscv-opc.h:

    #define CSR_FFLAGS 0x1
    [...]
    DECLARE_CSR(fflags, CSR_FFLAGS)

So, in effect it is RISCV_LAST_FP_REGNUM + 2.


But then, e.g., in the 32-bit FPU description:

Andrew> +static int
Andrew> +create_feature_riscv_32bit_fpu (struct target_desc *result, long regnum)
Andrew> +{
[...]
Andrew> +  tdesc_create_reg (feature, "ft11", regnum++, 1, NULL, 32, "ieee_single");
Andrew> +  tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 32, "int");

I think this is where the discrepancy lies.


I'm not really sure what ought to be done here.  Do you have any ideas?

thanks,
Tom

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

* Re: [PATCH] gdb/riscv: Add target description support
  2019-02-22 17:42   ` Tom Tromey
@ 2019-02-22 19:24     ` Jim Wilson
  2019-02-23 20:51       ` Andrew Burgess
  2019-02-23 20:40     ` Andrew Burgess
  1 sibling, 1 reply; 27+ messages in thread
From: Jim Wilson @ 2019-02-22 19:24 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Andrew Burgess, gdb-patches, Palmer Dabbelt, John Baldwin

On Fri, Feb 22, 2019 at 9:42 AM Tom Tromey <tom@tromey.com> wrote:
> With an older gdb (8.2), with remote debugging enabled:
>
>     (gdb) p $fflags
>     Sending packet: $p42#d6...Ack
>     Packet received: 0000000000000000
>     $1 = 0
>...
> However with a newer gdb, with an older qemu, I get a failure:
>
>     Sending packet: $p41#d5...Ack
>     Packet received: E14
>     Could not fetch register "fflags"; remote failure reply 'E14'
>
> Here you can see gdb is sending 0x41.

The renumbering is unfortunate, but there are a lot of historical
problems here, and compatibility with old tools may not be worth the
trouble.  We need to make this work right first, before we can worry
about backward compatibility.

fflags is a CSR not an F register.  But gdb is treating it as both an
F register and a CSR which may lead to some confusion.

Also, fflags is not a real register.  It is an alias for a field
inside the fcsr register.  If gdb is talking to something like
openocd/qemu that can translate fflags to fcsr that is OK, but for a
native riscv-linux gdb trying to read fflags won't do anything useful,
gdb needs to translate fflags into the fcsr field itself or this isn't
going to work.  Though maybe we can do something inside one of the
riscv-linux files to handle this.

There are a lot of problems with the old qemu gdbstub support.  I have
a patch set submitted for qemu to add the gdb xml files and proper
gdbstub support to use them.  gdb+qemu works much better with these
patches.  This patch set has been approved, and is queued for commit
behind one other patch in progress I think.  With this patch,
accessing fflags works with both a system qemu and a user qemu using
the current development gdb (8.3 pre-release).

(gdb) info registers fflags
fflags         Sending packet: $p4c#07...Ack
Packet received: 0000000000000000
Packet p (fetch-register) is supported
0x0 RD:0 NV:0 DZ:0 OF:0 UF:0 NX:0
(gdb)

Jim

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

* Re: [PATCH] gdb/riscv: Add target description support
  2019-02-22 17:42   ` Tom Tromey
  2019-02-22 19:24     ` Jim Wilson
@ 2019-02-23 20:40     ` Andrew Burgess
  2019-02-26 11:55       ` Joel Brobecker
  2019-03-04 16:18       ` Tom Tromey
  1 sibling, 2 replies; 27+ messages in thread
From: Andrew Burgess @ 2019-02-23 20:40 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches, jimw, palmer, jhb

* Tom Tromey <tom@tromey.com> [2019-02-22 10:42:50 -0700]:

> >>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:
> 
> Andrew> This is a slightly revised version of the RISC-V target descriptions
> Andrew> patch.
> 
> I'm seeing a difference that I think was introduced by this patch and I
> am wondering whether it is intentional and whether something ought to be
> done about it.  I'm really not sure, this is my first foray into RISC-V
> and into target descriptions.
> 
> With an older gdb (8.2), with remote debugging enabled:
> 
>     (gdb) p $fflags
>     Sending packet: $p42#d6...Ack
>     Packet received: 0000000000000000
>     $1 = 0
> 
> Here you can see that gdb thinks the register number for fflags is 0x42.
> And, that is the value of RISCV_CSR_FFLAGS_REGNUM, even in today's gdb
> master:
> 
>     (top-gdb) p/x RISCV_CSR_FFLAGS_REGNUM
>     $1 = 0x42
> 
> However with a newer gdb, with an older qemu, I get a failure:
> 
>     Sending packet: $p41#d5...Ack
>     Packet received: E14
>     Could not fetch register "fflags"; remote failure reply 'E14'
> 
> Here you can see gdb is sending 0x41.
> 
> RISCV_CSR_FFLAGS_REGNUM is computed by:
> 
>     RISCV_LAST_FP_REGNUM = 64,	/* Last Floating Point Register */
>     RISCV_FIRST_CSR_REGNUM = 65,  /* First CSR */
>     [...]
>     #define DECLARE_CSR(name, num) \
>       RISCV_ ## num ## _REGNUM = RISCV_FIRST_CSR_REGNUM + num,
> 
> Then from riscv-opc.h:
> 
>     #define CSR_FFLAGS 0x1
>     [...]
>     DECLARE_CSR(fflags, CSR_FFLAGS)
> 
> So, in effect it is RISCV_LAST_FP_REGNUM + 2.
> 
> 
> But then, e.g., in the 32-bit FPU description:
> 
> Andrew> +static int
> Andrew> +create_feature_riscv_32bit_fpu (struct target_desc *result, long regnum)
> Andrew> +{
> [...]
> Andrew> +  tdesc_create_reg (feature, "ft11", regnum++, 1, NULL, 32, "ieee_single");
> Andrew> +  tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 32, "int");
> 
> I think this is where the discrepancy lies.
> 
> 
> I'm not really sure what ought to be done here.  Do you have any ideas?

So you are correct.  When I added the target description support I
failed to consider backward compatibility with existing tools enough.

So, when GDB connect to a target that doesn't provide a target
description a default description is used.  This default has features
created by calls to the functions like create_feature_riscv_32bit_fpu
and friends, and it is these functions that are picking the default
register numbering.

In an ideal world, with no legacy baggage, these create_feature_*
functions shouldn't really care about register numbering, which is how
I have them setup right now.  However, it doesn't have to be that way,
we can force the numbering in the create_feature_* functions.

The patch below tries to restore the legacy numbering for fcsr, frm,
and fflags.  Does this restore the behaviour you are expecting?

One other thing to note about the change to target descriptions was
that the default target descriptions don't include any CSRs.  At the
time I figured that guessing about what CSRs a target supports wasn't
a good thing to do, and instead we should be encouraging targets to
move to proper target description support in order to support CSRs.
The consequence is that when you connect to your legacy QEMU the only
CSRs you'll have access too are the fcsr, frm, and fflags (as these
get grouped in with FP registers as they should be available if the FP
registers are available).

One possibility as an alternative to this patch is writing a target
description file that describes you legacy QEMU and loading this into
GDB with 'set tdesc filename FILENAME', with this approach you could
force the register numbering to match your expectations, and you'd get
access to your CSRs back.

Let me know if you think the patch below is an improvement, though
it's possibly not as pure (with hard-coded register numbering) than
before, I'd be happy to have this merged if the compatibility was
important.

Thanks,
Andrew

--

[PATCH] gdb/riscv: Use legacy register numbers in default target description

When the target description support was added to RISC-V, the register
numbers assigned to the fflags, frm, and fcsr control registers in the
default target descriptions didn't match the register numbers used by
GDB before the target description support was added.

What this means is that if a tools exists in the wild that is using
hard-coded register number, setup to match GDB's old behaviour, then
this will have been broken (for fflags, frm, and fcsr) by the move to
target descriptions.  QEMU is such a tool.

There are a couple of solutions that could be used to work around this
issue:

 - The user can create their own xml description file with the
   register numbers setup to match their old tool, then load this by
   telling GDB 'set tdesc filename FILENAME'.

 - Update their old tool to use the newer default numbering scheme, or
   better yet add proper target description support to their tool.

 - We could have RISC-V GDB change to maintain the old defaults.

This patch implements the last of these ideas, changing the default
numbering to match the old behaviour.

This change is only visible to targets that don't supply their own xml
description file and instead rely on GDB's default numbering.

gdb/ChangeLog:

	* features/riscv/32bit-cpu.xml: Add register numbers.
	* features/riscv/32bit-fpu.c: Regenerate.
	* features/riscv/32bit-fpu.xml: Add register numbers.
	* features/riscv/64bit-cpu.xml: Add register numbers.
	* features/riscv/64bit-fpu.c: Regenerate.
	* features/riscv/64bit-fpu.xml: Add register numbers.
---
 gdb/ChangeLog                    |  9 +++++++++
 gdb/features/riscv/32bit-cpu.xml |  6 +++++-
 gdb/features/riscv/32bit-fpu.c   |  2 ++
 gdb/features/riscv/32bit-fpu.xml | 12 ++++++++----
 gdb/features/riscv/64bit-cpu.xml |  6 +++++-
 gdb/features/riscv/64bit-fpu.c   |  2 ++
 gdb/features/riscv/64bit-fpu.xml | 12 ++++++++----
 7 files changed, 39 insertions(+), 10 deletions(-)

diff --git a/gdb/features/riscv/32bit-cpu.xml b/gdb/features/riscv/32bit-cpu.xml
index 466f2c0648..0d07aaec85 100644
--- a/gdb/features/riscv/32bit-cpu.xml
+++ b/gdb/features/riscv/32bit-cpu.xml
@@ -5,9 +5,13 @@
      are permitted in any medium without royalty provided the copyright
      notice and this notice are preserved.  -->
 
+<!-- Register numbers are hard-coded in order to maintain backward
+     compatibility with older versions of tools that didn't use xml
+     register descriptions.  -->
+
 <!DOCTYPE feature SYSTEM "gdb-target.dtd">
 <feature name="org.gnu.gdb.riscv.cpu">
-  <reg name="zero" bitsize="32" type="int"/>
+  <reg name="zero" bitsize="32" type="int" regnum="0"/>
   <reg name="ra" bitsize="32" type="code_ptr"/>
   <reg name="sp" bitsize="32" type="data_ptr"/>
   <reg name="gp" bitsize="32" type="data_ptr"/>
diff --git a/gdb/features/riscv/32bit-fpu.c b/gdb/features/riscv/32bit-fpu.c
index 22e80d640e..a19780aab0 100644
--- a/gdb/features/riscv/32bit-fpu.c
+++ b/gdb/features/riscv/32bit-fpu.c
@@ -9,6 +9,7 @@ create_feature_riscv_32bit_fpu (struct target_desc *result, long regnum)
   struct tdesc_feature *feature;
 
   feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.fpu");
+  regnum = 33;
   tdesc_create_reg (feature, "ft0", regnum++, 1, NULL, 32, "ieee_single");
   tdesc_create_reg (feature, "ft1", regnum++, 1, NULL, 32, "ieee_single");
   tdesc_create_reg (feature, "ft2", regnum++, 1, NULL, 32, "ieee_single");
@@ -41,6 +42,7 @@ create_feature_riscv_32bit_fpu (struct target_desc *result, long regnum)
   tdesc_create_reg (feature, "ft9", regnum++, 1, NULL, 32, "ieee_single");
   tdesc_create_reg (feature, "ft10", regnum++, 1, NULL, 32, "ieee_single");
   tdesc_create_reg (feature, "ft11", regnum++, 1, NULL, 32, "ieee_single");
+  regnum = 66;
   tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 32, "int");
   tdesc_create_reg (feature, "frm", regnum++, 1, NULL, 32, "int");
   tdesc_create_reg (feature, "fcsr", regnum++, 1, NULL, 32, "int");
diff --git a/gdb/features/riscv/32bit-fpu.xml b/gdb/features/riscv/32bit-fpu.xml
index 6a44b842b8..1eaae9119e 100644
--- a/gdb/features/riscv/32bit-fpu.xml
+++ b/gdb/features/riscv/32bit-fpu.xml
@@ -5,9 +5,13 @@
      are permitted in any medium without royalty provided the copyright
      notice and this notice are preserved.  -->
 
+<!-- Register numbers are hard-coded in order to maintain backward
+     compatibility with older versions of tools that didn't use xml
+     register descriptions.  -->
+
 <!DOCTYPE feature SYSTEM "gdb-target.dtd">
 <feature name="org.gnu.gdb.riscv.fpu">
-  <reg name="ft0" bitsize="32" type="ieee_single"/>
+  <reg name="ft0" bitsize="32" type="ieee_single" regnum="33"/>
   <reg name="ft1" bitsize="32" type="ieee_single"/>
   <reg name="ft2" bitsize="32" type="ieee_single"/>
   <reg name="ft3" bitsize="32" type="ieee_single"/>
@@ -40,7 +44,7 @@
   <reg name="ft10" bitsize="32" type="ieee_single"/>
   <reg name="ft11" bitsize="32" type="ieee_single"/>
 
-  <reg name="fflags" bitsize="32" type="int"/>
-  <reg name="frm" bitsize="32" type="int"/>
-  <reg name="fcsr" bitsize="32" type="int"/>
+  <reg name="fflags" bitsize="32" type="int" regnum="66"/>
+  <reg name="frm" bitsize="32" type="int" regnum="67"/>
+  <reg name="fcsr" bitsize="32" type="int" regnum="68"/>
 </feature>
diff --git a/gdb/features/riscv/64bit-cpu.xml b/gdb/features/riscv/64bit-cpu.xml
index c4d83de09b..b8aa424ae4 100644
--- a/gdb/features/riscv/64bit-cpu.xml
+++ b/gdb/features/riscv/64bit-cpu.xml
@@ -5,9 +5,13 @@
      are permitted in any medium without royalty provided the copyright
      notice and this notice are preserved.  -->
 
+<!-- Register numbers are hard-coded in order to maintain backward
+     compatibility with older versions of tools that didn't use xml
+     register descriptions.  -->
+
 <!DOCTYPE feature SYSTEM "gdb-target.dtd">
 <feature name="org.gnu.gdb.riscv.cpu">
-  <reg name="zero" bitsize="64" type="int"/>
+  <reg name="zero" bitsize="64" type="int" regnum="0"/>
   <reg name="ra" bitsize="64" type="code_ptr"/>
   <reg name="sp" bitsize="64" type="data_ptr"/>
   <reg name="gp" bitsize="64" type="data_ptr"/>
diff --git a/gdb/features/riscv/64bit-fpu.c b/gdb/features/riscv/64bit-fpu.c
index 8cbd7484ab..b93cb4ec03 100644
--- a/gdb/features/riscv/64bit-fpu.c
+++ b/gdb/features/riscv/64bit-fpu.c
@@ -17,6 +17,7 @@ create_feature_riscv_64bit_fpu (struct target_desc *result, long regnum)
   field_type = tdesc_named_type (feature, "ieee_double");
   tdesc_add_field (type_with_fields, "double", field_type);
 
+  regnum = 33;
   tdesc_create_reg (feature, "ft0", regnum++, 1, NULL, 64, "riscv_double");
   tdesc_create_reg (feature, "ft1", regnum++, 1, NULL, 64, "riscv_double");
   tdesc_create_reg (feature, "ft2", regnum++, 1, NULL, 64, "riscv_double");
@@ -49,6 +50,7 @@ create_feature_riscv_64bit_fpu (struct target_desc *result, long regnum)
   tdesc_create_reg (feature, "ft9", regnum++, 1, NULL, 64, "riscv_double");
   tdesc_create_reg (feature, "ft10", regnum++, 1, NULL, 64, "riscv_double");
   tdesc_create_reg (feature, "ft11", regnum++, 1, NULL, 64, "riscv_double");
+  regnum = 66;
   tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 32, "int");
   tdesc_create_reg (feature, "frm", regnum++, 1, NULL, 32, "int");
   tdesc_create_reg (feature, "fcsr", regnum++, 1, NULL, 32, "int");
diff --git a/gdb/features/riscv/64bit-fpu.xml b/gdb/features/riscv/64bit-fpu.xml
index fd14ebced8..794854cc01 100644
--- a/gdb/features/riscv/64bit-fpu.xml
+++ b/gdb/features/riscv/64bit-fpu.xml
@@ -5,6 +5,10 @@
      are permitted in any medium without royalty provided the copyright
      notice and this notice are preserved.  -->
 
+<!-- Register numbers are hard-coded in order to maintain backward
+     compatibility with older versions of tools that didn't use xml
+     register descriptions.  -->
+
 <!DOCTYPE feature SYSTEM "gdb-target.dtd">
 <feature name="org.gnu.gdb.riscv.fpu">
 
@@ -13,7 +17,7 @@
     <field name="double" type="ieee_double"/>
   </union>
 
-  <reg name="ft0" bitsize="64" type="riscv_double"/>
+  <reg name="ft0" bitsize="64" type="riscv_double" regnum="33"/>
   <reg name="ft1" bitsize="64" type="riscv_double"/>
   <reg name="ft2" bitsize="64" type="riscv_double"/>
   <reg name="ft3" bitsize="64" type="riscv_double"/>
@@ -46,7 +50,7 @@
   <reg name="ft10" bitsize="64" type="riscv_double"/>
   <reg name="ft11" bitsize="64" type="riscv_double"/>
 
-  <reg name="fflags" bitsize="32" type="int"/>
-  <reg name="frm" bitsize="32" type="int"/>
-  <reg name="fcsr" bitsize="32" type="int"/>
+  <reg name="fflags" bitsize="32" type="int" regnum="66"/>
+  <reg name="frm" bitsize="32" type="int" regnum="67"/>
+  <reg name="fcsr" bitsize="32" type="int" regnum="68"/>
 </feature>
-- 
2.14.5


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

* Re: [PATCH] gdb/riscv: Add target description support
  2019-02-22 19:24     ` Jim Wilson
@ 2019-02-23 20:51       ` Andrew Burgess
  2019-02-24  6:21         ` Jim Wilson
  0 siblings, 1 reply; 27+ messages in thread
From: Andrew Burgess @ 2019-02-23 20:51 UTC (permalink / raw)
  To: Jim Wilson; +Cc: Tom Tromey, gdb-patches, Palmer Dabbelt, John Baldwin

* Jim Wilson <jimw@sifive.com> [2019-02-22 11:24:15 -0800]:

> On Fri, Feb 22, 2019 at 9:42 AM Tom Tromey <tom@tromey.com> wrote:
> > With an older gdb (8.2), with remote debugging enabled:
> >
> >     (gdb) p $fflags
> >     Sending packet: $p42#d6...Ack
> >     Packet received: 0000000000000000
> >     $1 = 0
> >...
> > However with a newer gdb, with an older qemu, I get a failure:
> >
> >     Sending packet: $p41#d5...Ack
> >     Packet received: E14
> >     Could not fetch register "fflags"; remote failure reply 'E14'
> >
> > Here you can see gdb is sending 0x41.
> 
> The renumbering is unfortunate, but there are a lot of historical
> problems here, and compatibility with old tools may not be worth the
> trouble.  We need to make this work right first, before we can worry
> about backward compatibility.
> 
> fflags is a CSR not an F register.  But gdb is treating it as both an
> F register and a CSR which may lead to some confusion.

I think we should be OK.  The existing CSR feature file should
possibly be deleted, it's not actually used right now.

When targets supply a target description then the fflags, frm, and
fcsr should only be in one feature otherwise (I think, but haven't
tested) GDB will get upset.  However, I don't think we should prevent
bundling the FP status registers in the FP feature set, personally, I
think that the argument for having them there is almost as strong as
for having them in with the CSRs.

> 
> Also, fflags is not a real register.  It is an alias for a field
> inside the fcsr register.  If gdb is talking to something like
> openocd/qemu that can translate fflags to fcsr that is OK, but for a
> native riscv-linux gdb trying to read fflags won't do anything useful,
> gdb needs to translate fflags into the fcsr field itself or this isn't
> going to work.  Though maybe we can do something inside one of the
> riscv-linux files to handle this.

I started working on, and do plan to finish soon(ish) a change where
if GDB finds an $fcsr register, but no $fflags or $frm then a
pseudo-register would be setup (for each) that just reads/writes the
bits for $fcsr.

This would work for all targets, so the native linux case should be
covered.

> 
> There are a lot of problems with the old qemu gdbstub support.  I have
> a patch set submitted for qemu to add the gdb xml files and proper
> gdbstub support to use them.  gdb+qemu works much better with these
> patches.  This patch set has been approved, and is queued for commit
> behind one other patch in progress I think.  With this patch,
> accessing fflags works with both a system qemu and a user qemu using
> the current development gdb (8.3 pre-release).

That's great news.  Thanks for all your effort on this.

Thanks,
Andrew


> 
> (gdb) info registers fflags
> fflags         Sending packet: $p4c#07...Ack
> Packet received: 0000000000000000
> Packet p (fetch-register) is supported
> 0x0 RD:0 NV:0 DZ:0 OF:0 UF:0 NX:0
> (gdb)
> 
> Jim

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

* Re: [PATCH] gdb/riscv: Add target description support
  2019-02-23 20:51       ` Andrew Burgess
@ 2019-02-24  6:21         ` Jim Wilson
  2019-02-26  5:02           ` Joel Brobecker
  0 siblings, 1 reply; 27+ messages in thread
From: Jim Wilson @ 2019-02-24  6:21 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: Tom Tromey, gdb-patches, Palmer Dabbelt, John Baldwin

On Sat, Feb 23, 2019 at 12:51 PM Andrew Burgess
<andrew.burgess@embecosm.com> wrote:
> I think we should be OK.  The existing CSR feature file should
> possibly be deleted, it's not actually used right now.

I added the gdb CSR feature file to qemu in my patch.  The lack of
register numbers means I had to add a table to translate the xml CSR
register numbers into actual hardware numbers inside qemu.  But this
does work.  For the subset of CSRs that both qemu and gdb know about,
I can print register values from gdb and it works.  This is an
important feature for people using system qemu to debug bootloaders,
and maybe kernels.  This is part of the reason I wrote the qemu
gdbstub support.  For user qemu, we don't allow CSR access of course,
other than the ones readable from user space like fcsr.

(gdb) target remote :1234
Remote debugging using :1234
0x0000000000001000 in ?? ()
(gdb) set debug remote 1
(gdb) info registers misa
misa           Sending packet: $pa0#01...Ack
Packet received: 2d11140000000080
Packet p (fetch-register) is supported
0x800000000014112d RV64ACDFIMSU
(gdb)

I'm not sure what adding registers numbers to the gp and fp xml files
will do to the qemu support.  I will have to test that.  Hopefully
there is no effect unless I add the new files to qemu, in which case I
might need to update the gdbstub support then to match the new
numbers.  My understanding is that the qemu copy of the files is
supposed to be the same as the gdb copy of these files, but I'm not an
expert on this.  This is true for several targets that I checked.

OpenOCD also has support for sending a csr xml file to gdb, though of
course it does not use the gdb version of the file.  It has (or
creates) ifs own csr xml file.

Jim


Jim

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

* Re: [PATCH] gdb/riscv: Add target description support
  2019-02-24  6:21         ` Jim Wilson
@ 2019-02-26  5:02           ` Joel Brobecker
  2019-02-26 17:26             ` Jim Wilson
  0 siblings, 1 reply; 27+ messages in thread
From: Joel Brobecker @ 2019-02-26  5:02 UTC (permalink / raw)
  To: Jim Wilson
  Cc: Andrew Burgess, Tom Tromey, gdb-patches, Palmer Dabbelt, John Baldwin

Hello,

> On Sat, Feb 23, 2019 at 12:51 PM Andrew Burgess
> <andrew.burgess@embecosm.com> wrote:
> > I think we should be OK.  The existing CSR feature file should
> > possibly be deleted, it's not actually used right now.
> 
> I added the gdb CSR feature file to qemu in my patch.  The lack of
> register numbers means I had to add a table to translate the xml CSR
> register numbers into actual hardware numbers inside qemu.  But this
> does work.  For the subset of CSRs that both qemu and gdb know about,
> I can print register values from gdb and it works.  This is an
> important feature for people using system qemu to debug bootloaders,
> and maybe kernels.  This is part of the reason I wrote the qemu
> gdbstub support.  For user qemu, we don't allow CSR access of course,
> other than the ones readable from user space like fcsr.
> 
> (gdb) target remote :1234
> Remote debugging using :1234
> 0x0000000000001000 in ?? ()
> (gdb) set debug remote 1
> (gdb) info registers misa
> misa           Sending packet: $pa0#01...Ack
> Packet received: 2d11140000000080
> Packet p (fetch-register) is supported
> 0x800000000014112d RV64ACDFIMSU
> (gdb)
> 
> I'm not sure what adding registers numbers to the gp and fp xml files
> will do to the qemu support.  I will have to test that.  Hopefully
> there is no effect unless I add the new files to qemu, in which case I
> might need to update the gdbstub support then to match the new
> numbers.  My understanding is that the qemu copy of the files is
> supposed to be the same as the gdb copy of these files, but I'm not an
> expert on this.  This is true for several targets that I checked.
> 
> OpenOCD also has support for sending a csr xml file to gdb, though of
> course it does not use the gdb version of the file.  It has (or
> creates) ifs own csr xml file.

I think if QEMU sends an XML with the various register description,
then whatever numbering GDB uses by default will no longer apply,
and so things should just-work(tm) regardless of what GDB decided
to do in terms of register numbering.

I think the work you're doing in QEMU can only be a good thing which
will robustify the debugging, because they will avoid the need to
synchronize QEMU and GDB versions.

I'd like to suggest we do try to restore the original register
numbering in GDB as well, though. I've discovered recently that
it's not always so easy to switch to a newer version of QEMU.
So I think Andrew's patch, if good, should go in as well (and be
backported to GDB 8.3 as well).

-- 
Joel

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

* Re: [PATCH] gdb/riscv: Add target description support
  2019-02-23 20:40     ` Andrew Burgess
@ 2019-02-26 11:55       ` Joel Brobecker
  2019-03-04 16:18       ` Tom Tromey
  1 sibling, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2019-02-26 11:55 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: Tom Tromey, gdb-patches, jimw, palmer, jhb

Hi Andrew,

> [PATCH] gdb/riscv: Use legacy register numbers in default target description
> 
> When the target description support was added to RISC-V, the register
> numbers assigned to the fflags, frm, and fcsr control registers in the
> default target descriptions didn't match the register numbers used by
> GDB before the target description support was added.
> 
> What this means is that if a tools exists in the wild that is using
> hard-coded register number, setup to match GDB's old behaviour, then
> this will have been broken (for fflags, frm, and fcsr) by the move to
> target descriptions.  QEMU is such a tool.
> 
> There are a couple of solutions that could be used to work around this
> issue:
> 
>  - The user can create their own xml description file with the
>    register numbers setup to match their old tool, then load this by
>    telling GDB 'set tdesc filename FILENAME'.
> 
>  - Update their old tool to use the newer default numbering scheme, or
>    better yet add proper target description support to their tool.
> 
>  - We could have RISC-V GDB change to maintain the old defaults.
> 
> This patch implements the last of these ideas, changing the default
> numbering to match the old behaviour.
> 
> This change is only visible to targets that don't supply their own xml
> description file and instead rely on GDB's default numbering.
> 
> gdb/ChangeLog:
> 
> 	* features/riscv/32bit-cpu.xml: Add register numbers.
> 	* features/riscv/32bit-fpu.c: Regenerate.
> 	* features/riscv/32bit-fpu.xml: Add register numbers.
> 	* features/riscv/64bit-cpu.xml: Add register numbers.
> 	* features/riscv/64bit-fpu.c: Regenerate.
> 	* features/riscv/64bit-fpu.xml: Add register numbers.

I've had a chance to look at the patch, and fwiw, it looks good to me.
If others agree that it is OK, I think it would be nice if we pushed
the patch before I create the gdb-8.3-branch, and then create the first
pre-release (8.2.90).

-- 
Joel

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

* Re: [PATCH] gdb/riscv: Add target description support
  2019-02-26  5:02           ` Joel Brobecker
@ 2019-02-26 17:26             ` Jim Wilson
  2019-02-26 18:22               ` Andrew Burgess
  0 siblings, 1 reply; 27+ messages in thread
From: Jim Wilson @ 2019-02-26 17:26 UTC (permalink / raw)
  To: Joel Brobecker
  Cc: Andrew Burgess, Tom Tromey, gdb-patches, Palmer Dabbelt, John Baldwin

On Mon, Feb 25, 2019 at 9:02 PM Joel Brobecker <brobecker@adacore.com> wrote:
> I think if QEMU sends an XML with the various register description,
> then whatever numbering GDB uses by default will no longer apply,
> and so things should just-work(tm) regardless of what GDB decided
> to do in terms of register numbering.

Yes, it shouldn't affect qemu until we try to copy the new gdb xml
files into qemu, at which point we might need to update the qemu
gdbstub support to work with the changed register numbers.  We can
worry about this later.  This issues doesn't need to delay any gdb
work.

Jim

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

* Re: [PATCH] gdb/riscv: Add target description support
  2019-02-26 17:26             ` Jim Wilson
@ 2019-02-26 18:22               ` Andrew Burgess
  2019-02-26 18:40                 ` Jim Wilson
  0 siblings, 1 reply; 27+ messages in thread
From: Andrew Burgess @ 2019-02-26 18:22 UTC (permalink / raw)
  To: Jim Wilson
  Cc: Joel Brobecker, Tom Tromey, gdb-patches, Palmer Dabbelt, John Baldwin

* Jim Wilson <jimw@sifive.com> [2019-02-26 09:26:04 -0800]:

> On Mon, Feb 25, 2019 at 9:02 PM Joel Brobecker <brobecker@adacore.com> wrote:
> > I think if QEMU sends an XML with the various register description,
> > then whatever numbering GDB uses by default will no longer apply,
> > and so things should just-work(tm) regardless of what GDB decided
> > to do in terms of register numbering.
> 
> Yes, it shouldn't affect qemu until we try to copy the new gdb xml
> files into qemu, at which point we might need to update the qemu
> gdbstub support to work with the changed register numbers.  We can
> worry about this later.  This issues doesn't need to delay any gdb
> work.

Jim, if you're happy then I'll go ahead and merge the fix-up patch.

I'll summarise the changes in the patch, and what impact I think they
will have now I've had a look at the QEMU code (all these changes are
identical for 32 and 64 bit)...

  (1) Added forced register number for register 'zero'.  This will
  have no impact the default register numbering before had the
  x-registers numbered from 0.  I added this just to make the
  numbering explicit.

  (2) Added forced register number 33 to the first floating pointer
  register ($ft0).  Again, this should have no impact as the
  f-registers were traditionally numbered after the 32 x-registers and
  the program-counter.

  (3) Renumbered fflags, frm, and fcsr as 66, 67, and 68.  This is
  where the issues will appear for QEMU, Jim's QEMU patch had adopted
  the "new" default numbering which placed these registers after the
  floating point registers (so they had become 65, 66, and 67).

If we want backward compatibility then we should merge this GDB patch,
and fix QEMU asap to avoid having two incompatible versions in the
wild.

What I don't understand about all this is why QEMU appears to be
discarding one of the big benefits of xml register descriptions; the
ability to disconnect their register numbering from GDB's register
numbering.

Jim: I think your comments above indicate you want my fix merged, but
if you could just confirm then I'll get it merged.

Thanks,
Andrew

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

* Re: [PATCH] gdb/riscv: Add target description support
  2019-02-26 18:22               ` Andrew Burgess
@ 2019-02-26 18:40                 ` Jim Wilson
  2019-02-26 19:27                   ` Jim Wilson
  0 siblings, 1 reply; 27+ messages in thread
From: Jim Wilson @ 2019-02-26 18:40 UTC (permalink / raw)
  To: Andrew Burgess
  Cc: Joel Brobecker, Tom Tromey, gdb-patches, Palmer Dabbelt, John Baldwin

On Tue, Feb 26, 2019 at 10:22 AM Andrew Burgess
<andrew.burgess@embecosm.com> wrote:
>
> * Jim Wilson <jimw@sifive.com> [2019-02-26 09:26:04 -0800]:
>
> > On Mon, Feb 25, 2019 at 9:02 PM Joel Brobecker <brobecker@adacore.com> wrote:
> > > I think if QEMU sends an XML with the various register description,
> > > then whatever numbering GDB uses by default will no longer apply,
> > > and so things should just-work(tm) regardless of what GDB decided
> > > to do in terms of register numbering.
> >
> > Yes, it shouldn't affect qemu until we try to copy the new gdb xml
> > files into qemu, at which point we might need to update the qemu
> > gdbstub support to work with the changed register numbers.  We can
> > worry about this later.  This issues doesn't need to delay any gdb
> > work.
>
> Jim, if you're happy then I'll go ahead and merge the fix-up patch.
>
> I'll summarise the changes in the patch, and what impact I think they
> will have now I've had a look at the QEMU code (all these changes are
> identical for 32 and 64 bit)...
>
>   (1) Added forced register number for register 'zero'.  This will
>   have no impact the default register numbering before had the
>   x-registers numbered from 0.  I added this just to make the
>   numbering explicit.
>
>   (2) Added forced register number 33 to the first floating pointer
>   register ($ft0).  Again, this should have no impact as the
>   f-registers were traditionally numbered after the 32 x-registers and
>   the program-counter.
>
>   (3) Renumbered fflags, frm, and fcsr as 66, 67, and 68.  This is
>   where the issues will appear for QEMU, Jim's QEMU patch had adopted
>   the "new" default numbering which placed these registers after the
>   floating point registers (so they had become 65, 66, and 67).
>
> If we want backward compatibility then we should merge this GDB patch,
> and fix QEMU asap to avoid having two incompatible versions in the
> wild.
>
> What I don't understand about all this is why QEMU appears to be
> discarding one of the big benefits of xml register descriptions; the
> ability to disconnect their register numbering from GDB's register
> numbering.
>
> Jim: I think your comments above indicate you want my fix merged, but
> if you could just confirm then I'll get it merged.
>
> Thanks,
> Andrew

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

* Re: [PATCH] gdb/riscv: Add target description support
  2019-02-26 18:40                 ` Jim Wilson
@ 2019-02-26 19:27                   ` Jim Wilson
  2019-02-26 20:30                     ` Andrew Burgess
  0 siblings, 1 reply; 27+ messages in thread
From: Jim Wilson @ 2019-02-26 19:27 UTC (permalink / raw)
  To: Andrew Burgess
  Cc: Joel Brobecker, Tom Tromey, gdb-patches, Palmer Dabbelt, John Baldwin

On Tue, Feb 26, 2019 at 10:40 AM Jim Wilson <jimw@sifive.com> wrote:
> >   (3) Renumbered fflags, frm, and fcsr as 66, 67, and 68.  This is
> >   where the issues will appear for QEMU, Jim's QEMU patch had adopted
> >   the "new" default numbering which placed these registers after the
> >   floating point registers (so they had become 65, 66, and 67).

qemu just assigns numbers to xml regs if they don't have them,
incrementing by one for each reg.  If we change the qemu xml files at
the same time as we change the qemu gdbstub hooks, then qemu will
always be internally consistent.  These xml register numbers aren't
user visible anywhere inside qemu, they are only used for
communication with gdb.

> > If we want backward compatibility then we should merge this GDB patch,
> > and fix QEMU asap to avoid having two incompatible versions in the
> > wild.

I have no control over qemu.  I can only suggest a patch, and ping it,
and maybe in a few months it will get merged in.

> > What I don't understand about all this is why QEMU appears to be
> > discarding one of the big benefits of xml register descriptions; the
> > ability to disconnect their register numbering from GDB's register
> > numbering.

I don't understand the comment.  We still must have numbers for the
registers, otherwise we can't communicate with gdb about them.  But
these xml register numbers don't affect the user or hardware register
numbers, the qemu gdbstub converts between hardware register numbers
and xml register numbers.

> > Jim: I think your comments above indicate you want my fix merged, but
> > if you could just confirm then I'll get it merged.

Yes, I think this is OK.  We can worry about qemu later.

Jim

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

* Re: [PATCH] gdb/riscv: Add target description support
  2019-02-26 19:27                   ` Jim Wilson
@ 2019-02-26 20:30                     ` Andrew Burgess
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Burgess @ 2019-02-26 20:30 UTC (permalink / raw)
  To: Jim Wilson
  Cc: Joel Brobecker, Tom Tromey, gdb-patches, Palmer Dabbelt, John Baldwin

* Jim Wilson <jimw@sifive.com> [2019-02-26 11:27:24 -0800]:

> On Tue, Feb 26, 2019 at 10:40 AM Jim Wilson <jimw@sifive.com> wrote:
> > >   (3) Renumbered fflags, frm, and fcsr as 66, 67, and 68.  This is
> > >   where the issues will appear for QEMU, Jim's QEMU patch had adopted
> > >   the "new" default numbering which placed these registers after the
> > >   floating point registers (so they had become 65, 66, and 67).
> 
> qemu just assigns numbers to xml regs if they don't have them,
> incrementing by one for each reg.  If we change the qemu xml files at
> the same time as we change the qemu gdbstub hooks, then qemu will
> always be internally consistent.  These xml register numbers aren't
> user visible anywhere inside qemu, they are only used for
> communication with gdb.
> 
> > > If we want backward compatibility then we should merge this GDB patch,
> > > and fix QEMU asap to avoid having two incompatible versions in the
> > > wild.
> 
> I have no control over qemu.  I can only suggest a patch, and ping it,
> and maybe in a few months it will get merged in.

Sure, I understand that, but I was wrong with the severity of the
problem.  So, there's no rush on changing QEMU.

> 
> > > What I don't understand about all this is why QEMU appears to be
> > > discarding one of the big benefits of xml register descriptions; the
> > > ability to disconnect their register numbering from GDB's register
> > > numbering.
> 
> I don't understand the comment.  We still must have numbers for the
> registers, otherwise we can't communicate with gdb about them.  But
> these xml register numbers don't affect the user or hardware register
> numbers, the qemu gdbstub converts between hardware register numbers
> and xml register numbers.

So, I miss-understood the problem slightly, I'll explain what I was
trying to say, then explain why it doesn't really matter...

Consider this cut-down version the 32bit-fpu.xml for RISC-V:

  <feature name="org.gnu.gdb.riscv.fpu">
    <reg name="ft0" bitsize="32" type="ieee_single"/>
  </feature>

Internally QEMU will have its hardware register number that represents
register $ft0, this could be anything, lets pick 105 at random.

GDB will also have a number that represents register $ft0, this too
could be anything, lets pick 33 at random, this isn't the xml register
number you mention above, this is just GDBs internal number.

If QEMU sends this to GDB:

  <feature name="org.gnu.gdb.riscv.fpu">
    <reg name="ft0" bitsize="32" type="ieee_single" regnum="105"/>
  </feature>

Then internally GDB will call $ft0 #33, but, when it talks to QEMU it
will use #105.

If GDB changes its numbering it will continue to use #105 when talking
to QEMU.

However, what QEMU _actually_ sends is this:

  <feature name="org.gnu.gdb.riscv.fpu">
    <reg name="ft0" bitsize="32" type="ieee_single"/>
  </feature>

An exact copy of GDBs XML file.  Without being told how the remote
would like to number its registers GDB just numbers the registers in
the order that they are sent from the remote, and this establishes
fairly arbitrary numbering scheme that QEMU is forced to adopt, if GDB
ever changes the feature files and QEMU picks these changes up, then
it would have to adopt its GDB <-> QEMU mapping code too.

I'd originally worried that without a specified 'regnum' in the
transmitted xml GDB would use its _internal_ numbering when talking to
QEMU, not the sequence number as its transmitted.  By using the
sequence number we make this a QEMU problem, not a GDB problem, and
that's fine; by which I mean, when QEMU changes its xml, it has to
change its own mapping, but a change in GDB doesn't impact QEMU.

Phew! Sorry for the long email, but I do understand xml target
descriptions more now :)

> 
> > > Jim: I think your comments above indicate you want my fix merged, but
> > > if you could just confirm then I'll get it merged.
> 
> Yes, I think this is OK.  We can worry about qemu later.

OK, will merge shortly...

Thanks,
Andrew

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

* Re: [PATCH] gdb/riscv: Add target description support
  2019-02-23 20:40     ` Andrew Burgess
  2019-02-26 11:55       ` Joel Brobecker
@ 2019-03-04 16:18       ` Tom Tromey
  1 sibling, 0 replies; 27+ messages in thread
From: Tom Tromey @ 2019-03-04 16:18 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

Tom> I'm not really sure what ought to be done here.  Do you have any
Tom> ideas?

Andrew> So you are correct.  When I added the target description support I
Andrew> failed to consider backward compatibility with existing tools enough.
[...]

I just wanted to say thanks for doing this.
I can confirm it helped.

Tom

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

end of thread, other threads:[~2019-03-04 16:18 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-08 16:08 [RFC] gdb/riscv: Add target description support Andrew Burgess
2018-11-08 18:33 ` John Baldwin
2018-11-08 19:32   ` Palmer Dabbelt
2018-11-08 19:41     ` John Baldwin
2018-11-14 14:29   ` Andrew Burgess
2018-11-14 17:42     ` John Baldwin
2018-11-08 21:57 ` Jim Wilson
2018-11-13 15:05   ` Andrew Burgess
2018-11-13 20:08 ` Pedro Alves
2018-11-14 14:58 ` [PATCH] " Andrew Burgess
2018-11-19  3:51   ` Jim Wilson
2018-11-21 11:23     ` Andrew Burgess
2018-11-21 12:37       ` Eli Zaretskii
2018-11-21 13:19         ` Andrew Burgess
2019-02-22 17:42   ` Tom Tromey
2019-02-22 19:24     ` Jim Wilson
2019-02-23 20:51       ` Andrew Burgess
2019-02-24  6:21         ` Jim Wilson
2019-02-26  5:02           ` Joel Brobecker
2019-02-26 17:26             ` Jim Wilson
2019-02-26 18:22               ` Andrew Burgess
2019-02-26 18:40                 ` Jim Wilson
2019-02-26 19:27                   ` Jim Wilson
2019-02-26 20:30                     ` Andrew Burgess
2019-02-23 20:40     ` Andrew Burgess
2019-02-26 11:55       ` Joel Brobecker
2019-03-04 16:18       ` Tom Tromey

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