public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 1/2] RISC-V GDB Port
  2017-03-06 20:31 RISC-V GDB Port v3 Palmer Dabbelt
@ 2017-03-06 20:31 ` Palmer Dabbelt
  2017-04-04 21:48   ` Yao Qi
  2017-04-05  9:22   ` Yao Qi
  2017-03-06 20:31 ` [PATCH 2/2] RISC-V sim Port Palmer Dabbelt
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 17+ messages in thread
From: Palmer Dabbelt @ 2017-03-06 20:31 UTC (permalink / raw)
  To: gdb-patches; +Cc: Palmer Dabbelt

---
 gdb/Makefile.in                 |    5 +
 gdb/config/riscv/linux.mh       |   30 +
 gdb/features/Makefile           |    2 +
 gdb/features/riscv.c            |   86 +++
 gdb/features/riscv.xml          |   81 +++
 gdb/gdbserver/linux-riscv-low.c |  221 +++++++
 gdb/regformats/riscv.dat        |   69 ++
 gdb/riscv-linux-nat.c           |   77 +++
 gdb/riscv-linux-tdep.c          |   80 +++
 gdb/riscv-linux-tdep.h          |   30 +
 gdb/riscv-tdep.c                | 1368 +++++++++++++++++++++++++++++++++++++++
 gdb/riscv-tdep.h                |   96 +++
 include/gdb/sim-riscv.h         |   98 +++
 13 files changed, 2243 insertions(+)
 create mode 100644 gdb/config/riscv/linux.mh
 create mode 100644 gdb/features/riscv.c
 create mode 100644 gdb/features/riscv.xml
 create mode 100644 gdb/gdbserver/linux-riscv-low.c
 create mode 100644 gdb/regformats/riscv.dat
 create mode 100644 gdb/riscv-linux-nat.c
 create mode 100644 gdb/riscv-linux-tdep.c
 create mode 100644 gdb/riscv-linux-tdep.h
 create mode 100644 gdb/riscv-tdep.c
 create mode 100644 gdb/riscv-tdep.h
 create mode 100644 include/gdb/sim-riscv.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 268c2c6..e92c13c 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -853,6 +853,8 @@ ALL_TARGET_OBS = \
 	ppc-sysv-tdep.o \
 	ppc64-tdep.o \
 	ravenscar-thread.o \
+	riscv-tdep.o \
+	riscv-linux-tdep.o \
 	rl78-tdep.o \
 	rs6000-aix-tdep.o \
 	rs6000-lynx178-tdep.o \
@@ -1406,6 +1408,7 @@ HFILES_NO_SRCDIR = \
 	remote.h \
 	remote-fileio.h \
 	remote-notif.h \
+	riscv-tdep.h \
 	rs6000-aix-tdep.h \
 	rs6000-tdep.h \
 	s390-linux-tdep.h \
@@ -2595,6 +2598,8 @@ ALLDEPFILES = \
 	procfs.c \
 	ravenscar-thread.c \
 	remote-sim.c \
+	riscv-tdep.c \
+	riscv-linux-tdep.c \
 	rl78-tdep.c \
 	rs6000-lynx178-tdep.c \
 	rs6000-nat.c \
diff --git a/gdb/config/riscv/linux.mh b/gdb/config/riscv/linux.mh
new file mode 100644
index 0000000..4ec9f47
--- /dev/null
+++ b/gdb/config/riscv/linux.mh
@@ -0,0 +1,30 @@
+#  Host: RISC-V based machine running GNU/Linux
+#
+#  Copyright (C) 2016 Free Software Foundation, Inc.
+#  Contributed by Albert Ou <albert@sifive.com>.
+#
+#  This file is part of GDB.
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 3 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+NAT_FILE= config/nm-linux.h
+NATDEPFILES= inf-ptrace.o fork-child.o riscv-linux-nat.o \
+	proc-service.o linux-thread-db.o linux-nat.o linux-fork.o \
+	linux-procfs.o linux-ptrace.o linux-osdata.o linux-waitpid.o \
+	linux-namespaces.o linux-personality.o
+NAT_CDEPS = $(srcdir)/proc-service.list
+
+# The dynamically loaded libthread_db needs access to symbols in the
+# gdb executable.
+LOADLIBES= -ldl $(RDYNAMIC)
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 3bc8b5a..318fa53 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -66,6 +66,7 @@ WHICH = aarch64 \
 	microblaze-with-stack-protect \
 	mips64-linux mips64-dsp-linux \
 	nios2-linux \
+	riscv \
 	rs6000/powerpc-32 \
 	rs6000/powerpc-32l rs6000/powerpc-altivec32l rs6000/powerpc-e500l \
 	rs6000/powerpc-64l rs6000/powerpc-altivec64l rs6000/powerpc-vsx32l \
@@ -179,6 +180,7 @@ XMLTOC = \
 	nds32.xml \
 	nios2-linux.xml \
 	nios2.xml \
+	riscv.xml \
 	rs6000/powerpc-32.xml \
 	rs6000/powerpc-32l.xml \
 	rs6000/powerpc-403.xml \
diff --git a/gdb/features/riscv.c b/gdb/features/riscv.c
new file mode 100644
index 0000000..8422976
--- /dev/null
+++ b/gdb/features/riscv.c
@@ -0,0 +1,86 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: riscv.xml */
+
+#include "defs.h"
+#include "osabi.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_riscv;
+static void
+initialize_tdesc_riscv (void)
+{
+  struct target_desc *result = allocate_target_description ();
+  struct tdesc_feature *feature;
+
+  set_tdesc_architecture (result, bfd_scan_arch ("riscv:rv64"));
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.rv64i");
+  tdesc_create_reg (feature, "x0", 0, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x1", 1, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x2", 2, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x3", 3, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x4", 4, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x5", 5, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x6", 6, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x7", 7, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x8", 8, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x9", 9, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x10", 10, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x11", 11, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x12", 12, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x13", 13, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x14", 14, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x15", 15, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x16", 16, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x17", 17, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x18", 18, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x19", 19, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x20", 20, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x21", 21, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x22", 22, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x23", 23, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x24", 24, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x25", 25, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x26", 26, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x27", 27, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x28", 28, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x29", 29, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x30", 30, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x31", 31, 1, "general", 64, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.rv64d");
+  tdesc_create_reg (feature, "f0", 32, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f1", 33, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f2", 34, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f3", 35, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f4", 36, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f5", 37, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f6", 38, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f7", 39, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f8", 40, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f9", 41, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f10", 42, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f11", 43, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f12", 44, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f13", 45, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f14", 46, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f15", 47, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f16", 48, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f17", 49, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f18", 50, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f19", 51, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f20", 52, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f21", 53, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f22", 54, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f23", 55, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f24", 56, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f25", 57, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f26", 58, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f27", 59, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f28", 60, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f29", 61, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f30", 62, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f31", 63, 1, "float", 64, "float");
+
+  tdesc_riscv = result;
+}
diff --git a/gdb/features/riscv.xml b/gdb/features/riscv.xml
new file mode 100644
index 0000000..94e630c
--- /dev/null
+++ b/gdb/features/riscv.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2015-2017 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>riscv:rv64</architecture>
+
+  <feature name="org.gnu.gdb.riscv.rv64i">
+    <reg name="x0"  bitsize="64" group="general"/>
+    <reg name="x1"  bitsize="64" group="general"/>
+    <reg name="x2"  bitsize="64" group="general"/>
+    <reg name="x3"  bitsize="64" group="general"/>
+    <reg name="x4"  bitsize="64" group="general"/>
+    <reg name="x5"  bitsize="64" group="general"/>
+    <reg name="x6"  bitsize="64" group="general"/>
+    <reg name="x7"  bitsize="64" group="general"/>
+    <reg name="x8"  bitsize="64" group="general"/>
+    <reg name="x9"  bitsize="64" group="general"/>
+    <reg name="x10" bitsize="64" group="general"/>
+    <reg name="x11" bitsize="64" group="general"/>
+    <reg name="x12" bitsize="64" group="general"/>
+    <reg name="x13" bitsize="64" group="general"/>
+    <reg name="x14" bitsize="64" group="general"/>
+    <reg name="x15" bitsize="64" group="general"/>
+    <reg name="x16" bitsize="64" group="general"/>
+    <reg name="x17" bitsize="64" group="general"/>
+    <reg name="x18" bitsize="64" group="general"/>
+    <reg name="x19" bitsize="64" group="general"/>
+    <reg name="x20" bitsize="64" group="general"/>
+    <reg name="x21" bitsize="64" group="general"/>
+    <reg name="x22" bitsize="64" group="general"/>
+    <reg name="x23" bitsize="64" group="general"/>
+    <reg name="x24" bitsize="64" group="general"/>
+    <reg name="x25" bitsize="64" group="general"/>
+    <reg name="x26" bitsize="64" group="general"/>
+    <reg name="x27" bitsize="64" group="general"/>
+    <reg name="x28" bitsize="64" group="general"/>
+    <reg name="x29" bitsize="64" group="general"/>
+    <reg name="x30" bitsize="64" group="general"/>
+    <reg name="x31" bitsize="64" group="general"/>
+  </feature>
+
+  <feature name="org.gnu.gdb.riscv.rv64d">
+    <reg name="f0"  bitsize="64" group="float" type="float"/>
+    <reg name="f1"  bitsize="64" group="float" type="float"/>
+    <reg name="f2"  bitsize="64" group="float" type="float"/>
+    <reg name="f3"  bitsize="64" group="float" type="float"/>
+    <reg name="f4"  bitsize="64" group="float" type="float"/>
+    <reg name="f5"  bitsize="64" group="float" type="float"/>
+    <reg name="f6"  bitsize="64" group="float" type="float"/>
+    <reg name="f7"  bitsize="64" group="float" type="float"/>
+    <reg name="f8"  bitsize="64" group="float" type="float"/>
+    <reg name="f9"  bitsize="64" group="float" type="float"/>
+    <reg name="f10" bitsize="64" group="float" type="float"/>
+    <reg name="f11" bitsize="64" group="float" type="float"/>
+    <reg name="f12" bitsize="64" group="float" type="float"/>
+    <reg name="f13" bitsize="64" group="float" type="float"/>
+    <reg name="f14" bitsize="64" group="float" type="float"/>
+    <reg name="f15" bitsize="64" group="float" type="float"/>
+    <reg name="f16" bitsize="64" group="float" type="float"/>
+    <reg name="f17" bitsize="64" group="float" type="float"/>
+    <reg name="f18" bitsize="64" group="float" type="float"/>
+    <reg name="f19" bitsize="64" group="float" type="float"/>
+    <reg name="f20" bitsize="64" group="float" type="float"/>
+    <reg name="f21" bitsize="64" group="float" type="float"/>
+    <reg name="f22" bitsize="64" group="float" type="float"/>
+    <reg name="f23" bitsize="64" group="float" type="float"/>
+    <reg name="f24" bitsize="64" group="float" type="float"/>
+    <reg name="f25" bitsize="64" group="float" type="float"/>
+    <reg name="f26" bitsize="64" group="float" type="float"/>
+    <reg name="f27" bitsize="64" group="float" type="float"/>
+    <reg name="f28" bitsize="64" group="float" type="float"/>
+    <reg name="f29" bitsize="64" group="float" type="float"/>
+    <reg name="f30" bitsize="64" group="float" type="float"/>
+    <reg name="f31" bitsize="64" group="float" type="float"/>
+  </feature>
+</target>
diff --git a/gdb/gdbserver/linux-riscv-low.c b/gdb/gdbserver/linux-riscv-low.c
new file mode 100644
index 0000000..444082c
--- /dev/null
+++ b/gdb/gdbserver/linux-riscv-low.c
@@ -0,0 +1,221 @@
+/* GNU/Linux/RISC-V specific low level interface, GDBserver.
+
+   Copyright (C) 2012-2017 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 "server.h"
+#include "linux-low.h"
+
+#include <arch/abi.h>
+#include "nat/gdb_ptrace.h"
+
+/* Defined in auto-generated file reg-riscv.c.  */
+void init_registers_riscv (void);
+extern const struct target_desc *tdesc_riscv;
+
+#define riscv_num_regs 32
+
+static int riscv_regmap[] =
+{
+   0,  1,  2,  3,  4,  5,  6,  7,
+   8,  9, 10, 11, 12, 13, 14, 15,
+  16, 17, 18, 19, 20, 21, 22, 23,
+  24, 25, 26, 27, 28, 29, 30, 31,
+  32, 33, 34, 35, 36, 37, 38, 39,
+  40, 41, 42, 43, 44, 45, 46, 47,
+  48, 49, 50, 51, 52, 53, 54, 55,
+  56, 57, 58, 59, 60, 61, 62, 63
+};
+
+static int
+riscv_cannot_fetch_register (int regno)
+{
+  if (regno >= 0 && regno < 63)
+    return 0;
+  else
+    return 1;
+}
+
+static int
+riscv_cannot_store_register (int regno)
+{
+  if (regno >= 0 && regno < 63)
+    return 0;
+  else
+    return 1;
+}
+
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte ebreak[] = { 0x73, 0x00, 0x10, 0x00, };
+static const gdb_byte c_ebreak[] = { 0x02, 0x90 };
+
+static const gdb_byte *
+riscv_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = kind;
+  switch (kind)
+    {
+    case 2:
+      return c_ebreak;
+    case 4:
+      return ebreak;
+    default:
+      gdb_assert(0);
+    }
+}
+
+static int
+riscv_breakpoint_at (CORE_ADDR where)
+{
+  uint8_t insn[4];
+
+  (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
+  if (insn[0] == ebreak[0] && inst[1] == ebreak[1]
+      && inst[2] == ebreak[2] && inst[3] == ebreak[3])
+    return 1;
+  if (insn[0] == c_ebreak[0] && inst[1] == c_ebreak[1])
+    return 1;
+
+  /* If necessary, recognize more trap instructions here.  GDB only uses the
+     one.  */
+  return 0;
+}
+
+static void
+riscv_fill_gregset (struct regcache *regcache, void *buf)
+{
+  int i;
+
+  for (i = 0; i < riscv_num_regs; i++)
+    if (riscv_regmap[i] != -1)
+      collect_register (regcache, i, ((uint_reg_t *) buf) + riscv_regmap[i]);
+}
+
+static void
+riscv_store_gregset (struct regcache *regcache, const void *buf)
+{
+  int i;
+
+  for (i = 0; i < riscv_num_regs; i++)
+    if (riscv_regmap[i] != -1)
+      supply_register (regcache, i, ((uint_reg_t *) buf) + riscv_regmap[i]);
+}
+
+static struct regset_info riscv_regsets[] =
+{
+  { PTRACE_GETREGS, PTRACE_SETREGS, 0, riscv_num_regs * 8,
+    GENERAL_REGS, riscv_fill_gregset, riscv_store_gregset },
+  NULL_REGSET
+};
+
+static struct regsets_info riscv_regsets_info =
+  {
+    riscv_regsets, /* regsets */
+    0, /* num_regsets */
+    NULL, /* disabled_regsets */
+  };
+
+static struct usrregs_info riscv_usrregs_info =
+  {
+    riscv_num_regs,
+    riscv_regmap,
+  };
+
+static struct regs_info regs_info =
+  {
+    NULL, /* regset_bitmap */
+    &riscv_usrregs_info,
+    &riscv_regsets_info,
+  };
+
+static const struct regs_info *
+riscv_regs_info (void)
+{
+  return &regs_info;
+}
+
+static void
+riscv_arch_setup (void)
+{
+  int pid = pid_of (current_thread);
+  unsigned int machine;
+  int is_elf64 = linux_pid_exe_is_elf_64_file (pid, &machine);
+
+  if (sizeof (void *) == 4)
+    if (is_elf64 > 0)
+      error (_("Can't debug 64-bit process with 32-bit GDBserver"));
+
+  if (!is_elf64)
+    current_process ()->tdesc = tdesc_riscvgx32;
+  else
+    current_process ()->tdesc = tdesc_riscvgx;
+}
+
+/* Support for hardware single step.  */
+
+static int
+riscv_supports_hardware_single_step (void)
+{
+  return 0;
+}
+
+
+struct linux_target_ops the_low_target =
+{
+  riscv_arch_setup,
+  riscv_regs_info,
+  riscv_cannot_fetch_register,
+  riscv_cannot_store_register,
+  NULL,
+  linux_get_pc_64bit,
+  linux_set_pc_64bit,
+  NULL, /* breakpoint_kind_from_pc */
+  riscv_sw_breakpoint_from_kind,
+  NULL,
+  0,
+  riscv_breakpoint_at,
+  NULL, /* supports_z_point_type */
+  NULL, /* insert_point */
+  NULL, /* remove_point */
+  NULL, /* stopped_by_watchpoint */
+  NULL, /* stopped_data_address */
+  NULL, /* collect_ptrace_register */
+  NULL, /* supply_ptrace_register */
+  NULL, /* siginfo_fixup */
+  NULL, /* new_process */
+  NULL, /* new_thread */
+  NULL, /* new_fork */
+  NULL, /* prepare_to_resume */
+  NULL, /* process_qsupported */
+  NULL, /* supports_tracepoints */
+  NULL, /* get_thread_area */
+  NULL, /* install_fast_tracepoint_jump_pad */
+  NULL, /* emit_ops */
+  NULL, /* get_min_fast_tracepoint_insn_len */
+  NULL, /* supports_range_stepping */
+  NULL, /* breakpoint_kind_from_current_state */
+  riscv_supports_hardware_single_step,
+};
+
+void
+initialize_low_arch (void)
+{
+  init_registers_riscv();
+
+  initialize_regsets_info (&riscv_regsets_info);
+}
diff --git a/gdb/regformats/riscv.dat b/gdb/regformats/riscv.dat
new file mode 100644
index 0000000..01047fa
--- /dev/null
+++ b/gdb/regformats/riscv.dat
@@ -0,0 +1,69 @@
+# THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi :set ro:
+# Generated from: riscv.xml
+name:riscv
+xmltarget:riscv.xml
+expedite:
+64:x0
+64:x1
+64:x2
+64:x3
+64:x4
+64:x5
+64:x6
+64:x7
+64:x8
+64:x9
+64:x10
+64:x11
+64:x12
+64:x13
+64:x14
+64:x15
+64:x16
+64:x17
+64:x18
+64:x19
+64:x20
+64:x21
+64:x22
+64:x23
+64:x24
+64:x25
+64:x26
+64:x27
+64:x28
+64:x29
+64:x30
+64:x31
+64:f0
+64:f1
+64:f2
+64:f3
+64:f4
+64:f5
+64:f6
+64:f7
+64:f8
+64:f9
+64:f10
+64:f11
+64:f12
+64:f13
+64:f14
+64:f15
+64:f16
+64:f17
+64:f18
+64:f19
+64:f20
+64:f21
+64:f22
+64:f23
+64:f24
+64:f25
+64:f26
+64:f27
+64:f28
+64:f29
+64:f30
+64:f31
diff --git a/gdb/riscv-linux-nat.c b/gdb/riscv-linux-nat.c
new file mode 100644
index 0000000..6accb7a
--- /dev/null
+++ b/gdb/riscv-linux-nat.c
@@ -0,0 +1,77 @@
+/* Native-dependent code for GNU/Linux RISC-V.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+   Contributed by Albert Ou <albert@sifive.com>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+
+#include "inferior.h"
+#include "regcache.h"
+
+#include <sys/ptrace.h>
+#include "gregset.h"
+
+#include "riscv-tdep.h"
+#include "riscv-linux-tdep.h"
+
+/* Transfering the general-purpose registers between GDB, inferiors
+   and core files.  */
+
+/* Fill GDB's register cache with the general-purpose register values
+   in *GREGSETP.  */
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
+{
+  regcache_supply_regset (&riscv_linux_gregset, regcache, -1,
+			  (const gdb_byte *) gregsetp,
+			  (RISCV_NGREG));
+}
+
+/* Fill register REGNUM (if it is a general-purpose register) in
+   *GREGSETP with the value in GDB's register cache.  If REGNUM is -1,
+   do this for all registers.  */
+
+void
+fill_gregset (const struct regcache *regcache,
+	      gdb_gregset_t *gregsetp, int regno)
+{
+  regcache_collect_regset (&riscv_linux_gregset, regcache,
+			   regno, (gdb_byte *) gregsetp,
+			   (RISCV_NGREG));
+}
+
+/* Transfering floating-point registers between GDB, inferiors and cores.  */
+
+/* Fill GDB's register cache with the floating-point and SSE register
+   values in *FPREGSETP.  */
+
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
+{
+}
+
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+   *FPREGSETP with the value in GDB's register cache.  If REGNUM is
+   -1, do this for all registers.  */
+
+void
+fill_fpregset (const struct regcache *regcache,
+	       gdb_fpregset_t *fpregsetp, int regnum)
+{
+}
diff --git a/gdb/riscv-linux-tdep.c b/gdb/riscv-linux-tdep.c
new file mode 100644
index 0000000..145a3cf
--- /dev/null
+++ b/gdb/riscv-linux-tdep.c
@@ -0,0 +1,80 @@
+/* Target-dependent code for GNU/Linux RISC-V.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+   Contributed by Albert Ou <albert@sifive.com>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+
+#include "gdbarch.h"
+#include "osabi.h"
+#include "linux-tdep.h"
+#include "solib-svr4.h"
+#include "glibc-tdep.h"
+
+#include "riscv-tdep.h"
+#include "riscv-linux-tdep.h"
+
+#include "regcache.h"
+#include "regset.h"
+
+static const struct regcache_map_entry riscv_linux_gregmap[] =
+{
+  { 1,  RISCV_PC_REGNUM, 0 },
+  { 31, RISCV_RA_REGNUM, 0 }, /* x1 to x31 */
+  { 0 }
+};
+
+const struct regset riscv_linux_gregset =
+{
+  riscv_linux_gregmap, regcache_supply_regset, regcache_collect_regset
+};
+
+static void
+riscv_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+					  iterate_over_regset_sections_cb *cb,
+					  void *cb_data,
+					  const struct regcache *regcache)
+{
+  cb (".reg", (RISCV_NGREG * riscv_isa_regsize (gdbarch)),
+      &riscv_linux_gregset, NULL, cb_data);
+}
+
+static void
+riscv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  linux_init_abi (info, gdbarch);
+
+  /* GNU/Linux uses SVR4-style shared libraries.  */
+  set_solib_svr4_fetch_link_map_offsets
+    (gdbarch, gdbarch_tdep (gdbarch)->riscv_abi == RISCV_ABI_FLAG_RV32I ?
+      svr4_ilp32_fetch_link_map_offsets :
+      svr4_lp64_fetch_link_map_offsets);
+
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, riscv_linux_iterate_over_regset_sections);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_riscv_linux_tdep;
+
+void
+_initialize_riscv_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_LINUX,
+			  riscv_linux_init_abi);
+}
diff --git a/gdb/riscv-linux-tdep.h b/gdb/riscv-linux-tdep.h
new file mode 100644
index 0000000..d5758ca
--- /dev/null
+++ b/gdb/riscv-linux-tdep.h
@@ -0,0 +1,30 @@
+/* Target-dependent header for GNU/Linux RISC-V.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+   Contributed by Albert Ou <albert@sifive.com>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef RISCV_LINUX_TDEP_H
+#define RISCV_LINUX_TDEP_H
+
+#include "regset.h"
+
+#define RISCV_NGREG (32)
+
+extern const struct regset riscv_linux_gregset;
+
+#endif
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
new file mode 100644
index 0000000..7522cfa
--- /dev/null
+++ b/gdb/riscv-tdep.c
@@ -0,0 +1,1368 @@
+/* Target-dependent code for the RISC-V architecture, for GDB.
+
+   Copyright (C) 1988-2015 Free Software Foundation, Inc.
+
+   Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
+   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
+   and by Todd Snyder <todd@bluespec.com>
+   and by Mike Frysinger <vapier@gentoo.org>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "gdbcore.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "target.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "osabi.h"
+#include "riscv-tdep.h"
+#include "block.h"
+#include "reggroups.h"
+#include "opcode/riscv.h"
+#include "elf/riscv.h"
+#include "elf-bfd.h"
+#include "symcat.h"
+#include "sim-regno.h"
+#include "gdb/sim-riscv.h"
+#include "dis-asm.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+#include "infcall.h"
+#include "floatformat.h"
+#include "remote.h"
+#include "target-descriptions.h"
+#include "dwarf2-frame.h"
+#include "user-regs.h"
+#include "valprint.h"
+#include "common-defs.h"
+#include "opcode/riscv-opc.h"
+#include <algorithm>
+
+#define DECLARE_INSN(INSN_NAME, INSN_MATCH, INSN_MASK) \
+static inline bool is_ ## INSN_NAME ## _insn (long insn) \
+{ \
+  return (insn & INSN_MASK) == INSN_MATCH; \
+}
+#include "opcode/riscv-opc.h"
+#undef DECLARE_INSN
+
+struct riscv_frame_cache
+{
+  CORE_ADDR base;
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+static const char * const riscv_gdb_reg_names[RISCV_LAST_FP_REGNUM + 1] =
+{
+  "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
+  "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
+  "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
+  "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
+  "pc",
+  "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
+  "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
+  "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+  "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+};
+
+struct register_alias
+{
+  const char *name;
+  int regnum;
+};
+
+static const struct register_alias riscv_register_aliases[] =
+{
+  { "zero", 0 },
+  { "ra", 1 },
+  { "sp", 2 },
+  { "gp", 3 },
+  { "tp", 4 },
+  { "t0", 5 },
+  { "t1", 6 },
+  { "t2", 7 },
+  { "fp", 8 },
+  { "s0", 8 },
+  { "s1", 9 },
+  { "a0", 10 },
+  { "a1", 11 },
+  { "a2", 12 },
+  { "a3", 13 },
+  { "a4", 14 },
+  { "a5", 15 },
+  { "a6", 16 },
+  { "a7", 17 },
+  { "s2", 18 },
+  { "s3", 19 },
+  { "s4", 20 },
+  { "s5", 21 },
+  { "s6", 22 },
+  { "s7", 23 },
+  { "s8", 24 },
+  { "s9", 25 },
+  { "s10", 26 },
+  { "s11", 27 },
+  { "t3", 28 },
+  { "t4", 29 },
+  { "t5", 30 },
+  { "t6", 31 },
+  /* pc is 32.  */
+  { "ft0", 33 },
+  { "ft1", 34 },
+  { "ft2", 35 },
+  { "ft3", 36 },
+  { "ft4", 37 },
+  { "ft5", 38 },
+  { "ft6", 39 },
+  { "ft7", 40 },
+  { "fs0", 41 },
+  { "fs1", 42 },
+  { "fa0", 43 },
+  { "fa1", 44 },
+  { "fa2", 45 },
+  { "fa3", 46 },
+  { "fa4", 47 },
+  { "fa5", 48 },
+  { "fa6", 49 },
+  { "fa7", 50 },
+  { "fs2", 51 },
+  { "fs3", 52 },
+  { "fs4", 53 },
+  { "fs5", 54 },
+  { "fs6", 55 },
+  { "fs7", 56 },
+  { "fs8", 57 },
+  { "fs9", 58 },
+  { "fs10", 59 },
+  { "fs11", 60 },
+  { "ft8", 61 },
+  { "ft9", 62 },
+  { "ft10", 63 },
+  { "ft11", 64 },
+#define DECLARE_CSR(name, num) { #name, (num) + 65 },
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+};
+
+static enum auto_boolean use_compressed_breakpoints;
+/*
+static void
+show_use_compressed_breakpoints (struct ui_file *file, int from_tty,
+			    struct cmd_list_element *c,
+			    const char *value)
+{
+  fprintf_filtered (file,
+		    _("Debugger's behavior regarding "
+		      "compressed breakpoints is %s.\n"),
+		    value);
+}
+*/
+
+static struct cmd_list_element *setriscvcmdlist = NULL;
+static struct cmd_list_element *showriscvcmdlist = NULL;
+
+static void
+show_riscv_command (char *args, int from_tty)
+{
+  help_list (showriscvcmdlist, "show riscv ", all_commands, gdb_stdout);
+}
+
+static void
+set_riscv_command (char *args, int from_tty)
+{
+  printf_unfiltered
+    ("\"set riscv\" must be followed by an appropriate subcommand.\n");
+  help_list (setriscvcmdlist, "set riscv ", all_commands, gdb_stdout);
+}
+
+/* Implement the breakpoint_kind_from_pc gdbarch method.  */
+
+static int
+riscv_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
+{
+  if (use_compressed_breakpoints == AUTO_BOOLEAN_AUTO) {
+    if (gdbarch_tdep (gdbarch)->supports_compressed_isa == AUTO_BOOLEAN_AUTO)
+    {
+      /* TODO: Because we try to read misa, it is not possible to set a
+         breakpoint before connecting to a live target. A suggested workaround is
+         to look at the ELF file in this case.  */
+      struct frame_info *frame = get_current_frame ();
+      uint32_t misa = get_frame_register_unsigned (frame, RISCV_CSR_MISA_REGNUM);
+      if (misa & (1<<2))
+        gdbarch_tdep (gdbarch)->supports_compressed_isa = AUTO_BOOLEAN_TRUE;
+      else
+        gdbarch_tdep (gdbarch)->supports_compressed_isa = AUTO_BOOLEAN_FALSE;
+    }
+
+    if (gdbarch_tdep (gdbarch)->supports_compressed_isa == AUTO_BOOLEAN_TRUE)
+      return 2;
+    else
+      return 4;
+  } else if (use_compressed_breakpoints == AUTO_BOOLEAN_TRUE) {
+    return 2;
+  } else {
+    return 4;
+  }
+}
+
+/* Implement the sw_breakpoint_from_kind gdbarch method.  */
+
+static const gdb_byte *
+riscv_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
+{
+  static const gdb_byte ebreak[] = { 0x73, 0x00, 0x10, 0x00, };
+  static const gdb_byte c_ebreak[] = { 0x02, 0x90 };
+
+  *size = kind;
+  switch (kind)
+    {
+    case 2:
+      return c_ebreak;
+    case 4:
+      return ebreak;
+    default:
+      gdb_assert(0);
+    }
+}
+
+static struct value *
+value_of_riscv_user_reg (struct frame_info *frame, const void *baton)
+{
+  const int *reg_p = (const int *)baton;
+
+  return value_of_register (*reg_p, frame);
+}
+
+static const char *
+register_name (struct gdbarch *gdbarch,
+	       int regnum,
+	       int prefer_alias)
+{
+  int i;
+  static char buf[20];
+
+  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+    return tdesc_register_name (gdbarch, regnum);
+  /* Prefer to use the alias. */
+  if (prefer_alias &&
+      regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_REGNUM)
+    {
+      for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i)
+	if (regnum == riscv_register_aliases[i].regnum)
+	  return riscv_register_aliases[i].name;
+    }
+
+  if (regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
+      return riscv_gdb_reg_names[regnum];
+
+  if (regnum >= RISCV_FIRST_CSR_REGNUM && regnum <= RISCV_LAST_CSR_REGNUM)
+    {
+      sprintf(buf, "csr%d", regnum - RISCV_FIRST_CSR_REGNUM);
+      return buf;
+    }
+
+  if (regnum == RISCV_PRIV_REGNUM)
+    {
+      return "priv";
+    }
+
+  return NULL;
+}
+
+/* Implement the register_name gdbarch method.  */
+
+static const char *
+riscv_register_name (struct gdbarch *gdbarch,
+		     int regnum)
+{
+  return register_name(gdbarch, regnum, 0);
+}
+
+/* Reads a function return value of type TYPE.  */
+
+static void
+riscv_extract_return_value (struct type *type,
+			    struct regcache *regs,
+			    gdb_byte *dst,
+			    int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regs);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int regsize = riscv_isa_regsize (gdbarch);
+  bfd_byte *valbuf = dst;
+  int len = TYPE_LENGTH (type);
+  int st_len = std::min (regsize, len);
+  ULONGEST tmp;
+
+  gdb_assert (len <= 2 * regsize);
+
+  while (len > 0)
+    {
+      regcache_cooked_read_unsigned (regs, regnum++, &tmp);
+      store_unsigned_integer (valbuf, st_len, byte_order, tmp);
+      len -= regsize;
+      valbuf += regsize;
+    }
+}
+
+/* Write into appropriate registers a function return value of type
+   TYPE, given in virtual format.  */
+
+static void
+riscv_store_return_value (struct type *type,
+			  struct regcache *regs,
+			  const gdb_byte *src,
+			  int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regs);
+  int regsize = riscv_isa_regsize (gdbarch);
+  const bfd_byte *valbuf = src;
+
+  /* Integral values greater than one word are stored in consecutive
+     registers starting with R0.  This will always be a multiple of
+     the register size.  */
+
+  int len = TYPE_LENGTH (type);
+
+  gdb_assert (len <= 2 * regsize);
+
+  while (len > 0)
+    {
+      regcache_cooked_write (regs, regnum++, valbuf);
+      len -= regsize;
+      valbuf += regsize;
+    }
+}
+
+/* Implement the return_value gdbarch method.  */
+
+static enum return_value_convention
+riscv_return_value (struct gdbarch  *gdbarch,
+		    struct value *function,
+		    struct type *type,
+		    struct regcache *regcache,
+		    gdb_byte *readbuf,
+		    const gdb_byte *writebuf)
+{
+  enum type_code rv_type = TYPE_CODE (type);
+  unsigned int rv_size = TYPE_LENGTH (type);
+  int fp, regnum;
+  ULONGEST tmp;
+
+  /* Paragraph on return values taken from RISC-V specification (post v2.0):
+
+     Values are returned from functions in integer registers a0 and a1 and
+     floating-point registers fa0 and fa1.  Floating-point values are returned
+     in floating-point registers only if they are primitives or members of a
+     struct consisting of only one or two floating-point values.  Other return
+     values that fit into two pointer-words are returned in a0 and a1.  Larger
+     return values are passed entirely in memory; the caller allocates this
+     memory region and passes a pointer to it as an implicit first parameter
+     to the callee.  */
+
+  /* Deal with struct/unions first that are passed via memory.  */
+  if (rv_size > 2 * riscv_isa_regsize (gdbarch))
+    {
+      if (readbuf || writebuf)
+	regcache_cooked_read_unsigned (regcache, RISCV_A0_REGNUM, &tmp);
+      if (readbuf)
+	read_memory (tmp, readbuf, rv_size);
+      if (writebuf)
+	write_memory (tmp, writebuf, rv_size);
+      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
+    }
+
+  /* Are we dealing with a floating point value?  */
+  fp = 0;
+  if (rv_type == TYPE_CODE_FLT)
+    fp = 1;
+  else if (rv_type == TYPE_CODE_STRUCT || rv_type == TYPE_CODE_UNION)
+    {
+      unsigned int rv_fields = TYPE_NFIELDS (type);
+
+      if (rv_fields == 1)
+	{
+	  struct type *fieldtype = TYPE_FIELD_TYPE (type, 0);
+	  if (TYPE_CODE (check_typedef (fieldtype)) == TYPE_CODE_FLT)
+	    fp = 1;
+	}
+      else if (rv_fields == 2)
+	{
+	  struct type *fieldtype0 = TYPE_FIELD_TYPE (type, 0);
+	  struct type *fieldtype1 = TYPE_FIELD_TYPE (type, 1);
+
+	  if (TYPE_CODE (check_typedef (fieldtype0)) == TYPE_CODE_FLT
+	      && TYPE_CODE (check_typedef (fieldtype1)) == TYPE_CODE_FLT)
+	    fp = 1;
+	}
+    }
+
+  /* Handle return value in a register.  */
+  regnum = fp ? RISCV_FA0_REGNUM : RISCV_A0_REGNUM;
+
+  if (readbuf)
+    riscv_extract_return_value (type, regcache, readbuf, regnum);
+
+  if (writebuf)
+    riscv_store_return_value (type, regcache, writebuf, regnum);
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the pseudo_register_read gdbarch method.  */
+
+static enum register_status
+riscv_pseudo_register_read (struct gdbarch *gdbarch,
+			    struct regcache *regcache,
+			    int regnum,
+			    gdb_byte *buf)
+{
+  return regcache_raw_read (regcache, regnum, buf);
+}
+
+/* Implement the pseudo_register_write gdbarch method.  */
+
+static void
+riscv_pseudo_register_write (struct gdbarch *gdbarch,
+			     struct regcache *regcache,
+			     int cookednum,
+			     const gdb_byte *buf)
+{
+  regcache_raw_write (regcache, cookednum, buf);
+}
+
+/* Implement the register_type gdbarch method.  */
+
+static struct type *
+riscv_register_type (struct gdbarch *gdbarch,
+		     int regnum)
+{
+  int regsize = riscv_isa_regsize (gdbarch);
+
+  if (regnum < RISCV_FIRST_FP_REGNUM)
+    {
+      /*
+       * GPRs and especially the PC are listed as unsigned so that gdb can
+       * interpret them as addresses without any problems. Specifically, if a
+       * user runs "x/i $pc" then they should see the instruction at the PC.
+       * But on a 32-bit system, with a signed PC of eg. 0x8000_0000, gdb will
+       * internally sign extend the value and then attempt to read from
+       * 0xffff_ffff_8000_0000, which it then concludes it can't read.
+       */
+      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);
+	}
+    }
+  else if (regnum <= RISCV_LAST_FP_REGNUM)
+    {
+      switch (regsize)
+	{
+	case 4:
+	  return builtin_type (gdbarch)->builtin_float;
+	case 8:
+	case 16:
+	  return builtin_type (gdbarch)->builtin_double;
+	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;
+
+      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);
+	}
+    }
+}
+
+static void
+riscv_print_fp_register (struct ui_file *file, struct frame_info *frame,
+			 int regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct value_print_options opts;
+  const char *regname;
+  value *val = get_frame_register_value(frame, regnum);
+
+  fprintf_filtered (file, "%-15s", gdbarch_register_name (gdbarch, regnum));
+
+  get_formatted_print_options (&opts, 'f');
+  val_print_scalar_formatted (value_type (val),
+			      value_embedded_offset (val),
+			      val,
+			      &opts, 0, file);
+}
+
+static void
+riscv_print_register_formatted (struct ui_file *file, struct frame_info *frame,
+				int regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  gdb_byte raw_buffer[MAX_REGISTER_SIZE];
+  struct value_print_options opts;
+
+  if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
+    riscv_print_fp_register (file, frame, regnum);
+  else
+    {
+      /* Integer type.  */
+      int offset, size;
+      unsigned long long d;
+
+      if (!deprecated_frame_register_read (frame, regnum, raw_buffer))
+	{
+	  fprintf_filtered (file, "%-15s[Invalid]\n",
+			    register_name (gdbarch, regnum, 1));
+	  return;
+	}
+
+      fprintf_filtered (file, "%-15s", register_name (gdbarch, regnum, 1));
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	offset = register_size (gdbarch, regnum) - register_size (gdbarch, regnum);
+      else
+	offset = 0;
+
+      size = register_size (gdbarch, regnum);
+      get_formatted_print_options (&opts, 'x');
+      print_scalar_formatted (raw_buffer + offset,
+			      register_type (gdbarch, regnum), &opts,
+			      size == 8 ? 'g' : 'w', file);
+      fprintf_filtered (file, "\t");
+      if (size == 4 && riscv_isa_regsize (gdbarch) == 8)
+	fprintf_filtered (file, "\t");
+
+      if (regnum == RISCV_CSR_MSTATUS_REGNUM)
+	{
+	  if (size == 4)
+	    d = unpack_long (builtin_type (gdbarch)->builtin_uint32, raw_buffer);
+	  else if (size == 8)
+	    d = unpack_long (builtin_type (gdbarch)->builtin_uint64, raw_buffer);
+	  else
+	    internal_error (__FILE__, __LINE__, _("unknown size for mstatus"));
+	  unsigned xlen = size * 4;
+	  fprintf_filtered (file,
+			    "SD:%X VM:%02X MXR:%X PUM:%X MPRV:%X XS:%X "
+			    "FS:%X MPP:%x HPP:%X SPP:%X MPIE:%X HPIE:%X "
+			    "SPIE:%X UPIE:%X MIE:%X HIE:%X SIE:%X UIE:%X",
+			    (int)((d >> (xlen-1)) & 0x1),
+			    (int)((d >> 24) & 0x1f),
+			    (int)((d >> 19) & 0x1),
+			    (int)((d >> 18) & 0x1),
+			    (int)((d >> 17) & 0x1),
+			    (int)((d >> 15) & 0x3),
+			    (int)((d >> 13) & 0x3),
+			    (int)((d >> 11) & 0x3),
+			    (int)((d >> 9) & 0x3),
+			    (int)((d >> 8) & 0x1),
+			    (int)((d >> 7) & 0x1),
+			    (int)((d >> 6) & 0x1),
+			    (int)((d >> 5) & 0x1),
+			    (int)((d >> 4) & 0x1),
+			    (int)((d >> 3) & 0x1),
+			    (int)((d >> 2) & 0x1),
+			    (int)((d >> 1) & 0x1),
+			    (int)((d >> 0) & 0x1));
+	}
+      else if (regnum == RISCV_CSR_MISA_REGNUM)
+        {
+          int base;
+          if (size == 4) {
+            d = unpack_long (builtin_type (gdbarch)->builtin_uint32, raw_buffer);
+            base = d >> 30;
+          } else if (size == 8) {
+            d = unpack_long (builtin_type (gdbarch)->builtin_uint64, raw_buffer);
+            base = d >> 62;
+          } else {
+            internal_error (__FILE__, __LINE__, _("unknown size for misa"));
+          }
+          unsigned xlen = 16;
+          for (; base > 0; base--) {
+            xlen *= 2;
+          }
+	  fprintf_filtered (file, "RV%d", xlen);
+
+          for (unsigned i = 0; i < 26; i++) {
+            if (d & (1<<i)) {
+              fprintf_filtered (file, "%c", 'A' + i);
+            }
+          }
+        }
+      else if (regnum == RISCV_CSR_FCSR_REGNUM
+	       || regnum == RISCV_CSR_FFLAGS_REGNUM
+	       || regnum == RISCV_CSR_FRM_REGNUM)
+	{
+	  d = unpack_long (builtin_type (gdbarch)->builtin_int32, raw_buffer);
+
+	  if (regnum != RISCV_CSR_FRM_REGNUM)
+	    fprintf_filtered (file, "RD:%01X NV:%d DZ:%d OF:%d UF:%d NX:%d   ",
+			      (int)((d >> 5) & 0x7),
+			      (int)((d >> 4) & 0x1),
+			      (int)((d >> 3) & 0x1),
+			      (int)((d >> 2) & 0x1),
+			      (int)((d >> 1) & 0x1),
+			      (int)((d >> 0) & 0x1));
+
+	  if (regnum != RISCV_CSR_FFLAGS_REGNUM)
+	    {
+	      static const char * const sfrm[] = {
+		"RNE (round to nearest; ties to even)",
+		"RTZ (Round towards zero)",
+		"RDN (Round down towards -∞)",
+		"RUP (Round up towards +∞)",
+		"RMM (Round to nearest; tiest to max magnitude)",
+		"INVALID[5]",
+		"INVALID[6]",
+		"dynamic rounding mode",
+	      };
+	      int frm = ((regnum == RISCV_CSR_FCSR_REGNUM) ? (d >> 5) : d) & 0x3;
+
+	      fprintf_filtered (file, "FRM:%i [%s]", frm, sfrm[frm]);
+	    }
+	}
+      else if (regnum == RISCV_PRIV_REGNUM)
+        {
+          uint8_t priv = raw_buffer[0];
+          if (priv >= 0 && priv < 4)
+            {
+              static const char * const sprv[] = {
+                "User/Application",
+                "Supervisor",
+                "Hypervisor",
+                "Machine"
+              };
+              fprintf_filtered (file, "prv:%d [%s]", priv, sprv[priv]);
+            }
+          else
+            {
+              fprintf_filtered (file, "prv:%d [INVALID]", priv);
+            }
+        }
+      else
+	{
+	  get_formatted_print_options (&opts, 'd');
+	  print_scalar_formatted (raw_buffer + offset,
+				  register_type (gdbarch, regnum),
+				  &opts, 0, file);
+	}
+    }
+  fprintf_filtered (file, "\n");
+}
+
+/* Implement the register_reggroup_p gdbarch method.  */
+
+static int
+riscv_register_reggroup_p (struct gdbarch  *gdbarch,
+			   int regnum,
+			   struct reggroup *reggroup)
+{
+  int float_p;
+  int raw_p;
+  unsigned int i;
+
+  /* Used by 'info registers' and 'info registers <groupname>'.  */
+
+  if (gdbarch_register_name (gdbarch, regnum) == NULL
+      || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
+    return 0;
+
+  if (reggroup == all_reggroup) {
+    if (regnum < RISCV_FIRST_CSR_REGNUM || regnum == RISCV_PRIV_REGNUM)
+      return 1;
+    /* Only include CSRs that have aliases.  */
+    for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i) {
+	if (regnum == riscv_register_aliases[i].regnum)
+          return 1;
+    }
+    return 0;
+  } else if (reggroup == float_reggroup)
+    return (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
+	    || (regnum == RISCV_CSR_FCSR_REGNUM
+	        || regnum == RISCV_CSR_FFLAGS_REGNUM
+	        || regnum == RISCV_CSR_FRM_REGNUM);
+  else if (reggroup == general_reggroup)
+    return regnum < RISCV_FIRST_FP_REGNUM;
+  else if (reggroup == restore_reggroup || reggroup == save_reggroup)
+    return regnum <= RISCV_LAST_FP_REGNUM;
+  else if (reggroup == system_reggroup) {
+    if (regnum == RISCV_PRIV_REGNUM)
+      return 1;
+    if (regnum < RISCV_FIRST_CSR_REGNUM || regnum > RISCV_LAST_CSR_REGNUM)
+      return 0;
+    /* Only include CSRs that have aliases.  */
+    for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i) {
+	if (regnum == riscv_register_aliases[i].regnum)
+          return 1;
+    }
+    return 0;
+  } else if (reggroup == vector_reggroup)
+    return 0;
+  else
+    internal_error (__FILE__, __LINE__, _("unhandled reggroup"));
+}
+
+/* Implement the print_registers_info gdbarch method.  */
+
+static void
+riscv_print_registers_info (struct gdbarch    *gdbarch,
+			    struct ui_file    *file,
+			    struct frame_info *frame,
+			    int                regnum,
+			    int                all)
+{
+  /* Use by 'info all-registers'.  */
+  struct reggroup *reggroup;
+
+  if (regnum != -1)
+    {
+      /* Print one specified register.  */
+      gdb_assert (regnum <= RISCV_LAST_REGNUM);
+      if (NULL == register_name (gdbarch, regnum, 1))
+        error (_("Not a valid register for the current processor type"));
+      riscv_print_register_formatted (file, frame, regnum);
+      return;
+    }
+
+  if (all)
+    reggroup = all_reggroup;
+  else
+    reggroup = general_reggroup;
+  for (regnum = 0; regnum <= RISCV_LAST_REGNUM; ++regnum)
+    {
+      /* Zero never changes, so might as well hide by default.  */
+      if (regnum == RISCV_ZERO_REGNUM && !all)
+        continue;
+      if (riscv_register_reggroup_p(gdbarch, regnum, reggroup))
+        riscv_print_register_formatted (file, frame, regnum);
+    }
+}
+
+static ULONGEST
+riscv_fetch_instruction (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order_for_code (gdbarch);
+  gdb_byte buf[8];
+  int instlen, status;
+
+  /* All insns are at least 16 bits.  */
+  status = target_read_memory (addr, buf, 2);
+  if (status)
+    memory_error (TARGET_XFER_E_IO, addr);
+
+  /* If we need more, grab it now.  */
+  instlen = riscv_insn_length (buf[0]);
+  if (instlen > sizeof (buf))
+    internal_error (__FILE__, __LINE__, _("%s: riscv_insn_length returned %i"),
+		    __func__, instlen);
+  else if (instlen > 2)
+    {
+      status = target_read_memory (addr + 2, buf + 2, instlen - 2);
+      if (status)
+	memory_error (TARGET_XFER_E_IO, addr + 2);
+    }
+
+  return extract_unsigned_integer (buf, instlen, byte_order);
+}
+
+static void
+set_reg_offset (struct gdbarch *gdbarch, struct riscv_frame_cache *this_cache,
+		int regnum, CORE_ADDR offset)
+{
+  if (this_cache != NULL && this_cache->saved_regs[regnum].addr == -1)
+    this_cache->saved_regs[regnum].addr = offset;
+}
+
+static void
+reset_saved_regs (struct gdbarch *gdbarch, struct riscv_frame_cache *this_cache)
+{
+  const int num_regs = gdbarch_num_regs (gdbarch);
+  int i;
+
+  if (this_cache == NULL || this_cache->saved_regs == NULL)
+    return;
+
+  for (i = 0; i < num_regs; ++i)
+    this_cache->saved_regs[i].addr = 0;
+}
+
+static int riscv_decode_register_index(unsigned long opcode, int offset)
+{
+    return (opcode >> offset) & 0x1F;
+}
+
+static CORE_ADDR
+riscv_scan_prologue (struct gdbarch *gdbarch,
+		     CORE_ADDR start_pc, CORE_ADDR limit_pc,
+		     struct frame_info *this_frame,
+		     struct riscv_frame_cache *this_cache)
+{
+  CORE_ADDR cur_pc;
+  CORE_ADDR frame_addr = 0;
+  CORE_ADDR sp;
+  long frame_offset;
+  int frame_reg = RISCV_SP_REGNUM;
+
+  CORE_ADDR end_prologue_addr = 0;
+  int seen_sp_adjust = 0;
+  int load_immediate_bytes = 0;
+
+  /* Can be called when there's no process, and hence when there's no THIS_FRAME.  */
+  if (this_frame != NULL)
+    sp = get_frame_register_signed (this_frame, RISCV_SP_REGNUM);
+  else
+    sp = 0;
+
+  if (limit_pc > start_pc + 200)
+    limit_pc = start_pc + 200;
+
+ restart:
+
+  frame_offset = 0;
+  /* TODO: Handle compressed extensions.  */
+  for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4)
+    {
+      ULONGEST inst;
+      unsigned long opcode;
+      int reg, rs1, imm12, rs2, offset12, funct3;
+
+      /* Fetch the instruction.  */
+      inst = riscv_fetch_instruction (gdbarch, cur_pc);
+
+      /* Decode the instruction.  These offsets are defined in the RISC-V ISA
+       * manual.  */
+      reg = riscv_decode_register_index(inst, 7);
+      rs1 = riscv_decode_register_index(inst, 15);
+      rs2 = riscv_decode_register_index(inst, 20);
+      imm12 = (inst >> 20) & 0xFFF;
+      offset12 = (((inst >> 25) & 0x7F) << 5) + ((inst >> 7) & 0x1F);
+
+      /* Look for common stack adjustment insns.  */
+      if ((is_addi_insn(inst) || is_addiw_insn(inst))
+	  && reg == RISCV_SP_REGNUM && rs1 == RISCV_SP_REGNUM)
+	{
+	  /* addi sp, sp, -i */
+	  /* addiw sp, sp, -i */
+	  if (imm12 & 0x800)
+	    frame_offset += 0x1000 - imm12;
+	  else
+	    break;
+	  seen_sp_adjust = 1;
+	}
+      else if (is_sw_insn(inst) && rs1 == RISCV_SP_REGNUM)
+	{
+	  /* sw reg, offset(sp) */
+	  set_reg_offset (gdbarch, this_cache, rs1, sp + offset12);
+	}
+      else if (is_sd_insn(inst) && rs1 == RISCV_SP_REGNUM)
+	{
+	  /* sd reg, offset(sp) */
+	  set_reg_offset (gdbarch, this_cache, rs1, sp + offset12);
+	}
+      else if (is_addi_insn(inst) && reg == RISCV_FP_REGNUM
+	       && rs1 == RISCV_SP_REGNUM)
+	{
+	  /* addi s0, sp, size */
+	  if ((long)imm12 != frame_offset)
+	    frame_addr = sp + imm12;
+	}
+      else if (this_frame && frame_reg == RISCV_SP_REGNUM)
+	{
+	  unsigned alloca_adjust;
+
+	  frame_reg = RISCV_FP_REGNUM;
+	  frame_addr = get_frame_register_signed (this_frame, RISCV_FP_REGNUM);
+
+	  alloca_adjust = (unsigned)(frame_addr - (sp - imm12));
+	  if (alloca_adjust > 0)
+	    {
+	      sp += alloca_adjust;
+	      reset_saved_regs (gdbarch, this_cache);
+	      goto restart;
+	    }
+	}
+      else if ((is_add_insn(inst) || is_addw_insn(inst))
+	       && reg == RISCV_FP_REGNUM && rs1 == RISCV_SP_REGNUM
+               && rs2 == RISCV_ZERO_REGNUM)
+	{
+	  /* add s0, sp, 0 */
+	  /* addw s0, sp, 0 */
+	  if (this_frame && frame_reg == RISCV_SP_REGNUM)
+	    {
+	      unsigned alloca_adjust;
+	      frame_reg = RISCV_FP_REGNUM;
+	      frame_addr = get_frame_register_signed (this_frame,
+						      RISCV_FP_REGNUM);
+
+	      alloca_adjust = (unsigned)(frame_addr - sp);
+	      if (alloca_adjust > 0)
+		{
+		  sp = frame_addr;
+		  reset_saved_regs (gdbarch, this_cache);
+		  goto restart;
+		}
+	    }
+	}
+      else if (is_sw_insn(inst) && rs1 == RISCV_FP_REGNUM)
+	{
+	  /* sw reg, offset(s0) */
+	  set_reg_offset (gdbarch, this_cache, rs1, frame_addr + offset12);
+	}
+      else if (reg == RISCV_GP_REGNUM
+	       && (is_auipc_insn(inst)
+                   || is_lui_insn(inst)
+		   || (is_addi_insn(inst) && rs1 == RISCV_GP_REGNUM)
+		   || (is_add_insn(inst) && (rs1 == RISCV_GP_REGNUM
+					  || rs2 == RISCV_GP_REGNUM))))
+	{
+	  /* auipc gp, n */
+	  /* addi gp, gp, n */
+	  /* add gp, gp, reg */
+	  /* add gp, reg, gp */
+	  /* lui gp, n */
+	  /* These instructions are part of the prologue, but we don't need to
+	     do anything special to handle them.  */
+	}
+      else
+	{
+	  if (end_prologue_addr == 0)
+	    end_prologue_addr = cur_pc;
+	}
+    }
+
+  if (this_cache != NULL)
+    {
+      this_cache->base = get_frame_register_signed (this_frame, frame_reg)
+	+ frame_offset;
+      this_cache->saved_regs[RISCV_PC_REGNUM] =
+	this_cache->saved_regs[RISCV_RA_REGNUM];
+    }
+
+  if (end_prologue_addr == 0)
+    end_prologue_addr = cur_pc;
+
+  if (load_immediate_bytes && !seen_sp_adjust)
+    end_prologue_addr -= load_immediate_bytes;
+
+  return end_prologue_addr;
+}
+
+/* Implement the riscv_skip_prologue gdbarch method.  */
+
+static CORE_ADDR
+riscv_skip_prologue (struct gdbarch *gdbarch,
+		     CORE_ADDR       pc)
+{
+  CORE_ADDR limit_pc;
+  CORE_ADDR func_addr;
+
+  /* See if we can determine the end of the prologue via the symbol table.
+     If so, then return either PC, or the PC after the prologue, whichever
+     is greater.  */
+  if (find_pc_partial_function (pc, NULL, &func_addr, NULL))
+    {
+      CORE_ADDR post_prologue_pc = skip_prologue_using_sal (gdbarch, func_addr);
+      if (post_prologue_pc != 0)
+	return std::max (pc, post_prologue_pc);
+    }
+
+  /* Can't determine prologue from the symbol table, need to examine
+     instructions.  */
+
+  /* Find an upper limit on the function prologue using the debug information.
+     If the debug information could not be used to provide that bound, then use
+     an arbitrary large number as the upper bound.  */
+  limit_pc = skip_prologue_using_sal (gdbarch, pc);
+  if (limit_pc == 0)
+    limit_pc = pc + 100;   /* MAGIC! */
+
+  return riscv_scan_prologue (gdbarch, pc, limit_pc, NULL, NULL);
+}
+
+static CORE_ADDR
+riscv_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr,
+		       struct value **args, int nargs, struct type *value_type,
+		       CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+		       struct regcache *regcache)
+{
+  *bp_addr = sp;
+  *real_pc = funaddr;
+
+  /* Keep the stack aligned.  */
+  return sp - 16;
+}
+
+static CORE_ADDR
+riscv_push_dummy_call (struct gdbarch *gdbarch,
+		       struct value *function,
+		       struct regcache *regcache,
+		       CORE_ADDR bp_addr,
+		       int nargs,
+		       struct value **args,
+		       CORE_ADDR sp,
+		       int struct_return,
+		       CORE_ADDR struct_addr)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  gdb_byte buf[4];
+  int i;
+  CORE_ADDR func_addr = find_function_addr (function, NULL);
+
+  /* Push excess arguments in reverse order.  */
+
+  for (i = nargs; i >= 8; --i)
+    {
+      struct type *value_type = value_enclosing_type (args[i]);
+      int container_len = align_up (TYPE_LENGTH (value_type), 3);
+
+      sp -= container_len;
+      write_memory (sp, value_contents_writeable (args[i]), container_len);
+    }
+
+  /* Initialize argument registers.  */
+
+  for (i = 0; i < nargs && i < 8; ++i)
+    {
+      struct type *value_type = value_enclosing_type (args[i]);
+      const gdb_byte *arg_bits = value_contents_all (args[i]);
+      int regnum = (TYPE_CODE (value_type) == TYPE_CODE_FLT
+		    ? RISCV_FA0_REGNUM : RISCV_A0_REGNUM);
+
+      regcache_cooked_write_unsigned
+	(regcache, regnum + i,
+	 extract_unsigned_integer
+	   (arg_bits, riscv_isa_regsize(gdbarch), byte_order));
+    }
+
+  /* Store struct value address.  */
+
+  if (struct_return)
+    regcache_cooked_write_unsigned (regcache, RISCV_A0_REGNUM, struct_addr);
+
+  /* Set the dummy return value to bp_addr.
+     A dummy breakpoint will be setup to execute the call.  */
+
+  regcache_cooked_write_unsigned (regcache, RISCV_RA_REGNUM, bp_addr);
+
+  /* Finally, update the stack pointer.  */
+
+  regcache_cooked_write_unsigned (regcache, RISCV_SP_REGNUM, sp);
+
+  return sp;
+}
+
+/* Implement the frame_align gdbarch method.  */
+
+static CORE_ADDR
+riscv_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  return align_down (addr, 16);
+}
+
+/* Implement the unwind_pc gdbarch method.  */
+
+static CORE_ADDR
+riscv_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, RISCV_PC_REGNUM);
+}
+
+/* Implement the unwind_sp gdbarch method.  */
+
+static CORE_ADDR
+riscv_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, RISCV_SP_REGNUM);
+}
+
+/* Implement the dummy_id gdbarch method.  */
+
+static struct frame_id
+riscv_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return frame_id_build (get_frame_register_signed (this_frame, RISCV_SP_REGNUM),
+			 get_frame_pc (this_frame));
+}
+
+static struct trad_frame_cache *
+riscv_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  CORE_ADDR pc;
+  CORE_ADDR start_addr;
+  CORE_ADDR stack_addr;
+  struct trad_frame_cache *this_trad_cache;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
+  if ((*this_cache) != NULL)
+    return (struct trad_frame_cache *) *this_cache;
+  this_trad_cache = trad_frame_cache_zalloc (this_frame);
+  (*this_cache) = this_trad_cache;
+
+  trad_frame_set_reg_realreg (this_trad_cache, gdbarch_pc_regnum (gdbarch),
+			      RISCV_RA_REGNUM);
+
+  pc = get_frame_pc (this_frame);
+  find_pc_partial_function (pc, NULL, &start_addr, NULL);
+  stack_addr = get_frame_register_signed (this_frame, RISCV_SP_REGNUM);
+  trad_frame_set_id (this_trad_cache, frame_id_build (stack_addr, start_addr));
+
+  trad_frame_set_this_base (this_trad_cache, stack_addr);
+
+  return this_trad_cache;
+}
+
+static void
+riscv_frame_this_id (struct frame_info *this_frame,
+		     void              **prologue_cache,
+		     struct frame_id   *this_id)
+{
+  struct trad_frame_cache *info = riscv_frame_cache (this_frame, prologue_cache);
+  trad_frame_get_id (info, this_id);
+}
+
+static struct value *
+riscv_frame_prev_register (struct frame_info *this_frame,
+			   void              **prologue_cache,
+			   int                regnum)
+{
+  struct trad_frame_cache *info = riscv_frame_cache (this_frame, prologue_cache);
+  return trad_frame_get_register (info, this_frame, regnum);
+}
+
+static const struct frame_unwind riscv_frame_unwind =
+{
+  /*.type          =*/ NORMAL_FRAME,
+  /*.stop_reason   =*/ default_frame_unwind_stop_reason,
+  /*.this_id       =*/ riscv_frame_this_id,
+  /*.prev_register =*/ riscv_frame_prev_register,
+  /*.unwind_data   =*/ NULL,
+  /*.sniffer       =*/ default_frame_sniffer,
+  /*.dealloc_cache =*/ NULL,
+  /*.prev_arch     =*/ NULL,
+};
+
+static struct gdbarch *
+riscv_gdbarch_init (struct gdbarch_info info,
+		    struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  const struct bfd_arch_info *binfo = info.bfd_arch_info;
+
+  int abi, i;
+
+  /* For now, base the abi on the elf class.  */
+  /* Allow the ELF class to override the register size. Ideally the target
+   * (OpenOCD/spike/...) would communicate the register size to gdb instead. */
+  abi = RISCV_ABI_FLAG_RV32I;
+  if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    {
+      unsigned char eclass = elf_elfheader (info.abfd)->e_ident[EI_CLASS];
+
+      if (eclass == ELFCLASS32)
+	abi = RISCV_ABI_FLAG_RV32I;
+      else if (eclass == ELFCLASS64)
+	abi = RISCV_ABI_FLAG_RV64I;
+      else
+        internal_error (__FILE__, __LINE__, _("unknown ELF header class %d"), eclass);
+    }
+  else
+    {
+      if (binfo->bits_per_word == 32)
+        abi = RISCV_ABI_FLAG_RV32I;
+      else if (binfo->bits_per_word == 64)
+        abi = RISCV_ABI_FLAG_RV64I;
+      else
+        internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"),
+            binfo->bits_per_word);
+    }
+
+  /* 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)->riscv_abi == abi)
+      return arches->gdbarch;
+
+  /* None found, so create a new architecture from the information provided.
+     Can't initialize all the target dependencies until we actually know which
+     target we are talking to, but put in some defaults for now.  */
+
+  tdep = (struct gdbarch_tdep *) xmalloc (sizeof *tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  tdep->riscv_abi = abi;
+  tdep->supports_compressed_isa = AUTO_BOOLEAN_AUTO;
+
+  /* Target data types.  */
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 32);
+  set_gdbarch_long_bit (gdbarch, riscv_isa_regsize (gdbarch) * 8);
+  set_gdbarch_float_bit (gdbarch, 32);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 128);
+  set_gdbarch_ptr_bit (gdbarch, riscv_isa_regsize (gdbarch) * 8);
+  set_gdbarch_char_signed (gdbarch, 1);
+
+  /* Information about the target architecture.  */
+  set_gdbarch_return_value (gdbarch, riscv_return_value);
+  set_gdbarch_breakpoint_kind_from_pc (gdbarch, riscv_breakpoint_kind_from_pc);
+  set_gdbarch_sw_breakpoint_from_kind (gdbarch, riscv_sw_breakpoint_from_kind);
+  set_gdbarch_print_insn (gdbarch, print_insn_riscv);
+
+  /* Register architecture.  */
+  set_gdbarch_pseudo_register_read (gdbarch, riscv_pseudo_register_read);
+  set_gdbarch_pseudo_register_write (gdbarch, riscv_pseudo_register_write);
+  set_gdbarch_num_regs (gdbarch, RISCV_NUM_REGS);
+  set_gdbarch_num_pseudo_regs (gdbarch, RISCV_NUM_REGS);
+  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);
+  set_gdbarch_frame_align (gdbarch, riscv_frame_align);
+
+  /* Functions to access frame data.  */
+  set_gdbarch_unwind_pc (gdbarch, riscv_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, riscv_unwind_sp);
+
+  /* Functions handling dummy frames.  */
+  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+  set_gdbarch_push_dummy_code (gdbarch, riscv_push_dummy_code);
+  set_gdbarch_push_dummy_call (gdbarch, riscv_push_dummy_call);
+  set_gdbarch_dummy_id (gdbarch, riscv_dummy_id);
+
+  /* Frame unwinders.  Use DWARF debug info if available, otherwise use our own
+     unwinder.  */
+  dwarf2_append_unwinders (gdbarch);
+  frame_unwind_append_unwinder (gdbarch, &riscv_frame_unwind);
+
+  /* Check any target description for validity.  */
+  if (tdesc_has_registers (info.target_desc))
+    {
+      const struct tdesc_feature *feature;
+      struct tdesc_arch_data *tdesc_data;
+      int valid_p;
+
+      feature = tdesc_find_feature (info.target_desc, "org.gnu.gdb.riscv.cpu");
+      if (feature == NULL)
+	goto no_tdata;
+
+      tdesc_data = tdesc_data_alloc ();
+
+      valid_p = 1;
+      for (i = RISCV_ZERO_REGNUM; i <= RISCV_LAST_FP_REGNUM; ++i)
+        valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+                                            riscv_gdb_reg_names[i]);
+      for (i = RISCV_FIRST_CSR_REGNUM; i <= RISCV_LAST_CSR_REGNUM; ++i)
+        {
+          char buf[20];
+          sprintf (buf, "csr%d", i - RISCV_FIRST_CSR_REGNUM);
+          valid_p &= tdesc_numbered_register (feature, tdesc_data, i, buf);
+        }
+
+      valid_p &= tdesc_numbered_register (feature, tdesc_data, i++, "priv");
+
+      if (!valid_p)
+	tdesc_data_cleanup (tdesc_data);
+      else
+	tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
+    }
+ no_tdata:
+
+  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);
+
+  return gdbarch;
+}
+
+extern initialize_file_ftype _initialize_riscv_tdep; /* -Wmissing-prototypes */
+
+void
+_initialize_riscv_tdep (void)
+{
+  gdbarch_register (bfd_arch_riscv, riscv_gdbarch_init, NULL);
+
+  /* Add root prefix command for all "set riscv"/"show riscv" commands.  */
+  add_prefix_cmd ("riscv", no_class, set_riscv_command,
+      _("RISC-V specific commands."),
+      &setriscvcmdlist, "set riscv ", 0, &setlist);
+
+  add_prefix_cmd ("riscv", no_class, show_riscv_command,
+      _("RISC-V specific commands."),
+      &showriscvcmdlist, "show riscv ", 0, &showlist);
+
+  use_compressed_breakpoints = AUTO_BOOLEAN_AUTO;
+  add_setshow_auto_boolean_cmd ("use_compressed_breakpoints", no_class,
+      &use_compressed_breakpoints,
+      _("Configure whether to use compressed breakpoints."),
+      _("Show whether to use compressed breakpoints."),
+      _("\
+Debugging compressed code requires compressed breakpoints to be used. If left\n\
+to 'auto' then gdb will use them if $misa indicates the C extension is\n\
+supported. If that doesn't give the correct behavior, then this option can be\n\
+used."),
+      NULL,
+      NULL,
+      &setriscvcmdlist,
+      &showriscvcmdlist);
+}
diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
new file mode 100644
index 0000000..f2e6b9d
--- /dev/null
+++ b/gdb/riscv-tdep.h
@@ -0,0 +1,96 @@
+/* Target-dependent header for the RISC-V architecture, for GDB, the GNU Debugger.
+
+   Copyright (C) 2002-2015 Free Software Foundation, Inc.
+
+   Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
+   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
+   and by Todd Snyder <todd@bluespec.com>
+   and by Mike Frysinger <vapier@gentoo.org>.
+
+   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 RISCV_TDEP_H
+#define RISCV_TDEP_H
+
+struct gdbarch;
+
+/* All the official RISC-V ABIs.  These mostly line up with mcpuid purely for
+   convenience.  */
+#define RISCV_ABI_FLAG_RV32I	(0x00000000)	/* 32-bit Integer GPRs.  */
+#define RISCV_ABI_FLAG_RV64I	(0x40000000)	/* 64-bit Integer GPRs.  */
+#define RISCV_ABI_FLAG_D	(1 << 3)	/* Double-Precision Floating-Point.  */
+#define RISCV_ABI_FLAG_F	(1 << 5)	/* Single-Precision Floating-Point.  */
+
+#define IS_RV32I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV32I)
+#define IS_RV64I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV64I)
+
+#define HAS_FPU(x)	((x) & (RISCV_ABI_FLAG_D | RISCV_ABI_FLAG_F))
+
+enum {
+  RISCV_ZERO_REGNUM = 0,	/* Read-only register, always 0.  */
+  RISCV_RA_REGNUM = 1,		/* Return Address.  */
+  RISCV_SP_REGNUM = 2,		/* Stack Pointer.  */
+  RISCV_GP_REGNUM = 3,		/* Global Pointer.  */
+  RISCV_TP_REGNUM = 4,		/* Thread Pointer.  */
+  RISCV_FP_REGNUM = 8,		/* Frame Pointer.  */
+  RISCV_A0_REGNUM = 10,		/* First argument.  */
+  RISCV_A1_REGNUM = 11,		/* Second argument.  */
+  RISCV_PC_REGNUM = 32,		/* Program Counter.  */
+
+  RISCV_FIRST_FP_REGNUM = 33,	/* First Floating Point Register */
+  RISCV_FA0_REGNUM = 49,
+  RISCV_FA1_REGNUM = 50,
+  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_LAST_FP_REGNUM + 1 + num,
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+  RISCV_LAST_CSR_REGNUM = 4160,
+
+  RISCV_PRIV_REGNUM = 4161,
+
+  /* Leave this as the last enum.  */
+  RISCV_NUM_REGS
+};
+
+#define RISCV_LAST_REGNUM (RISCV_NUM_REGS - 1)
+
+/* RISC-V specific per-architecture information.  */
+struct gdbarch_tdep
+{
+  int riscv_abi;
+  enum auto_boolean supports_compressed_isa;
+};
+
+static inline int
+riscv_isa_regsize (struct gdbarch *gdbarch)
+{
+  int abi = gdbarch_tdep (gdbarch)->riscv_abi;
+
+  switch (abi)
+    {
+      case RISCV_ABI_FLAG_RV32I:
+	return 4;
+      case RISCV_ABI_FLAG_RV64I:
+	return 8;
+      default:
+	internal_error (__FILE__, __LINE__, _("unknown abi %i"), abi);
+	return 4;
+    }
+}
+
+#endif /* RISCV_TDEP_H */
diff --git a/include/gdb/sim-riscv.h b/include/gdb/sim-riscv.h
new file mode 100644
index 0000000..932cf49
--- /dev/null
+++ b/include/gdb/sim-riscv.h
@@ -0,0 +1,98 @@
+/* This file defines the interface between the RISC-V simulator and GDB.
+
+   Copyright (C) 2005-2015 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/>.  */
+
+/* Order has to match gdb riscv-tdep list.  */
+enum sim_riscv_regnum {
+  SIM_RISCV_ZERO_REGNUM = 0,
+  SIM_RISCV_RA_REGNUM,
+  SIM_RISCV_SP_REGNUM,
+  SIM_RISCV_GP_REGNUM,
+  SIM_RISCV_TP_REGNUM,
+  SIM_RISCV_T0_REGNUM,
+  SIM_RISCV_T1_REGNUM,
+  SIM_RISCV_T2_REGNUM,
+  SIM_RISCV_S0_REGNUM,
+#define SIM_RISCV_FP_REGNUM SIM_RISCV_S0_REGNUM
+  SIM_RISCV_S1_REGNUM,
+  SIM_RISCV_A0_REGNUM,
+  SIM_RISCV_A1_REGNUM,
+  SIM_RISCV_A2_REGNUM,
+  SIM_RISCV_A3_REGNUM,
+  SIM_RISCV_A4_REGNUM,
+  SIM_RISCV_A5_REGNUM,
+  SIM_RISCV_A6_REGNUM,
+  SIM_RISCV_A7_REGNUM,
+  SIM_RISCV_S2_REGNUM,
+  SIM_RISCV_S3_REGNUM,
+  SIM_RISCV_S4_REGNUM,
+  SIM_RISCV_S5_REGNUM,
+  SIM_RISCV_S6_REGNUM,
+  SIM_RISCV_S7_REGNUM,
+  SIM_RISCV_S8_REGNUM,
+  SIM_RISCV_S9_REGNUM,
+  SIM_RISCV_S10_REGNUM,
+  SIM_RISCV_S11_REGNUM,
+  SIM_RISCV_T3_REGNUM,
+  SIM_RISCV_T4_REGNUM,
+  SIM_RISCV_T5_REGNUM,
+  SIM_RISCV_T6_REGNUM,
+  SIM_RISCV_PC_REGNUM,
+  SIM_RISCV_FT0_REGNUM,
+#define SIM_RISCV_FIRST_FP_REGNUM SIM_RISCV_FT0_REGNUM
+  SIM_RISCV_FT1_REGNUM,
+  SIM_RISCV_FT2_REGNUM,
+  SIM_RISCV_FT3_REGNUM,
+  SIM_RISCV_FT4_REGNUM,
+  SIM_RISCV_FT5_REGNUM,
+  SIM_RISCV_FT6_REGNUM,
+  SIM_RISCV_FT7_REGNUM,
+  SIM_RISCV_FS0_REGNUM,
+  SIM_RISCV_FS1_REGNUM,
+  SIM_RISCV_FA0_REGNUM,
+  SIM_RISCV_FA1_REGNUM,
+  SIM_RISCV_FA2_REGNUM,
+  SIM_RISCV_FA3_REGNUM,
+  SIM_RISCV_FA4_REGNUM,
+  SIM_RISCV_FA5_REGNUM,
+  SIM_RISCV_FA6_REGNUM,
+  SIM_RISCV_FA7_REGNUM,
+  SIM_RISCV_FS2_REGNUM,
+  SIM_RISCV_FS3_REGNUM,
+  SIM_RISCV_FS4_REGNUM,
+  SIM_RISCV_FS5_REGNUM,
+  SIM_RISCV_FS6_REGNUM,
+  SIM_RISCV_FS7_REGNUM,
+  SIM_RISCV_FS8_REGNUM,
+  SIM_RISCV_FS9_REGNUM,
+  SIM_RISCV_FS10_REGNUM,
+  SIM_RISCV_FS11_REGNUM,
+  SIM_RISCV_FT8_REGNUM,
+  SIM_RISCV_FT9_REGNUM,
+  SIM_RISCV_FT10_REGNUM,
+  SIM_RISCV_FT11_REGNUM,
+#define SIM_RISCV_LAST_FP_REGNUM SIM_RISCV_FT11_REGNUM
+
+#define SIM_RISCV_FIRST_CSR_REGNUM SIM_RISCV_LAST_FP_REGNUM + 1
+#define DECLARE_CSR(name, num) SIM_RISCV_ ## num ## _REGNUM,
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+#define SIM_RISCV_LAST_CSR_REGNUM SIM_RISCV_LAST_REGNUM - 1
+
+  SIM_RISCV_LAST_REGNUM
+};
-- 
2.10.2

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

* [PATCH 2/2] RISC-V sim Port
  2017-03-06 20:31 RISC-V GDB Port v3 Palmer Dabbelt
  2017-03-06 20:31 ` [PATCH 1/2] RISC-V GDB Port Palmer Dabbelt
@ 2017-03-06 20:31 ` Palmer Dabbelt
  2017-03-10 19:38 ` RISC-V GDB Port v3 Palmer Dabbelt
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 17+ messages in thread
From: Palmer Dabbelt @ 2017-03-06 20:31 UTC (permalink / raw)
  To: gdb-patches; +Cc: Palmer Dabbelt

---
 sim/riscv/ChangeLog                   |    6 +
 sim/riscv/Makefile.in                 |   35 +
 sim/riscv/config.in                   |  248 +++++++
 sim/riscv/interp.c                    |  177 +++++
 sim/riscv/machs.c                     |  125 ++++
 sim/riscv/machs.h                     |   45 ++
 sim/riscv/sim-main.c                  | 1189 +++++++++++++++++++++++++++++++++
 sim/riscv/sim-main.h                  |   87 +++
 sim/riscv/tconfig.h                   |    4 +
 sim/testsuite/sim/riscv/ChangeLog     |    3 +
 sim/testsuite/sim/riscv/allinsn.exp   |   15 +
 sim/testsuite/sim/riscv/pass.s        |    7 +
 sim/testsuite/sim/riscv/testutils.inc |   50 ++
 13 files changed, 1991 insertions(+)
 create mode 100644 sim/riscv/ChangeLog
 create mode 100644 sim/riscv/Makefile.in
 create mode 100644 sim/riscv/config.in
 create mode 100644 sim/riscv/interp.c
 create mode 100644 sim/riscv/machs.c
 create mode 100644 sim/riscv/machs.h
 create mode 100644 sim/riscv/sim-main.c
 create mode 100644 sim/riscv/sim-main.h
 create mode 100644 sim/riscv/tconfig.h
 create mode 100644 sim/testsuite/sim/riscv/ChangeLog
 create mode 100644 sim/testsuite/sim/riscv/allinsn.exp
 create mode 100644 sim/testsuite/sim/riscv/pass.s
 create mode 100644 sim/testsuite/sim/riscv/testutils.inc

diff --git a/sim/riscv/ChangeLog b/sim/riscv/ChangeLog
new file mode 100644
index 0000000..a960da8
--- /dev/null
+++ b/sim/riscv/ChangeLog
@@ -0,0 +1,6 @@
+2015-04-27  Mike Frysinger  <vapier@gentoo.org>
+
+	* configure.ac, interp.c, Makefile.in, README, README-ISA,
+	sim-main.c, sim-main.h: New files for example simulator.
+	* aclocal.m4, config.in, configure: Regenerated.
+
diff --git a/sim/riscv/Makefile.in b/sim/riscv/Makefile.in
new file mode 100644
index 0000000..2902cf6
--- /dev/null
+++ b/sim/riscv/Makefile.in
@@ -0,0 +1,35 @@
+#    Makefile template for Configure for the example basic simulator.
+#    Copyright (C) 2005-2015 Free Software Foundation, Inc.
+#    Written by Mike Frysinger.
+# 
+# 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/>.
+
+# This selects the newlib/libgloss syscall definitions.
+NL_TARGET = -DNL_TARGET_riscv
+
+## COMMON_PRE_CONFIG_FRAG
+
+SIM_OBJS = \
+	$(SIM_NEW_COMMON_OBJS) \
+	sim-hload.o \
+	sim-model.o \
+	sim-reason.o \
+	sim-reg.o \
+	sim-resume.o \
+	sim-stop.o \
+	interp.o \
+	machs.o \
+	sim-main.o
+
+## COMMON_POST_CONFIG_FRAG
diff --git a/sim/riscv/config.in b/sim/riscv/config.in
new file mode 100644
index 0000000..aa3e45c
--- /dev/null
+++ b/sim/riscv/config.in
@@ -0,0 +1,248 @@
+/* config.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Sim debug setting */
+#undef DEBUG
+
+/* Define to 1 if translation of program messages to the user's native
+   language is requested. */
+#undef ENABLE_NLS
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <errno.h> header file. */
+#undef HAVE_ERRNO_H
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the <fpu_control.h> header file. */
+#undef HAVE_FPU_CONTROL_H
+
+/* Define to 1 if you have the `ftruncate' function. */
+#undef HAVE_FTRUNCATE
+
+/* Define to 1 if you have the `getrusage' function. */
+#undef HAVE_GETRUSAGE
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the `lstat' function. */
+#undef HAVE_LSTAT
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mmap' function. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the `munmap' function. */
+#undef HAVE_MUNMAP
+
+/* Define to 1 if you have the `posix_fallocate' function. */
+#undef HAVE_POSIX_FALLOCATE
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if the system has the type `socklen_t'. */
+#undef HAVE_SOCKLEN_T
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if `struct stat' is a member of `st_atime'. */
+#undef HAVE_STRUCT_STAT_ST_ATIME
+
+/* Define to 1 if `struct stat' is a member of `st_blksize'. */
+#undef HAVE_STRUCT_STAT_ST_BLKSIZE
+
+/* Define to 1 if `struct stat' is a member of `st_blocks'. */
+#undef HAVE_STRUCT_STAT_ST_BLOCKS
+
+/* Define to 1 if `struct stat' is a member of `st_ctime'. */
+#undef HAVE_STRUCT_STAT_ST_CTIME
+
+/* Define to 1 if `struct stat' is a member of `st_dev'. */
+#undef HAVE_STRUCT_STAT_ST_DEV
+
+/* Define to 1 if `struct stat' is a member of `st_gid'. */
+#undef HAVE_STRUCT_STAT_ST_GID
+
+/* Define to 1 if `struct stat' is a member of `st_ino'. */
+#undef HAVE_STRUCT_STAT_ST_INO
+
+/* Define to 1 if `struct stat' is a member of `st_mode'. */
+#undef HAVE_STRUCT_STAT_ST_MODE
+
+/* Define to 1 if `struct stat' is a member of `st_mtime'. */
+#undef HAVE_STRUCT_STAT_ST_MTIME
+
+/* Define to 1 if `struct stat' is a member of `st_nlink'. */
+#undef HAVE_STRUCT_STAT_ST_NLINK
+
+/* Define to 1 if `struct stat' is a member of `st_rdev'. */
+#undef HAVE_STRUCT_STAT_ST_RDEV
+
+/* Define to 1 if `struct stat' is a member of `st_size'. */
+#undef HAVE_STRUCT_STAT_ST_SIZE
+
+/* Define to 1 if `struct stat' is a member of `st_uid'. */
+#undef HAVE_STRUCT_STAT_ST_UID
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/times.h> header file. */
+#undef HAVE_SYS_TIMES_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the `time' function. */
+#undef HAVE_TIME
+
+/* Define to 1 if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* Define to 1 if you have the `truncate' function. */
+#undef HAVE_TRUNCATE
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the <windows.h> header file. */
+#undef HAVE_WINDOWS_H
+
+/* Define to 1 if you have the `__setfpucw' function. */
+#undef HAVE___SETFPUCW
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Name of this package. */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Additional package description */
+#undef PKGVERSION
+
+/* Sim profile settings */
+#undef PROFILE
+
+/* Bug reporting address */
+#undef REPORT_BUGS_TO
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Sim assert settings */
+#undef WITH_ASSERT
+
+/* Sim debug setting */
+#undef WITH_DEBUG
+
+/* Sim default environment */
+#undef WITH_ENVIRONMENT
+
+/* Sim profile settings */
+#undef WITH_PROFILE
+
+/* How to route I/O */
+#undef WITH_STDIO
+
+/* Sim trace settings */
+#undef WITH_TRACE
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
diff --git a/sim/riscv/interp.c b/sim/riscv/interp.c
new file mode 100644
index 0000000..8e6d454
--- /dev/null
+++ b/sim/riscv/interp.c
@@ -0,0 +1,177 @@
+/* RISC-V simulator.
+
+   Copyright (C) 2005-2015 Free Software Foundation, Inc.
+   Contributed by Mike Frysinger.
+
+   This file is part of simulators.
+
+   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/>.  */
+
+/* This file contains the main glue logic between the sim core and the target
+   specific simulator.  Normally this file will be kept small and the target
+   details will live in other files.
+
+   For more specific details on these functions, see the gdb/remote-sim.h
+   header file.  */
+
+#include "config.h"
+
+#include "sim-main.h"
+#include "sim-options.h"
+\f
+/* This function is the main loop.  It should process ticks and decode+execute
+   a single instruction.
+
+   Usually you do not need to change things here.  */
+
+void
+sim_engine_run (SIM_DESC sd,
+		int next_cpu_nr, /* ignore  */
+		int nr_cpus, /* ignore  */
+		int siggnal) /* ignore  */
+{
+  SIM_CPU *cpu;
+
+  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+
+  cpu = STATE_CPU (sd, 0);
+
+  while (1)
+    {
+      step_once (cpu);
+      if (sim_events_tick (sd))
+	sim_events_process (sd);
+    }
+}
+\f
+/* Initialize the simulator from scratch.  This is called once per lifetime of
+   the simulation.  Think of it as a processor reset.
+
+   Usually all cpu-specific setup is handled in the initialize_cpu callback.
+   If you want to do cpu-independent stuff, then it should go at the end (see
+   where memory is initialized).  */
+
+static void
+free_state (SIM_DESC sd)
+{
+  if (STATE_MODULES (sd) != NULL)
+    sim_module_uninstall (sd);
+  sim_cpu_free_all (sd);
+  sim_state_free (sd);
+}
+
+SIM_DESC
+sim_open (SIM_OPEN_KIND kind, host_callback *callback,
+	  struct bfd *abfd, char * const *argv)
+{
+  char c;
+  int i;
+  SIM_DESC sd = sim_state_alloc (kind, callback);
+
+  /* The cpu data is kept in a separately allocated chunk of memory.  */
+  if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  /* XXX: Default to the Virtual environment.  */
+  if (STATE_ENVIRONMENT (sd) == ALL_ENVIRONMENT)
+    STATE_ENVIRONMENT (sd) = VIRTUAL_ENVIRONMENT;
+
+  /* getopt will print the error message so we just have to exit if this fails.
+     FIXME: Hmmm...  in the case of gdb we need getopt to call
+     print_filtered.  */
+  if (sim_parse_args (sd, argv) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  /* Check for/establish the a reference program image.  */
+  if (sim_analyze_program (sd,
+			   (STATE_PROG_ARGV (sd) != NULL
+			    ? *STATE_PROG_ARGV (sd)
+			    : NULL), abfd) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  /* Establish any remaining configuration options.  */
+  if (sim_config (sd) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  if (sim_post_argv_init (sd) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  /* CPU specific initialization.  */
+  for (i = 0; i < MAX_NR_PROCESSORS; ++i)
+    {
+      SIM_CPU *cpu = STATE_CPU (sd, i);
+
+      initialize_cpu (sd, cpu, i);
+    }
+
+  /* Allocate external memory if none specified by user.
+     Use address 4 here in case the user wanted address 0 unmapped.  */
+  if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0)
+    sim_do_commandf (sd, "memory-size %#x", DEFAULT_MEM_SIZE);
+
+  return sd;
+}
+\f
+/* Prepare to run a program that has already been loaded into memory.
+
+   Usually you do not need to change things here.  */
+
+SIM_RC
+sim_create_inferior (SIM_DESC sd, struct bfd *abfd,
+		     char * const *argv, char * const *env)
+{
+  SIM_CPU *cpu = STATE_CPU (sd, 0);
+  sim_cia addr;
+
+  /* Set the PC.  */
+  if (abfd != NULL)
+    addr = bfd_get_start_address (abfd);
+  else
+    addr = 0;
+  sim_pc_set (cpu, addr);
+
+  /* Standalone mode (i.e. `run`) will take care of the argv for us in
+     sim_open() -> sim_parse_args().  But in debug mode (i.e. 'target sim'
+     with `gdb`), we need to handle it.  */
+  if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
+    {
+      freeargv (STATE_PROG_ARGV (sd));
+      STATE_PROG_ARGV (sd) = dupargv (argv);
+    }
+
+  initialize_env (sd, (void *)argv, (void *)env);
+
+  return SIM_RC_OK;
+}
diff --git a/sim/riscv/machs.c b/sim/riscv/machs.c
new file mode 100644
index 0000000..78ed28d
--- /dev/null
+++ b/sim/riscv/machs.c
@@ -0,0 +1,125 @@
+/* RISC-V simulator.
+
+   Copyright (C) 2005-2015 Free Software Foundation, Inc.
+   Contributed by Mike Frysinger.
+
+   This file is part of simulators.
+
+   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 "config.h"
+
+#include "sim-main.h"
+
+static void
+riscv_model_init (SIM_CPU *cpu)
+{
+}
+
+static void
+riscv_init_cpu (SIM_CPU *cpu)
+{
+}
+
+static void
+riscv_prepare_run (SIM_CPU *cpu)
+{
+}
+
+static const SIM_MACH_IMP_PROPERTIES riscv_imp_properties =
+{
+  sizeof (SIM_CPU),
+  0,
+};
+
+#if WITH_TARGET_WORD_BITSIZE >= 32
+
+static const SIM_MACH rv32i_mach;
+
+static const SIM_MODEL rv32_models[] =
+{
+#define M(ext) { "RV32"#ext, &rv32i_mach, MODEL_RV32##ext, NULL, riscv_model_init },
+#include "model_list.def"
+#undef M
+  { 0, NULL, 0, NULL, NULL, }
+};
+
+static const SIM_MACH rv32i_mach =
+{
+  "rv32i", "riscv:rv32", MACH_RV32I,
+  32, 32, &rv32_models[0], &riscv_imp_properties,
+  riscv_init_cpu,
+  riscv_prepare_run
+};
+
+#endif
+
+#if WITH_TARGET_WORD_BITSIZE >= 64
+
+static const SIM_MACH rv64i_mach;
+
+static const SIM_MODEL rv64_models[] =
+{
+#define M(ext) { "RV64"#ext, &rv64i_mach, MODEL_RV64##ext, NULL, riscv_model_init },
+#include "model_list.def"
+#undef M
+  { 0, NULL, 0, NULL, NULL, }
+};
+
+static const SIM_MACH rv64i_mach =
+{
+  "rv64i", "riscv:rv64", MACH_RV64I,
+  64, 64, &rv64_models[0], &riscv_imp_properties,
+  riscv_init_cpu,
+  riscv_prepare_run
+};
+
+#endif
+
+#if WITH_TARGET_WORD_BITSIZE >= 128
+
+static const SIM_MACH rv128i_mach;
+
+static const SIM_MODEL rv128_models[] =
+{
+#define M(ext) { "RV128"#ext, &rv128i_mach, MODEL_RV128##ext, NULL, riscv_model_init },
+#include "model_list.def"
+#undef M
+  { 0, NULL, 0, NULL, NULL, }
+};
+
+static const SIM_MACH rv128i_mach =
+{
+  "rv128i", "riscv:rv128", MACH_RV128I,
+  128, 128, &rv128_models[0], &riscv_imp_properties,
+  riscv_init_cpu,
+  riscv_prepare_run
+};
+
+#endif
+
+/* Order matters here.  */
+const SIM_MACH *sim_machs[] =
+{
+#if WITH_TARGET_WORD_BITSIZE >= 128
+  &rv128i_mach,
+#endif
+#if WITH_TARGET_WORD_BITSIZE >= 64
+  &rv64i_mach,
+#endif
+#if WITH_TARGET_WORD_BITSIZE >= 32
+  &rv32i_mach,
+#endif
+  NULL
+};
diff --git a/sim/riscv/machs.h b/sim/riscv/machs.h
new file mode 100644
index 0000000..6c8cd43
--- /dev/null
+++ b/sim/riscv/machs.h
@@ -0,0 +1,45 @@
+/* RISC-V simulator.
+
+   Copyright (C) 2005-2014 Free Software Foundation, Inc.
+   Contributed by Mike Frysinger.
+
+   This file is part of simulators.
+
+   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 RISCV_SIM_MACHS_H
+#define RISCV_SIM_MACHS_H
+
+typedef enum model_type {
+#define M(ext) MODEL_RV32##ext,
+#include "model_list.def"
+#undef M
+#define M(ext) MODEL_RV64##ext,
+#include "model_list.def"
+#undef M
+#define M(ext) MODEL_RV128##ext,
+#include "model_list.def"
+#undef M
+  MODEL_MAX
+} MODEL_TYPE;
+
+typedef enum mach_attr {
+  MACH_BASE,
+  MACH_RV32I,
+  MACH_RV64I,
+  MACH_RV128I,
+  MACH_MAX
+} MACH_ATTR;
+
+#endif
diff --git a/sim/riscv/sim-main.c b/sim/riscv/sim-main.c
new file mode 100644
index 0000000..97e37d2
--- /dev/null
+++ b/sim/riscv/sim-main.c
@@ -0,0 +1,1189 @@
+/* RISC-V simulator.
+
+   Copyright (C) 2005-2014 Free Software Foundation, Inc.
+   Contributed by Mike Frysinger.
+
+   This file is part of simulators.
+
+   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/>.  */
+
+/* This file contains the main simulator decoding logic.  i.e. everything that
+   is architecture specific.  */
+
+#include "config.h"
+
+#include <inttypes.h>
+#include <time.h>
+
+#include "sim-main.h"
+#include "sim-syscall.h"
+
+#include "opcode/riscv.h"
+
+#include "gdb/sim-riscv.h"
+
+#include "targ-vals.h"
+\f
+
+#define TRACE_REG(cpu, reg) TRACE_REGISTER (cpu, "wrote %s = %#"PRIxTW, riscv_gpr_names_abi[reg], cpu->regs[reg])
+\f
+static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
+#define OP_HASH_IDX(i) ((i) & (riscv_insn_length (i) == 2 ? 0x3 : 0x7f))
+
+#define RISCV_ASSERT_RV32(cpu, fmt, args...) \
+  do { \
+    if (RISCV_XLEN (cpu) != 32) \
+      { \
+	SIM_DESC sd = CPU_STATE (cpu); \
+	TRACE_INSN (cpu, "RV32I-only " fmt, ## args); \
+	sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); \
+      } \
+  } while (0)
+
+#define RISCV_ASSERT_RV64(cpu, fmt, args...) \
+  do { \
+    if (RISCV_XLEN (cpu) != 64) \
+      { \
+	SIM_DESC sd = CPU_STATE (cpu); \
+	TRACE_INSN (cpu, "RV64I-only " fmt, ## args); \
+	sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); \
+      } \
+  } while (0)
+
+static INLINE void
+store_rd (SIM_CPU *cpu, int rd, unsigned_word val)
+{
+  if (rd)
+    {
+      cpu->regs[rd] = val;
+      TRACE_REG (cpu, rd);
+    }
+}
+
+static INLINE unsigned_word
+fetch_csr (SIM_CPU *cpu, const char *name, int csr, unsigned_word *reg)
+{
+  /* Handle pseudo registers.  */
+  switch (csr)
+    {
+    /* Allow certain registers only in respective modes.  */
+    case CSR_CYCLEH:
+    case CSR_INSTRETH:
+    case CSR_TIMEH:
+      RISCV_ASSERT_RV32 (cpu, "CSR: %s", name);
+      break;
+    }
+
+  return *reg;
+}
+
+static INLINE void
+store_csr (SIM_CPU *cpu, const char *name, int csr, unsigned_word *reg,
+	   unsigned_word val)
+{
+  switch (csr)
+    {
+    /* These are pseudo registers that modify sub-fields of fcsr.  */
+    case CSR_FRM:
+      val &= 0x7;
+      *reg = val;
+      cpu->csr.fcsr = (cpu->csr.fcsr & ~0xe0) | (val << 5);
+      break;
+    case CSR_FFLAGS:
+      val &= 0x1f;
+      *reg = val;
+      cpu->csr.fcsr = (cpu->csr.fcsr & ~0x1f) | val;
+      break;
+    /* Keep the sub-fields in sync.  */
+    case CSR_FCSR:
+      *reg = val;
+      cpu->csr.frm = (val >> 5) & 0x7;
+      cpu->csr.fflags = val & 0x1f;
+      break;
+
+    /* Allow certain registers only in respective modes.  */
+    case CSR_CYCLEH:
+    case CSR_INSTRETH:
+    case CSR_TIMEH:
+      RISCV_ASSERT_RV32 (cpu, "CSR: %s", name);
+
+    /* All the rest are immutable.  */
+    default:
+      val = *reg;
+      break;
+    }
+
+  TRACE_REGISTER (cpu, "wrote CSR %s = %#"PRIxTW, name, val);
+}
+
+static inline unsigned_word
+ashiftrt (unsigned_word val, unsigned_word shift)
+{
+  unsigned32 sign = (val & 0x80000000) ? ~(0xfffffffful >> shift) : 0;
+  return (val >> shift) | sign;
+}
+
+static inline unsigned_word
+ashiftrt64 (unsigned_word val, unsigned_word shift)
+{
+  unsigned64 sign = (val & 0x8000000000000000ull) ? ~(0xffffffffffffffffull >> shift) : 0;
+  return (val >> shift) | sign;
+}
+
+static sim_cia
+execute_i (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
+{
+  SIM_DESC sd = CPU_STATE (cpu);
+  int rd = (iw >> OP_SH_RD) & OP_MASK_RD;
+  int rs1 = (iw >> OP_SH_RS1) & OP_MASK_RS1;
+  int rs2 = (iw >> OP_SH_RS2) & OP_MASK_RS2;
+  const char *rd_name = riscv_gpr_names_abi[rd];
+  const char *rs1_name = riscv_gpr_names_abi[rs1];
+  const char *rs2_name = riscv_gpr_names_abi[rs2];
+  unsigned int csr = (iw >> OP_SH_CSR) & OP_MASK_CSR;
+  unsigned_word i_imm = EXTRACT_ITYPE_IMM (iw);
+  unsigned_word u_imm = EXTRACT_UTYPE_IMM ((unsigned64) iw);
+  unsigned_word s_imm = EXTRACT_STYPE_IMM (iw);
+  unsigned_word sb_imm = EXTRACT_SBTYPE_IMM (iw);
+  unsigned_word shamt_imm = ((iw >> OP_SH_SHAMT) & OP_MASK_SHAMT);
+  unsigned_word tmp;
+  sim_cia pc = cpu->pc + 4;
+
+  TRACE_EXTRACT (cpu, "rd:%-2i:%-4s  rs1:%-2i:%-4s %0*"PRIxTW"  rs2:%-2i:%-4s %0*"PRIxTW"  match:%#x mask:%#x",
+		 rd, rd_name,
+		 rs1, rs1_name, (int)sizeof (unsigned_word) * 2, cpu->regs[rs1],
+		 rs2, rs2_name, (int)sizeof (unsigned_word) * 2, cpu->regs[rs2],
+		 (unsigned) op->match, (unsigned) op->mask);
+
+  switch (op->match)
+    {
+    case MATCH_ADD:
+      TRACE_INSN (cpu, "add %s, %s, %s;  // %s = %s + %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      store_rd (cpu, rd, cpu->regs[rs1] + cpu->regs[rs2]);
+      break;
+    case MATCH_ADDW:
+      TRACE_INSN (cpu, "addw %s, %s, %s;  // %s = %s + %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd, EXTEND32 (cpu->regs[rs1] + cpu->regs[rs2]));
+      break;
+    case MATCH_ADDI:
+      TRACE_INSN (cpu, "addi %s, %s, %#"PRIxTW";  // %s = %s + %#"PRIxTW,
+		  rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
+      store_rd (cpu, rd, cpu->regs[rs1] + i_imm);
+      break;
+    case MATCH_ADDIW:
+      TRACE_INSN (cpu, "addiw %s, %s, %#"PRIxTW";  // %s = %s + %#"PRIxTW,
+		  rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd, EXTEND32 (cpu->regs[rs1] + i_imm));
+      break;
+    case MATCH_AND:
+      TRACE_INSN (cpu, "and %s, %s, %s;  // %s = %s & %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      store_rd (cpu, rd, cpu->regs[rs1] & cpu->regs[rs2]);
+      break;
+    case MATCH_ANDI:
+      TRACE_INSN (cpu, "andi %s, %s, %"PRIiTW";  // %s = %s & %#"PRIxTW,
+		  rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
+      store_rd (cpu, rd, cpu->regs[rs1] & i_imm);
+      break;
+    case MATCH_OR:
+      TRACE_INSN (cpu, "or %s, %s, %s;  // %s = %s | %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      store_rd (cpu, rd, cpu->regs[rs1] | cpu->regs[rs2]);
+      break;
+    case MATCH_ORI:
+      TRACE_INSN (cpu, "ori %s, %s, %"PRIiTW";  // %s = %s | %#"PRIxTW,
+		  rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
+      store_rd (cpu, rd, cpu->regs[rs1] | i_imm);
+      break;
+    case MATCH_XOR:
+      TRACE_INSN (cpu, "xor %s, %s, %s;  // %s = %s ^ %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      store_rd (cpu, rd, cpu->regs[rs1] ^ cpu->regs[rs2]);
+      break;
+    case MATCH_XORI:
+      TRACE_INSN (cpu, "xori %s, %s, %"PRIiTW";  // %s = %s ^ %#"PRIxTW,
+		  rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm);
+      store_rd (cpu, rd, cpu->regs[rs1] ^ i_imm);
+      break;
+    case MATCH_SUB:
+      TRACE_INSN (cpu, "sub %s, %s, %s;  // %s = %s - %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      store_rd (cpu, rd, cpu->regs[rs1] - cpu->regs[rs2]);
+      break;
+    case MATCH_SUBW:
+      TRACE_INSN (cpu, "subw %s, %s, %s;  // %s = %s - %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd, EXTEND32 (cpu->regs[rs1] - cpu->regs[rs2]));
+      break;
+    case MATCH_LUI:
+      TRACE_INSN (cpu, "lui %s, %#"PRIxTW";", rd_name, u_imm);
+      store_rd (cpu, rd, u_imm);
+      break;
+    case MATCH_SLL:
+      TRACE_INSN (cpu, "sll %s, %s, %s;  // %s = %s << %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      u_imm = RISCV_XLEN (cpu) == 32 ? 0x1f : 0x3f;
+      store_rd (cpu, rd, cpu->regs[rs1] << (cpu->regs[rs2] & u_imm));
+      break;
+    case MATCH_SLLW:
+      TRACE_INSN (cpu, "sllw %s, %s, %s;  // %s = %s << %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd, EXTEND32 ((unsigned32)cpu->regs[rs1] << (cpu->regs[rs2] & 0x1f)));
+      break;
+    case MATCH_SLLI:
+      TRACE_INSN (cpu, "slli %s, %s, %"PRIiTW";  // %s = %s << %#"PRIxTW,
+		  rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
+      if (RISCV_XLEN (cpu) == 32 && shamt_imm > 0x1f)
+	sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
+      store_rd (cpu, rd, cpu->regs[rs1] << shamt_imm);
+      break;
+    case MATCH_SLLIW:
+      TRACE_INSN (cpu, "slliw %s, %s, %"PRIiTW";  // %s = %s << %#"PRIxTW,
+		  rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd, EXTEND32 ((unsigned32)cpu->regs[rs1] << shamt_imm));
+      break;
+    case MATCH_SRL:
+      TRACE_INSN (cpu, "srl %s, %s, %s;  // %s = %s >> %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      u_imm = RISCV_XLEN (cpu) == 32 ? 0x1f : 0x3f;
+      store_rd (cpu, rd, cpu->regs[rs1] >> (cpu->regs[rs2] & u_imm));
+      break;
+    case MATCH_SRLW:
+      TRACE_INSN (cpu, "srlw %s, %s, %s;  // %s = %s >> %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd, EXTEND32 ((unsigned32)cpu->regs[rs1] >> (cpu->regs[rs2] & 0x1f)));
+      break;
+    case MATCH_SRLI:
+      TRACE_INSN (cpu, "srli %s, %s, %"PRIiTW";  // %s = %s >> %#"PRIxTW,
+		  rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
+      if (RISCV_XLEN (cpu) == 32 && shamt_imm > 0x1f)
+	sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
+      store_rd (cpu, rd, cpu->regs[rs1] >> shamt_imm);
+      break;
+    case MATCH_SRLIW:
+      TRACE_INSN (cpu, "srliw %s, %s, %"PRIiTW";  // %s = %s >> %#"PRIxTW,
+		  rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd, EXTEND32 ((unsigned32)cpu->regs[rs1] >> shamt_imm));
+      break;
+    case MATCH_SRA:
+      TRACE_INSN (cpu, "sra %s, %s, %s;  // %s = %s >>> %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      if (RISCV_XLEN (cpu) == 32)
+	tmp = ashiftrt (cpu->regs[rs1], cpu->regs[rs2] & 0x1f);
+      else
+	tmp = ashiftrt64 (cpu->regs[rs1], cpu->regs[rs2] & 0x3f);
+      store_rd (cpu, rd, tmp);
+      break;
+    case MATCH_SRAW:
+      TRACE_INSN (cpu, "sraw %s, %s, %s;  // %s = %s >>> %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd, EXTEND32 (ashiftrt ((signed32)cpu->regs[rs1], cpu->regs[rs2] & 0x1f)));
+      break;
+    case MATCH_SRAI:
+      TRACE_INSN (cpu, "srai %s, %s, %"PRIiTW";  // %s = %s >>> %#"PRIxTW,
+		  rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
+      if (RISCV_XLEN (cpu) == 32)
+	{
+	  if (shamt_imm > 0x1f)
+	    sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
+	  tmp = ashiftrt (cpu->regs[rs1], shamt_imm);
+	}
+      else
+	tmp = ashiftrt64 (cpu->regs[rs1], shamt_imm);
+      store_rd (cpu, rd, tmp);
+      break;
+    case MATCH_SRAIW:
+      TRACE_INSN (cpu, "sraiw %s, %s, %"PRIiTW";  // %s = %s >>> %#"PRIxTW,
+		  rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd, EXTEND32 (ashiftrt ((signed32)cpu->regs[rs1], shamt_imm)));
+      break;
+    case MATCH_SLT:
+      TRACE_INSN (cpu, "slt");
+      store_rd (cpu, rd, !!((signed_word)cpu->regs[rs1] < (signed_word)cpu->regs[rs2]));
+      break;
+    case MATCH_SLTU:
+      TRACE_INSN (cpu, "sltu");
+      store_rd (cpu, rd, !!((unsigned_word)cpu->regs[rs1] < (unsigned_word)cpu->regs[rs2]));
+      break;
+    case MATCH_SLTI:
+      TRACE_INSN (cpu, "slti");
+      store_rd (cpu, rd, !!((signed_word)cpu->regs[rs1] < (signed_word)i_imm));
+      break;
+    case MATCH_SLTIU:
+      TRACE_INSN (cpu, "sltiu");
+      store_rd (cpu, rd, !!((unsigned_word)cpu->regs[rs1] < (unsigned_word)i_imm));
+      break;
+    case MATCH_AUIPC:
+      TRACE_INSN (cpu, "auipc %s, %"PRIiTW";  // %s = pc + %"PRIiTW,
+		  rd_name, u_imm, rd_name, u_imm);
+      store_rd (cpu, rd, cpu->pc + u_imm);
+      break;
+    case MATCH_BEQ:
+      TRACE_INSN (cpu, "beq %s, %s, %#"PRIxTW";  // if (%s == %s) goto %#"PRIxTW,
+		  rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
+      if (cpu->regs[rs1] == cpu->regs[rs2])
+	{
+	  pc = cpu->pc + sb_imm;
+	  TRACE_BRANCH (cpu, "to %#"PRIxTW, pc);
+	}
+      break;
+    case MATCH_BLT:
+      TRACE_INSN (cpu, "blt %s, %s, %#"PRIxTW";  // if (%s < %s) goto %#"PRIxTW,
+		  rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
+      if ((signed_word)cpu->regs[rs1] < (signed_word)cpu->regs[rs2])
+	{
+	  pc = cpu->pc + sb_imm;
+	  TRACE_BRANCH (cpu, "to %#"PRIxTW, pc);
+	}
+      break;
+    case MATCH_BLTU:
+      TRACE_INSN (cpu, "bltu %s, %s, %#"PRIxTW";  // if (%s < %s) goto %#"PRIxTW,
+		  rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
+      if ((unsigned_word)cpu->regs[rs1] < (unsigned_word)cpu->regs[rs2])
+	{
+	  pc = cpu->pc + sb_imm;
+	  TRACE_BRANCH (cpu, "to %#"PRIxTW, pc);
+	}
+      break;
+    case MATCH_BGE:
+      TRACE_INSN (cpu, "bge %s, %s, %#"PRIxTW";  // if (%s >= %s) goto %#"PRIxTW,
+		  rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
+      if ((signed_word)cpu->regs[rs1] >= (signed_word)cpu->regs[rs2])
+	{
+	  pc = cpu->pc + sb_imm;
+	  TRACE_BRANCH (cpu, "to %#"PRIxTW, pc);
+	}
+      break;
+    case MATCH_BGEU:
+      TRACE_INSN (cpu, "bgeu %s, %s, %#"PRIxTW";  // if (%s >= %s) goto %#"PRIxTW,
+		  rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
+      if ((unsigned_word)cpu->regs[rs1] >= (unsigned_word)cpu->regs[rs2])
+	{
+	  pc = cpu->pc + sb_imm;
+	  TRACE_BRANCH (cpu, "to %#"PRIxTW, pc);
+	}
+      break;
+    case MATCH_BNE:
+      TRACE_INSN (cpu, "bne %s, %s, %#"PRIxTW";  // if (%s != %s) goto %#"PRIxTW,
+		  rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm);
+      if (cpu->regs[rs1] != cpu->regs[rs2])
+	{
+	  pc = cpu->pc + sb_imm;
+	  TRACE_BRANCH (cpu, "to %#"PRIxTW, pc);
+	}
+      break;
+    case MATCH_JAL:
+      TRACE_INSN (cpu, "jal %s, %"PRIiTW";", rd_name, EXTRACT_UJTYPE_IMM (iw));
+      store_rd (cpu, rd, cpu->pc + 4);
+      pc = cpu->pc + EXTRACT_UJTYPE_IMM (iw);
+      TRACE_BRANCH (cpu, "to %#"PRIxTW, pc);
+      break;
+    case MATCH_JALR:
+      TRACE_INSN (cpu, "jalr %s, %s, %"PRIiTW";", rd_name, rs1_name, i_imm);
+      store_rd (cpu, rd, cpu->pc + 4);
+      pc = cpu->regs[rs1] + i_imm;
+      TRACE_BRANCH (cpu, "to %#"PRIxTW, pc);
+      break;
+
+    case MATCH_LD:
+      TRACE_INSN (cpu, "ld %s, %"PRIiTW"(%s); // ",
+		  rd_name, i_imm, rs1_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd,
+	sim_core_read_unaligned_8 (cpu, cpu->pc, read_map,
+				   cpu->regs[rs1] + i_imm));
+      break;
+    case MATCH_LW:
+      TRACE_INSN (cpu, "lw %s, %"PRIiTW"(%s); // ",
+		  rd_name, i_imm, rs1_name);
+      store_rd (cpu, rd, EXTEND32 (
+	sim_core_read_unaligned_4 (cpu, cpu->pc, read_map,
+				   cpu->regs[rs1] + i_imm)));
+      break;
+    case MATCH_LWU:
+      TRACE_INSN (cpu, "lwu %s, %"PRIiTW"(%s); // ",
+		  rd_name, i_imm, rs1_name);
+      store_rd (cpu, rd,
+	sim_core_read_unaligned_4 (cpu, cpu->pc, read_map,
+				   cpu->regs[rs1] + i_imm));
+      break;
+    case MATCH_LH:
+      TRACE_INSN (cpu, "lh %s, %"PRIiTW"(%s); // ",
+		  rd_name, i_imm, rs1_name);
+      store_rd (cpu, rd, EXTEND16 (
+	sim_core_read_unaligned_2 (cpu, cpu->pc, read_map,
+				   cpu->regs[rs1] + i_imm)));
+      break;
+    case MATCH_LHU:
+      TRACE_INSN (cpu, "lbu %s, %"PRIiTW"(%s); // ",
+		  rd_name, i_imm, rs1_name);
+      store_rd (cpu, rd,
+	sim_core_read_unaligned_2 (cpu, cpu->pc, read_map,
+				   cpu->regs[rs1] + i_imm));
+      break;
+    case MATCH_LB:
+      TRACE_INSN (cpu, "lb %s, %"PRIiTW"(%s); // ",
+		  rd_name, i_imm, rs1_name);
+      store_rd (cpu, rd, EXTEND8 (
+	sim_core_read_unaligned_1 (cpu, cpu->pc, read_map,
+				   cpu->regs[rs1] + i_imm)));
+      break;
+    case MATCH_LBU:
+      TRACE_INSN (cpu, "lbu %s, %"PRIiTW"(%s); // ",
+		  rd_name, i_imm, rs1_name);
+      store_rd (cpu, rd,
+	sim_core_read_unaligned_1 (cpu, cpu->pc, read_map,
+				   cpu->regs[rs1] + i_imm));
+      break;
+    case MATCH_SD:
+      TRACE_INSN (cpu, "sd %s, %"PRIiTW"(%s); // ",
+		  rs2_name, s_imm, rs1_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      sim_core_write_unaligned_8 (cpu, cpu->pc, write_map,
+				  cpu->regs[rs1] + s_imm, cpu->regs[rs2]);
+      break;
+    case MATCH_SW:
+      TRACE_INSN (cpu, "sw %s, %"PRIiTW"(%s); // ",
+		  rs2_name, s_imm, rs1_name);
+      sim_core_write_unaligned_4 (cpu, cpu->pc, write_map,
+				  cpu->regs[rs1] + s_imm, cpu->regs[rs2]);
+      break;
+    case MATCH_SH:
+      TRACE_INSN (cpu, "sh %s, %"PRIiTW"(%s); // ",
+		  rs2_name, s_imm, rs1_name);
+      sim_core_write_unaligned_2 (cpu, cpu->pc, write_map,
+				  cpu->regs[rs1] + s_imm, cpu->regs[rs2]);
+      break;
+    case MATCH_SB:
+      TRACE_INSN (cpu, "sb %s, %"PRIiTW"(%s); // ",
+		  rs2_name, s_imm, rs1_name);
+      sim_core_write_unaligned_1 (cpu, cpu->pc, write_map,
+				  cpu->regs[rs1] + s_imm, cpu->regs[rs2]);
+      break;
+
+    case MATCH_CSRRC:
+      TRACE_INSN (cpu, "csrrc");
+      switch (csr)
+	{
+#define DECLARE_CSR(name, num) \
+	case num: \
+	  store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
+	  store_csr (cpu, #name, num, &cpu->csr.name, \
+		     cpu->csr.name & !cpu->regs[rs1]); \
+	  break;
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+	}
+      break;
+    case MATCH_CSRRS:
+      TRACE_INSN (cpu, "csrrs");
+      switch (csr)
+	{
+#define DECLARE_CSR(name, num) \
+	case num: \
+	  store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
+	  store_csr (cpu, #name, num, &cpu->csr.name, \
+		     cpu->csr.name | cpu->regs[rs1]); \
+	  break;
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+	}
+      break;
+    case MATCH_CSRRW:
+      TRACE_INSN (cpu, "csrrw");
+      switch (csr)
+	{
+#define DECLARE_CSR(name, num) \
+	case num: \
+	  store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \
+	  store_csr (cpu, #name, num, &cpu->csr.name, cpu->regs[rs1]); \
+	  break;
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+	}
+      break;
+
+    case MATCH_RDCYCLE:
+      TRACE_INSN (cpu, "rdcycle %s;", rd_name);
+      store_rd (cpu, rd, fetch_csr (cpu, "cycle", CSR_CYCLE, &cpu->csr.cycle));
+      break;
+    case MATCH_RDCYCLEH:
+      TRACE_INSN (cpu, "rdcycleh %s;", rd_name);
+      RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd, fetch_csr (cpu, "cycleh", CSR_CYCLEH, &cpu->csr.cycleh));
+      break;
+    case MATCH_RDINSTRET:
+      TRACE_INSN (cpu, "rdinstret %s;", rd_name);
+      store_rd (cpu, rd, fetch_csr (cpu, "instret", CSR_INSTRET, &cpu->csr.instret));
+      break;
+    case MATCH_RDINSTRETH:
+      TRACE_INSN (cpu, "rdinstreth %s;", rd_name);
+      RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd, fetch_csr (cpu, "instreth", CSR_INSTRETH, &cpu->csr.instreth));
+      break;
+    case MATCH_RDTIME:
+      TRACE_INSN (cpu, "rdtime %s;", rd_name);
+      store_rd (cpu, rd, fetch_csr (cpu, "time", CSR_TIME, &cpu->csr.cycle));
+      break;
+    case MATCH_RDTIMEH:
+      TRACE_INSN (cpu, "rdtimeh %s;", rd_name);
+      RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd, fetch_csr (cpu, "timeh", CSR_TIMEH, &cpu->csr.cycleh));
+      break;
+
+    case MATCH_FENCE:
+      TRACE_INSN (cpu, "fence;");
+      break;
+    case MATCH_FENCE_I:
+      TRACE_INSN (cpu, "fence.i;");
+      break;
+    case MATCH_SBREAK:
+      TRACE_INSN (cpu, "sbreak;");
+      /* GDB expects us to step over SBREAK.  */
+      sim_engine_halt (sd, cpu, NULL, cpu->pc + 4, sim_stopped, SIM_SIGTRAP);
+      break;
+    case MATCH_ECALL:
+      TRACE_INSN (cpu, "ecall;");
+      cpu->a0 = sim_syscall (cpu, cpu->a7, cpu->a0, cpu->a1, cpu->a2, cpu->a3);
+      break;
+    default:
+      TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
+      sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
+    }
+
+  return pc;
+}
+
+static unsigned64
+mulhu (unsigned64 a, unsigned64 b)
+{
+  uint64_t t;
+  uint32_t y1, y2, y3;
+  uint64_t a0 = (uint32_t)a, a1 = a >> 32;
+  uint64_t b0 = (uint32_t)b, b1 = b >> 32;
+
+  t = a1*b0 + ((a0*b0) >> 32);
+  y1 = t;
+  y2 = t >> 32;
+
+  t = a0*b1 + y1;
+  y1 = t;
+
+  t = a1*b1 + y2 + (t >> 32);
+  y2 = t;
+  y3 = t >> 32;
+
+  return ((uint64_t)y3 << 32) | y2;
+}
+
+static unsigned64
+mulh (signed64 a, signed64 b)
+{
+  int negate = (a < 0) != (b < 0);
+  uint64_t res = mulhu (a < 0 ? -a : a, b < 0 ? -b : b);
+  return negate ? ~res + (a * b == 0) : res;
+}
+
+static unsigned64
+mulhsu (signed64 a, unsigned64 b)
+{
+  int negate = a < 0;
+  uint64_t res = mulhu (a < 0 ? -a : a, b);
+  return negate ? ~res + (a * b == 0) : res;
+}
+
+static sim_cia
+execute_m (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
+{
+  SIM_DESC sd = CPU_STATE (cpu);
+  int rd = (iw >> OP_SH_RD) & OP_MASK_RD;
+  int rs1 = (iw >> OP_SH_RS1) & OP_MASK_RS1;
+  int rs2 = (iw >> OP_SH_RS2) & OP_MASK_RS2;
+  const char *rd_name = riscv_gpr_names_abi[rd];
+  const char *rs1_name = riscv_gpr_names_abi[rs1];
+  const char *rs2_name = riscv_gpr_names_abi[rs2];
+  unsigned_word tmp, dividend_max;
+  signed_word dividend32_max;
+  sim_cia pc = cpu->pc + 4;
+
+  dividend_max = -((unsigned_word)1 << (WITH_TARGET_WORD_BITSIZE - 1));
+  dividend32_max = INT32_MIN;
+
+  switch (op->match)
+    {
+    case MATCH_DIV:
+      TRACE_INSN (cpu, "div %s, %s, %s;  // %s = %s / %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      if (cpu->regs[rs1] == dividend_max && cpu->regs[rs2] == -1)
+	tmp = dividend_max;
+      else if (cpu->regs[rs2])
+	tmp = (signed_word)cpu->regs[rs1] / (signed_word)cpu->regs[rs2];
+      else
+	tmp = -1;
+      store_rd (cpu, rd, tmp);
+      break;
+    case MATCH_DIVW:
+      TRACE_INSN (cpu, "divw %s, %s, %s;  // %s = %s / %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      if (EXTEND32 (cpu->regs[rs1]) == dividend32_max
+	  && EXTEND32 (cpu->regs[rs2]) == -1)
+	tmp = 1 << 31;
+      else if (EXTEND32 (cpu->regs[rs2]))
+	tmp = EXTEND32 (cpu->regs[rs1]) / EXTEND32 (cpu->regs[rs2]);
+      else
+	tmp = -1;
+      store_rd (cpu, rd, EXTEND32 (tmp));
+      break;
+    case MATCH_DIVU:
+      TRACE_INSN (cpu, "divu %s, %s, %s;  // %s = %s / %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      if (cpu->regs[rs2])
+	store_rd (cpu, rd, (unsigned_word)cpu->regs[rs1]
+			   / (unsigned_word)cpu->regs[rs2]);
+      else
+	store_rd (cpu, rd, -1);
+      break;
+    case MATCH_DIVUW:
+      TRACE_INSN (cpu, "divuw %s, %s, %s;  // %s = %s / %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      if ((unsigned32)cpu->regs[rs2])
+	tmp = (unsigned32)cpu->regs[rs1] / (unsigned32)cpu->regs[rs2];
+      else
+	tmp = -1;
+      store_rd (cpu, rd, EXTEND32 (tmp));
+      break;
+    case MATCH_MUL:
+      TRACE_INSN (cpu, "mul %s, %s, %s;  // %s = %s * %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      store_rd (cpu, rd, cpu->regs[rs1] * cpu->regs[rs2]);
+      break;
+    case MATCH_MULW:
+      TRACE_INSN (cpu, "mulw %s, %s, %s;  // %s = %s * %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd, EXTEND32 ((signed32)cpu->regs[rs1]
+				   * (signed32)cpu->regs[rs2]));
+      break;
+    case MATCH_MULH:
+      TRACE_INSN (cpu, "mulh %s, %s, %s;  // %s = %s * %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      if (RISCV_XLEN (cpu) == 32)
+	store_rd (cpu, rd, ((signed64)(signed_word)cpu->regs[rs1]
+			    * (signed64)(signed_word)cpu->regs[rs2]) >> 32);
+      else
+	store_rd (cpu, rd, mulh (cpu->regs[rs1], cpu->regs[rs2]));
+      break;
+    case MATCH_MULHU:
+      TRACE_INSN (cpu, "mulhu %s, %s, %s;  // %s = %s * %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      if (RISCV_XLEN (cpu) == 32)
+	store_rd (cpu, rd, ((unsigned64)cpu->regs[rs1]
+			    * (unsigned64)cpu->regs[rs2]) >> 32);
+      else
+	store_rd (cpu, rd, mulhu (cpu->regs[rs1], cpu->regs[rs2]));
+      break;
+    case MATCH_MULHSU:
+      TRACE_INSN (cpu, "mulhsu %s, %s, %s;  // %s = %s * %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      if (RISCV_XLEN (cpu) == 32)
+	store_rd (cpu, rd, ((signed64)(signed_word)cpu->regs[rs1]
+			    * (unsigned64)cpu->regs[rs2]) >> 32);
+      else
+	store_rd (cpu, rd, mulhsu (cpu->regs[rs1], cpu->regs[rs2]));
+      break;
+    case MATCH_REM:
+      TRACE_INSN (cpu, "rem %s, %s, %s;  // %s = %s %% %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      if (cpu->regs[rs1] == dividend_max && cpu->regs[rs2] == -1)
+	tmp = 0;
+      else if (cpu->regs[rs2])
+	tmp = (signed_word)cpu->regs[rs1] % (signed_word)cpu->regs[rs2];
+      else
+	tmp = cpu->regs[rs1];
+      store_rd (cpu, rd, tmp);
+      break;
+    case MATCH_REMW:
+      TRACE_INSN (cpu, "remw %s, %s, %s;  // %s = %s %% %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      if (EXTEND32 (cpu->regs[rs1]) == dividend32_max
+	  && EXTEND32 (cpu->regs[rs2]) == -1)
+	tmp = 0;
+      else if (EXTEND32 (cpu->regs[rs2]))
+	tmp = EXTEND32 (cpu->regs[rs1]) % EXTEND32 (cpu->regs[rs2]);
+      else
+	tmp = cpu->regs[rs1];
+      store_rd (cpu, rd, EXTEND32 (tmp));
+      break;
+    case MATCH_REMU:
+      TRACE_INSN (cpu, "remu %s, %s, %s;  // %s = %s %% %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      if (cpu->regs[rs2])
+	store_rd (cpu, rd, cpu->regs[rs1] % cpu->regs[rs2]);
+      else
+	store_rd (cpu, rd, cpu->regs[rs1]);
+      break;
+    case MATCH_REMUW:
+      TRACE_INSN (cpu, "remuw %s, %s, %s;  // %s = %s %% %s",
+		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      if ((unsigned32)cpu->regs[rs2])
+	tmp = (unsigned32)cpu->regs[rs1] % (unsigned32)cpu->regs[rs2];
+      else
+	tmp = cpu->regs[rs1];
+      store_rd (cpu, rd, EXTEND32 (tmp));
+      break;
+    default:
+      TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
+      sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
+    }
+
+  return pc;
+}
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+static sim_cia
+execute_a (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
+{
+  SIM_DESC sd = CPU_STATE (cpu);
+  int rd = (iw >> OP_SH_RD) & OP_MASK_RD;
+  int rs1 = (iw >> OP_SH_RS1) & OP_MASK_RS1;
+  int rs2 = (iw >> OP_SH_RS2) & OP_MASK_RS2;
+  const char *rd_name = riscv_gpr_names_abi[rd];
+  const char *rs1_name = riscv_gpr_names_abi[rs1];
+  const char *rs2_name = riscv_gpr_names_abi[rs2];
+  struct atomic_mem_reserved_list *amo_prev, *amo_curr;
+  unsigned_word tmp;
+  sim_cia pc = cpu->pc + 4;
+
+  /* Handle these two load/store operations specifically.  */
+  switch (op->match)
+    {
+    case MATCH_LR_W:
+      TRACE_INSN (cpu, "%s %s, (%s);", op->name, rd_name, rs1_name);
+      store_rd (cpu, rd,
+	sim_core_read_unaligned_4 (cpu, cpu->pc, read_map, cpu->regs[rs1]));
+
+      /* Walk the reservation list to find an existing match.  */
+      amo_curr = sd->amo_reserved_list;
+      while (amo_curr)
+	{
+	  if (amo_curr->addr == cpu->regs[rs1])
+	    goto done;
+	  amo_curr = amo_curr->next;
+	}
+
+      /* No reservation exists, so add one.  */
+      amo_curr = xmalloc (sizeof (*amo_curr));
+      amo_curr->addr = cpu->regs[rs1];
+      amo_curr->next = sd->amo_reserved_list;
+      sd->amo_reserved_list = amo_curr;
+      goto done;
+    case MATCH_SC_W:
+      TRACE_INSN (cpu, "%s %s, %s, (%s);", op->name, rd_name, rs2_name, rs1_name);
+
+      /* Walk the reservation list to find a match.  */
+      amo_curr = amo_prev = sd->amo_reserved_list;
+      while (amo_curr)
+	{
+	  if (amo_curr->addr == cpu->regs[rs1])
+	    {
+	      /* We found a reservation, so operate it.  */
+	      sim_core_write_unaligned_4 (cpu, cpu->pc, write_map,
+					  cpu->regs[rs1], cpu->regs[rs2]);
+	      store_rd (cpu, rd, 0);
+	      if (amo_curr == sd->amo_reserved_list)
+		sd->amo_reserved_list = amo_curr->next;
+	      else
+		amo_prev->next = amo_curr->next;
+	      free (amo_curr);
+	      goto done;
+	    }
+	  amo_prev = amo_curr;
+	  amo_curr = amo_curr->next;
+	}
+
+      /* If we're still here, then no reservation exists, so mark as failed.  */
+      store_rd (cpu, rd, 1);
+      goto done;
+    }
+
+  /* Handle the rest of the atomic insns with common code paths.  */
+  TRACE_INSN (cpu, "%s %s, %s, (%s);",
+	      op->name, rd_name, rs2_name, rs1_name);
+  if (op->subset[0] == '6')
+    store_rd (cpu, rd,
+      sim_core_read_unaligned_8 (cpu, cpu->pc, read_map, cpu->regs[rs1]));
+  else
+    store_rd (cpu, rd, EXTEND32 (
+      sim_core_read_unaligned_4 (cpu, cpu->pc, read_map, cpu->regs[rs1])));
+
+  switch (op->match)
+    {
+    case MATCH_AMOADD_D:
+    case MATCH_AMOADD_W:
+      tmp = cpu->regs[rd] + cpu->regs[rs2];
+      break;
+    case MATCH_AMOAND_D:
+    case MATCH_AMOAND_W:
+      tmp = cpu->regs[rd] & cpu->regs[rs2];
+      break;
+    case MATCH_AMOMAX_D:
+    case MATCH_AMOMAX_W:
+      tmp = MAX ((signed_word)cpu->regs[rd], (signed_word)cpu->regs[rs2]);
+      break;
+    case MATCH_AMOMAXU_D:
+    case MATCH_AMOMAXU_W:
+      tmp = MAX ((unsigned_word)cpu->regs[rd], (unsigned_word)cpu->regs[rs2]);
+      break;
+    case MATCH_AMOMIN_D:
+    case MATCH_AMOMIN_W:
+      tmp = MIN ((signed_word)cpu->regs[rd], (signed_word)cpu->regs[rs2]);
+      break;
+    case MATCH_AMOMINU_D:
+    case MATCH_AMOMINU_W:
+      tmp = MIN ((unsigned_word)cpu->regs[rd], (unsigned_word)cpu->regs[rs2]);
+      break;
+    case MATCH_AMOOR_D:
+    case MATCH_AMOOR_W:
+      tmp = cpu->regs[rd] | cpu->regs[rs2];
+      break;
+    case MATCH_AMOSWAP_D:
+    case MATCH_AMOSWAP_W:
+      tmp = cpu->regs[rs2];
+      break;
+    case MATCH_AMOXOR_D:
+    case MATCH_AMOXOR_W:
+      tmp = cpu->regs[rd] ^ cpu->regs[rs2];
+      break;
+    default:
+      TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
+      sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
+    }
+
+  if (op->subset[0] == '6')
+    sim_core_write_unaligned_8 (cpu, cpu->pc, write_map, cpu->regs[rs1], tmp);
+  else
+    sim_core_write_unaligned_4 (cpu, cpu->pc, write_map, cpu->regs[rs1], tmp);
+
+ done:
+  return pc;
+}
+
+static sim_cia
+execute_one (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
+{
+  SIM_DESC sd = CPU_STATE (cpu);
+  const char *subset = op->subset;
+
+ rescan:
+  switch (subset[0])
+    {
+    case 'A':
+      return execute_a (cpu, iw, op);
+    case 'I':
+      return execute_i (cpu, iw, op);
+    case 'M':
+      return execute_m (cpu, iw, op);
+    case '3':
+      if (subset[1] == '2')
+	{
+	  RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name);
+	  subset += 2;
+	  goto rescan;
+	}
+      goto case_default;
+    case '6':
+      if (subset[1] == '4')
+	{
+	  RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+	  subset += 2;
+	  goto rescan;
+	}
+      goto case_default;
+    case_default:
+    default:
+      TRACE_INSN (cpu, "UNHANDLED EXTENSION: %s", op->subset);
+      sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
+    }
+
+  return cpu->pc + riscv_insn_length (iw);
+}
+
+/* Decode & execute a single instruction.  */
+void step_once (SIM_CPU *cpu)
+{
+  SIM_DESC sd = CPU_STATE (cpu);
+  unsigned_word iw;
+  unsigned int len;
+  sim_cia pc = cpu->pc;
+  const struct riscv_opcode *op;
+
+  if (TRACE_ANY_P (cpu))
+    trace_prefix (sd, cpu, NULL_CIA, pc, TRACE_LINENUM_P (cpu),
+		  NULL, 0, " "); /* Use a space for gcc warnings.  */
+
+  iw = sim_core_read_aligned_2 (cpu, pc, exec_map, pc);
+
+  /* Reject non-32-bit opcodes first.  */
+  len = riscv_insn_length (iw);
+  if (len != 4)
+    {
+      sim_io_printf (sd, "sim: bad insn len %#x @ %#"PRIxTA": %#"PRIxTW"\n",
+		     len, pc, iw);
+      sim_engine_halt (sd, cpu, NULL, pc, sim_signalled, SIM_SIGILL);
+    }
+
+  iw |= ((unsigned_word)sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2) << 16);
+
+  TRACE_CORE (cpu, "0x%08"PRIxTW, iw);
+
+  op = riscv_hash[OP_HASH_IDX (iw)];
+  if (!op)
+    sim_engine_halt (sd, cpu, NULL, pc, sim_signalled, SIM_SIGILL);
+
+  for (; op->name; op++)
+    if ((op->match_func) (op, iw) && !(op->pinfo & INSN_ALIAS))
+      {
+	pc = execute_one (cpu, iw, op);
+	break;
+      }
+
+  /* TODO: Handle overflow into high 32 bits.  */
+  /* TODO: Try to use a common counter and only update on demand (reads).  */
+  ++cpu->csr.cycle;
+  ++cpu->csr.instret;
+
+  cpu->pc = pc;
+}
+\f
+/* Return the program counter for this cpu. */
+static sim_cia
+pc_get (sim_cpu *cpu)
+{
+  return cpu->pc;
+}
+
+/* Set the program counter for this cpu to the new pc value. */
+static void
+pc_set (sim_cpu *cpu, sim_cia pc)
+{
+  cpu->pc = pc;
+}
+
+static int
+reg_fetch (sim_cpu *cpu, int rn, unsigned char *buf, int len)
+{
+  if (len <= 0 || len > sizeof (unsigned_word))
+    return -1;
+
+  switch (rn)
+    {
+    case SIM_RISCV_RA_REGNUM ... SIM_RISCV_T6_REGNUM:
+      memcpy (buf, &cpu->regs[rn], len);
+      return len;
+    case SIM_RISCV_FIRST_FP_REGNUM ... SIM_RISCV_LAST_FP_REGNUM:
+      memcpy (buf, &cpu->fpregs[rn], len);
+      return len;
+    case SIM_RISCV_PC_REGNUM:
+      memcpy (buf, &cpu->pc, len);
+      return len;
+
+#define DECLARE_CSR(name, num) \
+    case SIM_RISCV_ ## num ## _REGNUM: \
+      memcpy (buf, &cpu->csr.name, len); \
+      return len;
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+
+    default:
+      return -1;
+    }
+}
+
+static int
+reg_store (sim_cpu *cpu, int rn, unsigned char *buf, int len)
+{
+  if (len <= 0 || len > sizeof (unsigned_word))
+    return -1;
+
+  switch (rn)
+    {
+    case SIM_RISCV_RA_REGNUM ... SIM_RISCV_T6_REGNUM:
+      memcpy (&cpu->regs[rn], buf, len);
+      return len;
+    case SIM_RISCV_FIRST_FP_REGNUM ... SIM_RISCV_LAST_FP_REGNUM:
+      memcpy (&cpu->fpregs[rn], buf, len);
+      return len;
+    case SIM_RISCV_PC_REGNUM:
+      memcpy (&cpu->pc, buf, len);
+      return len;
+
+#define DECLARE_CSR(name, num) \
+    case SIM_RISCV_ ## num ## _REGNUM: \
+      memcpy (&cpu->csr.name, buf, len); \
+      return len;
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+
+    default:
+      return -1;
+    }
+}
+
+/* Initialize the state for a single cpu.  Usuaully this involves clearing all
+   registers back to their reset state.  Should also hook up the fetch/store
+   helper functions too.  */
+void initialize_cpu (SIM_DESC sd, SIM_CPU *cpu, int mhartid)
+{
+  const char *extensions;
+  int i;
+
+  memset (cpu->regs, 0, sizeof (cpu->regs));
+
+  CPU_PC_FETCH (cpu) = pc_get;
+  CPU_PC_STORE (cpu) = pc_set;
+  CPU_REG_FETCH (cpu) = reg_fetch;
+  CPU_REG_STORE (cpu) = reg_store;
+
+  if (!riscv_hash[0])
+    {
+      const struct riscv_opcode *op;
+
+      for (op = riscv_opcodes; op->name; op++)
+	if (!riscv_hash[OP_HASH_IDX (op->match)])
+	  riscv_hash[OP_HASH_IDX (op->match)] = op;
+    }
+
+  cpu->csr.misa = 0;
+  /* RV32 sets this field to 0, and we don't really support RV128 yet.  */
+  if (RISCV_XLEN (cpu) == 64)
+    cpu->csr.misa |= (unsigned64)2 << 62;
+
+  /* Skip the leading "rv" prefix and the two numbers.  */
+  extensions = MODEL_NAME (CPU_MODEL (cpu)) + 4;
+  for (i = 0; i < 26; ++i)
+    {
+      char ext = 'A' + i;
+
+      if (ext == 'X')
+	continue;
+      else if (strchr (extensions, ext) != NULL)
+	{
+	  if (ext == 'G')
+	    cpu->csr.misa |= 0x1129;  /* G = IMAFD.  */
+	  else
+	    cpu->csr.misa |= (1 << i);
+	}
+    }
+
+  cpu->csr.mimpid = 0x8000;
+  cpu->csr.mhartid = mhartid;
+}
+\f
+/* Some utils don't like having a NULL environ.  */
+static const char * const simple_env[] = { "HOME=/", "PATH=/bin", NULL };
+
+/* Count the number of arguments in an argv.  */
+static int
+count_argv (const char * const *argv)
+{
+  int i;
+
+  if (!argv)
+    return -1;
+
+  for (i = 0; argv[i] != NULL; ++i)
+    continue;
+  return i;
+}
+
+void initialize_env (SIM_DESC sd, const char * const *argv,
+		     const char * const *env)
+{
+  SIM_CPU *cpu = STATE_CPU (sd, 0);
+  int i;
+  int argc, argv_flat;
+  int envc, env_flat;
+  address_word sp, sp_flat;
+  unsigned char null[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
+
+  /* Figure out how many bytes the argv strings take up.  */
+  argc = count_argv (argv);
+  if (argc == -1)
+    argc = 0;
+  argv_flat = argc; /* NUL bytes.  */
+  for (i = 0; i < argc; ++i)
+    argv_flat += strlen (argv[i]);
+
+  /* Figure out how many bytes the environ strings take up.  */
+  if (!env)
+    env = simple_env;
+  envc = count_argv (env);
+  env_flat = envc; /* NUL bytes.  */
+  for (i = 0; i < envc; ++i)
+    env_flat += strlen (env[i]);
+
+  /* Make space for the strings themselves.  */
+  sp_flat = (DEFAULT_MEM_SIZE - argv_flat - env_flat) & -sizeof (address_word);
+  /* Then the pointers to the strings.  */
+  sp = sp_flat - ((argc + 1 + envc + 1) * sizeof (address_word));
+  /* Then the argc.  */
+  sp -= sizeof (unsigned_word);
+
+  /* Set up the regs the libgloss crt0 expects.  */
+  cpu->a0 = argc;
+  cpu->sp = sp;
+
+  /* First push the argc value.  */
+  sim_write (sd, sp, (void *)&argc, sizeof (unsigned_word));
+  sp += sizeof (unsigned_word);
+
+  /* Then the actual argv strings so we know where to point argv[].  */
+  for (i = 0; i < argc; ++i)
+    {
+      unsigned len = strlen (argv[i]) + 1;
+      sim_write (sd, sp_flat, (void *)argv[i], len);
+      sim_write (sd, sp, (void *)&sp_flat, sizeof (address_word));
+      sp_flat += len;
+      sp += sizeof (address_word);
+    }
+  sim_write (sd, sp, null, sizeof (address_word));
+  sp += sizeof (address_word);
+
+  /* Then the actual env strings so we know where to point env[].  */
+  for (i = 0; i < envc; ++i)
+    {
+      unsigned len = strlen (env[i]) + 1;
+      sim_write (sd, sp_flat, (void *)env[i], len);
+      sim_write (sd, sp, (void *)&sp_flat, sizeof (address_word));
+      sp_flat += len;
+      sp += sizeof (address_word);
+    }
+}
diff --git a/sim/riscv/sim-main.h b/sim/riscv/sim-main.h
new file mode 100644
index 0000000..6e53587
--- /dev/null
+++ b/sim/riscv/sim-main.h
@@ -0,0 +1,87 @@
+/* RISC-V simulator.
+
+   Copyright (C) 2005-2014 Free Software Foundation, Inc.
+   Contributed by Mike Frysinger.
+
+   This file is part of simulators.
+
+   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 SIM_MAIN_H
+#define SIM_MAIN_H
+
+#include "tconfig.h"
+#include "sim-basics.h"
+#include "machs.h"
+#include "sim-base.h"
+
+struct _sim_cpu {
+  union {
+    unsigned_word regs[32];
+    struct {
+      /* These are the ABI names.  */
+      unsigned_word zero, ra, sp, gp, tp;
+      unsigned_word t0, t1, t2;
+      unsigned_word s0, s1;
+      unsigned_word a0, a1, a2, a3, a4, a5, a6, a7;
+      unsigned_word s2, s3, s4, s5, s6, s7, s8, s9, s10, s11;
+      unsigned_word t3, t4, t5, t6;
+    };
+  };
+  union {
+    unsigned_word fpregs[32];
+    struct {
+      /* These are the ABI names.  */
+      unsigned_word ft0, ft1, ft2, ft3, ft4, ft5, ft6, ft7;
+      unsigned_word fs0, fs1;
+      unsigned_word fa0, fa1, fa2, fa3, fa4, fa5, fa6, fa7;
+      unsigned_word fs2, fs3, fs4, fs5, fs6, fs7, fs8, fs9, fs10, fs11;
+      unsigned_word ft8, ft9, ft10, ft11;
+    };
+  };
+  sim_cia pc;
+
+  struct {
+#define DECLARE_CSR(name, num) unsigned_word name;
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+  } csr;
+
+  sim_cpu_base base;
+};
+
+struct atomic_mem_reserved_list;
+struct atomic_mem_reserved_list {
+  struct atomic_mem_reserved_list *next;
+  address_word addr;
+};
+
+struct sim_state {
+  sim_cpu *cpu[MAX_NR_PROCESSORS];
+  struct atomic_mem_reserved_list *amo_reserved_list;
+
+  /* ... simulator specific members ... */
+  sim_state_base base;
+};
+
+extern void step_once (SIM_CPU *);
+extern void initialize_cpu (SIM_DESC, SIM_CPU *, int);
+extern void initialize_env (SIM_DESC, const char * const *argv,
+			    const char * const *env);
+
+#define DEFAULT_MEM_SIZE (16 * 1024 * 1024)
+
+#define RISCV_XLEN(cpu) MACH_WORD_BITSIZE (CPU_MACH (cpu))
+
+#endif
diff --git a/sim/riscv/tconfig.h b/sim/riscv/tconfig.h
new file mode 100644
index 0000000..25e6a79
--- /dev/null
+++ b/sim/riscv/tconfig.h
@@ -0,0 +1,4 @@
+/* RISC-V target configuration file.  -*- C -*- */
+
+/* ??? Temporary hack until model support unified.  */
+#define SIM_HAVE_MODEL
diff --git a/sim/testsuite/sim/riscv/ChangeLog b/sim/testsuite/sim/riscv/ChangeLog
new file mode 100644
index 0000000..72dd0c3
--- /dev/null
+++ b/sim/testsuite/sim/riscv/ChangeLog
@@ -0,0 +1,3 @@
+2015-03-29  Mike Frysinger  <vapier@gentoo.org>
+
+	* allinsn.exp, exit-0.s, exit-7.s, isa.inc, testutils.inc: New files.
diff --git a/sim/testsuite/sim/riscv/allinsn.exp b/sim/testsuite/sim/riscv/allinsn.exp
new file mode 100644
index 0000000..4ed7cff
--- /dev/null
+++ b/sim/testsuite/sim/riscv/allinsn.exp
@@ -0,0 +1,15 @@
+# mcore simulator testsuite
+
+if [istarget riscv-*] {
+    # all machines
+    set all_machs "riscv"
+
+    foreach src [lsort [glob -nocomplain $srcdir/$subdir/*.s]] {
+	# If we're only testing specific files and this isn't one of them,
+	# skip it.
+	if ![runtest_file_p $runtests $src] {
+	    continue
+	}
+	run_sim_test $src $all_machs
+    }
+}
diff --git a/sim/testsuite/sim/riscv/pass.s b/sim/testsuite/sim/riscv/pass.s
new file mode 100644
index 0000000..bd428ca
--- /dev/null
+++ b/sim/testsuite/sim/riscv/pass.s
@@ -0,0 +1,7 @@
+# check that the sim doesn't die immediately.
+# mach: riscv
+
+.include "testutils.inc"
+
+	start
+	pass
diff --git a/sim/testsuite/sim/riscv/testutils.inc b/sim/testsuite/sim/riscv/testutils.inc
new file mode 100644
index 0000000..bb92ac0
--- /dev/null
+++ b/sim/testsuite/sim/riscv/testutils.inc
@@ -0,0 +1,50 @@
+# MACRO: exit
+	.macro exit nr
+	li a0, \nr
+	# The exit utility function.
+	li a7, 93;
+	.endm
+
+# MACRO: pass
+# Write 'pass' to stdout and quit
+	.macro pass
+	# syscall write().
+	li a7, 64;
+	# Use stdout.
+	li a0, 1;
+	# Point to the string.
+	lla a1, 1f;
+	# Number of bytes to write.
+	li a2, 5;
+	# Trigger OS trap.
+	ecall;
+	exit 0;
+	.data
+	1: .asciz "pass\n"
+	.endm
+
+# MACRO: fail
+# Write 'fail' to stdout and quit
+	.macro fail
+	# syscall write();
+	li a7, 64;
+	# Use stdout.
+	li a0, 1;
+	# Point to the string.
+	lla a1, 1f;
+	# Number of bytes to write.
+	li a2, 5;
+	# Trigger OS trap.
+	ecall;
+	exit 0;
+	.data
+	1: .asciz "fail\n"
+	.endm
+
+# MACRO: start
+# All assembler tests should start with a call to "start"
+	.macro start
+	.text
+.global _start
+_start:
+	.endm
-- 
2.10.2

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

* RISC-V GDB Port v3
@ 2017-03-06 20:31 Palmer Dabbelt
  2017-03-06 20:31 ` [PATCH 1/2] RISC-V GDB Port Palmer Dabbelt
                   ` (4 more replies)
  0 siblings, 5 replies; 17+ messages in thread
From: Palmer Dabbelt @ 2017-03-06 20:31 UTC (permalink / raw)
  To: gdb-patches

Sorry it took me so long to get around to all the feedback, I was trying to
finish up grad school so I could start working full time on RISC-V software and
the GDB port fell through the cracks.  This is now part of my job, so hopefully
I'll be able to be better about this in the future.

I've attempted to fix all the outstanding comments with the v2 patch set, but
since it's been a while I'm not 100% sure I got everything.  Here's the
differences I remember since v2:

 * Changes the frame walking code to use riscv-opc.h instead of hard-coded
   constants.

 * Don't call deprecated functions when printing FP registers.

 * Use the sw_breakpoint_from_kind interface.

 * Add a RISC-V XML target description file, but I think it doesn't do anything
   yet.

I think the only thing I know of that's bad is the target XML description file,
which I don't think works yet.  That said, I want to send this patch set out
just so we can all get on the same page.

If I understand correctly, GDB-8 is set to be branched on the 15th so if I can
fix up our port quickly we can still get it in?

Sorry this took so long!

[PATCH 1/2] RISC-V GDB Port
[PATCH 2/2] RISC-V sim Port

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

* Re: RISC-V GDB Port v3
  2017-03-06 20:31 RISC-V GDB Port v3 Palmer Dabbelt
  2017-03-06 20:31 ` [PATCH 1/2] RISC-V GDB Port Palmer Dabbelt
  2017-03-06 20:31 ` [PATCH 2/2] RISC-V sim Port Palmer Dabbelt
@ 2017-03-10 19:38 ` Palmer Dabbelt
  2017-03-21  9:23 ` Yao Qi
  2017-04-05  9:30 ` Yao Qi
  4 siblings, 0 replies; 17+ messages in thread
From: Palmer Dabbelt @ 2017-03-10 19:38 UTC (permalink / raw)
  To: gdb-patches

On Mon, 06 Mar 2017 20:30:27 PST (-0800), Palmer Dabbelt wrote:
> Sorry it took me so long to get around to all the feedback, I was trying to
> finish up grad school so I could start working full time on RISC-V software and
> the GDB port fell through the cracks.  This is now part of my job, so hopefully
> I'll be able to be better about this in the future.
>
> I've attempted to fix all the outstanding comments with the v2 patch set, but
> since it's been a while I'm not 100% sure I got everything.  Here's the
> differences I remember since v2:
>
>  * Changes the frame walking code to use riscv-opc.h instead of hard-coded
>    constants.
>
>  * Don't call deprecated functions when printing FP registers.
>
>  * Use the sw_breakpoint_from_kind interface.
>
>  * Add a RISC-V XML target description file, but I think it doesn't do anything
>    yet.
>
> I think the only thing I know of that's bad is the target XML description file,
> which I don't think works yet.  That said, I want to send this patch set out
> just so we can all get on the same page.
>
> If I understand correctly, GDB-8 is set to be branched on the 15th so if I can
> fix up our port quickly we can still get it in?
>
> Sorry this took so long!
>
> [PATCH 1/2] RISC-V GDB Port
> [PATCH 2/2] RISC-V sim Port

I just wanted to ping this patch set because I haven't gotten any comment all
week.  Does anyone have any reviews, or do the patches look OK this time
around?

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

* Re: RISC-V GDB Port v3
  2017-03-06 20:31 RISC-V GDB Port v3 Palmer Dabbelt
                   ` (2 preceding siblings ...)
  2017-03-10 19:38 ` RISC-V GDB Port v3 Palmer Dabbelt
@ 2017-03-21  9:23 ` Yao Qi
  2017-03-21 16:04   ` Palmer Dabbelt
  2017-04-05  9:30 ` Yao Qi
  4 siblings, 1 reply; 17+ messages in thread
From: Yao Qi @ 2017-03-21  9:23 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: gdb-patches

Palmer Dabbelt <palmer@dabbelt.com> writes:

> I think the only thing I know of that's bad is the target XML description file,
> which I don't think works yet.  That said, I want to send this patch set out
> just so we can all get on the same page.
>
> If I understand correctly, GDB-8 is set to be branched on the 15th so if I can
> fix up our port quickly we can still get it in?

Hi Palmer,
I don't have cycles reviewing the patches now, because of 8.0 release.
I can only offer some time after 8.0 release.

-- 
Yao (齐尧)

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

* Re: RISC-V GDB Port v3
  2017-03-21  9:23 ` Yao Qi
@ 2017-03-21 16:04   ` Palmer Dabbelt
  0 siblings, 0 replies; 17+ messages in thread
From: Palmer Dabbelt @ 2017-03-21 16:04 UTC (permalink / raw)
  To: qiyaoltc; +Cc: gdb-patches

On Tue, 21 Mar 2017 02:23:09 PDT (-0700), qiyaoltc@gmail.com wrote:
> Palmer Dabbelt <palmer@dabbelt.com> writes:
>
>> I think the only thing I know of that's bad is the target XML description file,
>> which I don't think works yet.  That said, I want to send this patch set out
>> just so we can all get on the same page.
>>
>> If I understand correctly, GDB-8 is set to be branched on the 15th so if I can
>> fix up our port quickly we can still get it in?
>
> Hi Palmer,
> I don't have cycles reviewing the patches now, because of 8.0 release.
> I can only offer some time after 8.0 release.

That's OK.  Can you just send a mail when you're ready to review?  If I have
anything meaningful then I'll spin a v4 for you.

Thanks for your time!

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

* Re: [PATCH 1/2] RISC-V GDB Port
  2017-03-06 20:31 ` [PATCH 1/2] RISC-V GDB Port Palmer Dabbelt
@ 2017-04-04 21:48   ` Yao Qi
  2017-04-24 16:12     ` Palmer Dabbelt
  2017-04-05  9:22   ` Yao Qi
  1 sibling, 1 reply; 17+ messages in thread
From: Yao Qi @ 2017-04-04 21:48 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: gdb-patches

Palmer Dabbelt <palmer@dabbelt.com> writes:

Hi,
I have some time today, so I can review the patch.

>  gdb/Makefile.in                 |    5 +
>  gdb/config/riscv/linux.mh       |   30 +
>  gdb/features/Makefile           |    2 +
>  gdb/features/riscv.c            |   86 +++
>  gdb/features/riscv.xml          |   81 +++
>  gdb/gdbserver/linux-riscv-low.c |  221 +++++++
>  gdb/regformats/riscv.dat        |   69 ++
>  gdb/riscv-linux-nat.c           |   77 +++
>  gdb/riscv-linux-tdep.c          |   80 +++
>  gdb/riscv-linux-tdep.h          |   30 +
>  gdb/riscv-tdep.c                | 1368 +++++++++++++++++++++++++++++++++++++++
>  gdb/riscv-tdep.h                |   96 +++
>  include/gdb/sim-riscv.h         |   98 +++

Before I read the patch further, my suggestion is to split your patch
to following parts next time,

 - bare metal support, riscv-tdep.c
 - linux target support, riscv-linux-tdep.c,
 - linux host support, riscv-linux-nat.c,
 - gdbserver support, gdbserver/linux-riscv-low.c
 - target description,

I am surprised that there is no change to gdb/testsuite/.

-- 
Yao (齐尧)

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

* Re: [PATCH 1/2] RISC-V GDB Port
  2017-03-06 20:31 ` [PATCH 1/2] RISC-V GDB Port Palmer Dabbelt
  2017-04-04 21:48   ` Yao Qi
@ 2017-04-05  9:22   ` Yao Qi
  1 sibling, 0 replies; 17+ messages in thread
From: Yao Qi @ 2017-04-05  9:22 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: gdb-patches

Palmer Dabbelt <palmer@dabbelt.com> writes:

> diff --git a/gdb/config/riscv/linux.mh b/gdb/config/riscv/linux.mh
> new file mode 100644
> index 0000000..4ec9f47
> --- /dev/null
> +++ b/gdb/config/riscv/linux.mh
> @@ -0,0 +1,30 @@
> +#  Host: RISC-V based machine running GNU/Linux
> +#
> +#  Copyright (C) 2016 Free Software Foundation, Inc.

2016 - 2017

> +#  Contributed by Albert Ou <albert@sifive.com>.

Remove this line, because of
https://sourceware.org/gdb/wiki/ContributionChecklist#Attribution

> diff --git a/gdb/features/riscv.xml b/gdb/features/riscv.xml
> new file mode 100644
> index 0000000..94e630c
> --- /dev/null
> +++ b/gdb/features/riscv.xml
> @@ -0,0 +1,81 @@
> +<?xml version="1.0"?>
> +<!-- Copyright (C) 2015-2017 Free Software Foundation, Inc.
> +
> +     Copying and distribution of this file, with or without modification,
> +     are permitted in any medium without royalty provided the copyright
> +     notice and this notice are preserved.  -->
> +
> +<!DOCTYPE target SYSTEM "gdb-target.dtd">
> +<target>
> +  <architecture>riscv:rv64</architecture>
> +
> +  <feature name="org.gnu.gdb.riscv.rv64i">

You defined this feature, but this feature is not used else where.

> +
> +static struct regset_info riscv_regsets[] =
> +{
> +  { PTRACE_GETREGS, PTRACE_SETREGS, 0, riscv_num_regs * 8,

https://github.com/riscv/riscv-linux/blob/master/arch/riscv/kernel/ptrace.c
tells that riscv kernel support regset, so why don't you do

     { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS,
      .....


> +    GENERAL_REGS, riscv_fill_gregset, riscv_store_gregset },
> +  NULL_REGSET
> +};

> diff --git a/gdb/riscv-linux-nat.c b/gdb/riscv-linux-nat.c
> new file mode 100644
> index 0000000..6accb7a
> --- /dev/null
> +++ b/gdb/riscv-linux-nat.c
> @@ -0,0 +1,77 @@
> +/* Native-dependent code for GNU/Linux RISC-V.
> +
> +   Copyright (C) 2015 Free Software Foundation, Inc.

2015 - 2017

> +   Contributed by Albert Ou <albert@sifive.com>.

Please remove this line.

> +
> +   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/>.  */
> +



> +
> +#define DECLARE_INSN(INSN_NAME, INSN_MATCH, INSN_MASK) \
> +static inline bool is_ ## INSN_NAME ## _insn (long insn) \
> +{ \
> +  return (insn & INSN_MASK) == INSN_MATCH; \
> +}
> +#include "opcode/riscv-opc.h"
> +#undef DECLARE_INSN
> +
> +struct riscv_frame_cache
> +{
> +  CORE_ADDR base;
> +  struct trad_frame_saved_reg *saved_regs;
> +};
> +
> +static const char * const riscv_gdb_reg_names[RISCV_LAST_FP_REGNUM + 1] =
> +{
> +  "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
> +  "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
> +  "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
> +  "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
> +  "pc",
> +  "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
> +  "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
> +  "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
> +  "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
> +};
> +
> +struct register_alias
> +{
> +  const char *name;
> +  int regnum;
> +};
> +
> +static const struct register_alias riscv_register_aliases[] =
> +{
> +  { "zero", 0 },
> +  { "ra", 1 },
> +  { "sp", 2 },
> +  { "gp", 3 },
> +  { "tp", 4 },
> +  { "t0", 5 },
> +  { "t1", 6 },
> +  { "t2", 7 },
> +  { "fp", 8 },
> +  { "s0", 8 },
> +  { "s1", 9 },
> +  { "a0", 10 },
> +  { "a1", 11 },
> +  { "a2", 12 },
> +  { "a3", 13 },
> +  { "a4", 14 },
> +  { "a5", 15 },
> +  { "a6", 16 },
> +  { "a7", 17 },
> +  { "s2", 18 },
> +  { "s3", 19 },
> +  { "s4", 20 },
> +  { "s5", 21 },
> +  { "s6", 22 },
> +  { "s7", 23 },
> +  { "s8", 24 },
> +  { "s9", 25 },
> +  { "s10", 26 },
> +  { "s11", 27 },
> +  { "t3", 28 },
> +  { "t4", 29 },
> +  { "t5", 30 },
> +  { "t6", 31 },
> +  /* pc is 32.  */
> +  { "ft0", 33 },
> +  { "ft1", 34 },
> +  { "ft2", 35 },
> +  { "ft3", 36 },
> +  { "ft4", 37 },
> +  { "ft5", 38 },
> +  { "ft6", 39 },
> +  { "ft7", 40 },
> +  { "fs0", 41 },
> +  { "fs1", 42 },
> +  { "fa0", 43 },
> +  { "fa1", 44 },
> +  { "fa2", 45 },
> +  { "fa3", 46 },
> +  { "fa4", 47 },
> +  { "fa5", 48 },
> +  { "fa6", 49 },
> +  { "fa7", 50 },
> +  { "fs2", 51 },
> +  { "fs3", 52 },
> +  { "fs4", 53 },
> +  { "fs5", 54 },
> +  { "fs6", 55 },
> +  { "fs7", 56 },
> +  { "fs8", 57 },
> +  { "fs9", 58 },
> +  { "fs10", 59 },
> +  { "fs11", 60 },
> +  { "ft8", 61 },
> +  { "ft9", 62 },
> +  { "ft10", 63 },
> +  { "ft11", 64 },
> +#define DECLARE_CSR(name, num) { #name, (num) + 65 },
> +#include "opcode/riscv-opc.h"
> +#undef DECLARE_CSR
> +};
> +
> +static enum auto_boolean use_compressed_breakpoints;
> +/*
> +static void
> +show_use_compressed_breakpoints (struct ui_file *file, int from_tty,
> +			    struct cmd_list_element *c,
> +			    const char *value)
> +{
> +  fprintf_filtered (file,
> +		    _("Debugger's behavior regarding "
> +		      "compressed breakpoints is %s.\n"),
> +		    value);
> +}
> +*/

Remove it.

> +
> +static struct cmd_list_element *setriscvcmdlist = NULL;
> +static struct cmd_list_element *showriscvcmdlist = NULL;
> +
> +static void
> +show_riscv_command (char *args, int from_tty)
> +{
> +  help_list (showriscvcmdlist, "show riscv ", all_commands, gdb_stdout);
> +}
> +
> +static void
> +set_riscv_command (char *args, int from_tty)
> +{
> +  printf_unfiltered
> +    ("\"set riscv\" must be followed by an appropriate subcommand.\n");
> +  help_list (setriscvcmdlist, "set riscv ", all_commands, gdb_stdout);
> +}
> +
> +/* Implement the breakpoint_kind_from_pc gdbarch method.  */
> +
> +static int
> +riscv_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
> +{
> +  if (use_compressed_breakpoints == AUTO_BOOLEAN_AUTO) {

"{" should be in the new line.

> +    if (gdbarch_tdep (gdbarch)->supports_compressed_isa == AUTO_BOOLEAN_AUTO)

supports_compressed_isa's type can be "enum tribool".

> +    {
> +      /* TODO: Because we try to read misa, it is not possible to set a
> +         breakpoint before connecting to a live target. A suggested workaround is
> +         to look at the ELF file in this case.  */
> +      struct frame_info *frame = get_current_frame ();

The information of using compressed isa should be saved in ELF, and GDB
read it from ELF.

> +      uint32_t misa = get_frame_register_unsigned (frame, RISCV_CSR_MISA_REGNUM);
> +      if (misa & (1<<2))
> +        gdbarch_tdep (gdbarch)->supports_compressed_isa = AUTO_BOOLEAN_TRUE;
> +      else
> +        gdbarch_tdep (gdbarch)->supports_compressed_isa = AUTO_BOOLEAN_FALSE;
> +    }
> +
> +    if (gdbarch_tdep (gdbarch)->supports_compressed_isa == AUTO_BOOLEAN_TRUE)
> +      return 2;
> +    else
> +      return 4;
> +  } else if (use_compressed_breakpoints == AUTO_BOOLEAN_TRUE) {
> +    return 2;
> +  } else {
> +    return 4;
> +  }
> +}
> +
> +/* Implement the sw_breakpoint_from_kind gdbarch method.  */
> +
> +static const gdb_byte *
> +riscv_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
> +{
> +  static const gdb_byte ebreak[] = { 0x73, 0x00, 0x10, 0x00, };
> +  static const gdb_byte c_ebreak[] = { 0x02, 0x90 };
> +
> +  *size = kind;
> +  switch (kind)
> +    {
> +    case 2:
> +      return c_ebreak;
> +    case 4:
> +      return ebreak;
> +    default:
> +      gdb_assert(0);

gdb_assert_not_reached?

> +    }
> +}
> +
> +static struct value *
> +value_of_riscv_user_reg (struct frame_info *frame, const void *baton)
> +{
> +  const int *reg_p = (const int *)baton;
> +
> +  return value_of_register (*reg_p, frame);
> +}
> +
> +static const char *
> +register_name (struct gdbarch *gdbarch,
> +	       int regnum,
> +	       int prefer_alias)
> +{
> +  int i;
> +  static char buf[20];
> +
> +  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
> +    return tdesc_register_name (gdbarch, regnum);
> +  /* Prefer to use the alias. */
> +  if (prefer_alias &&
> +      regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_REGNUM)
> +    {
> +      for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i)
> +	if (regnum == riscv_register_aliases[i].regnum)
> +	  return riscv_register_aliases[i].name;
> +    }

If you prefer alias over the tdesc register name, put this block in
front of tdesc_register_name.

> +
> +  if (regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
> +      return riscv_gdb_reg_names[regnum];

If target description is always available, this is not needed.

> +
> +  if (regnum >= RISCV_FIRST_CSR_REGNUM && regnum <= RISCV_LAST_CSR_REGNUM)
> +    {
> +      sprintf(buf, "csr%d", regnum - RISCV_FIRST_CSR_REGNUM);
> +      return buf;
> +    }
> +
> +  if (regnum == RISCV_PRIV_REGNUM)
> +    {
> +      return "priv";
> +    }
> +
> +  return NULL;
> +}
> +
> +/* Implement the register_name gdbarch method.  */
> +
> +static const char *
> +riscv_register_name (struct gdbarch *gdbarch,
> +		     int regnum)
> +{
> +  return register_name(gdbarch, regnum, 0);

space before "(".

> +}
> +
> +/* Reads a function return value of type TYPE.  */
> +
> +static void
> +riscv_extract_return_value (struct type *type,
> +			    struct regcache *regs,
> +			    gdb_byte *dst,
> +			    int regnum)
> +{
> +  struct gdbarch *gdbarch = get_regcache_arch (regs);
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +  int regsize = riscv_isa_regsize (gdbarch);
> +  bfd_byte *valbuf = dst;
> +  int len = TYPE_LENGTH (type);
> +  int st_len = std::min (regsize, len);
> +  ULONGEST tmp;
> +
> +  gdb_assert (len <= 2 * regsize);
> +
> +  while (len > 0)
> +    {
> +      regcache_cooked_read_unsigned (regs, regnum++, &tmp);
> +      store_unsigned_integer (valbuf, st_len, byte_order, tmp);
> +      len -= regsize;
> +      valbuf += regsize;
> +    }
> +}
> +
> +/* Write into appropriate registers a function return value of type
> +   TYPE, given in virtual format.  */
> +
> +static void
> +riscv_store_return_value (struct type *type,
> +			  struct regcache *regs,
> +			  const gdb_byte *src,
> +			  int regnum)
> +{
> +  struct gdbarch *gdbarch = get_regcache_arch (regs);
> +  int regsize = riscv_isa_regsize (gdbarch);
> +  const bfd_byte *valbuf = src;
> +
> +  /* Integral values greater than one word are stored in consecutive
> +     registers starting with R0.  This will always be a multiple of
> +     the register size.  */
> +
> +  int len = TYPE_LENGTH (type);
> +
> +  gdb_assert (len <= 2 * regsize);
> +
> +  while (len > 0)
> +    {
> +      regcache_cooked_write (regs, regnum++, valbuf);
> +      len -= regsize;
> +      valbuf += regsize;
> +    }
> +}
> +
> +/* Implement the return_value gdbarch method.  */
> +
> +static enum return_value_convention
> +riscv_return_value (struct gdbarch  *gdbarch,
> +		    struct value *function,
> +		    struct type *type,
> +		    struct regcache *regcache,
> +		    gdb_byte *readbuf,
> +		    const gdb_byte *writebuf)
> +{
> +  enum type_code rv_type = TYPE_CODE (type);
> +  unsigned int rv_size = TYPE_LENGTH (type);
> +  int fp, regnum;
> +  ULONGEST tmp;
> +
> +  /* Paragraph on return values taken from RISC-V specification (post v2.0):
> +
> +     Values are returned from functions in integer registers a0 and a1 and
> +     floating-point registers fa0 and fa1.  Floating-point values are returned
> +     in floating-point registers only if they are primitives or members of a
> +     struct consisting of only one or two floating-point values.  Other return
> +     values that fit into two pointer-words are returned in a0 and a1.  Larger
> +     return values are passed entirely in memory; the caller allocates this
> +     memory region and passes a pointer to it as an implicit first parameter
> +     to the callee.  */
> +
> +  /* Deal with struct/unions first that are passed via memory.  */
> +  if (rv_size > 2 * riscv_isa_regsize (gdbarch))
> +    {
> +      if (readbuf || writebuf)
> +	regcache_cooked_read_unsigned (regcache, RISCV_A0_REGNUM, &tmp);
> +      if (readbuf)
> +	read_memory (tmp, readbuf, rv_size);
> +      if (writebuf)
> +	write_memory (tmp, writebuf, rv_size);
> +      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
> +    }
> +
> +  /* Are we dealing with a floating point value?  */
> +  fp = 0;

pass_arg_in_fp = false;

> +  if (rv_type == TYPE_CODE_FLT)
> +    fp = 1;
> +  else if (rv_type == TYPE_CODE_STRUCT || rv_type == TYPE_CODE_UNION)
> +    {
> +      unsigned int rv_fields = TYPE_NFIELDS (type);
> +
> +      if (rv_fields == 1)
> +	{
> +	  struct type *fieldtype = TYPE_FIELD_TYPE (type, 0);
> +	  if (TYPE_CODE (check_typedef (fieldtype)) == TYPE_CODE_FLT)
> +	    fp = 1;
> +	}
> +      else if (rv_fields == 2)
> +	{
> +	  struct type *fieldtype0 = TYPE_FIELD_TYPE (type, 0);
> +	  struct type *fieldtype1 = TYPE_FIELD_TYPE (type, 1);
> +
> +	  if (TYPE_CODE (check_typedef (fieldtype0)) == TYPE_CODE_FLT
> +	      && TYPE_CODE (check_typedef (fieldtype1)) == TYPE_CODE_FLT)
> +	    fp = 1;
> +	}
> +    }
> +

> +  /* Handle return value in a register.  */
> +  regnum = fp ? RISCV_FA0_REGNUM : RISCV_A0_REGNUM;
> +
> +  if (readbuf)
> +    riscv_extract_return_value (type, regcache, readbuf, regnum);
> +
> +  if (writebuf)
> +    riscv_store_return_value (type, regcache, writebuf, regnum);
> +
> +  return RETURN_VALUE_REGISTER_CONVENTION;
> +}
> +
> +/* Implement the pseudo_register_read gdbarch method.  */
> +
> +static enum register_status
> +riscv_pseudo_register_read (struct gdbarch *gdbarch,
> +			    struct regcache *regcache,
> +			    int regnum,
> +			    gdb_byte *buf)
> +{
> +  return regcache_raw_read (regcache, regnum, buf);
> +}
> +
> +/* Implement the pseudo_register_write gdbarch method.  */
> +
> +static void
> +riscv_pseudo_register_write (struct gdbarch *gdbarch,
> +			     struct regcache *regcache,
> +			     int cookednum,
> +			     const gdb_byte *buf)
> +{
> +  regcache_raw_write (regcache, cookednum, buf);
> +}

I don't see riscv has pseudo registers.

> +
> +static void
> +riscv_print_register_formatted (struct ui_file *file, struct frame_info *frame,
> +				int regnum)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (frame);
> +  gdb_byte raw_buffer[MAX_REGISTER_SIZE];
> +  struct value_print_options opts;
> +
> +  if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
> +    riscv_print_fp_register (file, frame, regnum);
> +  else
> +    {
> +      /* Integer type.  */
> +      int offset, size;
> +      unsigned long long d;
> +
> +      if (!deprecated_frame_register_read (frame, regnum, raw_buffer))

Don't use deprecated_frame_register_read, use other frame apis.

> +	{
> +	  fprintf_filtered (file, "%-15s[Invalid]\n",
> +			    register_name (gdbarch, regnum, 1));
> +	  return;
> +	}
> +
> +      fprintf_filtered (file, "%-15s", register_name (gdbarch, regnum, 1));
> +      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
> +	offset = register_size (gdbarch, regnum) - register_size (gdbarch, regnum);

offset is zero.

> +      else
> +	offset = 0;
> +
> +      size = register_size (gdbarch, regnum);
> +      get_formatted_print_options (&opts, 'x');
> +      print_scalar_formatted (raw_buffer + offset,
> +			      register_type (gdbarch, regnum), &opts,
> +			      size == 8 ? 'g' : 'w', file);
> +      fprintf_filtered (file, "\t");
> +      if (size == 4 && riscv_isa_regsize (gdbarch) == 8)
> +	fprintf_filtered (file, "\t");
> +
> +      if (regnum == RISCV_CSR_MSTATUS_REGNUM)
> +	{
> +	  if (size == 4)
> +	    d = unpack_long (builtin_type (gdbarch)->builtin_uint32, raw_buffer);
> +	  else if (size == 8)
> +	    d = unpack_long (builtin_type (gdbarch)->builtin_uint64, raw_buffer);
> +	  else
> +	    internal_error (__FILE__, __LINE__, _("unknown size for mstatus"));
> +	  unsigned xlen = size * 4;
> +	  fprintf_filtered (file,
> +			    "SD:%X VM:%02X MXR:%X PUM:%X MPRV:%X XS:%X "
> +			    "FS:%X MPP:%x HPP:%X SPP:%X MPIE:%X HPIE:%X "
> +			    "SPIE:%X UPIE:%X MIE:%X HIE:%X SIE:%X UIE:%X",
> +			    (int)((d >> (xlen-1)) & 0x1),
> +			    (int)((d >> 24) & 0x1f),
> +			    (int)((d >> 19) & 0x1),
> +			    (int)((d >> 18) & 0x1),
> +			    (int)((d >> 17) & 0x1),
> +			    (int)((d >> 15) & 0x3),
> +			    (int)((d >> 13) & 0x3),
> +			    (int)((d >> 11) & 0x3),
> +			    (int)((d >> 9) & 0x3),
> +			    (int)((d >> 8) & 0x1),
> +			    (int)((d >> 7) & 0x1),
> +			    (int)((d >> 6) & 0x1),
> +			    (int)((d >> 5) & 0x1),
> +			    (int)((d >> 4) & 0x1),
> +			    (int)((d >> 3) & 0x1),
> +			    (int)((d >> 2) & 0x1),
> +			    (int)((d >> 1) & 0x1),
> +			    (int)((d >> 0) & 0x1));
> +	}
> +      else if (regnum == RISCV_CSR_MISA_REGNUM)
> +        {
> +          int base;
> +          if (size == 4) {
> +            d = unpack_long (builtin_type (gdbarch)->builtin_uint32, raw_buffer);
> +            base = d >> 30;
> +          } else if (size == 8) {
> +            d = unpack_long (builtin_type (gdbarch)->builtin_uint64, raw_buffer);
> +            base = d >> 62;
> +          } else {
> +            internal_error (__FILE__, __LINE__, _("unknown size for misa"));
> +          }
> +          unsigned xlen = 16;
> +          for (; base > 0; base--) {
> +            xlen *= 2;
> +          }
> +	  fprintf_filtered (file, "RV%d", xlen);
> +
> +          for (unsigned i = 0; i < 26; i++) {
> +            if (d & (1<<i)) {
> +              fprintf_filtered (file, "%c", 'A' + i);
> +            }
> +          }
> +        }
> +      else if (regnum == RISCV_CSR_FCSR_REGNUM
> +	       || regnum == RISCV_CSR_FFLAGS_REGNUM
> +	       || regnum == RISCV_CSR_FRM_REGNUM)
> +	{
> +	  d = unpack_long (builtin_type (gdbarch)->builtin_int32, raw_buffer);
> +
> +	  if (regnum != RISCV_CSR_FRM_REGNUM)
> +	    fprintf_filtered (file, "RD:%01X NV:%d DZ:%d OF:%d UF:%d NX:%d   ",
> +			      (int)((d >> 5) & 0x7),
> +			      (int)((d >> 4) & 0x1),
> +			      (int)((d >> 3) & 0x1),
> +			      (int)((d >> 2) & 0x1),
> +			      (int)((d >> 1) & 0x1),
> +			      (int)((d >> 0) & 0x1));
> +
> +	  if (regnum != RISCV_CSR_FFLAGS_REGNUM)
> +	    {
> +	      static const char * const sfrm[] = {
> +		"RNE (round to nearest; ties to even)",
> +		"RTZ (Round towards zero)",
> +		"RDN (Round down towards -∞)",
> +		"RUP (Round up towards +∞)",
> +		"RMM (Round to nearest; tiest to max magnitude)",
> +		"INVALID[5]",
> +		"INVALID[6]",
> +		"dynamic rounding mode",
> +	      };
> +	      int frm = ((regnum == RISCV_CSR_FCSR_REGNUM) ? (d >> 5) : d) & 0x3;
> +
> +	      fprintf_filtered (file, "FRM:%i [%s]", frm, sfrm[frm]);
> +	    }
> +	}
> +      else if (regnum == RISCV_PRIV_REGNUM)
> +        {
> +          uint8_t priv = raw_buffer[0];
> +          if (priv >= 0 && priv < 4)
> +            {
> +              static const char * const sprv[] = {
> +                "User/Application",
> +                "Supervisor",
> +                "Hypervisor",
> +                "Machine"
> +              };
> +              fprintf_filtered (file, "prv:%d [%s]", priv, sprv[priv]);
> +            }
> +          else
> +            {
> +              fprintf_filtered (file, "prv:%d [INVALID]", priv);
> +            }
> +        }
> +      else
> +	{
> +	  get_formatted_print_options (&opts, 'd');
> +	  print_scalar_formatted (raw_buffer + offset,
> +				  register_type (gdbarch, regnum),
> +				  &opts, 0, file);
> +	}
> +    }
> +  fprintf_filtered (file, "\n");
> +}
> +
> +/* Implement the register_reggroup_p gdbarch method.  */
> +
> +static int
> +riscv_register_reggroup_p (struct gdbarch  *gdbarch,
> +			   int regnum,
> +			   struct reggroup *reggroup)
> +{
> +  int float_p;
> +  int raw_p;
> +  unsigned int i;
> +
> +  /* Used by 'info registers' and 'info registers <groupname>'.  */
> +
> +  if (gdbarch_register_name (gdbarch, regnum) == NULL
> +      || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
> +    return 0;
> +
> +  if (reggroup == all_reggroup) {

"{" should be put to next line.  Many instances of this style problems.



> +
> +static ULONGEST
> +riscv_fetch_instruction (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> +  enum bfd_endian byte_order = gdbarch_byte_order_for_code (gdbarch);
> +  gdb_byte buf[8];
> +  int instlen, status;
> +
> +  /* All insns are at least 16 bits.  */
> +  status = target_read_memory (addr, buf, 2);

Use target_read_code.

> +  if (status)
> +    memory_error (TARGET_XFER_E_IO, addr);
> +
> +  /* If we need more, grab it now.  */
> +  instlen = riscv_insn_length (buf[0]);
> +  if (instlen > sizeof (buf))
> +    internal_error (__FILE__, __LINE__, _("%s: riscv_insn_length returned %i"),
> +		    __func__, instlen);
> +  else if (instlen > 2)
> +    {
> +      status = target_read_memory (addr + 2, buf + 2, instlen - 2);

Likewise.

> +      if (status)
> +	memory_error (TARGET_XFER_E_IO, addr + 2);
> +    }
> +
> +  return extract_unsigned_integer (buf, instlen, byte_order);
> +}
> +
> +static void
> +set_reg_offset (struct gdbarch *gdbarch, struct riscv_frame_cache *this_cache,
> +		int regnum, CORE_ADDR offset)

Comments of this function is missing.  Some instances of this problem.

> +{
> +  if (this_cache != NULL && this_cache->saved_regs[regnum].addr == -1)
> +    this_cache->saved_regs[regnum].addr = offset;
> +}
> +

> +
> +static CORE_ADDR
> +riscv_scan_prologue (struct gdbarch *gdbarch,
> +		     CORE_ADDR start_pc, CORE_ADDR limit_pc,
> +		     struct frame_info *this_frame,
> +		     struct riscv_frame_cache *this_cache)
> +{
> +  CORE_ADDR cur_pc;
> +  CORE_ADDR frame_addr = 0;
> +  CORE_ADDR sp;
> +  long frame_offset;
> +  int frame_reg = RISCV_SP_REGNUM;
> +
> +  CORE_ADDR end_prologue_addr = 0;
> +  int seen_sp_adjust = 0;

s/int/bool/

> +  int load_immediate_bytes = 0;
> +
> +  /* Can be called when there's no process, and hence when there's no THIS_FRAME.  */
> +  if (this_frame != NULL)
> +    sp = get_frame_register_signed (this_frame, RISCV_SP_REGNUM);
> +  else
> +    sp = 0;
> +
> +  if (limit_pc > start_pc + 200)
> +    limit_pc = start_pc + 200;
> +
> + restart:
> +
> +  frame_offset = 0;
> +  /* TODO: Handle compressed extensions.  */

Is compressed extension handled?

> +  for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4)

looks not, because cur_pc is increased by 4.


> +
> +static struct trad_frame_cache *
> +riscv_frame_cache (struct frame_info *this_frame, void **this_cache)
> +{
> +  CORE_ADDR pc;
> +  CORE_ADDR start_addr;
> +  CORE_ADDR stack_addr;
> +  struct trad_frame_cache *this_trad_cache;
> +  struct gdbarch *gdbarch = get_frame_arch (this_frame);
> +
> +  if ((*this_cache) != NULL)
> +    return (struct trad_frame_cache *) *this_cache;
> +  this_trad_cache = trad_frame_cache_zalloc (this_frame);
> +  (*this_cache) = this_trad_cache;
> +
> +  trad_frame_set_reg_realreg (this_trad_cache, gdbarch_pc_regnum (gdbarch),
> +			      RISCV_RA_REGNUM);
> +
> +  pc = get_frame_pc (this_frame);
> +  find_pc_partial_function (pc, NULL, &start_addr, NULL);
> +  stack_addr = get_frame_register_signed (this_frame, RISCV_SP_REGNUM);

get_frame_register_unsiged?

> +  trad_frame_set_id (this_trad_cache, frame_id_build (stack_addr, start_addr));
> +
> +  trad_frame_set_this_base (this_trad_cache, stack_addr);
> +
> +  return this_trad_cache;
> +}
> +

> +
> +static const struct frame_unwind riscv_frame_unwind =
> +{
> +  /*.type          =*/ NORMAL_FRAME,

Usually, we put such comment at the end of each statement, like

  NORMAL_FRAME,  /* type */

> +  /*.stop_reason   =*/ default_frame_unwind_stop_reason,
> +  /*.this_id       =*/ riscv_frame_this_id,
> +  /*.prev_register =*/ riscv_frame_prev_register,
> +  /*.unwind_data   =*/ NULL,
> +  /*.sniffer       =*/ default_frame_sniffer,
> +  /*.dealloc_cache =*/ NULL,
> +  /*.prev_arch     =*/ NULL,
> +};
> +
> +static struct gdbarch *
> +riscv_gdbarch_init (struct gdbarch_info info,
> +		    struct gdbarch_list *arches)
> +{
> +  struct gdbarch *gdbarch;
> +  struct gdbarch_tdep *tdep;
> +  const struct bfd_arch_info *binfo = info.bfd_arch_info;
> +
> +  int abi, i;
> +
> +  /* For now, base the abi on the elf class.  */
> +  /* Allow the ELF class to override the register size. Ideally the target
> +   * (OpenOCD/spike/...) would communicate the register size to gdb instead. */
> +  abi = RISCV_ABI_FLAG_RV32I;
> +  if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
> +    {
> +      unsigned char eclass = elf_elfheader (info.abfd)->e_ident[EI_CLASS];
> +
> +      if (eclass == ELFCLASS32)
> +	abi = RISCV_ABI_FLAG_RV32I;
> +      else if (eclass == ELFCLASS64)
> +	abi = RISCV_ABI_FLAG_RV64I;
> +      else
> +        internal_error (__FILE__, __LINE__, _("unknown ELF header class %d"), eclass);
> +    }
> +  else
> +    {
> +      if (binfo->bits_per_word == 32)
> +        abi = RISCV_ABI_FLAG_RV32I;
> +      else if (binfo->bits_per_word == 64)
> +        abi = RISCV_ABI_FLAG_RV64I;
> +      else
> +        internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"),
> +            binfo->bits_per_word);

Do you support object file format other than ELF?

> +    }
> +
> +  /* 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)->riscv_abi == abi)
> +      return arches->gdbarch;
> +
> +  /* None found, so create a new architecture from the information provided.
> +     Can't initialize all the target dependencies until we actually know which
> +     target we are talking to, but put in some defaults for now.  */
> +
> +  tdep = (struct gdbarch_tdep *) xmalloc (sizeof *tdep);
> +  gdbarch = gdbarch_alloc (&info, tdep);
> +
> +  tdep->riscv_abi = abi;
> +  tdep->supports_compressed_isa = AUTO_BOOLEAN_AUTO;
> +
> +  /* Target data types.  */
> +  set_gdbarch_short_bit (gdbarch, 16);
> +  set_gdbarch_int_bit (gdbarch, 32);
> +  set_gdbarch_long_bit (gdbarch, riscv_isa_regsize (gdbarch) * 8);
> +  set_gdbarch_float_bit (gdbarch, 32);
> +  set_gdbarch_double_bit (gdbarch, 64);
> +  set_gdbarch_long_double_bit (gdbarch, 128);
> +  set_gdbarch_ptr_bit (gdbarch, riscv_isa_regsize (gdbarch) * 8);
> +  set_gdbarch_char_signed (gdbarch, 1);
> +
> +  /* Information about the target architecture.  */
> +  set_gdbarch_return_value (gdbarch, riscv_return_value);
> +  set_gdbarch_breakpoint_kind_from_pc (gdbarch, riscv_breakpoint_kind_from_pc);
> +  set_gdbarch_sw_breakpoint_from_kind (gdbarch, riscv_sw_breakpoint_from_kind);
> +  set_gdbarch_print_insn (gdbarch, print_insn_riscv);
> +
> +  /* Register architecture.  */
> +  set_gdbarch_pseudo_register_read (gdbarch, riscv_pseudo_register_read);
> +  set_gdbarch_pseudo_register_write (gdbarch, riscv_pseudo_register_write);
> +  set_gdbarch_num_regs (gdbarch, RISCV_NUM_REGS);
> +  set_gdbarch_num_pseudo_regs (gdbarch, RISCV_NUM_REGS);
> +  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);
> +  set_gdbarch_frame_align (gdbarch, riscv_frame_align);
> +
> +  /* Functions to access frame data.  */
> +  set_gdbarch_unwind_pc (gdbarch, riscv_unwind_pc);
> +  set_gdbarch_unwind_sp (gdbarch, riscv_unwind_sp);
> +
> +  /* Functions handling dummy frames.  */
> +  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
> +  set_gdbarch_push_dummy_code (gdbarch, riscv_push_dummy_code);
> +  set_gdbarch_push_dummy_call (gdbarch, riscv_push_dummy_call);
> +  set_gdbarch_dummy_id (gdbarch, riscv_dummy_id);
> +
> +  /* Frame unwinders.  Use DWARF debug info if available, otherwise use our own
> +     unwinder.  */
> +  dwarf2_append_unwinders (gdbarch);
> +  frame_unwind_append_unwinder (gdbarch, &riscv_frame_unwind);
> +
> +  /* Check any target description for validity.  */
> +  if (tdesc_has_registers (info.target_desc))
> +    {
> +      const struct tdesc_feature *feature;
> +      struct tdesc_arch_data *tdesc_data;
> +      int valid_p;
> +
> +      feature = tdesc_find_feature (info.target_desc, "org.gnu.gdb.riscv.cpu");
> +      if (feature == NULL)
> +	goto no_tdata;
> +

Don't use "goto".

> +      tdesc_data = tdesc_data_alloc ();
> +
> +      valid_p = 1;
> +      for (i = RISCV_ZERO_REGNUM; i <= RISCV_LAST_FP_REGNUM; ++i)
> +        valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
> +                                            riscv_gdb_reg_names[i]);
> +      for (i = RISCV_FIRST_CSR_REGNUM; i <= RISCV_LAST_CSR_REGNUM; ++i)
> +        {
> +          char buf[20];
> +          sprintf (buf, "csr%d", i - RISCV_FIRST_CSR_REGNUM);
> +          valid_p &= tdesc_numbered_register (feature, tdesc_data, i, buf);
> +        }
> +
> +      valid_p &= tdesc_numbered_register (feature, tdesc_data, i++, "priv");
> +
> +      if (!valid_p)
> +	tdesc_data_cleanup (tdesc_data);
> +      else
> +	tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
> +    }
> + no_tdata:
> +
> +  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);
> +
> +  return gdbarch;
> +}
> +


> +
> +/* All the official RISC-V ABIs.  These mostly line up with mcpuid purely for
> +   convenience.  */
> +#define RISCV_ABI_FLAG_RV32I	(0x00000000)	/* 32-bit Integer GPRs.  */
> +#define RISCV_ABI_FLAG_RV64I	(0x40000000)	/* 64-bit Integer GPRs.  */
> +#define RISCV_ABI_FLAG_D	(1 << 3)	/* Double-Precision Floating-Point.  */
> +#define RISCV_ABI_FLAG_F	(1 << 5)	/* Single-Precision Floating-Point.  */
> +
> +#define IS_RV32I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV32I)
> +#define IS_RV64I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV64I)
> +
> +#define HAS_FPU(x)	((x) & (RISCV_ABI_FLAG_D | RISCV_ABI_FLAG_F))
> +
> +enum {
> +  RISCV_ZERO_REGNUM = 0,	/* Read-only register, always 0.  */
> +  RISCV_RA_REGNUM = 1,		/* Return Address.  */
> +  RISCV_SP_REGNUM = 2,		/* Stack Pointer.  */
> +  RISCV_GP_REGNUM = 3,		/* Global Pointer.  */
> +  RISCV_TP_REGNUM = 4,		/* Thread Pointer.  */
> +  RISCV_FP_REGNUM = 8,		/* Frame Pointer.  */
> +  RISCV_A0_REGNUM = 10,		/* First argument.  */
> +  RISCV_A1_REGNUM = 11,		/* Second argument.  */
> +  RISCV_PC_REGNUM = 32,		/* Program Counter.  */
> +
> +  RISCV_FIRST_FP_REGNUM = 33,	/* First Floating Point Register */
> +  RISCV_FA0_REGNUM = 49,
> +  RISCV_FA1_REGNUM = 50,
> +  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_LAST_FP_REGNUM + 1 + num,
> +#include "opcode/riscv-opc.h"
> +#undef DECLARE_CSR
> +  RISCV_LAST_CSR_REGNUM = 4160,
> +
> +  RISCV_PRIV_REGNUM = 4161,
> +
> +  /* Leave this as the last enum.  */
> +  RISCV_NUM_REGS
> +};
> +
> +#define RISCV_LAST_REGNUM (RISCV_NUM_REGS - 1)
> +
> +/* RISC-V specific per-architecture information.  */
> +struct gdbarch_tdep
> +{
> +  int riscv_abi;
> +  enum auto_boolean supports_compressed_isa;
> +};
> +
> +static inline int
> +riscv_isa_regsize (struct gdbarch *gdbarch)

Can you move it to tdep.c file?

> +{
> +  int abi = gdbarch_tdep (gdbarch)->riscv_abi;
> +
> +  switch (abi)
> +    {
> +      case RISCV_ABI_FLAG_RV32I:
> +	return 4;
> +      case RISCV_ABI_FLAG_RV64I:
> +	return 8;
> +      default:
> +	internal_error (__FILE__, __LINE__, _("unknown abi %i"), abi);
> +	return 4;
> +    }
> +}
> +


-- 
Yao (齐尧)

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

* Re: RISC-V GDB Port v3
  2017-03-06 20:31 RISC-V GDB Port v3 Palmer Dabbelt
                   ` (3 preceding siblings ...)
  2017-03-21  9:23 ` Yao Qi
@ 2017-04-05  9:30 ` Yao Qi
  4 siblings, 0 replies; 17+ messages in thread
From: Yao Qi @ 2017-04-05  9:30 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: gdb-patches

Palmer Dabbelt <palmer@dabbelt.com> writes:

>  * Add a RISC-V XML target description file, but I think it doesn't do anything
>    yet.
>
> I think the only thing I know of that's bad is the target XML description file,
> which I don't think works yet.  That said, I want to send this patch set out
> just so we can all get on the same page.

If it doesn't work, don't have to add them.  XML target description is
not mandatory.  The target description in your patch is for 64-bit
gpr.  Does riscv has 32-bit gpr?  If so, you need another xml file for
32-bit gprs.

-- 
Yao (齐尧)

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

* Re: [PATCH 1/2] RISC-V GDB Port
  2017-04-04 21:48   ` Yao Qi
@ 2017-04-24 16:12     ` Palmer Dabbelt
  0 siblings, 0 replies; 17+ messages in thread
From: Palmer Dabbelt @ 2017-04-24 16:12 UTC (permalink / raw)
  To: qiyaoltc; +Cc: gdb-patches

On Tue, 04 Apr 2017 14:48:24 PDT (-0700), qiyaoltc@gmail.com wrote:
> Palmer Dabbelt <palmer@dabbelt.com> writes:
>
> Hi,
> I have some time today, so I can review the patch.
>
>>  gdb/Makefile.in                 |    5 +
>>  gdb/config/riscv/linux.mh       |   30 +
>>  gdb/features/Makefile           |    2 +
>>  gdb/features/riscv.c            |   86 +++
>>  gdb/features/riscv.xml          |   81 +++
>>  gdb/gdbserver/linux-riscv-low.c |  221 +++++++
>>  gdb/regformats/riscv.dat        |   69 ++
>>  gdb/riscv-linux-nat.c           |   77 +++
>>  gdb/riscv-linux-tdep.c          |   80 +++
>>  gdb/riscv-linux-tdep.h          |   30 +
>>  gdb/riscv-tdep.c                | 1368 +++++++++++++++++++++++++++++++++++++++
>>  gdb/riscv-tdep.h                |   96 +++
>>  include/gdb/sim-riscv.h         |   98 +++
>
> Before I read the patch further, my suggestion is to split your patch
> to following parts next time,
>
>  - bare metal support, riscv-tdep.c
>  - linux target support, riscv-linux-tdep.c,
>  - linux host support, riscv-linux-nat.c,
>  - gdbserver support, gdbserver/linux-riscv-low.c
>  - target description,

Thanks for all the time you've spent on this, I'll try to get the port in
better shape.

> I am surprised that there is no change to gdb/testsuite/.

We've generally not tested things well, I'll have some tests for the next
round.

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

* Re: [PATCH 1/2] RISC-V GDB Port
  2016-11-14 22:39       ` Palmer Dabbelt
  2016-11-16 19:36         ` Pedro Alves
@ 2016-11-16 21:40         ` Yao Qi
  1 sibling, 0 replies; 17+ messages in thread
From: Yao Qi @ 2016-11-16 21:40 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: Andrew Waterman, gdb-patches, Alan Modra

On Mon, Nov 14, 2016 at 10:39 PM, Palmer Dabbelt <palmer@dabbelt.com> wrote:
>>
>> /* Implement the return_value gdbarch method.  */
>
> I'm not sure what you mean by this.
>

I suggested that such comment is needed to any gdbarch methods implemented
for riscv.  In this case, it is riscv_return_value.

>>> +
>>> +static enum return_value_convention
>>> +riscv_return_value (struct gdbarch  *gdbarch,
>>> +                struct value *function,
>>> +                struct type     *type,
>>> +                struct regcache *regcache,
>>> +                gdb_byte        *readbuf,
>>> +                const gdb_byte  *writebuf)
>>

>> /* Implement the XXX gdbarch method.  */
>
> I'm afraid I'm not sure what you're trying to say here, sorry!
>

Likewise.  Such comments are needed.

>>> +{
>>> +  return regcache_raw_read (regcache, regnum, buf);
>>> +}
>>> +
>>
>>> +

>>> +static void
>>> +riscv_read_fp_register_single (struct frame_info *frame, int regno,
>>> +                           gdb_byte *rare_buffer)
>>> +{
>>> +  struct gdbarch *gdbarch = get_frame_arch (frame);
>>> +  int raw_size = register_size (gdbarch, regno);
>>> +  gdb_byte *raw_buffer = (gdb_byte *) alloca (raw_size);
>>> +
>>> +  if (!deprecated_frame_register_read (frame, regno, raw_buffer))
>>
>> Use get_frame_register_value, your code can be simpler.
>
> MIPS (where this code came from) still uses the deprecated function.  I can't
> figure out why this was deprecated or why MIPS is still using the old version,
> and since this code does dangerous looking things (silently copying half of a
> double-precision float) I'm not really sure how to change it.
>

riscv_read_fp_register_single is called for printing registers, so you can
use value and print it via val_print.  Then, riscv_read_fp_register_single can
be removed.  Just grep get_frame_register_value, and see how it is used
in other ports.

>>> +
>>> +static void
>>> +set_reg_offset (struct gdbarch *gdbarch, struct riscv_frame_cache *this_cache,
>>> +            int regnum, CORE_ADDR offset)
>>> +{
>>> +  if (this_cache != NULL && this_cache->saved_regs[regnum].addr == -1)
>>> +    this_cache->saved_regs[regnum].addr = offset;
>>> +}
>>> +
>>> +static void
>>> +reset_saved_regs (struct gdbarch *gdbarch, struct riscv_frame_cache *this_cache)
>>> +{
>>> +  const int num_regs = gdbarch_num_regs (gdbarch);
>>> +  int i;
>>> +
>>> +  if (this_cache == NULL || this_cache->saved_regs == NULL)
>>> +    return;
>>> +
>>> +  for (i = 0; i < num_regs; ++i)
>>> +    this_cache->saved_regs[i].addr = -1;
>>
>> IIRC, .addr's type is CORE_ADDR, which is unsigned.  Don't assign -1 to
>> a unsigned type.
>
> It looks like this is another one we got from MIPS.  I'm OK changing it, but
> I'm not sure what the implications are.  I think 0 is the sanest value to put
> in there?
>
>   https://github.com/riscv/riscv-binutils-gdb/commit/73656f235a8b7cedaab10ee49bbc55dbf02e86ce
>
> If that looks OK to you then I can go try to figure out if it's the right thing
> to do.
>

save_regs is a an array of struct trad_frame_saved_reg, and the type of
.addr is LONGEST, so it would be fine to set it to -1.  I withdraw my comments
on this.

>>> +      opcode = inst & 0x7F;
>>> +      reg = (inst >> 7) & 0x1F;
>>> +      rs1 = (inst >> 15) & 0x1F;
>>> +      imm12 = (inst >> 20) & 0xFFF;
>>> +      rs2 = (inst >> 20) & 0x1F;
>>> +      offset12 = (((inst >> 25) & 0x7F) << 5) + ((inst >> 7) & 0x1F);
>>> +      funct3 = (inst >> 12) & 0x7;
>>> +
>>> +      /* Look for common stack adjustment insns.  */
>>> +      if ((opcode == 0x13 || opcode == 0x1B) && reg == RISCV_SP_REGNUM
>>> +      && rs1 == RISCV_SP_REGNUM)
>>
>> Please use macros defined in include/opcode/riscv-opc.h, then the code
>> is much more readable.
>
> I agree.  Whoever wrote this code must have either not known about riscv-opc.h,
> or not liked those macros.  I added a FIXME for now
>
>   https://github.com/riscv/riscv-binutils-gdb/commit/1b58570b0310850290ed5355776e78192e893d71
>

Well, FIXME is not enough :-)  Please replace these magic numbers with macro.

-- 
Yao (齐尧)

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

* Re: [PATCH 1/2] RISC-V GDB Port
  2016-11-16 19:40           ` Palmer Dabbelt
@ 2016-11-16 19:48             ` Pedro Alves
  0 siblings, 0 replies; 17+ messages in thread
From: Pedro Alves @ 2016-11-16 19:48 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: qiyaoltc, Andrew Waterman, gdb-patches, amodra

On 11/16/2016 07:40 PM, Palmer Dabbelt wrote:
> On Wed, 16 Nov 2016 11:36:29 PST (-0800), palves@redhat.com wrote:
>> On 11/14/2016 10:39 PM, Palmer Dabbelt wrote:
>>>>>>> +
>>>>>>> +  /* Check any target description for validity.  */
>>>>>>> +  if (tdesc_has_registers (info.target_desc))
>>>>>>> +    {
>>>>>
>>>>> We don't have riscv target description yet.
>>> Yes.  I'm amenable to adding one, but I'm not sure how.
>>>
>>
>> You should really add them.  Take a look at the ARC port,
>> which was recently added:
>>
>>   https://sourceware.org/ml/gdb-patches/2016-09/msg00248.html
> 
> Great, thanks -- I was looking for .dtd files, not .xml files.  

dtd files are standard xml Document Type Definition files.
The dtd file in question is features/gdb-target.dtd.  
I.e., the xml file you'll write follows that dtd.

> From looking at
> their port, it looks like I want to add a
> 
>   gdb/features/riscv.xml

Yup.

> 
> patterned off of
> 
>   gdb/features/arc-v2.xml
> 
> It looks like there's a whole bunch of examples in there, so if I'm on the
> right track I can probably figure it out.

See here too:

 https://sourceware.org/gdb/onlinedocs/gdb/Target-Description-Format.html

FYI, with target descriptions, the remote stub send a target description
that includes whatever custom registers the chip has, and gdb will
include them in "info registers", etc. all without any gdb modification.

Thanks,
Pedro Alves

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

* Re: [PATCH 1/2] RISC-V GDB Port
  2016-11-16 19:36         ` Pedro Alves
@ 2016-11-16 19:40           ` Palmer Dabbelt
  2016-11-16 19:48             ` Pedro Alves
  0 siblings, 1 reply; 17+ messages in thread
From: Palmer Dabbelt @ 2016-11-16 19:40 UTC (permalink / raw)
  To: palves; +Cc: qiyaoltc, Andrew Waterman, gdb-patches, amodra

On Wed, 16 Nov 2016 11:36:29 PST (-0800), palves@redhat.com wrote:
> On 11/14/2016 10:39 PM, Palmer Dabbelt wrote:
>>>> >> +
>>>> >> +  /* Check any target description for validity.  */
>>>> >> +  if (tdesc_has_registers (info.target_desc))
>>>> >> +    {
>>> >
>>> > We don't have riscv target description yet.
>> Yes.  I'm amenable to adding one, but I'm not sure how.
>>
>
> You should really add them.  Take a look at the ARC port,
> which was recently added:
>
>   https://sourceware.org/ml/gdb-patches/2016-09/msg00248.html

Great, thanks -- I was looking for .dtd files, not .xml files.  From looking at
their port, it looks like I want to add a

  gdb/features/riscv.xml

patterned off of

  gdb/features/arc-v2.xml

It looks like there's a whole bunch of examples in there, so if I'm on the
right track I can probably figure it out.

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

* Re: [PATCH 1/2] RISC-V GDB Port
  2016-11-14 22:39       ` Palmer Dabbelt
@ 2016-11-16 19:36         ` Pedro Alves
  2016-11-16 19:40           ` Palmer Dabbelt
  2016-11-16 21:40         ` Yao Qi
  1 sibling, 1 reply; 17+ messages in thread
From: Pedro Alves @ 2016-11-16 19:36 UTC (permalink / raw)
  To: Palmer Dabbelt, qiyaoltc; +Cc: Andrew Waterman, gdb-patches, amodra

On 11/14/2016 10:39 PM, Palmer Dabbelt wrote:
>>> >> +
>>> >> +  /* Check any target description for validity.  */
>>> >> +  if (tdesc_has_registers (info.target_desc))
>>> >> +    {
>> >
>> > We don't have riscv target description yet.
> Yes.  I'm amenable to adding one, but I'm not sure how.
> 

You should really add them.  Take a look at the ARC port,
which was recently added:

  https://sourceware.org/ml/gdb-patches/2016-09/msg00248.html

Thanks,
Pedro Alves

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

* Re: [PATCH 1/2] RISC-V GDB Port
  2016-11-03 12:39     ` Yao Qi
@ 2016-11-14 22:39       ` Palmer Dabbelt
  2016-11-16 19:36         ` Pedro Alves
  2016-11-16 21:40         ` Yao Qi
  0 siblings, 2 replies; 17+ messages in thread
From: Palmer Dabbelt @ 2016-11-14 22:39 UTC (permalink / raw)
  To: qiyaoltc; +Cc: Andrew Waterman, gdb-patches, amodra

Sorry for taking a while to respond to this, we got a bit distracted by other
parts of the binutils port upstreaming process.

On Thu, 03 Nov 2016 05:38:53 PDT (-0700), qiyaoltc@gmail.com wrote:
> Palmer Dabbelt <palmer@dabbelt.com> writes:
>
> Hi Palmer,
> you need a ChangeLog entry, and a news entry for this new gdb port.
> There are some code style issues, please look at
> https://sourceware.org/gdb/wiki/ContributionChecklist
>
>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>> index 2c88434..e4e497b 100644
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>> @@ -691,7 +691,7 @@ ALL_TARGET_OBS = \
>>  	nios2-tdep.o nios2-linux-tdep.o \
>>  	nto-tdep.o \
>>  	ppc-linux-tdep.o ppcfbsd-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o  \
>> -	ppc-sysv-tdep.o ppc64-tdep.o rl78-tdep.o \
>> +	ppc-sysv-tdep.o ppc64-tdep.o riscv-tdep.o rl78-tdep.o \
>
> Miss riscv-linux-tdep.o?

  https://github.com/riscv/riscv-binutils-gdb/commit/76e33b6883db0e2a21b5fa460e7d2952f5760c08

>
>>  	rs6000-aix-tdep.o rs6000-tdep.o solib-aix.o ppc-ravenscar-thread.o \
>>  	rs6000-lynx178-tdep.o \
>>  	rx-tdep.o \
>> @@ -946,7 +946,7 @@ sparc64-tdep.h ppcobsd-tdep.h \
>>  coff-pe-read.h parser-defs.h gdb_ptrace.h mips-linux-tdep.h \
>>  m68k-tdep.h spu-tdep.h environ.h amd64-tdep.h \
>>  doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h ppc64-tdep.h \
>> -rs6000-tdep.h rs6000-aix-tdep.h \
>> +riscv-tdep.h rs6000-tdep.h rs6000-aix-tdep.h \
>>  common/gdb_locale.h arch-utils.h trad-frame.h gnu-nat.h \
>>  language.h nbsd-tdep.h solib-svr4.h \
>>  macroexp.h ui-file.h regcache.h tracepoint.h tracefile.h i386-tdep.h \
>> @@ -1734,6 +1734,7 @@ ALLDEPFILES = \
>>  	ravenscar-thread.c \
>>  	remote-sim.c \
>>  	dcache.c \
>> +	riscv-tdep.c \
>
> Miss riscv-linux-tdep.c?

  https://github.com/riscv/riscv-binutils-gdb/commit/76e33b6883db0e2a21b5fa460e7d2952f5760c08

>>  	rl78-tdep.c \
>>  	rs6000-nat.c rs6000-tdep.c solib-aix.c ppc-ravenscar-thread.c \
>>  	rs6000-lynx178-tdep.c \
>> diff --git a/gdb/config/riscv/linux.mh b/gdb/config/riscv/linux.mh
>> new file mode 100644
>> index 0000000..f68f371
>> --- /dev/null
>> +++ b/gdb/config/riscv/linux.mh
>> @@ -0,0 +1,30 @@
>> +#  Host: RISC-V based machine running GNU/Linux
>> +#
>> +#  Copyright (C) 2015 Free Software Foundation, Inc.
>
> 2016

  https://github.com/riscv/riscv-binutils-gdb/commit/7f008660df2b4859b80f1e7f8a29257ba831423d

>
>> +#  Contributed by Albert Ou <albert@sifive.com>.
>> +#
>
> Albert Ou doesn't have FSF copyright assignment.

Sorry about that, we got his paperwork all sorted out.

>> --- a/gdb/configure.ac
>> +++ b/gdb/configure.ac
>> @@ -515,6 +515,9 @@ esac
>>  # We might need to link with -lm; most simulators need it.
>>  AC_CHECK_LIB(m, main)
>>
>> +# The RISC-V simulator needs clock_gettime()
>> +AC_SEARCH_LIBS([clock_gettime], [rt])
>> +
>
> I don't know much in sim configure, but this is about sim, so I think
> this should be moved to sim/riscv/configure.ac.

I agree, but I couldn't make that work when I initially tried to implement this
(something about SIM_EXTRA_LIBS not getting passed far enough around).
Luckily, we've actually removed the dependency of our simulatior on
clock_gettime, so this can just be removed entirely.

  https://github.com/riscv/riscv-binutils-gdb/commit/f64950f9d68068acf1236f1ee9dd36eebc7b807e

>> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
>> index 8e34b7e..4457304 100644
>> --- a/gdb/infcmd.c
>> +++ b/gdb/infcmd.c
>> @@ -3447,8 +3447,9 @@ otherwise all the threads in the program are stopped.  To \n\
>>  interrupt all running threads in non-stop mode, use the -a option."));
>>
>>    c = add_info ("registers", nofp_registers_info, _("\
>> -List of integer registers and their contents, for selected stack frame.\n\
>> -Register name as argument means describe only that register."));
>> +Display registers and their contents, for the selected stack frame.\n\
>> +Usage: info registers [all|register|register group] ...\n\
>> +By default, the general register group will be shown."));
>
> Please split this change out this patch.  Put it into a separated patch,
> and give the reason why do you change that.

Sorry, I can't figure out why that's there.  I'm going to assume I screwed up
merging something at some point and drop the diff.

  https://github.com/riscv/riscv-binutils-gdb/commit/4ee773ddb3334393e0912c21db660a5d4a6f0ba4

Thanks for noticing!

>> diff --git a/gdb/riscv-linux-tdep.c b/gdb/riscv-linux-tdep.c
>> new file mode 100644
>> index 0000000..b66860c
>> --- /dev/null
>> +++ b/gdb/riscv-linux-tdep.c
>> @@ -0,0 +1,83 @@
>> +/* Target-dependent code for GNU/Linux RISC-V.
>> +
>> +   Copyright (C) 2015 Free Software Foundation, Inc.
>> +   Contributed by Albert Ou <albert@sifive.com>.
>> +
>> +   This file is part of GDB.
>> +
>> +   This program is free software; you can redistribute it and/or modify
>> +   it under the terms of the GNU General Public License as published by
>> +   the Free Software Foundation; either version 3 of the License, or
>> +   (at your option) any later version.
>> +
>> +   This program is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +   GNU General Public License for more details.
>> +
>> +   You should have received a copy of the GNU General Public License
>> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>> +
>> +#include "defs.h"
>> +
>> +#include "gdbarch.h"
>> +#include "osabi.h"
>> +#include "linux-tdep.h"
>> +#include "solib-svr4.h"
>> +#include "glibc-tdep.h"
>> +
>> +#include "riscv-tdep.h"
>> +#include "riscv-linux-tdep.h"
>> +
>> +#include "regcache.h"
>> +#include "regset.h"
>> +
>> +static const struct regcache_map_entry riscv_linux_gregmap[] =
>> +{
>> +  { 1,  RISCV_PC_REGNUM, 0 },
>> +  { 31, RISCV_RA_REGNUM, 0 }, /* x1 to x31 */
>> +  { 0 }
>> +};
>> +
>> +const struct regset riscv_linux_gregset =
>> +{
>> +  riscv_linux_gregmap, regcache_supply_regset, regcache_collect_regset
>> +};
>> +
>
> All gdbarch methods are should be documented like this,
>
> /* Implement the iterate_over_regset_sections gdbarch method.  */
>
>> +static void
>> +riscv_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>> +					  iterate_over_regset_sections_cb *cb,
>> +					  void *cb_data,
>> +					  const struct regcache *regcache)
>> +{
>> +  cb (".reg", (RISCV_NGREG * riscv_isa_regsize (gdbarch)),
>> +      &riscv_linux_gregset, NULL, cb_data);
>> +}
>> +
>> +static void
>> +riscv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>> +{
>> +  linux_init_abi (info, gdbarch);
>> +
>> +  /* GNU/Linux uses SVR4-style shared libraries.  */
>> +  /* FIXME: This '0' should actually be a check to see if we're on
>> +     rv32, but I can't figure out how to hook that up (it's in
>> +     gdbarch_tdep, which we don't have here). */
>> +  set_solib_svr4_fetch_link_map_offsets
>> +    (gdbarch, (0) ?
>> +      svr4_ilp32_fetch_link_map_offsets :
>> +      svr4_lp64_fetch_link_map_offsets);
>
> gdbarch_tdep (gdbarch)->riscv_abi can tell you rv32 or rv64 is used.

OK, thanks!  At some point there was a merge that dropped the old way of doing
it and I couldn't figure out how to do it right.  Thanks for noticing!

  https://github.com/riscv/riscv-binutils-gdb/commit/0a9a29028cd26da628883bb49c0d5d06abaa30f4

>> --- /dev/null
>> +++ b/gdb/riscv-tdep.c
>> @@ -0,0 +1,1292 @@
>> +/* Target-dependent code for the RISC-V architecture, for GDB.
>> +
>> +   Copyright (C) 1988-2015 Free Software Foundation, Inc.
>> +
>> +   Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
>> +   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
>> +   and by Todd Snyder <todd@bluespec.com>
>> +   and by Mike Frysinger <vapier@gentoo.org>.
>
> I don't find Todd Snyder's FSF copyright assignment.

OK, we'll try to sort this out.  One of the other bluespec guys has this filled
out, so I don't think it'll be a big headache.  I must have just missed a
contributer.  Thanks for finding him!

>> +
>> +   This file is part of GDB.
>> +
>> +   This program is free software; you can redistribute it and/or modify
>> +   it under the terms of the GNU General Public License as published by
>> +   the Free Software Foundation; either version 3 of the License, or
>> +   (at your option) any later version.
>> +
>> +   This program is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +   GNU General Public License for more details.
>> +
>> +   You should have received a copy of the GNU General Public License
>> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>> +
>> +#include "defs.h"
>> +#include "frame.h"
>> +#include "inferior.h"
>> +#include "symtab.h"
>> +#include "value.h"
>> +#include "gdbcmd.h"
>> +#include "language.h"
>> +#include "gdbcore.h"
>> +#include "symfile.h"
>> +#include "objfiles.h"
>> +#include "gdbtypes.h"
>> +#include "target.h"
>> +#include "arch-utils.h"
>> +#include "regcache.h"
>> +#include "osabi.h"
>> +#include "riscv-tdep.h"
>> +#include "block.h"
>> +#include "reggroups.h"
>> +#include "opcode/riscv.h"
>> +#include "elf/riscv.h"
>> +#include "elf-bfd.h"
>> +#include "symcat.h"
>> +#include "sim-regno.h"
>> +#include "gdb/sim-riscv.h"
>> +#include "dis-asm.h"
>> +#include "frame-unwind.h"
>> +#include "frame-base.h"
>> +#include "trad-frame.h"
>> +#include "infcall.h"
>> +#include "floatformat.h"
>> +#include "remote.h"
>> +#include "target-descriptions.h"
>> +#include "dwarf2-frame.h"
>> +#include "user-regs.h"
>> +#include "valprint.h"
>> +#include "opcode/riscv-opc.h"
>> +#include <algorithm>
>> +
>
>
>
>> +
>> +static void
>> +riscv_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *kindptr)
>> +{
>> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
>> +
>> +  riscv_breakpoint_from_pc (gdbarch, pcptr, kindptr);
>> +}
>> +
>
> remote_breakpoint_from_pc is removed in my patches
> https://sourceware.org/ml/gdb-patches/2016-11/msg00031.html
> They are not committed yet.  It would be good if you can rebase your
> patches on top of mine when my patches are committed.

I'll rebase every patchset I submit on top of the latest master, but this
specific issue has already been fixed.  Thanks for the heads up!

>> +static struct value *
>> +value_of_riscv_user_reg (struct frame_info *frame, const void *baton)
>> +{
>> +  const int *reg_p = (const int *)baton;
>> +
>> +  return value_of_register (*reg_p, frame);
>> +}
>> +
>> +static const char *
>> +register_name (struct gdbarch *gdbarch,
>> +	       int             regnum,
>> +               int             prefer_alias)
>
> Code style issue, only one space is needed between "int" and "regnum".
> Many instances of such problem around your patch.

I went through and fixed those issues.  There was also a large style-fix commit
that went through, hopefully it's all OK now.

  https://github.com/riscv/riscv-binutils-gdb/commit/ad8325bd484c1b2d0eb27ab403b1e87d69dd594e

>> +{
>> +  int i;
>> +  static char buf[20];
>> +
>> +  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
>> +    return tdesc_register_name (gdbarch, regnum);
>
> I don't think riscv port has target description yet.

I'm not sure what a "target description" is.  Are you talking about this

  https://sourceware.org/gdb/onlinedocs/gdb/Target-Description-Format.html

?  If so then I don't think we have one, but I also can't figure out where
anyone else's is.

  riscv-binutils-gdb $ find -iname "*.dtd"
  ./gdb/features/threads.dtd
  ./gdb/features/btrace.dtd
  ./gdb/features/library-list.dtd
  ./gdb/features/osdata.dtd
  ./gdb/features/traceframe-info.dtd
  ./gdb/features/xinclude.dtd
  ./gdb/features/gdb-target.dtd
  ./gdb/features/library-list-svr4.dtd
  ./gdb/features/btrace-conf.dtd
  ./gdb/features/library-list-aix.dtd
  ./gdb/syscalls/gdb-syscalls.dtd
  riscv-binutils-gdb $ find -iname "*.dtd" | xargs grep 86

I feel like I must be missing something here.  Sorry!

>> +
>> +static void
>> +riscv_extract_return_value (struct type *type,
>> +			    struct regcache *regs,
>> +			    gdb_byte *dst,
>> +			    int regnum)
>
> You need some comments on this function.
>
>> +{
>> +  struct gdbarch *gdbarch = get_regcache_arch (regs);
>> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
>> +  int regsize = riscv_isa_regsize (gdbarch);
>> +  bfd_byte *valbuf = dst;
>> +  int len = TYPE_LENGTH (type);
>> +  ULONGEST tmp;
>> +
>> +  gdb_assert (len <= 2 * regsize);
>> +
>> +  while (len > 0)
>> +    {
>> +      regcache_cooked_read_unsigned (regs, regnum++, &tmp);
>> +      store_unsigned_integer (valbuf, std::min (regsize, len), byte_order, tmp);
>
> This line is too long.

Both fixed: https://github.com/riscv/riscv-binutils-gdb/commit/f75a58ffd7450915ee776594baceb95a0e10af99

>
>> +      len -= regsize;
>> +      valbuf += regsize;
>> +    }
>> +}
>> +
>
> /* Implement the return_value gdbarch method.  */

I'm not sure what you mean by this.

>> +
>> +static enum return_value_convention
>> +riscv_return_value (struct gdbarch  *gdbarch,
>> +		    struct value *function,
>> +		    struct type     *type,
>> +		    struct regcache *regcache,
>> +		    gdb_byte        *readbuf,
>> +		    const gdb_byte  *writebuf)
>> +{
>> +  enum type_code rv_type = TYPE_CODE (type);
>> +  unsigned int rv_size = TYPE_LENGTH (type);
>> +  int fp, regnum;
>> +  ULONGEST tmp;
>> +
>> +  /* Paragraph on return values taken from RISC-V specification (post v2.0):
>> +
>> +     Values are returned from functions in integer registers a0 and a1 and
>> +     floating-point registers fa0 and fa1.  Floating-point values are returned
>> +     in floating-point registers only if they are primitives or members of a
>> +     struct consisting of only one or two floating-point values.  Other return
>> +     values that fit into two pointer-words are returned in a0 and a1.  Larger
>> +     return values are passed entirely in memory; the caller allocates this
>> +     memory region and passes a pointer to it as an implicit first parameter to
>> +     the callee.  */
>> +
>
> Nit: some lines are too long.

I think it was only one

  https://github.com/riscv/riscv-binutils-gdb/commit/875e1bbf5b783d4b6b23786e73a89623fd4dadaa

>
>> +  /* Deal with struct/unions first that are passed via memory.  */
>> +  if (rv_size > 2 * riscv_isa_regsize (gdbarch))
>> +    {
>> +      if (readbuf || writebuf)
>> +	regcache_cooked_read_unsigned (regcache, RISCV_A0_REGNUM, &tmp);
>> +      if (readbuf)
>> +	read_memory (tmp, readbuf, rv_size);
>> +      if (writebuf)
>> +	write_memory (tmp, writebuf, rv_size);
>> +      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
>> +    }
>> +
>> +  /* Are we dealing with a floating point value?  */
>> +  fp = 0;
>> +  if (rv_type == TYPE_CODE_FLT)
>> +    fp = 1;
>> +  else if (rv_type == TYPE_CODE_STRUCT || rv_type == TYPE_CODE_UNION)
>> +    {
>> +      unsigned int rv_fields = TYPE_NFIELDS (type);
>> +
>> +      if (rv_fields == 1)
>> +	{
>> +	  struct type *fieldtype = TYPE_FIELD_TYPE (type, 0);
>> +	  if (TYPE_CODE (check_typedef (fieldtype)) == TYPE_CODE_FLT)
>> +	    fp = 1;
>> +	}
>> +      else if (rv_fields == 2)
>> +	{
>> +	  struct type *fieldtype0 = TYPE_FIELD_TYPE (type, 0);
>> +	  struct type *fieldtype1 = TYPE_FIELD_TYPE (type, 1);
>> +
>> +	  if (TYPE_CODE (check_typedef (fieldtype0)) == TYPE_CODE_FLT
>> +	      && TYPE_CODE (check_typedef (fieldtype1)) == TYPE_CODE_FLT)
>> +	    fp = 1;
>> +	}
>> +    }
>> +
>> +  /* Handle return value in a register.  */
>> +  regnum = fp ? RISCV_FA0_REGNUM : RISCV_A0_REGNUM;
>> +
>> +  if (readbuf)
>> +    riscv_extract_return_value (type, regcache, readbuf, regnum);
>> +
>> +  if (writebuf)
>> +    riscv_store_return_value (type, regcache, writebuf, regnum);
>> +
>> +  return RETURN_VALUE_REGISTER_CONVENTION;
>> +}
>> +
>
> /* Implement the XXX gdbarch method.  */

I'm afraid I'm not sure what you're trying to say here, sorry!

>> +{
>> +  return regcache_raw_read (regcache, regnum, buf);
>> +}
>> +
>
>> +
>> +static struct type *
>> +riscv_register_type (struct gdbarch  *gdbarch,
>> +		     int              regnum)
>> +{
>> +  int regsize = riscv_isa_regsize (gdbarch);
>> +
>> +  if (regnum < RISCV_FIRST_FP_REGNUM)
>> +    {
>> + int_regsizes:
>> +      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);
>> +	}
>> +    }
>> +  else if (regnum <= RISCV_LAST_FP_REGNUM)
>> +    {
>> +      switch (regsize)
>> +	{
>> +	case 4:
>> +	  return builtin_type (gdbarch)->builtin_float;
>> +	case 8:
>> +	case 16:
>> +	  return builtin_type (gdbarch)->builtin_double;
>
> return builtin_long_double in case regsize is 16?

I think this is actually correct as of right now -- we landed upstream a bit
quickly into binutils and one of the things that was still broken was that
"long double" was 64-bit on RISC-V.  Patches to fix this are part of the next
set I'm going to send to binutils, I'll fix this as well when they get
submitted.

>
>> +	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;
>> +
>> +      goto int_regsizes;
>
> goto is not necessarily needed.  Please remove it.

  https://github.com/riscv/riscv-binutils-gdb/commit/b8cfc4293684c3dcaa39fbcd68c75cb486452c00

>
>> +    }
>> +}
>> +
>> +/* TODO: Replace all this with tdesc XML files.  */
>> +static void
>> +riscv_read_fp_register_single (struct frame_info *frame, int regno,
>> +			       gdb_byte *rare_buffer)
>> +{
>> +  struct gdbarch *gdbarch = get_frame_arch (frame);
>> +  int raw_size = register_size (gdbarch, regno);
>> +  gdb_byte *raw_buffer = (gdb_byte *) alloca (raw_size);
>> +
>> +  if (!deprecated_frame_register_read (frame, regno, raw_buffer))
>
> Use get_frame_register_value, your code can be simpler.

MIPS (where this code came from) still uses the deprecated function.  I can't
figure out why this was deprecated or why MIPS is still using the old version,
and since this code does dangerous looking things (silently copying half of a
double-precision float) I'm not really sure how to change it.

>> +    error (_("can't read register %d (%s)"), regno,
>> +	   gdbarch_register_name (gdbarch, regno));
>> +
>> +  if (raw_size == 8)
>> +    {
>> +      int offset;
>> +
>> +      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
>> +	offset = 4;
>> +      else
>> +	offset = 0;
>> +
>> +      memcpy (rare_buffer, raw_buffer + offset, 4);
>> +    }
>> +  else
>> +    memcpy (rare_buffer, raw_buffer, 4);
>> +}
>> +
>> +static void
>> +riscv_read_fp_register_double (struct frame_info *frame, int regno,
>> +			       gdb_byte *rare_buffer)
>> +{
>> +  struct gdbarch *gdbarch = get_frame_arch (frame);
>> +  int raw_size = register_size (gdbarch, regno);
>> +
>> +  if (raw_size == 8)
>> +    {
>> +      if (!deprecated_frame_register_read (frame, regno, rare_buffer))
>> +	error (_("can't read register %d (%s)"), regno,
>> +	       gdbarch_register_name (gdbarch, regno));
>> +    }
>> +  else
>> +    internal_error (__FILE__, __LINE__,
>> +		    _("%s: size says 32-bits, read is 64-bits."), __func__);
>> +}
>> +
>> +static void
>> +riscv_print_fp_register (struct ui_file *file, struct frame_info *frame,
>> +			 int regnum)
>> +{
>> +  struct gdbarch *gdbarch = get_frame_arch (frame);
>> +  gdb_byte *raw_buffer;
>> +  struct value_print_options opts;
>> +  double val;
>> +  int inv;
>> +  const char *regname;
>> +
>> +  raw_buffer = (gdb_byte *) alloca (2 * register_size (gdbarch, RISCV_FIRST_FP_REGNUM));
>> +
>
> This line is too long.
>
>> +  fprintf_filtered (file, "%-15s", gdbarch_register_name (gdbarch, regnum));
>> +
>> +  if (register_size (gdbarch, regnum) == 4)
>> +    {
>> +      riscv_read_fp_register_single (frame, regnum, raw_buffer);
>> +      val = unpack_double (builtin_type (gdbarch)->builtin_float, raw_buffer,
>> +			   &inv);
>> +
>> +      get_formatted_print_options (&opts, 'x');
>> +      print_scalar_formatted (raw_buffer,
>> +			      builtin_type (gdbarch)->builtin_float,
>> +			      &opts, 'w', file);
>> +
>> +      if (!inv)
>> +	fprintf_filtered (file, "\t%-17.9g", val);
>> +    }
>> +  else
>> +    {
>> +      riscv_read_fp_register_double (frame, regnum, raw_buffer);
>> +      val = unpack_double (builtin_type (gdbarch)->builtin_double, raw_buffer,
>> +			   &inv);
>> +
>> +      get_formatted_print_options (&opts, 'x');
>> +      print_scalar_formatted (raw_buffer,
>> +			      builtin_type (gdbarch)->builtin_double,
>> +			      &opts, 'g', file);
>> +
>> +      if (!inv)
>> +	fprintf_filtered (file, "\t%-24.17g", val);
>> +    }
>> +
>> +  if (inv)
>> +    fprintf_filtered (file, "\t<invalid>");
>> +}
>> +
>
>
>
>
>> +
>> +static ULONGEST
>> +riscv_fetch_instruction (struct gdbarch *gdbarch, CORE_ADDR addr)
>> +{
>> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
>
> gdbarch_byte_order_for_code

Ah, thanks -- this would have been a pain to fix :)

  https://github.com/riscv/riscv-binutils-gdb/commit/f0ded1266c58a364481c8de57a884f8ac2d173a0

>> +
>> +static void
>> +set_reg_offset (struct gdbarch *gdbarch, struct riscv_frame_cache *this_cache,
>> +		int regnum, CORE_ADDR offset)
>> +{
>> +  if (this_cache != NULL && this_cache->saved_regs[regnum].addr == -1)
>> +    this_cache->saved_regs[regnum].addr = offset;
>> +}
>> +
>> +static void
>> +reset_saved_regs (struct gdbarch *gdbarch, struct riscv_frame_cache *this_cache)
>> +{
>> +  const int num_regs = gdbarch_num_regs (gdbarch);
>> +  int i;
>> +
>> +  if (this_cache == NULL || this_cache->saved_regs == NULL)
>> +    return;
>> +
>> +  for (i = 0; i < num_regs; ++i)
>> +    this_cache->saved_regs[i].addr = -1;
>
> IIRC, .addr's type is CORE_ADDR, which is unsigned.  Don't assign -1 to
> a unsigned type.

It looks like this is another one we got from MIPS.  I'm OK changing it, but
I'm not sure what the implications are.  I think 0 is the sanest value to put
in there?

  https://github.com/riscv/riscv-binutils-gdb/commit/73656f235a8b7cedaab10ee49bbc55dbf02e86ce

If that looks OK to you then I can go try to figure out if it's the right thing
to do.

>> +}
>> +
>> +static CORE_ADDR
>> +riscv_scan_prologue (struct gdbarch *gdbarch,
>> +		     CORE_ADDR start_pc, CORE_ADDR limit_pc,
>> +		     struct frame_info *this_frame,
>> +		     struct riscv_frame_cache *this_cache)
>> +{
>> +  CORE_ADDR cur_pc;
>> +  CORE_ADDR frame_addr = 0;
>> +  CORE_ADDR sp;
>> +  long frame_offset;
>> +  int frame_reg = RISCV_SP_REGNUM;
>> +
>> +  CORE_ADDR end_prologue_addr = 0;
>> +  int seen_sp_adjust = 0;
>> +  int load_immediate_bytes = 0;
>> +
>> +  /* Can be called when there's no process, and hence when there's no THIS_FRAME.  */
>> +  if (this_frame != NULL)
>> +    sp = get_frame_register_signed (this_frame, RISCV_SP_REGNUM);
>> +  else
>> +    sp = 0;
>> +
>> +  if (limit_pc > start_pc + 200)
>> +    limit_pc = start_pc + 200;
>> +
>> + restart:
>> +
>> +  frame_offset = 0;
>> +  /* TODO: Handle compressed extensions.  */
>> +  for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4)
>> +    {
>> +      unsigned long inst, opcode;
>> +      int reg, rs1, imm12, rs2, offset12, funct3;
>> +
>> +      /* Fetch the instruction.  */
>> +      inst = (unsigned long) riscv_fetch_instruction (gdbarch, cur_pc);
>
> What if (unsigned long) is 4-bytes long, but riscv instruction is
> 8-bytes long?

We don't currently have any RISC-V instructions that are longer than 4 bytes.
The standard allows for this, but it doesn't look like there'll be any in the
near future.  I fixed it anyway, because the old version was uglier

  https://github.com/riscv/riscv-binutils-gdb/commit/34a6a4b4f553171d55de955ce75346ee781b6b2a

>> +      opcode = inst & 0x7F;
>> +      reg = (inst >> 7) & 0x1F;
>> +      rs1 = (inst >> 15) & 0x1F;
>> +      imm12 = (inst >> 20) & 0xFFF;
>> +      rs2 = (inst >> 20) & 0x1F;
>> +      offset12 = (((inst >> 25) & 0x7F) << 5) + ((inst >> 7) & 0x1F);
>> +      funct3 = (inst >> 12) & 0x7;
>> +
>> +      /* Look for common stack adjustment insns.  */
>> +      if ((opcode == 0x13 || opcode == 0x1B) && reg == RISCV_SP_REGNUM
>> +	  && rs1 == RISCV_SP_REGNUM)
>
> Please use macros defined in include/opcode/riscv-opc.h, then the code
> is much more readable.

I agree.  Whoever wrote this code must have either not known about riscv-opc.h,
or not liked those macros.  I added a FIXME for now

  https://github.com/riscv/riscv-binutils-gdb/commit/1b58570b0310850290ed5355776e78192e893d71

>> +static CORE_ADDR
>> +riscv_push_dummy_call (struct gdbarch *gdbarch,
>> +		       struct value *function,
>> +		       struct regcache *regcache,
>> +		       CORE_ADDR bp_addr,
>> +		       int nargs,
>> +		       struct value **args,
>> +		       CORE_ADDR sp,
>> +		       int struct_return,
>> +		       CORE_ADDR struct_addr)
>> +{
>> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
>> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
>> +  gdb_byte buf[4];
>> +  int i;
>> +  CORE_ADDR func_addr = find_function_addr (function, NULL);
>> +
>> +  /* Push excess arguments in reverse order.  */
>> +
>> +  for (i = nargs; i >= 8; --i)
>> +    {
>> +      struct type *value_type = value_enclosing_type (args[i]);
>> +      int container_len = align_up (TYPE_LENGTH (value_type), 3);
>> +
>> +      sp -= container_len;
>> +      write_memory (sp, value_contents_writeable (args[i]), container_len);
>> +    }
>> +
>> +  /* Initialize argument registers.  */
>> +
>> +  for (i = 0; i < nargs && i < 8; ++i)
>> +    {
>> +      struct type *value_type = value_enclosing_type (args[i]);
>> +      const gdb_byte *arg_bits = value_contents_all (args[i]);
>> +      int regnum = TYPE_CODE (value_type) == TYPE_CODE_FLT ?
>> +	RISCV_FA0_REGNUM : RISCV_A0_REGNUM;
>> +
>
> code style issue,
> https://www.gnu.org/prep/standards/standards.html#Formatting
>
> int regnum = (TYPE_CODE (value_type) == TYPE_CODE_FLT
>                ? RISCV_FA0_REGNUM : RISCV_A0_REGNUM);
>

I think there were two formatting issues (one line was 80 characters)

  https://github.com/riscv/riscv-binutils-gdb/commit/c24e88a3e4464c922a669f84c1c67a1ae84444a1

>> +
>> +static struct gdbarch *
>> +riscv_gdbarch_init (struct gdbarch_info  info,
>> +		    struct gdbarch_list *arches)
>> +{
>> +  struct gdbarch *gdbarch;
>> +  struct gdbarch_tdep *tdep;
>> +  const struct bfd_arch_info *binfo = info.bfd_arch_info;
>> +
>> +  int abi, i;
>> +
>> +  /* For now, base the abi on the elf class.  */
>> +  /* Allow the ELF class to override the register size. Ideally the target
>> +   * (OpenOCD/spike/...) would communicate the register size to gdb instead. */
>> +  abi = RISCV_ABI_FLAG_RV32I;
>> +  if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
>> +    {
>> +      unsigned char eclass = elf_elfheader (info.abfd)->e_ident[EI_CLASS];
>> +
>> +      if (eclass == ELFCLASS32)
>> +	abi = RISCV_ABI_FLAG_RV32I;
>> +      else if (eclass == ELFCLASS64)
>> +	abi = RISCV_ABI_FLAG_RV64I;
>> +      else
>> +        internal_error (__FILE__, __LINE__, _("unknown ELF header class %d"), eclass);
>> +    }
>> +  else
>> +    {
>> +      if (binfo->bits_per_word == 32)
>> +        abi = RISCV_ABI_FLAG_RV32I;
>> +      else if (binfo->bits_per_word == 64)
>> +        abi = RISCV_ABI_FLAG_RV64I;
>> +      else
>> +        internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"),
>> +            binfo->bits_per_word);
>> +    }
>> +
>> +  /* 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)->riscv_abi == abi)
>> +      return arches->gdbarch;
>> +
>> +  /* None found, so create a new architecture from the information provided.
>> +     Can't initialize all the target dependencies until we actually know which
>> +     target we are talking to, but put in some defaults for now.  */
>> +
>> +  tdep = (struct gdbarch_tdep *) xmalloc (sizeof *tdep);
>> +  gdbarch = gdbarch_alloc (&info, tdep);
>> +
>> +  tdep->riscv_abi = abi;
>> +  switch (abi)
>> +    {
>> +    case RISCV_ABI_FLAG_RV32I:
>> +      tdep->register_size = 4;
>> +      break;
>> +    case RISCV_ABI_FLAG_RV64I:
>> +      tdep->register_size = 8;
>
> Since you've already had riscv_abi field in tdep, you can determine the
> registers size on the fly.  Then, field register_size is not necessary
> to me.

Sounds good to me.

  https://github.com/riscv/riscv-binutils-gdb/commit/09a286c89cdeea2c5ee21d239250a06bb3d92bc8

>> +
>> +  /* Information about the target architecture.  */
>> +  set_gdbarch_return_value (gdbarch, riscv_return_value);
>> +  set_gdbarch_breakpoint_from_pc (gdbarch, riscv_breakpoint_from_pc);
>
> breakpoint_from_pc will be replaced by two new gdbarch methods, added in
> my patches https://sourceware.org/ml/gdb-patches/2016-11/msg00031.html
>
>> +  set_gdbarch_remote_breakpoint_from_pc (gdbarch, riscv_remote_breakpoint_from_pc);

OK, thanks for the heads up.  I'll be sure to handle this when I rebase on top
of those, I don't think they've made it in yet.

>> +
>> +  /* Check any target description for validity.  */
>> +  if (tdesc_has_registers (info.target_desc))
>> +    {
>
> We don't have riscv target description yet.

Yes.  I'm amenable to adding one, but I'm not sure how.

>> +      const struct tdesc_feature *feature;
>> +      struct tdesc_arch_data *tdesc_data;
>> +      int valid_p;
>> +
>> +      feature = tdesc_find_feature (info.target_desc, "org.gnu.gdb.riscv.cpu");
>> +      if (feature == NULL)
>> +	goto no_tdata;
>> +
>> +      tdesc_data = tdesc_data_alloc ();
>> +
>> +      valid_p = 1;
>> +      for (i = RISCV_ZERO_REGNUM; i <= RISCV_LAST_FP_REGNUM; ++i)
>> +        valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
>> +                                            riscv_gdb_reg_names[i]);
>> +      for (i = RISCV_FIRST_CSR_REGNUM; i <= RISCV_LAST_CSR_REGNUM; ++i)
>> +        {
>> +          char buf[20];
>> +          sprintf (buf, "csr%d", i - RISCV_FIRST_CSR_REGNUM);
>> +          valid_p &= tdesc_numbered_register (feature, tdesc_data, i, buf);
>> +        }
>> +
>> +      valid_p &= tdesc_numbered_register (feature, tdesc_data, i++, "priv");
>> +
>> +      if (!valid_p)
>> +	tdesc_data_cleanup (tdesc_data);
>> +      else
>> +	tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
>> +    }
>> + no_tdata:
>> +
>> +  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);
>> +
>> +  return gdbarch;
>> +}
>> +
>
>> diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
>> new file mode 100644
>> index 0000000..ef10209
>> --- /dev/null
>> +++ b/gdb/riscv-tdep.h
>> @@ -0,0 +1,101 @@
>> +/* Target-dependent header for the RISC-V architecture, for GDB, the GNU Debugger.
>> +
>> +   Copyright (C) 2002-2015 Free Software Foundation, Inc.
>> +
>> +   Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
>> +   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
>> +   and by Todd Snyder <todd@bluespec.com>
>> +   and by Mike Frysinger <vapier@gentoo.org>.
>> +
>> +   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 RISCV_TDEP_H
>> +#define RISCV_TDEP_H
>> +
>> +struct gdbarch;
>> +
>> +/* All the official RISC-V ABIs.  These mostly line up with mcpuid purely for
>> +   convenience.  */
>> +#define RISCV_ABI_FLAG_RV32I	(0x00000000)	/* 32-bit Integer GPRs.  */
>> +#define RISCV_ABI_FLAG_RV32E	(0x10000000)	/* 32-bit Embedded Integer GPRs.  */
>> +#define RISCV_ABI_FLAG_RV64I	(0x40000000)	/* 64-bit Integer GPRs.  */
>> +#define RISCV_ABI_FLAG_RV128I	(0x80000000)	/* 128-bit Integer GPRs.  */
>> +#define RISCV_ABI_FLAG_A	(1 << 0)	/* Atomics.  */
>> +#define RISCV_ABI_FLAG_B	(1 << 1)	/* Bit Manipulation.  */
>> +#define RISCV_ABI_FLAG_C	(1 << 2)	/* 16-bit Compressed Instructions.  */
>> +#define RISCV_ABI_FLAG_D	(1 << 3)	/* Double-Precision Floating-Point.  */
>> +#define RISCV_ABI_FLAG_E	(1 << 4)	/* Embedded base.  */
>> +#define RISCV_ABI_FLAG_F	(1 << 5)	/* Single-Precision Floating-Point.  */
>> +#define RISCV_ABI_FLAG_H	(1 << 7)	/* Hypervisor mode.  */
>> +#define RISCV_ABI_FLAG_I	(1 << 8)	/* Base integer.  */
>> +#define RISCV_ABI_FLAG_L	(1 << 11)	/* Decimal Floating-Point.  */
>> +#define RISCV_ABI_FLAG_M	(1 << 12)	/* Integer Multiply and Division.  */
>> +#define RISCV_ABI_FLAG_P	(1 << 15)	/* Packed-SIMD Extensions.  */
>> +#define RISCV_ABI_FLAG_Q	(1 << 16)	/* Quad-Precision Floating-Point.  */
>> +#define RISCV_ABI_FLAG_S	(1 << 18)	/* Supervisor mode.  */
>> +#define RISCV_ABI_FLAG_T	(1 << 19)	/* Transactional Memory.  */
>> +#define RISCV_ABI_FLAG_U	(1 << 20)	/* User mode.  */
>
> I don't find where are they used.  Let us add them when they are really
> used somewhere in the code.

Sounds good to me.

  https://github.com/riscv/riscv-binutils-gdb/commit/69e45cdcc667371ce60db88ae613709e6f37dcce

>> +
>> +#define IS_RV32I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV32I)
>> +#define IS_RV64I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV64I)
>> +#define IS_RV128I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV128I)
>> +
>> +#define HAS_FPU(x)	((x) & (RISCV_ABI_FLAG_D | RISCV_ABI_FLAG_F))
>> +
>
>> +#endif /* RISCV_TDEP_H */
>> diff --git a/include/gdb/sim-riscv.h b/include/gdb/sim-riscv.h
>> new file mode 100644
>> index 0000000..932cf49
>> --- /dev/null
>> +++ b/include/gdb/sim-riscv.h
>> @@ -0,0 +1,98 @@
>> +/* This file defines the interface between the RISC-V simulator and GDB.
>> +
>> +   Copyright (C) 2005-2015 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/>.  */
>> +
>> +/* Order has to match gdb riscv-tdep list.  */
>> +enum sim_riscv_regnum {
>
> I don't see how is this header file related to this patch?  Probably
> this should be moved to sim patch.

Yes, I must have added it by mistake.

Thanks for all the feedback.  I'll incorporate all this into a v2, which will
be rebased onto the latest binutils-gdb master.

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

* Re: [PATCH 1/2] RISC-V GDB Port
  2016-10-22 23:40   ` [PATCH 1/2] RISC-V GDB Port Palmer Dabbelt
@ 2016-11-03 12:39     ` Yao Qi
  2016-11-14 22:39       ` Palmer Dabbelt
  0 siblings, 1 reply; 17+ messages in thread
From: Yao Qi @ 2016-11-03 12:39 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: Andrew Waterman, gdb-patches, amodra

Palmer Dabbelt <palmer@dabbelt.com> writes:

Hi Palmer,
you need a ChangeLog entry, and a news entry for this new gdb port.
There are some code style issues, please look at
https://sourceware.org/gdb/wiki/ContributionChecklist

> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 2c88434..e4e497b 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -691,7 +691,7 @@ ALL_TARGET_OBS = \
>  	nios2-tdep.o nios2-linux-tdep.o \
>  	nto-tdep.o \
>  	ppc-linux-tdep.o ppcfbsd-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o  \
> -	ppc-sysv-tdep.o ppc64-tdep.o rl78-tdep.o \
> +	ppc-sysv-tdep.o ppc64-tdep.o riscv-tdep.o rl78-tdep.o \

Miss riscv-linux-tdep.o?

>  	rs6000-aix-tdep.o rs6000-tdep.o solib-aix.o ppc-ravenscar-thread.o \
>  	rs6000-lynx178-tdep.o \
>  	rx-tdep.o \
> @@ -946,7 +946,7 @@ sparc64-tdep.h ppcobsd-tdep.h \
>  coff-pe-read.h parser-defs.h gdb_ptrace.h mips-linux-tdep.h \
>  m68k-tdep.h spu-tdep.h environ.h amd64-tdep.h \
>  doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h ppc64-tdep.h \
> -rs6000-tdep.h rs6000-aix-tdep.h \
> +riscv-tdep.h rs6000-tdep.h rs6000-aix-tdep.h \
>  common/gdb_locale.h arch-utils.h trad-frame.h gnu-nat.h \
>  language.h nbsd-tdep.h solib-svr4.h \
>  macroexp.h ui-file.h regcache.h tracepoint.h tracefile.h i386-tdep.h \
> @@ -1734,6 +1734,7 @@ ALLDEPFILES = \
>  	ravenscar-thread.c \
>  	remote-sim.c \
>  	dcache.c \
> +	riscv-tdep.c \

Miss riscv-linux-tdep.c?

>  	rl78-tdep.c \
>  	rs6000-nat.c rs6000-tdep.c solib-aix.c ppc-ravenscar-thread.c \
>  	rs6000-lynx178-tdep.c \
> diff --git a/gdb/config/riscv/linux.mh b/gdb/config/riscv/linux.mh
> new file mode 100644
> index 0000000..f68f371
> --- /dev/null
> +++ b/gdb/config/riscv/linux.mh
> @@ -0,0 +1,30 @@
> +#  Host: RISC-V based machine running GNU/Linux
> +#
> +#  Copyright (C) 2015 Free Software Foundation, Inc.

2016

> +#  Contributed by Albert Ou <albert@sifive.com>.
> +#

Albert Ou doesn't have FSF copyright assignment.

> --- a/gdb/configure.ac
> +++ b/gdb/configure.ac
> @@ -515,6 +515,9 @@ esac
>  # We might need to link with -lm; most simulators need it.
>  AC_CHECK_LIB(m, main)
>  
> +# The RISC-V simulator needs clock_gettime()
> +AC_SEARCH_LIBS([clock_gettime], [rt])
> +

I don't know much in sim configure, but this is about sim, so I think
this should be moved to sim/riscv/configure.ac.

> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 8e34b7e..4457304 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -3447,8 +3447,9 @@ otherwise all the threads in the program are stopped.  To \n\
>  interrupt all running threads in non-stop mode, use the -a option."));
>  
>    c = add_info ("registers", nofp_registers_info, _("\
> -List of integer registers and their contents, for selected stack frame.\n\
> -Register name as argument means describe only that register."));
> +Display registers and their contents, for the selected stack frame.\n\
> +Usage: info registers [all|register|register group] ...\n\
> +By default, the general register group will be shown."));

Please split this change out this patch.  Put it into a separated patch,
and give the reason why do you change that.


> diff --git a/gdb/riscv-linux-tdep.c b/gdb/riscv-linux-tdep.c
> new file mode 100644
> index 0000000..b66860c
> --- /dev/null
> +++ b/gdb/riscv-linux-tdep.c
> @@ -0,0 +1,83 @@
> +/* Target-dependent code for GNU/Linux RISC-V.
> +
> +   Copyright (C) 2015 Free Software Foundation, Inc.
> +   Contributed by Albert Ou <albert@sifive.com>.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include "defs.h"
> +
> +#include "gdbarch.h"
> +#include "osabi.h"
> +#include "linux-tdep.h"
> +#include "solib-svr4.h"
> +#include "glibc-tdep.h"
> +
> +#include "riscv-tdep.h"
> +#include "riscv-linux-tdep.h"
> +
> +#include "regcache.h"
> +#include "regset.h"
> +
> +static const struct regcache_map_entry riscv_linux_gregmap[] =
> +{
> +  { 1,  RISCV_PC_REGNUM, 0 },
> +  { 31, RISCV_RA_REGNUM, 0 }, /* x1 to x31 */
> +  { 0 }
> +};
> +
> +const struct regset riscv_linux_gregset =
> +{
> +  riscv_linux_gregmap, regcache_supply_regset, regcache_collect_regset
> +};
> +

All gdbarch methods are should be documented like this,

/* Implement the iterate_over_regset_sections gdbarch method.  */

> +static void
> +riscv_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
> +					  iterate_over_regset_sections_cb *cb,
> +					  void *cb_data,
> +					  const struct regcache *regcache)
> +{
> +  cb (".reg", (RISCV_NGREG * riscv_isa_regsize (gdbarch)),
> +      &riscv_linux_gregset, NULL, cb_data);
> +}
> +
> +static void
> +riscv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> +{
> +  linux_init_abi (info, gdbarch);
> +
> +  /* GNU/Linux uses SVR4-style shared libraries.  */
> +  /* FIXME: This '0' should actually be a check to see if we're on
> +     rv32, but I can't figure out how to hook that up (it's in
> +     gdbarch_tdep, which we don't have here). */
> +  set_solib_svr4_fetch_link_map_offsets
> +    (gdbarch, (0) ?
> +      svr4_ilp32_fetch_link_map_offsets :
> +      svr4_lp64_fetch_link_map_offsets);

gdbarch_tdep (gdbarch)->riscv_abi can tell you rv32 or rv64 is used.

> --- /dev/null
> +++ b/gdb/riscv-tdep.c
> @@ -0,0 +1,1292 @@
> +/* Target-dependent code for the RISC-V architecture, for GDB.
> +
> +   Copyright (C) 1988-2015 Free Software Foundation, Inc.
> +
> +   Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
> +   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
> +   and by Todd Snyder <todd@bluespec.com>
> +   and by Mike Frysinger <vapier@gentoo.org>.

I don't find Todd Snyder's FSF copyright assignment.

> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include "defs.h"
> +#include "frame.h"
> +#include "inferior.h"
> +#include "symtab.h"
> +#include "value.h"
> +#include "gdbcmd.h"
> +#include "language.h"
> +#include "gdbcore.h"
> +#include "symfile.h"
> +#include "objfiles.h"
> +#include "gdbtypes.h"
> +#include "target.h"
> +#include "arch-utils.h"
> +#include "regcache.h"
> +#include "osabi.h"
> +#include "riscv-tdep.h"
> +#include "block.h"
> +#include "reggroups.h"
> +#include "opcode/riscv.h"
> +#include "elf/riscv.h"
> +#include "elf-bfd.h"
> +#include "symcat.h"
> +#include "sim-regno.h"
> +#include "gdb/sim-riscv.h"
> +#include "dis-asm.h"
> +#include "frame-unwind.h"
> +#include "frame-base.h"
> +#include "trad-frame.h"
> +#include "infcall.h"
> +#include "floatformat.h"
> +#include "remote.h"
> +#include "target-descriptions.h"
> +#include "dwarf2-frame.h"
> +#include "user-regs.h"
> +#include "valprint.h"
> +#include "opcode/riscv-opc.h"
> +#include <algorithm>
> +



> +
> +static void
> +riscv_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *kindptr)
> +{
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +
> +  riscv_breakpoint_from_pc (gdbarch, pcptr, kindptr);
> +}
> +

remote_breakpoint_from_pc is removed in my patches
https://sourceware.org/ml/gdb-patches/2016-11/msg00031.html
They are not committed yet.  It would be good if you can rebase your
patches on top of mine when my patches are committed.

> +static struct value *
> +value_of_riscv_user_reg (struct frame_info *frame, const void *baton)
> +{
> +  const int *reg_p = (const int *)baton;
> +
> +  return value_of_register (*reg_p, frame);
> +}
> +
> +static const char *
> +register_name (struct gdbarch *gdbarch,
> +	       int             regnum,
> +               int             prefer_alias)

Code style issue, only one space is needed between "int" and "regnum".
Many instances of such problem around your patch.

> +{
> +  int i;
> +  static char buf[20];
> +
> +  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
> +    return tdesc_register_name (gdbarch, regnum);

I don't think riscv port has target description yet.



> +
> +static void
> +riscv_extract_return_value (struct type *type,
> +			    struct regcache *regs,
> +			    gdb_byte *dst,
> +			    int regnum)

You need some comments on this function.

> +{
> +  struct gdbarch *gdbarch = get_regcache_arch (regs);
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +  int regsize = riscv_isa_regsize (gdbarch);
> +  bfd_byte *valbuf = dst;
> +  int len = TYPE_LENGTH (type);
> +  ULONGEST tmp;
> +
> +  gdb_assert (len <= 2 * regsize);
> +
> +  while (len > 0)
> +    {
> +      regcache_cooked_read_unsigned (regs, regnum++, &tmp);
> +      store_unsigned_integer (valbuf, std::min (regsize, len), byte_order, tmp);

This line is too long.


> +      len -= regsize;
> +      valbuf += regsize;
> +    }
> +}
> +

/* Implement the return_value gdbarch method.  */

> +
> +static enum return_value_convention
> +riscv_return_value (struct gdbarch  *gdbarch,
> +		    struct value *function,
> +		    struct type     *type,
> +		    struct regcache *regcache,
> +		    gdb_byte        *readbuf,
> +		    const gdb_byte  *writebuf)
> +{
> +  enum type_code rv_type = TYPE_CODE (type);
> +  unsigned int rv_size = TYPE_LENGTH (type);
> +  int fp, regnum;
> +  ULONGEST tmp;
> +
> +  /* Paragraph on return values taken from RISC-V specification (post v2.0):
> +
> +     Values are returned from functions in integer registers a0 and a1 and
> +     floating-point registers fa0 and fa1.  Floating-point values are returned
> +     in floating-point registers only if they are primitives or members of a
> +     struct consisting of only one or two floating-point values.  Other return
> +     values that fit into two pointer-words are returned in a0 and a1.  Larger
> +     return values are passed entirely in memory; the caller allocates this
> +     memory region and passes a pointer to it as an implicit first parameter to
> +     the callee.  */
> +

Nit: some lines are too long.

> +  /* Deal with struct/unions first that are passed via memory.  */
> +  if (rv_size > 2 * riscv_isa_regsize (gdbarch))
> +    {
> +      if (readbuf || writebuf)
> +	regcache_cooked_read_unsigned (regcache, RISCV_A0_REGNUM, &tmp);
> +      if (readbuf)
> +	read_memory (tmp, readbuf, rv_size);
> +      if (writebuf)
> +	write_memory (tmp, writebuf, rv_size);
> +      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
> +    }
> +
> +  /* Are we dealing with a floating point value?  */
> +  fp = 0;
> +  if (rv_type == TYPE_CODE_FLT)
> +    fp = 1;
> +  else if (rv_type == TYPE_CODE_STRUCT || rv_type == TYPE_CODE_UNION)
> +    {
> +      unsigned int rv_fields = TYPE_NFIELDS (type);
> +
> +      if (rv_fields == 1)
> +	{
> +	  struct type *fieldtype = TYPE_FIELD_TYPE (type, 0);
> +	  if (TYPE_CODE (check_typedef (fieldtype)) == TYPE_CODE_FLT)
> +	    fp = 1;
> +	}
> +      else if (rv_fields == 2)
> +	{
> +	  struct type *fieldtype0 = TYPE_FIELD_TYPE (type, 0);
> +	  struct type *fieldtype1 = TYPE_FIELD_TYPE (type, 1);
> +
> +	  if (TYPE_CODE (check_typedef (fieldtype0)) == TYPE_CODE_FLT
> +	      && TYPE_CODE (check_typedef (fieldtype1)) == TYPE_CODE_FLT)
> +	    fp = 1;
> +	}
> +    }
> +
> +  /* Handle return value in a register.  */
> +  regnum = fp ? RISCV_FA0_REGNUM : RISCV_A0_REGNUM;
> +
> +  if (readbuf)
> +    riscv_extract_return_value (type, regcache, readbuf, regnum);
> +
> +  if (writebuf)
> +    riscv_store_return_value (type, regcache, writebuf, regnum);
> +
> +  return RETURN_VALUE_REGISTER_CONVENTION;
> +}
> +

/* Implement the XXX gdbarch method.  */

> +static enum register_status
> +riscv_pseudo_register_read (struct gdbarch  *gdbarch,
> +			    struct regcache *regcache,
> +			    int              regnum,
> +			    gdb_byte        *buf)

Code style issue.

> +{
> +  return regcache_raw_read (regcache, regnum, buf);
> +}
> +

> +
> +static struct type *
> +riscv_register_type (struct gdbarch  *gdbarch,
> +		     int              regnum)
> +{
> +  int regsize = riscv_isa_regsize (gdbarch);
> +
> +  if (regnum < RISCV_FIRST_FP_REGNUM)
> +    {
> + int_regsizes:
> +      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);
> +	}
> +    }
> +  else if (regnum <= RISCV_LAST_FP_REGNUM)
> +    {
> +      switch (regsize)
> +	{
> +	case 4:
> +	  return builtin_type (gdbarch)->builtin_float;
> +	case 8:
> +	case 16:
> +	  return builtin_type (gdbarch)->builtin_double;

return builtin_long_double in case regsize is 16?

> +	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;
> +
> +      goto int_regsizes;

goto is not necessarily needed.  Please remove it.

> +    }
> +}
> +
> +/* TODO: Replace all this with tdesc XML files.  */
> +static void
> +riscv_read_fp_register_single (struct frame_info *frame, int regno,
> +			       gdb_byte *rare_buffer)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (frame);
> +  int raw_size = register_size (gdbarch, regno);
> +  gdb_byte *raw_buffer = (gdb_byte *) alloca (raw_size);
> +
> +  if (!deprecated_frame_register_read (frame, regno, raw_buffer))

Use get_frame_register_value, your code can be simpler.

> +    error (_("can't read register %d (%s)"), regno,
> +	   gdbarch_register_name (gdbarch, regno));
> +
> +  if (raw_size == 8)
> +    {
> +      int offset;
> +
> +      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
> +	offset = 4;
> +      else
> +	offset = 0;
> +
> +      memcpy (rare_buffer, raw_buffer + offset, 4);
> +    }
> +  else
> +    memcpy (rare_buffer, raw_buffer, 4);
> +}
> +
> +static void
> +riscv_read_fp_register_double (struct frame_info *frame, int regno,
> +			       gdb_byte *rare_buffer)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (frame);
> +  int raw_size = register_size (gdbarch, regno);
> +
> +  if (raw_size == 8)
> +    {
> +      if (!deprecated_frame_register_read (frame, regno, rare_buffer))
> +	error (_("can't read register %d (%s)"), regno,
> +	       gdbarch_register_name (gdbarch, regno));
> +    }
> +  else
> +    internal_error (__FILE__, __LINE__,
> +		    _("%s: size says 32-bits, read is 64-bits."), __func__);
> +}
> +
> +static void
> +riscv_print_fp_register (struct ui_file *file, struct frame_info *frame,
> +			 int regnum)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (frame);
> +  gdb_byte *raw_buffer;
> +  struct value_print_options opts;
> +  double val;
> +  int inv;
> +  const char *regname;
> +
> +  raw_buffer = (gdb_byte *) alloca (2 * register_size (gdbarch, RISCV_FIRST_FP_REGNUM));
> +

This line is too long.

> +  fprintf_filtered (file, "%-15s", gdbarch_register_name (gdbarch, regnum));
> +
> +  if (register_size (gdbarch, regnum) == 4)
> +    {
> +      riscv_read_fp_register_single (frame, regnum, raw_buffer);
> +      val = unpack_double (builtin_type (gdbarch)->builtin_float, raw_buffer,
> +			   &inv);
> +
> +      get_formatted_print_options (&opts, 'x');
> +      print_scalar_formatted (raw_buffer,
> +			      builtin_type (gdbarch)->builtin_float,
> +			      &opts, 'w', file);
> +
> +      if (!inv)
> +	fprintf_filtered (file, "\t%-17.9g", val);
> +    }
> +  else
> +    {
> +      riscv_read_fp_register_double (frame, regnum, raw_buffer);
> +      val = unpack_double (builtin_type (gdbarch)->builtin_double, raw_buffer,
> +			   &inv);
> +
> +      get_formatted_print_options (&opts, 'x');
> +      print_scalar_formatted (raw_buffer,
> +			      builtin_type (gdbarch)->builtin_double,
> +			      &opts, 'g', file);
> +
> +      if (!inv)
> +	fprintf_filtered (file, "\t%-24.17g", val);
> +    }
> +
> +  if (inv)
> +    fprintf_filtered (file, "\t<invalid>");
> +}
> +




> +
> +static ULONGEST
> +riscv_fetch_instruction (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);

gdbarch_byte_order_for_code


> +
> +static void
> +set_reg_offset (struct gdbarch *gdbarch, struct riscv_frame_cache *this_cache,
> +		int regnum, CORE_ADDR offset)
> +{
> +  if (this_cache != NULL && this_cache->saved_regs[regnum].addr == -1)
> +    this_cache->saved_regs[regnum].addr = offset;
> +}
> +
> +static void
> +reset_saved_regs (struct gdbarch *gdbarch, struct riscv_frame_cache *this_cache)
> +{
> +  const int num_regs = gdbarch_num_regs (gdbarch);
> +  int i;
> +
> +  if (this_cache == NULL || this_cache->saved_regs == NULL)
> +    return;
> +
> +  for (i = 0; i < num_regs; ++i)
> +    this_cache->saved_regs[i].addr = -1;

IIRC, .addr's type is CORE_ADDR, which is unsigned.  Don't assign -1 to
a unsigned type.

> +}
> +
> +static CORE_ADDR
> +riscv_scan_prologue (struct gdbarch *gdbarch,
> +		     CORE_ADDR start_pc, CORE_ADDR limit_pc,
> +		     struct frame_info *this_frame,
> +		     struct riscv_frame_cache *this_cache)
> +{
> +  CORE_ADDR cur_pc;
> +  CORE_ADDR frame_addr = 0;
> +  CORE_ADDR sp;
> +  long frame_offset;
> +  int frame_reg = RISCV_SP_REGNUM;
> +
> +  CORE_ADDR end_prologue_addr = 0;
> +  int seen_sp_adjust = 0;
> +  int load_immediate_bytes = 0;
> +
> +  /* Can be called when there's no process, and hence when there's no THIS_FRAME.  */
> +  if (this_frame != NULL)
> +    sp = get_frame_register_signed (this_frame, RISCV_SP_REGNUM);
> +  else
> +    sp = 0;
> +
> +  if (limit_pc > start_pc + 200)
> +    limit_pc = start_pc + 200;
> +
> + restart:
> +
> +  frame_offset = 0;
> +  /* TODO: Handle compressed extensions.  */
> +  for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4)
> +    {
> +      unsigned long inst, opcode;
> +      int reg, rs1, imm12, rs2, offset12, funct3;
> +
> +      /* Fetch the instruction.  */
> +      inst = (unsigned long) riscv_fetch_instruction (gdbarch, cur_pc);

What if (unsigned long) is 4-bytes long, but riscv instruction is
8-bytes long?

> +      opcode = inst & 0x7F;
> +      reg = (inst >> 7) & 0x1F;
> +      rs1 = (inst >> 15) & 0x1F;
> +      imm12 = (inst >> 20) & 0xFFF;
> +      rs2 = (inst >> 20) & 0x1F;
> +      offset12 = (((inst >> 25) & 0x7F) << 5) + ((inst >> 7) & 0x1F);
> +      funct3 = (inst >> 12) & 0x7;
> +
> +      /* Look for common stack adjustment insns.  */
> +      if ((opcode == 0x13 || opcode == 0x1B) && reg == RISCV_SP_REGNUM
> +	  && rs1 == RISCV_SP_REGNUM)

Please use macros defined in include/opcode/riscv-opc.h, then the code
is much more readable.

> +static CORE_ADDR
> +riscv_push_dummy_call (struct gdbarch *gdbarch,
> +		       struct value *function,
> +		       struct regcache *regcache,
> +		       CORE_ADDR bp_addr,
> +		       int nargs,
> +		       struct value **args,
> +		       CORE_ADDR sp,
> +		       int struct_return,
> +		       CORE_ADDR struct_addr)
> +{
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +  gdb_byte buf[4];
> +  int i;
> +  CORE_ADDR func_addr = find_function_addr (function, NULL);
> +
> +  /* Push excess arguments in reverse order.  */
> +
> +  for (i = nargs; i >= 8; --i)
> +    {
> +      struct type *value_type = value_enclosing_type (args[i]);
> +      int container_len = align_up (TYPE_LENGTH (value_type), 3);
> +
> +      sp -= container_len;
> +      write_memory (sp, value_contents_writeable (args[i]), container_len);
> +    }
> +
> +  /* Initialize argument registers.  */
> +
> +  for (i = 0; i < nargs && i < 8; ++i)
> +    {
> +      struct type *value_type = value_enclosing_type (args[i]);
> +      const gdb_byte *arg_bits = value_contents_all (args[i]);
> +      int regnum = TYPE_CODE (value_type) == TYPE_CODE_FLT ?
> +	RISCV_FA0_REGNUM : RISCV_A0_REGNUM;
> +

code style issue,
https://www.gnu.org/prep/standards/standards.html#Formatting

int regnum = (TYPE_CODE (value_type) == TYPE_CODE_FLT
               ? RISCV_FA0_REGNUM : RISCV_A0_REGNUM);


> +
> +static struct gdbarch *
> +riscv_gdbarch_init (struct gdbarch_info  info,
> +		    struct gdbarch_list *arches)
> +{
> +  struct gdbarch *gdbarch;
> +  struct gdbarch_tdep *tdep;
> +  const struct bfd_arch_info *binfo = info.bfd_arch_info;
> +
> +  int abi, i;
> +
> +  /* For now, base the abi on the elf class.  */
> +  /* Allow the ELF class to override the register size. Ideally the target
> +   * (OpenOCD/spike/...) would communicate the register size to gdb instead. */
> +  abi = RISCV_ABI_FLAG_RV32I;
> +  if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
> +    {
> +      unsigned char eclass = elf_elfheader (info.abfd)->e_ident[EI_CLASS];
> +
> +      if (eclass == ELFCLASS32)
> +	abi = RISCV_ABI_FLAG_RV32I;
> +      else if (eclass == ELFCLASS64)
> +	abi = RISCV_ABI_FLAG_RV64I;
> +      else
> +        internal_error (__FILE__, __LINE__, _("unknown ELF header class %d"), eclass);
> +    }
> +  else
> +    {
> +      if (binfo->bits_per_word == 32)
> +        abi = RISCV_ABI_FLAG_RV32I;
> +      else if (binfo->bits_per_word == 64)
> +        abi = RISCV_ABI_FLAG_RV64I;
> +      else
> +        internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"),
> +            binfo->bits_per_word);
> +    }
> +
> +  /* 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)->riscv_abi == abi)
> +      return arches->gdbarch;
> +
> +  /* None found, so create a new architecture from the information provided.
> +     Can't initialize all the target dependencies until we actually know which
> +     target we are talking to, but put in some defaults for now.  */
> +
> +  tdep = (struct gdbarch_tdep *) xmalloc (sizeof *tdep);
> +  gdbarch = gdbarch_alloc (&info, tdep);
> +
> +  tdep->riscv_abi = abi;
> +  switch (abi)
> +    {
> +    case RISCV_ABI_FLAG_RV32I:
> +      tdep->register_size = 4;
> +      break;
> +    case RISCV_ABI_FLAG_RV64I:
> +      tdep->register_size = 8;

Since you've already had riscv_abi field in tdep, you can determine the
registers size on the fly.  Then, field register_size is not necessary
to me.

> +
> +  /* Information about the target architecture.  */
> +  set_gdbarch_return_value (gdbarch, riscv_return_value);
> +  set_gdbarch_breakpoint_from_pc (gdbarch, riscv_breakpoint_from_pc);

breakpoint_from_pc will be replaced by two new gdbarch methods, added in
my patches https://sourceware.org/ml/gdb-patches/2016-11/msg00031.html

> +  set_gdbarch_remote_breakpoint_from_pc (gdbarch, riscv_remote_breakpoint_from_pc);


> +
> +  /* Check any target description for validity.  */
> +  if (tdesc_has_registers (info.target_desc))
> +    {

We don't have riscv target description yet.

> +      const struct tdesc_feature *feature;
> +      struct tdesc_arch_data *tdesc_data;
> +      int valid_p;
> +
> +      feature = tdesc_find_feature (info.target_desc, "org.gnu.gdb.riscv.cpu");
> +      if (feature == NULL)
> +	goto no_tdata;
> +
> +      tdesc_data = tdesc_data_alloc ();
> +
> +      valid_p = 1;
> +      for (i = RISCV_ZERO_REGNUM; i <= RISCV_LAST_FP_REGNUM; ++i)
> +        valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
> +                                            riscv_gdb_reg_names[i]);
> +      for (i = RISCV_FIRST_CSR_REGNUM; i <= RISCV_LAST_CSR_REGNUM; ++i)
> +        {
> +          char buf[20];
> +          sprintf (buf, "csr%d", i - RISCV_FIRST_CSR_REGNUM);
> +          valid_p &= tdesc_numbered_register (feature, tdesc_data, i, buf);
> +        }
> +
> +      valid_p &= tdesc_numbered_register (feature, tdesc_data, i++, "priv");
> +
> +      if (!valid_p)
> +	tdesc_data_cleanup (tdesc_data);
> +      else
> +	tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
> +    }
> + no_tdata:
> +
> +  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);
> +
> +  return gdbarch;
> +}
> +

> diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
> new file mode 100644
> index 0000000..ef10209
> --- /dev/null
> +++ b/gdb/riscv-tdep.h
> @@ -0,0 +1,101 @@
> +/* Target-dependent header for the RISC-V architecture, for GDB, the GNU Debugger.
> +
> +   Copyright (C) 2002-2015 Free Software Foundation, Inc.
> +
> +   Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
> +   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
> +   and by Todd Snyder <todd@bluespec.com>
> +   and by Mike Frysinger <vapier@gentoo.org>.
> +
> +   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 RISCV_TDEP_H
> +#define RISCV_TDEP_H
> +
> +struct gdbarch;
> +
> +/* All the official RISC-V ABIs.  These mostly line up with mcpuid purely for
> +   convenience.  */
> +#define RISCV_ABI_FLAG_RV32I	(0x00000000)	/* 32-bit Integer GPRs.  */
> +#define RISCV_ABI_FLAG_RV32E	(0x10000000)	/* 32-bit Embedded Integer GPRs.  */
> +#define RISCV_ABI_FLAG_RV64I	(0x40000000)	/* 64-bit Integer GPRs.  */
> +#define RISCV_ABI_FLAG_RV128I	(0x80000000)	/* 128-bit Integer GPRs.  */
> +#define RISCV_ABI_FLAG_A	(1 << 0)	/* Atomics.  */
> +#define RISCV_ABI_FLAG_B	(1 << 1)	/* Bit Manipulation.  */
> +#define RISCV_ABI_FLAG_C	(1 << 2)	/* 16-bit Compressed Instructions.  */
> +#define RISCV_ABI_FLAG_D	(1 << 3)	/* Double-Precision Floating-Point.  */
> +#define RISCV_ABI_FLAG_E	(1 << 4)	/* Embedded base.  */
> +#define RISCV_ABI_FLAG_F	(1 << 5)	/* Single-Precision Floating-Point.  */
> +#define RISCV_ABI_FLAG_H	(1 << 7)	/* Hypervisor mode.  */
> +#define RISCV_ABI_FLAG_I	(1 << 8)	/* Base integer.  */
> +#define RISCV_ABI_FLAG_L	(1 << 11)	/* Decimal Floating-Point.  */
> +#define RISCV_ABI_FLAG_M	(1 << 12)	/* Integer Multiply and Division.  */
> +#define RISCV_ABI_FLAG_P	(1 << 15)	/* Packed-SIMD Extensions.  */
> +#define RISCV_ABI_FLAG_Q	(1 << 16)	/* Quad-Precision Floating-Point.  */
> +#define RISCV_ABI_FLAG_S	(1 << 18)	/* Supervisor mode.  */
> +#define RISCV_ABI_FLAG_T	(1 << 19)	/* Transactional Memory.  */
> +#define RISCV_ABI_FLAG_U	(1 << 20)	/* User mode.  */

I don't find where are they used.  Let us add them when they are really
used somewhere in the code.

> +
> +#define IS_RV32I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV32I)
> +#define IS_RV64I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV64I)
> +#define IS_RV128I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV128I)
> +
> +#define HAS_FPU(x)	((x) & (RISCV_ABI_FLAG_D | RISCV_ABI_FLAG_F))
> +

> +#endif /* RISCV_TDEP_H */
> diff --git a/include/gdb/sim-riscv.h b/include/gdb/sim-riscv.h
> new file mode 100644
> index 0000000..932cf49
> --- /dev/null
> +++ b/include/gdb/sim-riscv.h
> @@ -0,0 +1,98 @@
> +/* This file defines the interface between the RISC-V simulator and GDB.
> +
> +   Copyright (C) 2005-2015 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/>.  */
> +
> +/* Order has to match gdb riscv-tdep list.  */
> +enum sim_riscv_regnum {

I don't see how is this header file related to this patch?  Probably
this should be moved to sim patch.

-- 
Yao (齐尧)

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

* [PATCH 1/2] RISC-V GDB Port
  2016-10-22 23:40 ` GDB port for RISC-V Palmer Dabbelt
@ 2016-10-22 23:40   ` Palmer Dabbelt
  2016-11-03 12:39     ` Yao Qi
  0 siblings, 1 reply; 17+ messages in thread
From: Palmer Dabbelt @ 2016-10-22 23:40 UTC (permalink / raw)
  To: Andrew Waterman, gdb-patches, amodra; +Cc: Palmer Dabbelt

---
 gdb/Makefile.in           |    5 +-
 gdb/config/riscv/linux.mh |   30 ++
 gdb/configure.ac          |    3 +
 gdb/configure.host        |    3 +
 gdb/configure.tgt         |   12 +
 gdb/infcmd.c              |    5 +-
 gdb/riscv-linux-nat.c     |   77 +++
 gdb/riscv-linux-tdep.c    |   83 +++
 gdb/riscv-linux-tdep.h    |   30 ++
 gdb/riscv-tdep.c          | 1292 +++++++++++++++++++++++++++++++++++++++++++++
 gdb/riscv-tdep.h          |  101 ++++
 include/gdb/sim-riscv.h   |   98 ++++
 12 files changed, 1735 insertions(+), 4 deletions(-)
 create mode 100644 gdb/config/riscv/linux.mh
 create mode 100644 gdb/riscv-linux-nat.c
 create mode 100644 gdb/riscv-linux-tdep.c
 create mode 100644 gdb/riscv-linux-tdep.h
 create mode 100644 gdb/riscv-tdep.c
 create mode 100644 gdb/riscv-tdep.h
 create mode 100644 include/gdb/sim-riscv.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2c88434..e4e497b 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -691,7 +691,7 @@ ALL_TARGET_OBS = \
 	nios2-tdep.o nios2-linux-tdep.o \
 	nto-tdep.o \
 	ppc-linux-tdep.o ppcfbsd-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o  \
-	ppc-sysv-tdep.o ppc64-tdep.o rl78-tdep.o \
+	ppc-sysv-tdep.o ppc64-tdep.o riscv-tdep.o rl78-tdep.o \
 	rs6000-aix-tdep.o rs6000-tdep.o solib-aix.o ppc-ravenscar-thread.o \
 	rs6000-lynx178-tdep.o \
 	rx-tdep.o \
@@ -946,7 +946,7 @@ sparc64-tdep.h ppcobsd-tdep.h \
 coff-pe-read.h parser-defs.h gdb_ptrace.h mips-linux-tdep.h \
 m68k-tdep.h spu-tdep.h environ.h amd64-tdep.h \
 doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h ppc64-tdep.h \
-rs6000-tdep.h rs6000-aix-tdep.h \
+riscv-tdep.h rs6000-tdep.h rs6000-aix-tdep.h \
 common/gdb_locale.h arch-utils.h trad-frame.h gnu-nat.h \
 language.h nbsd-tdep.h solib-svr4.h \
 macroexp.h ui-file.h regcache.h tracepoint.h tracefile.h i386-tdep.h \
@@ -1734,6 +1734,7 @@ ALLDEPFILES = \
 	ravenscar-thread.c \
 	remote-sim.c \
 	dcache.c \
+	riscv-tdep.c \
 	rl78-tdep.c \
 	rs6000-nat.c rs6000-tdep.c solib-aix.c ppc-ravenscar-thread.c \
 	rs6000-lynx178-tdep.c \
diff --git a/gdb/config/riscv/linux.mh b/gdb/config/riscv/linux.mh
new file mode 100644
index 0000000..f68f371
--- /dev/null
+++ b/gdb/config/riscv/linux.mh
@@ -0,0 +1,30 @@
+#  Host: RISC-V based machine running GNU/Linux
+#
+#  Copyright (C) 2015 Free Software Foundation, Inc.
+#  Contributed by Albert Ou <albert@sifive.com>.
+#
+#  This file is part of GDB.
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 3 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+NAT_FILE= config/nm-linux.h
+NATDEPFILES= inf-ptrace.o fork-child.o riscv-linux-nat.o \
+	proc-service.o linux-thread-db.o linux-nat.o linux-fork.o \
+	linux-procfs.o linux-ptrace.o linux-osdata.o linux-waitpid.o \
+	linux-namespaces.o linux-personality.o
+NAT_CDEPS = $(srcdir)/proc-service.list
+
+# The dynamically loaded libthread_db needs access to symbols in the
+# gdb executable.
+LOADLIBES= -ldl $(RDYNAMIC)
diff --git a/gdb/configure.ac b/gdb/configure.ac
index e451e60..2147e62 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -515,6 +515,9 @@ esac
 # We might need to link with -lm; most simulators need it.
 AC_CHECK_LIB(m, main)
 
+# The RISC-V simulator needs clock_gettime()
+AC_SEARCH_LIBS([clock_gettime], [rt])
+
 # We need to link with -lw to get `wctype' on Solaris before Solaris
 # 2.6.  Solaris 2.6 and beyond have this function in libc, and have a
 # libw that some versions of the GNU linker cannot hanle (GNU ld 2.9.1
diff --git a/gdb/configure.host b/gdb/configure.host
index ef265eb..d887f44 100644
--- a/gdb/configure.host
+++ b/gdb/configure.host
@@ -64,6 +64,7 @@ m68*)			gdb_host_cpu=m68k ;;
 m88*)			gdb_host_cpu=m88k ;;
 mips*)			gdb_host_cpu=mips ;;
 powerpc* | rs6000)	gdb_host_cpu=powerpc ;;
+riscv*)                 gdb_host_cpu=riscv ;;
 sparcv9 | sparc64)	gdb_host_cpu=sparc ;;
 s390*)			gdb_host_cpu=s390 ;;
 sh*)			gdb_host_cpu=sh ;;
@@ -147,6 +148,8 @@ powerpc64*-*-linux*)	gdb_host=ppc64-linux
 			;;
 powerpc*-*-linux*)	gdb_host=linux ;;
 
+riscv*-linux*)          gdb_host=linux ;;
+
 s390*-*-linux*)		gdb_host=linux ;;
 
 sh*-*-netbsdelf* | sh*-*-knetbsd*-gnu)
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index d428dff..2dce609 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -478,6 +478,18 @@ s390*-*-linux*)
 	build_gdbserver=yes
 	;;
 
+riscv*-*-linux*)
+	# Target Linux/RISC-V
+	gdb_target_obs="riscv-tdep.o riscv-linux-tdep.o \
+			glibc-tdep.o linux-tdep.o solib-svr4.o"
+	;;
+
+riscv*-*-*)
+	# Target: RISC-V architecture
+	gdb_target_obs="riscv-tdep.o"
+	gdb_sim=../sim/riscv/libsim.a
+	;;
+
 rl78-*-elf)
 	# Target: Renesas rl78
 	gdb_target_obs="rl78-tdep.o"
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 8e34b7e..4457304 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -3447,8 +3447,9 @@ otherwise all the threads in the program are stopped.  To \n\
 interrupt all running threads in non-stop mode, use the -a option."));
 
   c = add_info ("registers", nofp_registers_info, _("\
-List of integer registers and their contents, for selected stack frame.\n\
-Register name as argument means describe only that register."));
+Display registers and their contents, for the selected stack frame.\n\
+Usage: info registers [all|register|register group] ...\n\
+By default, the general register group will be shown."));
   add_info_alias ("r", "registers", 1);
   set_cmd_completer (c, reg_or_group_completer);
 
diff --git a/gdb/riscv-linux-nat.c b/gdb/riscv-linux-nat.c
new file mode 100644
index 0000000..6accb7a
--- /dev/null
+++ b/gdb/riscv-linux-nat.c
@@ -0,0 +1,77 @@
+/* Native-dependent code for GNU/Linux RISC-V.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+   Contributed by Albert Ou <albert@sifive.com>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+
+#include "inferior.h"
+#include "regcache.h"
+
+#include <sys/ptrace.h>
+#include "gregset.h"
+
+#include "riscv-tdep.h"
+#include "riscv-linux-tdep.h"
+
+/* Transfering the general-purpose registers between GDB, inferiors
+   and core files.  */
+
+/* Fill GDB's register cache with the general-purpose register values
+   in *GREGSETP.  */
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
+{
+  regcache_supply_regset (&riscv_linux_gregset, regcache, -1,
+			  (const gdb_byte *) gregsetp,
+			  (RISCV_NGREG));
+}
+
+/* Fill register REGNUM (if it is a general-purpose register) in
+   *GREGSETP with the value in GDB's register cache.  If REGNUM is -1,
+   do this for all registers.  */
+
+void
+fill_gregset (const struct regcache *regcache,
+	      gdb_gregset_t *gregsetp, int regno)
+{
+  regcache_collect_regset (&riscv_linux_gregset, regcache,
+			   regno, (gdb_byte *) gregsetp,
+			   (RISCV_NGREG));
+}
+
+/* Transfering floating-point registers between GDB, inferiors and cores.  */
+
+/* Fill GDB's register cache with the floating-point and SSE register
+   values in *FPREGSETP.  */
+
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
+{
+}
+
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+   *FPREGSETP with the value in GDB's register cache.  If REGNUM is
+   -1, do this for all registers.  */
+
+void
+fill_fpregset (const struct regcache *regcache,
+	       gdb_fpregset_t *fpregsetp, int regnum)
+{
+}
diff --git a/gdb/riscv-linux-tdep.c b/gdb/riscv-linux-tdep.c
new file mode 100644
index 0000000..b66860c
--- /dev/null
+++ b/gdb/riscv-linux-tdep.c
@@ -0,0 +1,83 @@
+/* Target-dependent code for GNU/Linux RISC-V.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+   Contributed by Albert Ou <albert@sifive.com>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+
+#include "gdbarch.h"
+#include "osabi.h"
+#include "linux-tdep.h"
+#include "solib-svr4.h"
+#include "glibc-tdep.h"
+
+#include "riscv-tdep.h"
+#include "riscv-linux-tdep.h"
+
+#include "regcache.h"
+#include "regset.h"
+
+static const struct regcache_map_entry riscv_linux_gregmap[] =
+{
+  { 1,  RISCV_PC_REGNUM, 0 },
+  { 31, RISCV_RA_REGNUM, 0 }, /* x1 to x31 */
+  { 0 }
+};
+
+const struct regset riscv_linux_gregset =
+{
+  riscv_linux_gregmap, regcache_supply_regset, regcache_collect_regset
+};
+
+static void
+riscv_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+					  iterate_over_regset_sections_cb *cb,
+					  void *cb_data,
+					  const struct regcache *regcache)
+{
+  cb (".reg", (RISCV_NGREG * riscv_isa_regsize (gdbarch)),
+      &riscv_linux_gregset, NULL, cb_data);
+}
+
+static void
+riscv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  linux_init_abi (info, gdbarch);
+
+  /* GNU/Linux uses SVR4-style shared libraries.  */
+  /* FIXME: This '0' should actually be a check to see if we're on
+     rv32, but I can't figure out how to hook that up (it's in
+     gdbarch_tdep, which we don't have here). */
+  set_solib_svr4_fetch_link_map_offsets
+    (gdbarch, (0) ?
+      svr4_ilp32_fetch_link_map_offsets :
+      svr4_lp64_fetch_link_map_offsets);
+
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, riscv_linux_iterate_over_regset_sections);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_riscv_linux_tdep;
+
+void
+_initialize_riscv_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_LINUX,
+			  riscv_linux_init_abi);
+}
diff --git a/gdb/riscv-linux-tdep.h b/gdb/riscv-linux-tdep.h
new file mode 100644
index 0000000..d5758ca
--- /dev/null
+++ b/gdb/riscv-linux-tdep.h
@@ -0,0 +1,30 @@
+/* Target-dependent header for GNU/Linux RISC-V.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+   Contributed by Albert Ou <albert@sifive.com>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef RISCV_LINUX_TDEP_H
+#define RISCV_LINUX_TDEP_H
+
+#include "regset.h"
+
+#define RISCV_NGREG (32)
+
+extern const struct regset riscv_linux_gregset;
+
+#endif
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
new file mode 100644
index 0000000..9afd28d
--- /dev/null
+++ b/gdb/riscv-tdep.c
@@ -0,0 +1,1292 @@
+/* Target-dependent code for the RISC-V architecture, for GDB.
+
+   Copyright (C) 1988-2015 Free Software Foundation, Inc.
+
+   Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
+   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
+   and by Todd Snyder <todd@bluespec.com>
+   and by Mike Frysinger <vapier@gentoo.org>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "gdbcore.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "target.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "osabi.h"
+#include "riscv-tdep.h"
+#include "block.h"
+#include "reggroups.h"
+#include "opcode/riscv.h"
+#include "elf/riscv.h"
+#include "elf-bfd.h"
+#include "symcat.h"
+#include "sim-regno.h"
+#include "gdb/sim-riscv.h"
+#include "dis-asm.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+#include "infcall.h"
+#include "floatformat.h"
+#include "remote.h"
+#include "target-descriptions.h"
+#include "dwarf2-frame.h"
+#include "user-regs.h"
+#include "valprint.h"
+#include "opcode/riscv-opc.h"
+#include <algorithm>
+
+struct riscv_frame_cache
+{
+  CORE_ADDR base;
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+static const char * const riscv_gdb_reg_names[RISCV_LAST_FP_REGNUM + 1] =
+{
+  "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
+  "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
+  "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
+  "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
+  "pc",
+  "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
+  "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
+  "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+  "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+};
+
+struct register_alias
+{
+  const char *name;
+  int regnum;
+};
+
+static const struct register_alias riscv_register_aliases[] =
+{
+  { "zero", 0 },
+  { "ra", 1 },
+  { "sp", 2 },
+  { "gp", 3 },
+  { "tp", 4 },
+  { "t0", 5 },
+  { "t1", 6 },
+  { "t2", 7 },
+  { "fp", 8 },
+  { "s0", 8 },
+  { "s1", 9 },
+  { "a0", 10 },
+  { "a1", 11 },
+  { "a2", 12 },
+  { "a3", 13 },
+  { "a4", 14 },
+  { "a5", 15 },
+  { "a6", 16 },
+  { "a7", 17 },
+  { "s2", 18 },
+  { "s3", 19 },
+  { "s4", 20 },
+  { "s5", 21 },
+  { "s6", 22 },
+  { "s7", 23 },
+  { "s8", 24 },
+  { "s9", 25 },
+  { "s10", 26 },
+  { "s11", 27 },
+  { "t3", 28 },
+  { "t4", 29 },
+  { "t5", 30 },
+  { "t6", 31 },
+  /* pc is 32.  */
+  { "ft0", 33 },
+  { "ft1", 34 },
+  { "ft2", 35 },
+  { "ft3", 36 },
+  { "ft4", 37 },
+  { "ft5", 38 },
+  { "ft6", 39 },
+  { "ft7", 40 },
+  { "fs0", 41 },
+  { "fs1", 42 },
+  { "fa0", 43 },
+  { "fa1", 44 },
+  { "fa2", 45 },
+  { "fa3", 46 },
+  { "fa4", 47 },
+  { "fa5", 48 },
+  { "fa6", 49 },
+  { "fa7", 50 },
+  { "fs2", 51 },
+  { "fs3", 52 },
+  { "fs4", 53 },
+  { "fs5", 54 },
+  { "fs6", 55 },
+  { "fs7", 56 },
+  { "fs8", 57 },
+  { "fs9", 58 },
+  { "fs10", 59 },
+  { "fs11", 60 },
+  { "ft8", 61 },
+  { "ft9", 62 },
+  { "ft10", 63 },
+  { "ft11", 64 },
+#define DECLARE_CSR(name, num) { #name, (num) + 65 },
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+};
+
+static const gdb_byte *
+riscv_breakpoint_from_pc (struct gdbarch *gdbarch,
+			  CORE_ADDR      *bp_addr,
+			  int            *bp_size)
+{
+  /* TODO: Support C.EBREAK for compressed (16-bit) insns.  */
+  /* TODO: Support NOPs for >=6 byte insns.  */
+  static const gdb_byte sbreak_insn[] = { 0x73, 0x00, 0x10, 0x00, };
+
+  *bp_size = 4;
+
+  return sbreak_insn;
+}
+
+static void
+riscv_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *kindptr)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  riscv_breakpoint_from_pc (gdbarch, pcptr, kindptr);
+}
+
+static struct value *
+value_of_riscv_user_reg (struct frame_info *frame, const void *baton)
+{
+  const int *reg_p = (const int *)baton;
+
+  return value_of_register (*reg_p, frame);
+}
+
+static const char *
+register_name (struct gdbarch *gdbarch,
+	       int             regnum,
+               int             prefer_alias)
+{
+  int i;
+  static char buf[20];
+
+  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+    return tdesc_register_name (gdbarch, regnum);
+  /* Prefer to use the alias. */
+  if (prefer_alias &&
+      regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_REGNUM)
+    {
+      for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i)
+	if (regnum == riscv_register_aliases[i].regnum)
+	  return riscv_register_aliases[i].name;
+    }
+
+  if (regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
+      return riscv_gdb_reg_names[regnum];
+
+  if (regnum >= RISCV_FIRST_CSR_REGNUM && regnum <= RISCV_LAST_CSR_REGNUM)
+    {
+      sprintf(buf, "csr%d", regnum - RISCV_FIRST_CSR_REGNUM);
+      return buf;
+    }
+
+  if (regnum == RISCV_PRIV_REGNUM)
+    {
+      return "priv";
+    }
+
+  return NULL;
+}
+
+static const char *
+riscv_register_name (struct gdbarch *gdbarch,
+		     int             regnum)
+{
+  return register_name(gdbarch, regnum, 0);
+}
+
+static void
+riscv_extract_return_value (struct type *type,
+			    struct regcache *regs,
+			    gdb_byte *dst,
+			    int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regs);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int regsize = riscv_isa_regsize (gdbarch);
+  bfd_byte *valbuf = dst;
+  int len = TYPE_LENGTH (type);
+  ULONGEST tmp;
+
+  gdb_assert (len <= 2 * regsize);
+
+  while (len > 0)
+    {
+      regcache_cooked_read_unsigned (regs, regnum++, &tmp);
+      store_unsigned_integer (valbuf, std::min (regsize, len), byte_order, tmp);
+      len -= regsize;
+      valbuf += regsize;
+    }
+}
+
+/* Write into appropriate registers a function return value of type
+   TYPE, given in virtual format.  */
+
+static void
+riscv_store_return_value (struct type *type,
+			  struct regcache *regs,
+			  const gdb_byte *src,
+			  int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regs);
+  int regsize = riscv_isa_regsize (gdbarch);
+  const bfd_byte *valbuf = src;
+
+  /* Integral values greater than one word are stored in consecutive
+     registers starting with R0.  This will always be a multiple of
+     the register size.  */
+
+  int len = TYPE_LENGTH (type);
+
+  gdb_assert (len <= 2 * regsize);
+
+  while (len > 0)
+    {
+      regcache_cooked_write (regs, regnum++, valbuf);
+      len -= regsize;
+      valbuf += regsize;
+    }
+}
+
+static enum return_value_convention
+riscv_return_value (struct gdbarch  *gdbarch,
+		    struct value *function,
+		    struct type     *type,
+		    struct regcache *regcache,
+		    gdb_byte        *readbuf,
+		    const gdb_byte  *writebuf)
+{
+  enum type_code rv_type = TYPE_CODE (type);
+  unsigned int rv_size = TYPE_LENGTH (type);
+  int fp, regnum;
+  ULONGEST tmp;
+
+  /* Paragraph on return values taken from RISC-V specification (post v2.0):
+
+     Values are returned from functions in integer registers a0 and a1 and
+     floating-point registers fa0 and fa1.  Floating-point values are returned
+     in floating-point registers only if they are primitives or members of a
+     struct consisting of only one or two floating-point values.  Other return
+     values that fit into two pointer-words are returned in a0 and a1.  Larger
+     return values are passed entirely in memory; the caller allocates this
+     memory region and passes a pointer to it as an implicit first parameter to
+     the callee.  */
+
+  /* Deal with struct/unions first that are passed via memory.  */
+  if (rv_size > 2 * riscv_isa_regsize (gdbarch))
+    {
+      if (readbuf || writebuf)
+	regcache_cooked_read_unsigned (regcache, RISCV_A0_REGNUM, &tmp);
+      if (readbuf)
+	read_memory (tmp, readbuf, rv_size);
+      if (writebuf)
+	write_memory (tmp, writebuf, rv_size);
+      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
+    }
+
+  /* Are we dealing with a floating point value?  */
+  fp = 0;
+  if (rv_type == TYPE_CODE_FLT)
+    fp = 1;
+  else if (rv_type == TYPE_CODE_STRUCT || rv_type == TYPE_CODE_UNION)
+    {
+      unsigned int rv_fields = TYPE_NFIELDS (type);
+
+      if (rv_fields == 1)
+	{
+	  struct type *fieldtype = TYPE_FIELD_TYPE (type, 0);
+	  if (TYPE_CODE (check_typedef (fieldtype)) == TYPE_CODE_FLT)
+	    fp = 1;
+	}
+      else if (rv_fields == 2)
+	{
+	  struct type *fieldtype0 = TYPE_FIELD_TYPE (type, 0);
+	  struct type *fieldtype1 = TYPE_FIELD_TYPE (type, 1);
+
+	  if (TYPE_CODE (check_typedef (fieldtype0)) == TYPE_CODE_FLT
+	      && TYPE_CODE (check_typedef (fieldtype1)) == TYPE_CODE_FLT)
+	    fp = 1;
+	}
+    }
+
+  /* Handle return value in a register.  */
+  regnum = fp ? RISCV_FA0_REGNUM : RISCV_A0_REGNUM;
+
+  if (readbuf)
+    riscv_extract_return_value (type, regcache, readbuf, regnum);
+
+  if (writebuf)
+    riscv_store_return_value (type, regcache, writebuf, regnum);
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+static enum register_status
+riscv_pseudo_register_read (struct gdbarch  *gdbarch,
+			    struct regcache *regcache,
+			    int              regnum,
+			    gdb_byte        *buf)
+{
+  return regcache_raw_read (regcache, regnum, buf);
+}
+
+static void
+riscv_pseudo_register_write (struct gdbarch  *gdbarch,
+			     struct regcache *regcache,
+			     int              cookednum,
+			     const gdb_byte  *buf)
+{
+  regcache_raw_write (regcache, cookednum, buf);
+}
+
+static struct type *
+riscv_register_type (struct gdbarch  *gdbarch,
+		     int              regnum)
+{
+  int regsize = riscv_isa_regsize (gdbarch);
+
+  if (regnum < RISCV_FIRST_FP_REGNUM)
+    {
+ int_regsizes:
+      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);
+	}
+    }
+  else if (regnum <= RISCV_LAST_FP_REGNUM)
+    {
+      switch (regsize)
+	{
+	case 4:
+	  return builtin_type (gdbarch)->builtin_float;
+	case 8:
+	case 16:
+	  return builtin_type (gdbarch)->builtin_double;
+	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;
+
+      goto int_regsizes;
+    }
+}
+
+/* TODO: Replace all this with tdesc XML files.  */
+static void
+riscv_read_fp_register_single (struct frame_info *frame, int regno,
+			       gdb_byte *rare_buffer)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int raw_size = register_size (gdbarch, regno);
+  gdb_byte *raw_buffer = (gdb_byte *) alloca (raw_size);
+
+  if (!deprecated_frame_register_read (frame, regno, raw_buffer))
+    error (_("can't read register %d (%s)"), regno,
+	   gdbarch_register_name (gdbarch, regno));
+
+  if (raw_size == 8)
+    {
+      int offset;
+
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	offset = 4;
+      else
+	offset = 0;
+
+      memcpy (rare_buffer, raw_buffer + offset, 4);
+    }
+  else
+    memcpy (rare_buffer, raw_buffer, 4);
+}
+
+static void
+riscv_read_fp_register_double (struct frame_info *frame, int regno,
+			       gdb_byte *rare_buffer)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int raw_size = register_size (gdbarch, regno);
+
+  if (raw_size == 8)
+    {
+      if (!deprecated_frame_register_read (frame, regno, rare_buffer))
+	error (_("can't read register %d (%s)"), regno,
+	       gdbarch_register_name (gdbarch, regno));
+    }
+  else
+    internal_error (__FILE__, __LINE__,
+		    _("%s: size says 32-bits, read is 64-bits."), __func__);
+}
+
+static void
+riscv_print_fp_register (struct ui_file *file, struct frame_info *frame,
+			 int regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  gdb_byte *raw_buffer;
+  struct value_print_options opts;
+  double val;
+  int inv;
+  const char *regname;
+
+  raw_buffer = (gdb_byte *) alloca (2 * register_size (gdbarch, RISCV_FIRST_FP_REGNUM));
+
+  fprintf_filtered (file, "%-15s", gdbarch_register_name (gdbarch, regnum));
+
+  if (register_size (gdbarch, regnum) == 4)
+    {
+      riscv_read_fp_register_single (frame, regnum, raw_buffer);
+      val = unpack_double (builtin_type (gdbarch)->builtin_float, raw_buffer,
+			   &inv);
+
+      get_formatted_print_options (&opts, 'x');
+      print_scalar_formatted (raw_buffer,
+			      builtin_type (gdbarch)->builtin_float,
+			      &opts, 'w', file);
+
+      if (!inv)
+	fprintf_filtered (file, "\t%-17.9g", val);
+    }
+  else
+    {
+      riscv_read_fp_register_double (frame, regnum, raw_buffer);
+      val = unpack_double (builtin_type (gdbarch)->builtin_double, raw_buffer,
+			   &inv);
+
+      get_formatted_print_options (&opts, 'x');
+      print_scalar_formatted (raw_buffer,
+			      builtin_type (gdbarch)->builtin_double,
+			      &opts, 'g', file);
+
+      if (!inv)
+	fprintf_filtered (file, "\t%-24.17g", val);
+    }
+
+  if (inv)
+    fprintf_filtered (file, "\t<invalid>");
+}
+
+static void
+riscv_print_register_formatted (struct ui_file *file, struct frame_info *frame,
+				int regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  gdb_byte raw_buffer[MAX_REGISTER_SIZE];
+  struct value_print_options opts;
+
+  if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
+    riscv_print_fp_register (file, frame, regnum);
+  else
+    {
+      /* Integer type.  */
+      int offset, size;
+      unsigned long long d;
+
+      if (!deprecated_frame_register_read (frame, regnum, raw_buffer))
+	{
+	  fprintf_filtered (file, "%-15s[Invalid]\n",
+			    register_name (gdbarch, regnum, 1));
+	  return;
+	}
+
+      fprintf_filtered (file, "%-15s", register_name (gdbarch, regnum, 1));
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	offset = register_size (gdbarch, regnum) - register_size (gdbarch, regnum);
+      else
+	offset = 0;
+
+      size = register_size (gdbarch, regnum);
+      get_formatted_print_options (&opts, 'x');
+      print_scalar_formatted (raw_buffer + offset,
+			      register_type (gdbarch, regnum), &opts,
+			      size == 8 ? 'g' : 'w', file);
+      fprintf_filtered (file, "\t");
+      if (size == 4 && riscv_isa_regsize (gdbarch) == 8)
+	fprintf_filtered (file, "\t");
+
+      if (regnum == RISCV_CSR_MSTATUS_REGNUM)
+	{
+	  d = unpack_long (builtin_type (gdbarch)->builtin_int32, raw_buffer);
+	  fprintf_filtered (file, "IP:%02X IM:%02X EA:%d VM:%d S64:%d U64:%d EF:%d PEI:%d EI:%d PS:%d S:%d",
+			    (int)((d >> 24) & 0xFF),
+			    (int)((d >> 16) & 0xFF),
+			    (int)((d >> 8) & 0x1),
+			    (int)((d >> 7) & 0x1),
+			    (int)((d >> 6) & 0x1),
+			    (int)((d >> 5) & 0x1),
+			    (int)((d >> 4) & 0x1),
+			    (int)((d >> 3) & 0x1),
+			    (int)((d >> 2) & 0x1),
+			    (int)((d >> 1) & 0x1),
+			    (int)((d >> 0) & 0x1));
+	}
+      else if (regnum == RISCV_CSR_MISA_REGNUM)
+        {
+          int base;
+          if (size == 4) {
+            d = unpack_long (builtin_type (gdbarch)->builtin_uint32, raw_buffer);
+            base = d >> 30;
+          } else if (size == 8) {
+            d = unpack_long (builtin_type (gdbarch)->builtin_uint64, raw_buffer);
+            base = d >> 62;
+          } else {
+            internal_error (__FILE__, __LINE__, _("unknown size for misa"));
+          }
+          unsigned xlen = 16;
+          for (; base > 0; base--) {
+            xlen *= 2;
+          }
+	  fprintf_filtered (file, "RV%d", xlen);
+
+          for (unsigned i = 0; i < 26; i++) {
+            if (d & (1<<i)) {
+              fprintf_filtered (file, "%c", 'A' + i);
+            }
+          }
+        }
+      else if (regnum == RISCV_CSR_FCSR_REGNUM
+	       || regnum == RISCV_CSR_FFLAGS_REGNUM
+	       || regnum == RISCV_CSR_FRM_REGNUM)
+	{
+	  d = unpack_long (builtin_type (gdbarch)->builtin_int32, raw_buffer);
+
+	  if (regnum != RISCV_CSR_FRM_REGNUM)
+	    fprintf_filtered (file, "RD:%01X NV:%d DZ:%d OF:%d UF:%d NX:%d   ",
+			      (int)((d >> 5) & 0x7),
+			      (int)((d >> 4) & 0x1),
+			      (int)((d >> 3) & 0x1),
+			      (int)((d >> 2) & 0x1),
+			      (int)((d >> 1) & 0x1),
+			      (int)((d >> 0) & 0x1));
+
+	  if (regnum != RISCV_CSR_FFLAGS_REGNUM)
+	    {
+	      static const char * const sfrm[] = {
+		"RNE (round to nearest; ties to even)",
+		"RTZ (Round towards zero)",
+		"RDN (Round down towards -∞)",
+		"RUP (Round up towards +∞)",
+		"RMM (Round to nearest; tiest to max magnitude)",
+		"INVALID[5]",
+		"INVALID[6]",
+		"dynamic rounding mode",
+	      };
+	      int frm = ((regnum == RISCV_CSR_FCSR_REGNUM) ? (d >> 5) : d) & 0x3;
+
+	      fprintf_filtered (file, "FRM:%i [%s]", frm, sfrm[frm]);
+	    }
+	}
+      else if (regnum == RISCV_PRIV_REGNUM)
+        {
+          uint8_t priv = raw_buffer[0];
+          if (priv >= 0 && priv < 4)
+            {
+              static const char * const sprv[] = {
+                "User/Application",
+                "Supervisor",
+                "Hypervisor",
+                "Machine"
+              };
+              fprintf_filtered (file, "prv:%d [%s]", priv, sprv[priv]);
+            }
+          else
+            {
+              fprintf_filtered (file, "prv:%d [INVALID]", priv);
+            }
+        }
+      else
+	{
+	  get_formatted_print_options (&opts, 'd');
+	  print_scalar_formatted (raw_buffer + offset,
+				  register_type (gdbarch, regnum),
+				  &opts, 0, file);
+	}
+    }
+  fprintf_filtered (file, "\n");
+}
+
+static int
+riscv_register_reggroup_p (struct gdbarch  *gdbarch,
+			   int              regnum,
+			   struct reggroup *reggroup)
+{
+  int float_p;
+  int raw_p;
+  unsigned int i;
+
+  /* Used by 'info registers' and 'info registers <groupname>'.  */
+
+  if (gdbarch_register_name (gdbarch, regnum) == NULL
+      || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
+    return 0;
+
+  if (reggroup == all_reggroup) {
+    if (regnum < RISCV_FIRST_CSR_REGNUM || regnum == RISCV_PRIV_REGNUM)
+      return 1;
+    /* Only include CSRs that have aliases.  */
+    for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i) {
+	if (regnum == riscv_register_aliases[i].regnum)
+          return 1;
+    }
+    return 0;
+  } else if (reggroup == float_reggroup)
+    return (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
+	    || (regnum == RISCV_CSR_FCSR_REGNUM
+	        || regnum == RISCV_CSR_FFLAGS_REGNUM
+	        || regnum == RISCV_CSR_FRM_REGNUM);
+  else if (reggroup == general_reggroup)
+    return regnum < RISCV_FIRST_FP_REGNUM;
+  else if (reggroup == restore_reggroup || reggroup == save_reggroup)
+    return regnum <= RISCV_LAST_FP_REGNUM;
+  else if (reggroup == system_reggroup) {
+    if (regnum == RISCV_PRIV_REGNUM)
+      return 1;
+    if (regnum < RISCV_FIRST_CSR_REGNUM || regnum > RISCV_LAST_CSR_REGNUM)
+      return 0;
+    /* Only include CSRs that have aliases.  */
+    for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i) {
+	if (regnum == riscv_register_aliases[i].regnum)
+          return 1;
+    }
+    return 0;
+  } else if (reggroup == vector_reggroup)
+    return 0;
+  else
+    internal_error (__FILE__, __LINE__, _("unhandled reggroup"));
+}
+
+static void
+riscv_print_registers_info (struct gdbarch    *gdbarch,
+			    struct ui_file    *file,
+			    struct frame_info *frame,
+			    int                regnum,
+			    int                all)
+{
+  /* Use by 'info all-registers'.  */
+  struct reggroup *reggroup;
+
+  if (regnum != -1)
+    {
+      /* Print one specified register.  */
+      gdb_assert (regnum <= RISCV_LAST_REGNUM);
+      if (NULL == register_name (gdbarch, regnum, 1))
+        error (_("Not a valid register for the current processor type"));
+      riscv_print_register_formatted (file, frame, regnum);
+      return;
+    }
+
+  if (all)
+    reggroup = all_reggroup;
+  else
+    reggroup = general_reggroup;
+  for (regnum = 0; regnum <= RISCV_LAST_REGNUM; ++regnum)
+    {
+      /* Zero never changes, so might as well hide by default.  */
+      if (regnum == RISCV_ZERO_REGNUM && !all)
+        continue;
+      if (riscv_register_reggroup_p(gdbarch, regnum, reggroup))
+        riscv_print_register_formatted (file, frame, regnum);
+    }
+}
+
+static ULONGEST
+riscv_fetch_instruction (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  gdb_byte buf[8];
+  int instlen, status;
+
+  /* All insns are at least 16 bits.  */
+  status = target_read_memory (addr, buf, 2);
+  if (status)
+    memory_error (TARGET_XFER_E_IO, addr);
+
+  /* If we need more, grab it now.  */
+  instlen = riscv_insn_length (buf[0]);
+  if (instlen > sizeof (buf))
+    internal_error (__FILE__, __LINE__, _("%s: riscv_insn_length returned %i"),
+		    __func__, instlen);
+  else if (instlen > 2)
+    {
+      status = target_read_memory (addr + 2, buf + 2, instlen - 2);
+      if (status)
+	memory_error (TARGET_XFER_E_IO, addr + 2);
+    }
+
+  return extract_unsigned_integer (buf, instlen, byte_order);
+}
+
+static void
+set_reg_offset (struct gdbarch *gdbarch, struct riscv_frame_cache *this_cache,
+		int regnum, CORE_ADDR offset)
+{
+  if (this_cache != NULL && this_cache->saved_regs[regnum].addr == -1)
+    this_cache->saved_regs[regnum].addr = offset;
+}
+
+static void
+reset_saved_regs (struct gdbarch *gdbarch, struct riscv_frame_cache *this_cache)
+{
+  const int num_regs = gdbarch_num_regs (gdbarch);
+  int i;
+
+  if (this_cache == NULL || this_cache->saved_regs == NULL)
+    return;
+
+  for (i = 0; i < num_regs; ++i)
+    this_cache->saved_regs[i].addr = -1;
+}
+
+static CORE_ADDR
+riscv_scan_prologue (struct gdbarch *gdbarch,
+		     CORE_ADDR start_pc, CORE_ADDR limit_pc,
+		     struct frame_info *this_frame,
+		     struct riscv_frame_cache *this_cache)
+{
+  CORE_ADDR cur_pc;
+  CORE_ADDR frame_addr = 0;
+  CORE_ADDR sp;
+  long frame_offset;
+  int frame_reg = RISCV_SP_REGNUM;
+
+  CORE_ADDR end_prologue_addr = 0;
+  int seen_sp_adjust = 0;
+  int load_immediate_bytes = 0;
+
+  /* Can be called when there's no process, and hence when there's no THIS_FRAME.  */
+  if (this_frame != NULL)
+    sp = get_frame_register_signed (this_frame, RISCV_SP_REGNUM);
+  else
+    sp = 0;
+
+  if (limit_pc > start_pc + 200)
+    limit_pc = start_pc + 200;
+
+ restart:
+
+  frame_offset = 0;
+  /* TODO: Handle compressed extensions.  */
+  for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4)
+    {
+      unsigned long inst, opcode;
+      int reg, rs1, imm12, rs2, offset12, funct3;
+
+      /* Fetch the instruction.  */
+      inst = (unsigned long) riscv_fetch_instruction (gdbarch, cur_pc);
+      opcode = inst & 0x7F;
+      reg = (inst >> 7) & 0x1F;
+      rs1 = (inst >> 15) & 0x1F;
+      imm12 = (inst >> 20) & 0xFFF;
+      rs2 = (inst >> 20) & 0x1F;
+      offset12 = (((inst >> 25) & 0x7F) << 5) + ((inst >> 7) & 0x1F);
+      funct3 = (inst >> 12) & 0x7;
+
+      /* Look for common stack adjustment insns.  */
+      if ((opcode == 0x13 || opcode == 0x1B) && reg == RISCV_SP_REGNUM
+	  && rs1 == RISCV_SP_REGNUM)
+	{
+	  /* addi sp, sp, -i */
+	  /* addiw sp, sp, -i */
+	  if (imm12 & 0x800)
+	    frame_offset += 0x1000 - imm12;
+	  else
+	    break;
+	  seen_sp_adjust = 1;
+	}
+      else if (opcode == 0x23 && funct3 == 0x2 && rs1 == RISCV_SP_REGNUM)
+	{
+	  /* sw reg, offset(sp) */
+	  set_reg_offset (gdbarch, this_cache, rs1, sp + offset12);
+	}
+      else if (opcode == 0x23 && funct3 == 0x3 && rs1 == RISCV_SP_REGNUM)
+	{
+	  /* sd reg, offset(sp) */
+	  set_reg_offset (gdbarch, this_cache, rs1, sp + offset12);
+	}
+      else if (opcode == 0x13 && reg == RISCV_FP_REGNUM && rs1 == RISCV_SP_REGNUM)
+	{
+	  /* addi s0, sp, size */
+	  if ((long)imm12 != frame_offset)
+	    frame_addr = sp + imm12;
+	}
+      else if (this_frame && frame_reg == RISCV_SP_REGNUM)
+	{
+	  unsigned alloca_adjust;
+
+	  frame_reg = RISCV_FP_REGNUM;
+	  frame_addr = get_frame_register_signed (this_frame, RISCV_FP_REGNUM);
+
+	  alloca_adjust = (unsigned)(frame_addr - (sp - imm12));
+	  if (alloca_adjust > 0)
+	    {
+	      sp += alloca_adjust;
+	      reset_saved_regs (gdbarch, this_cache);
+	      goto restart;
+	    }
+	}
+      else if ((opcode == 0x33 || opcode == 0x3B) && reg == RISCV_FP_REGNUM
+	       && rs1 == RISCV_SP_REGNUM && rs2 == RISCV_ZERO_REGNUM)
+	{
+	  /* add s0, sp, 0 */
+	  /* addw s0, sp, 0 */
+	  if (this_frame && frame_reg == RISCV_SP_REGNUM)
+	    {
+	      unsigned alloca_adjust;
+	      frame_reg = RISCV_FP_REGNUM;
+	      frame_addr = get_frame_register_signed (this_frame,
+						      RISCV_FP_REGNUM);
+
+	      alloca_adjust = (unsigned)(frame_addr - sp);
+	      if (alloca_adjust > 0)
+		{
+		  sp = frame_addr;
+		  reset_saved_regs (gdbarch, this_cache);
+		  goto restart;
+		}
+	    }
+	}
+      else if (opcode == 0x23 && funct3 == 0x2 && rs1 == RISCV_FP_REGNUM)
+	{
+	  /* sw reg, offset(s0) */
+	  set_reg_offset (gdbarch, this_cache, rs1, frame_addr + offset12);
+	}
+      else if (reg == RISCV_GP_REGNUM
+	       && (opcode == 0x17 || opcode == 0x37
+		   || (opcode == 0x13 && rs1 == RISCV_GP_REGNUM)
+		   || (opcode == 0x33 && (rs1 == RISCV_GP_REGNUM
+					  || rs2 == RISCV_GP_REGNUM))))
+	{
+	  /* auipc gp, n */
+	  /* addi gp, gp, n */
+	  /* add gp, gp, reg */
+	  /* add gp, reg, gp */
+	  /* lui gp, n */
+	  /* These instructions are part of the prologue, but we don't need to
+	     do anything special to handle them.  */
+	}
+      else
+	{
+	  if (end_prologue_addr == 0)
+	    end_prologue_addr = cur_pc;
+	}
+    }
+
+  if (this_cache != NULL)
+    {
+      this_cache->base = get_frame_register_signed (this_frame, frame_reg)
+	+ frame_offset;
+      this_cache->saved_regs[RISCV_PC_REGNUM] =
+	this_cache->saved_regs[RISCV_RA_REGNUM];
+    }
+
+  if (end_prologue_addr == 0)
+    end_prologue_addr = cur_pc;
+
+  if (load_immediate_bytes && !seen_sp_adjust)
+    end_prologue_addr -= load_immediate_bytes;
+
+  return end_prologue_addr;
+}
+
+static CORE_ADDR
+riscv_skip_prologue (struct gdbarch *gdbarch,
+		     CORE_ADDR       pc)
+{
+  CORE_ADDR limit_pc;
+  CORE_ADDR func_addr;
+
+  /* See if we can determine the end of the prologue via the symbol table.
+     If so, then return either PC, or the PC after the prologue, whichever
+     is greater.  */
+  if (find_pc_partial_function (pc, NULL, &func_addr, NULL))
+    {
+      CORE_ADDR post_prologue_pc = skip_prologue_using_sal (gdbarch, func_addr);
+      if (post_prologue_pc != 0)
+	return std::max (pc, post_prologue_pc);
+    }
+
+  /* Can't determine prologue from the symbol table, need to examine
+     instructions.  */
+
+  /* Find an upper limit on the function prologue using the debug information.
+     If the debug information could not be used to provide that bound, then use
+     an arbitrary large number as the upper bound.  */
+  limit_pc = skip_prologue_using_sal (gdbarch, pc);
+  if (limit_pc == 0)
+    limit_pc = pc + 100;   /* MAGIC! */
+
+  return riscv_scan_prologue (gdbarch, pc, limit_pc, NULL, NULL);
+}
+
+static CORE_ADDR
+riscv_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr,
+		       struct value **args, int nargs, struct type *value_type,
+		       CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+		       struct regcache *regcache)
+{
+  *bp_addr = sp;
+  *real_pc = funaddr;
+
+  /* Keep the stack aligned.  */
+  return sp - 16;
+}
+
+static CORE_ADDR
+riscv_push_dummy_call (struct gdbarch *gdbarch,
+		       struct value *function,
+		       struct regcache *regcache,
+		       CORE_ADDR bp_addr,
+		       int nargs,
+		       struct value **args,
+		       CORE_ADDR sp,
+		       int struct_return,
+		       CORE_ADDR struct_addr)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  gdb_byte buf[4];
+  int i;
+  CORE_ADDR func_addr = find_function_addr (function, NULL);
+
+  /* Push excess arguments in reverse order.  */
+
+  for (i = nargs; i >= 8; --i)
+    {
+      struct type *value_type = value_enclosing_type (args[i]);
+      int container_len = align_up (TYPE_LENGTH (value_type), 3);
+
+      sp -= container_len;
+      write_memory (sp, value_contents_writeable (args[i]), container_len);
+    }
+
+  /* Initialize argument registers.  */
+
+  for (i = 0; i < nargs && i < 8; ++i)
+    {
+      struct type *value_type = value_enclosing_type (args[i]);
+      const gdb_byte *arg_bits = value_contents_all (args[i]);
+      int regnum = TYPE_CODE (value_type) == TYPE_CODE_FLT ?
+	RISCV_FA0_REGNUM : RISCV_A0_REGNUM;
+
+      regcache_cooked_write_unsigned
+	(regcache, regnum + i,
+	 extract_unsigned_integer (arg_bits, tdep->register_size, byte_order));
+    }
+
+  /* Store struct value address.  */
+
+  if (struct_return)
+    regcache_cooked_write_unsigned (regcache, RISCV_A0_REGNUM, struct_addr);
+
+  /* Set the dummy return value to bp_addr.
+     A dummy breakpoint will be setup to execute the call.  */
+
+  regcache_cooked_write_unsigned (regcache, RISCV_RA_REGNUM, bp_addr);
+
+  /* Finally, update the stack pointer.  */
+
+  regcache_cooked_write_unsigned (regcache, RISCV_SP_REGNUM, sp);
+
+  return sp;
+}
+
+static CORE_ADDR
+riscv_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  return align_down (addr, 16);
+}
+
+static CORE_ADDR
+riscv_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, RISCV_PC_REGNUM);
+}
+
+static CORE_ADDR
+riscv_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, RISCV_SP_REGNUM);
+}
+
+static struct frame_id
+riscv_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return frame_id_build (get_frame_register_signed (this_frame, RISCV_SP_REGNUM),
+			 get_frame_pc (this_frame));
+}
+
+static struct trad_frame_cache *
+riscv_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  CORE_ADDR pc;
+  CORE_ADDR start_addr;
+  CORE_ADDR stack_addr;
+  struct trad_frame_cache *this_trad_cache;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
+  if ((*this_cache) != NULL)
+    return (struct trad_frame_cache *) *this_cache;
+  this_trad_cache = trad_frame_cache_zalloc (this_frame);
+  (*this_cache) = this_trad_cache;
+
+  trad_frame_set_reg_realreg (this_trad_cache, gdbarch_pc_regnum (gdbarch),
+			      RISCV_RA_REGNUM);
+
+  pc = get_frame_pc (this_frame);
+  find_pc_partial_function (pc, NULL, &start_addr, NULL);
+  stack_addr = get_frame_register_signed (this_frame, RISCV_SP_REGNUM);
+  trad_frame_set_id (this_trad_cache, frame_id_build (stack_addr, start_addr));
+
+  trad_frame_set_this_base (this_trad_cache, stack_addr);
+
+  return this_trad_cache;
+}
+
+static void
+riscv_frame_this_id (struct frame_info *this_frame,
+		     void              **prologue_cache,
+		     struct frame_id   *this_id)
+{
+  struct trad_frame_cache *info = riscv_frame_cache (this_frame, prologue_cache);
+  trad_frame_get_id (info, this_id);
+}
+
+static struct value *
+riscv_frame_prev_register (struct frame_info *this_frame,
+			   void              **prologue_cache,
+			   int                regnum)
+{
+  struct trad_frame_cache *info = riscv_frame_cache (this_frame, prologue_cache);
+  return trad_frame_get_register (info, this_frame, regnum);
+}
+
+static const struct frame_unwind riscv_frame_unwind =
+{
+  /*.type          =*/ NORMAL_FRAME,
+  /*.stop_reason   =*/ default_frame_unwind_stop_reason,
+  /*.this_id       =*/ riscv_frame_this_id,
+  /*.prev_register =*/ riscv_frame_prev_register,
+  /*.unwind_data   =*/ NULL,
+  /*.sniffer       =*/ default_frame_sniffer,
+  /*.dealloc_cache =*/ NULL,
+  /*.prev_arch     =*/ NULL,
+};
+
+static struct gdbarch *
+riscv_gdbarch_init (struct gdbarch_info  info,
+		    struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  const struct bfd_arch_info *binfo = info.bfd_arch_info;
+
+  int abi, i;
+
+  /* For now, base the abi on the elf class.  */
+  /* Allow the ELF class to override the register size. Ideally the target
+   * (OpenOCD/spike/...) would communicate the register size to gdb instead. */
+  abi = RISCV_ABI_FLAG_RV32I;
+  if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    {
+      unsigned char eclass = elf_elfheader (info.abfd)->e_ident[EI_CLASS];
+
+      if (eclass == ELFCLASS32)
+	abi = RISCV_ABI_FLAG_RV32I;
+      else if (eclass == ELFCLASS64)
+	abi = RISCV_ABI_FLAG_RV64I;
+      else
+        internal_error (__FILE__, __LINE__, _("unknown ELF header class %d"), eclass);
+    }
+  else
+    {
+      if (binfo->bits_per_word == 32)
+        abi = RISCV_ABI_FLAG_RV32I;
+      else if (binfo->bits_per_word == 64)
+        abi = RISCV_ABI_FLAG_RV64I;
+      else
+        internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"),
+            binfo->bits_per_word);
+    }
+
+  /* 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)->riscv_abi == abi)
+      return arches->gdbarch;
+
+  /* None found, so create a new architecture from the information provided.
+     Can't initialize all the target dependencies until we actually know which
+     target we are talking to, but put in some defaults for now.  */
+
+  tdep = (struct gdbarch_tdep *) xmalloc (sizeof *tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  tdep->riscv_abi = abi;
+  switch (abi)
+    {
+    case RISCV_ABI_FLAG_RV32I:
+      tdep->register_size = 4;
+      break;
+    case RISCV_ABI_FLAG_RV64I:
+      tdep->register_size = 8;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, _("unknown abi %i"), abi);
+      tdep->register_size = 4;
+      break;
+    }
+
+  /* Target data types.  */
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 32);
+  set_gdbarch_long_bit (gdbarch, tdep->register_size * 8);
+  set_gdbarch_float_bit (gdbarch, 32);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 128);
+  set_gdbarch_ptr_bit (gdbarch, tdep->register_size * 8);
+  set_gdbarch_char_signed (gdbarch, 1);
+
+  /* Information about the target architecture.  */
+  set_gdbarch_return_value (gdbarch, riscv_return_value);
+  set_gdbarch_breakpoint_from_pc (gdbarch, riscv_breakpoint_from_pc);
+  set_gdbarch_remote_breakpoint_from_pc (gdbarch, riscv_remote_breakpoint_from_pc);
+  set_gdbarch_print_insn (gdbarch, print_insn_riscv);
+
+  /* Register architecture.  */
+  set_gdbarch_pseudo_register_read (gdbarch, riscv_pseudo_register_read);
+  set_gdbarch_pseudo_register_write (gdbarch, riscv_pseudo_register_write);
+  set_gdbarch_num_regs (gdbarch, RISCV_NUM_REGS);
+  set_gdbarch_num_pseudo_regs (gdbarch, RISCV_NUM_REGS);
+  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);
+  set_gdbarch_frame_align (gdbarch, riscv_frame_align);
+
+  /* Functions to access frame data.  */
+  set_gdbarch_unwind_pc (gdbarch, riscv_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, riscv_unwind_sp);
+
+  /* Functions handling dummy frames.  */
+  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+  set_gdbarch_push_dummy_code (gdbarch, riscv_push_dummy_code);
+  set_gdbarch_push_dummy_call (gdbarch, riscv_push_dummy_call);
+  set_gdbarch_dummy_id (gdbarch, riscv_dummy_id);
+
+  /* Frame unwinders.  Use DWARF debug info if available, otherwise use our own
+     unwinder.  */
+  dwarf2_append_unwinders (gdbarch);
+  frame_unwind_append_unwinder (gdbarch, &riscv_frame_unwind);
+
+  /* Check any target description for validity.  */
+  if (tdesc_has_registers (info.target_desc))
+    {
+      const struct tdesc_feature *feature;
+      struct tdesc_arch_data *tdesc_data;
+      int valid_p;
+
+      feature = tdesc_find_feature (info.target_desc, "org.gnu.gdb.riscv.cpu");
+      if (feature == NULL)
+	goto no_tdata;
+
+      tdesc_data = tdesc_data_alloc ();
+
+      valid_p = 1;
+      for (i = RISCV_ZERO_REGNUM; i <= RISCV_LAST_FP_REGNUM; ++i)
+        valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+                                            riscv_gdb_reg_names[i]);
+      for (i = RISCV_FIRST_CSR_REGNUM; i <= RISCV_LAST_CSR_REGNUM; ++i)
+        {
+          char buf[20];
+          sprintf (buf, "csr%d", i - RISCV_FIRST_CSR_REGNUM);
+          valid_p &= tdesc_numbered_register (feature, tdesc_data, i, buf);
+        }
+
+      valid_p &= tdesc_numbered_register (feature, tdesc_data, i++, "priv");
+
+      if (!valid_p)
+	tdesc_data_cleanup (tdesc_data);
+      else
+	tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
+    }
+ no_tdata:
+
+  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);
+
+  return gdbarch;
+}
+
+extern initialize_file_ftype _initialize_riscv_tdep; /* -Wmissing-prototypes */
+
+void
+_initialize_riscv_tdep (void)
+{
+  gdbarch_register (bfd_arch_riscv, riscv_gdbarch_init, NULL);
+}
diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
new file mode 100644
index 0000000..ef10209
--- /dev/null
+++ b/gdb/riscv-tdep.h
@@ -0,0 +1,101 @@
+/* Target-dependent header for the RISC-V architecture, for GDB, the GNU Debugger.
+
+   Copyright (C) 2002-2015 Free Software Foundation, Inc.
+
+   Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
+   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
+   and by Todd Snyder <todd@bluespec.com>
+   and by Mike Frysinger <vapier@gentoo.org>.
+
+   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 RISCV_TDEP_H
+#define RISCV_TDEP_H
+
+struct gdbarch;
+
+/* All the official RISC-V ABIs.  These mostly line up with mcpuid purely for
+   convenience.  */
+#define RISCV_ABI_FLAG_RV32I	(0x00000000)	/* 32-bit Integer GPRs.  */
+#define RISCV_ABI_FLAG_RV32E	(0x10000000)	/* 32-bit Embedded Integer GPRs.  */
+#define RISCV_ABI_FLAG_RV64I	(0x40000000)	/* 64-bit Integer GPRs.  */
+#define RISCV_ABI_FLAG_RV128I	(0x80000000)	/* 128-bit Integer GPRs.  */
+#define RISCV_ABI_FLAG_A	(1 << 0)	/* Atomics.  */
+#define RISCV_ABI_FLAG_B	(1 << 1)	/* Bit Manipulation.  */
+#define RISCV_ABI_FLAG_C	(1 << 2)	/* 16-bit Compressed Instructions.  */
+#define RISCV_ABI_FLAG_D	(1 << 3)	/* Double-Precision Floating-Point.  */
+#define RISCV_ABI_FLAG_E	(1 << 4)	/* Embedded base.  */
+#define RISCV_ABI_FLAG_F	(1 << 5)	/* Single-Precision Floating-Point.  */
+#define RISCV_ABI_FLAG_H	(1 << 7)	/* Hypervisor mode.  */
+#define RISCV_ABI_FLAG_I	(1 << 8)	/* Base integer.  */
+#define RISCV_ABI_FLAG_L	(1 << 11)	/* Decimal Floating-Point.  */
+#define RISCV_ABI_FLAG_M	(1 << 12)	/* Integer Multiply and Division.  */
+#define RISCV_ABI_FLAG_P	(1 << 15)	/* Packed-SIMD Extensions.  */
+#define RISCV_ABI_FLAG_Q	(1 << 16)	/* Quad-Precision Floating-Point.  */
+#define RISCV_ABI_FLAG_S	(1 << 18)	/* Supervisor mode.  */
+#define RISCV_ABI_FLAG_T	(1 << 19)	/* Transactional Memory.  */
+#define RISCV_ABI_FLAG_U	(1 << 20)	/* User mode.  */
+
+#define IS_RV32I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV32I)
+#define IS_RV64I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV64I)
+#define IS_RV128I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV128I)
+
+#define HAS_FPU(x)	((x) & (RISCV_ABI_FLAG_D | RISCV_ABI_FLAG_F))
+
+enum {
+  RISCV_ZERO_REGNUM = 0,	/* Read-only register, always 0.  */
+  RISCV_RA_REGNUM = 1,		/* Return Address.  */
+  RISCV_SP_REGNUM = 2,		/* Stack Pointer.  */
+  RISCV_GP_REGNUM = 3,		/* Global Pointer.  */
+  RISCV_TP_REGNUM = 4,		/* Thread Pointer.  */
+  RISCV_FP_REGNUM = 8,		/* Frame Pointer.  */
+  RISCV_A0_REGNUM = 10,		/* First argument.  */
+  RISCV_A1_REGNUM = 11,		/* Second argument.  */
+  RISCV_PC_REGNUM = 32,		/* Program Counter.  */
+
+  RISCV_FIRST_FP_REGNUM = 33,	/* First Floating Point Register */
+  RISCV_FA0_REGNUM = 49,
+  RISCV_FA1_REGNUM = 50,
+  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_LAST_FP_REGNUM + 1 + num,
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+  RISCV_LAST_CSR_REGNUM = 4160,
+
+  RISCV_PRIV_REGNUM = 4161,
+
+  /* Leave this as the last enum.  */
+  RISCV_NUM_REGS
+};
+
+#define RISCV_LAST_REGNUM (RISCV_NUM_REGS - 1)
+
+/* RISC-V specific per-architecture information.  */
+struct gdbarch_tdep
+{
+  int riscv_abi;
+  int register_size;
+};
+
+static inline int
+riscv_isa_regsize (struct gdbarch *gdbarch)
+{
+  return gdbarch_tdep (gdbarch)->register_size;
+}
+
+#endif /* RISCV_TDEP_H */
diff --git a/include/gdb/sim-riscv.h b/include/gdb/sim-riscv.h
new file mode 100644
index 0000000..932cf49
--- /dev/null
+++ b/include/gdb/sim-riscv.h
@@ -0,0 +1,98 @@
+/* This file defines the interface between the RISC-V simulator and GDB.
+
+   Copyright (C) 2005-2015 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/>.  */
+
+/* Order has to match gdb riscv-tdep list.  */
+enum sim_riscv_regnum {
+  SIM_RISCV_ZERO_REGNUM = 0,
+  SIM_RISCV_RA_REGNUM,
+  SIM_RISCV_SP_REGNUM,
+  SIM_RISCV_GP_REGNUM,
+  SIM_RISCV_TP_REGNUM,
+  SIM_RISCV_T0_REGNUM,
+  SIM_RISCV_T1_REGNUM,
+  SIM_RISCV_T2_REGNUM,
+  SIM_RISCV_S0_REGNUM,
+#define SIM_RISCV_FP_REGNUM SIM_RISCV_S0_REGNUM
+  SIM_RISCV_S1_REGNUM,
+  SIM_RISCV_A0_REGNUM,
+  SIM_RISCV_A1_REGNUM,
+  SIM_RISCV_A2_REGNUM,
+  SIM_RISCV_A3_REGNUM,
+  SIM_RISCV_A4_REGNUM,
+  SIM_RISCV_A5_REGNUM,
+  SIM_RISCV_A6_REGNUM,
+  SIM_RISCV_A7_REGNUM,
+  SIM_RISCV_S2_REGNUM,
+  SIM_RISCV_S3_REGNUM,
+  SIM_RISCV_S4_REGNUM,
+  SIM_RISCV_S5_REGNUM,
+  SIM_RISCV_S6_REGNUM,
+  SIM_RISCV_S7_REGNUM,
+  SIM_RISCV_S8_REGNUM,
+  SIM_RISCV_S9_REGNUM,
+  SIM_RISCV_S10_REGNUM,
+  SIM_RISCV_S11_REGNUM,
+  SIM_RISCV_T3_REGNUM,
+  SIM_RISCV_T4_REGNUM,
+  SIM_RISCV_T5_REGNUM,
+  SIM_RISCV_T6_REGNUM,
+  SIM_RISCV_PC_REGNUM,
+  SIM_RISCV_FT0_REGNUM,
+#define SIM_RISCV_FIRST_FP_REGNUM SIM_RISCV_FT0_REGNUM
+  SIM_RISCV_FT1_REGNUM,
+  SIM_RISCV_FT2_REGNUM,
+  SIM_RISCV_FT3_REGNUM,
+  SIM_RISCV_FT4_REGNUM,
+  SIM_RISCV_FT5_REGNUM,
+  SIM_RISCV_FT6_REGNUM,
+  SIM_RISCV_FT7_REGNUM,
+  SIM_RISCV_FS0_REGNUM,
+  SIM_RISCV_FS1_REGNUM,
+  SIM_RISCV_FA0_REGNUM,
+  SIM_RISCV_FA1_REGNUM,
+  SIM_RISCV_FA2_REGNUM,
+  SIM_RISCV_FA3_REGNUM,
+  SIM_RISCV_FA4_REGNUM,
+  SIM_RISCV_FA5_REGNUM,
+  SIM_RISCV_FA6_REGNUM,
+  SIM_RISCV_FA7_REGNUM,
+  SIM_RISCV_FS2_REGNUM,
+  SIM_RISCV_FS3_REGNUM,
+  SIM_RISCV_FS4_REGNUM,
+  SIM_RISCV_FS5_REGNUM,
+  SIM_RISCV_FS6_REGNUM,
+  SIM_RISCV_FS7_REGNUM,
+  SIM_RISCV_FS8_REGNUM,
+  SIM_RISCV_FS9_REGNUM,
+  SIM_RISCV_FS10_REGNUM,
+  SIM_RISCV_FS11_REGNUM,
+  SIM_RISCV_FT8_REGNUM,
+  SIM_RISCV_FT9_REGNUM,
+  SIM_RISCV_FT10_REGNUM,
+  SIM_RISCV_FT11_REGNUM,
+#define SIM_RISCV_LAST_FP_REGNUM SIM_RISCV_FT11_REGNUM
+
+#define SIM_RISCV_FIRST_CSR_REGNUM SIM_RISCV_LAST_FP_REGNUM + 1
+#define DECLARE_CSR(name, num) SIM_RISCV_ ## num ## _REGNUM,
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+#define SIM_RISCV_LAST_CSR_REGNUM SIM_RISCV_LAST_REGNUM - 1
+
+  SIM_RISCV_LAST_REGNUM
+};
-- 
2.7.3

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

end of thread, other threads:[~2017-04-24 16:12 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-06 20:31 RISC-V GDB Port v3 Palmer Dabbelt
2017-03-06 20:31 ` [PATCH 1/2] RISC-V GDB Port Palmer Dabbelt
2017-04-04 21:48   ` Yao Qi
2017-04-24 16:12     ` Palmer Dabbelt
2017-04-05  9:22   ` Yao Qi
2017-03-06 20:31 ` [PATCH 2/2] RISC-V sim Port Palmer Dabbelt
2017-03-10 19:38 ` RISC-V GDB Port v3 Palmer Dabbelt
2017-03-21  9:23 ` Yao Qi
2017-03-21 16:04   ` Palmer Dabbelt
2017-04-05  9:30 ` Yao Qi
     [not found] <1477179037-32066-1-git-send-email-palmer@dabbelt.com>
2016-10-22 23:40 ` GDB port for RISC-V Palmer Dabbelt
2016-10-22 23:40   ` [PATCH 1/2] RISC-V GDB Port Palmer Dabbelt
2016-11-03 12:39     ` Yao Qi
2016-11-14 22:39       ` Palmer Dabbelt
2016-11-16 19:36         ` Pedro Alves
2016-11-16 19:40           ` Palmer Dabbelt
2016-11-16 19:48             ` Pedro Alves
2016-11-16 21:40         ` Yao Qi

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