* [PATCH 1/2] RISC-V GDB Port
2017-03-06 20:31 RISC-V GDB Port v3 Palmer Dabbelt
@ 2017-03-06 20:31 ` Palmer Dabbelt
2017-04-04 21:48 ` Yao Qi
2017-04-05 9:22 ` Yao Qi
2017-03-06 20:31 ` [PATCH 2/2] RISC-V sim Port Palmer Dabbelt
` (3 subsequent siblings)
4 siblings, 2 replies; 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 ®s_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 ` [PATCH 1/2] RISC-V GDB Port Palmer Dabbelt
@ 2017-03-06 20:31 ` Palmer Dabbelt
2017-03-10 19:38 ` RISC-V GDB Port v3 Palmer Dabbelt
` (2 subsequent siblings)
4 siblings, 0 replies; 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