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 ` [PATCH 2/2] RISC-V sim Port 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-10 19:38 ` RISC-V GDB Port v3 Palmer Dabbelt
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 10+ 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] 10+ 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 ` Palmer Dabbelt
  2017-03-06 20:31 ` [PATCH 1/2] RISC-V GDB Port Palmer Dabbelt
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 10+ 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] 10+ messages in thread

* RISC-V GDB Port v3
@ 2017-03-06 20:31 Palmer Dabbelt
  2017-03-06 20:31 ` [PATCH 2/2] RISC-V sim Port Palmer Dabbelt
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ 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] 10+ 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 2/2] RISC-V sim Port Palmer Dabbelt
  2017-03-06 20:31 ` [PATCH 1/2] RISC-V GDB 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ messages in thread

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

Thread overview: 10+ 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 2/2] RISC-V sim Port 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-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

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