Merge remote-tracking branch 'origin/priv-1.10' into HEAD
authorMegan Wachs <megan@sifive.com>
Mon, 17 Apr 2017 17:59:38 +0000 (10:59 -0700)
committerMegan Wachs <megan@sifive.com>
Mon, 17 Apr 2017 17:59:38 +0000 (10:59 -0700)
87 files changed:
LICENSE
README.md
config.h.in
configure
configure.ac
remote_bitbang.cc [new file with mode: 0644]
remote_bitbang.h [new file with mode: 0644]
riscv/clint.cc [new file with mode: 0644]
riscv/decode.h
riscv/devices.h
riscv/encoding.h
riscv/execute.cc
riscv/extension.cc
riscv/insn_template.h
riscv/insns/c_ebreak.h
riscv/insns/c_fld.h
riscv/insns/c_fldsp.h
riscv/insns/c_flw.h
riscv/insns/c_flwsp.h
riscv/insns/c_fsd.h
riscv/insns/c_fsdsp.h
riscv/insns/c_fsw.h
riscv/insns/c_fswsp.h
riscv/insns/ebreak.h
riscv/insns/fadd_d.h
riscv/insns/fadd_s.h
riscv/insns/fcvt_d_l.h
riscv/insns/fcvt_d_lu.h
riscv/insns/fcvt_d_s.h
riscv/insns/fcvt_d_w.h
riscv/insns/fcvt_d_wu.h
riscv/insns/fcvt_s_d.h
riscv/insns/fcvt_s_l.h
riscv/insns/fcvt_s_lu.h
riscv/insns/fcvt_s_w.h
riscv/insns/fcvt_s_wu.h
riscv/insns/fdiv_d.h
riscv/insns/fdiv_s.h
riscv/insns/fld.h
riscv/insns/flw.h
riscv/insns/fmadd_d.h
riscv/insns/fmadd_s.h
riscv/insns/fmax_d.h
riscv/insns/fmax_s.h
riscv/insns/fmin_d.h
riscv/insns/fmin_s.h
riscv/insns/fmsub_d.h
riscv/insns/fmsub_s.h
riscv/insns/fmul_d.h
riscv/insns/fmul_s.h
riscv/insns/fmv_d_x.h
riscv/insns/fmv_s_x.h
riscv/insns/fmv_x_d.h
riscv/insns/fmv_x_s.h
riscv/insns/fnmadd_d.h
riscv/insns/fnmadd_s.h
riscv/insns/fnmsub_d.h
riscv/insns/fnmsub_s.h
riscv/insns/fsd.h
riscv/insns/fsgnj_d.h
riscv/insns/fsgnj_s.h
riscv/insns/fsgnjn_d.h
riscv/insns/fsgnjn_s.h
riscv/insns/fsgnjx_d.h
riscv/insns/fsgnjx_s.h
riscv/insns/fsqrt_d.h
riscv/insns/fsqrt_s.h
riscv/insns/fsub_d.h
riscv/insns/fsub_s.h
riscv/insns/fsw.h
riscv/insns/mret.h
riscv/insns/sfence_vm.h [deleted file]
riscv/insns/sfence_vma.h [new file with mode: 0644]
riscv/insns/sret.h
riscv/insns/wfi.h
riscv/interactive.cc
riscv/mmu.cc
riscv/mmu.h
riscv/processor.cc
riscv/processor.h
riscv/riscv.ac
riscv/riscv.mk.in
riscv/rtc.cc [deleted file]
riscv/sim.cc
riscv/sim.h
riscv/trap.h
spike_main/spike.cc

diff --git a/LICENSE b/LICENSE
index 53e0e6646f82cfad7c11ef7902de7ae5c9ae26f9..34f576ba819ce4b37747be1fda2ba6196b63f98d 100644 (file)
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
-Copyright (c) 2013, The Regents of the University of California (Regents).
-All Rights Reserved.
+Copyright (c) 2010-2017, The Regents of the University of California
+(Regents).  All Rights Reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
index 901c7f458e04cfb4e7f0cacec817ff3acf43869b..a5ed8022ef5a091649ca50262017001b5f981fd0 100644 (file)
--- a/README.md
+++ b/README.md
@@ -19,6 +19,7 @@ Build Steps
 We assume that the RISCV environment variable is set to the RISC-V tools
 install path, and that the riscv-fesvr package is installed there.
 
+    $ apt-get install device-tree-compiler
     $ mkdir build
     $ cd build
     $ ../configure --prefix=$RISCV --with-fesvr=$RISCV
index a4070ff0adba26218f0e45ad320ca023917c53a8..137f1950054e3e4b709a76233c2aadcee778c7cf 100644 (file)
@@ -6,6 +6,9 @@
 /* Default value for --isa switch */
 #undef DEFAULT_ISA
 
+/* Path to the device-tree-compiler */
+#undef DTC
+
 /* Define if subproject MCPPBS_SPROJ_NORM is enabled */
 #undef DUMMY_ROCC_ENABLED
 
 /* Enable commit log generation */
 #undef RISCV_ENABLE_COMMITLOG
 
+/* Enable hardware management of PTE accessed and dirty bits */
+#undef RISCV_ENABLE_DIRTY
+
 /* Enable PC histogram generation */
 #undef RISCV_ENABLE_HISTOGRAM
 
+/* Enable hardware support for misaligned loads and stores */
+#undef RISCV_ENABLE_MISALIGNED
+
 /* Define if subproject MCPPBS_SPROJ_NORM is enabled */
 #undef SOFTFLOAT_ENABLED
 
index 2c946e7f398b3c65d4df16f04cae5e62419bae9c..77bab3062880b745cdf0128660d58c44584e4b17 100755 (executable)
--- a/configure
+++ b/configure
@@ -636,6 +636,7 @@ enable_stow
 EGREP
 GREP
 CXXCPP
+DTC
 RANLIB
 AR
 ac_ct_CXX
@@ -675,6 +676,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -703,6 +705,8 @@ with_isa
 with_fesvr
 enable_commitlog
 enable_histogram
+enable_dirty
+enable_misaligned
 '
       ac_precious_vars='build_alias
 host_alias
@@ -756,6 +760,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1008,6 +1013,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1145,7 +1159,7 @@ fi
 for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
                datadir sysconfdir sharedstatedir localstatedir includedir \
                oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-               libdir localedir mandir
+               libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1298,6 +1312,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -1336,6 +1351,10 @@ Optional Features:
                           Enable all optional subprojects
   --enable-commitlog      Enable commit log generation
   --enable-histogram      Enable PC histogram generation
+  --enable-dirty          Enable hardware management of PTE accessed and dirty
+                          bits
+  --enable-misaligned     Enable hardware support for misaligned loads and
+                          stores
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -3363,6 +3382,51 @@ else
   RANLIB="$ac_cv_prog_RANLIB"
 fi
 
+# Extract the first word of "dtc", so it can be a program name with args.
+set dummy dtc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_DTC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $DTC in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_DTC="$DTC" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_DTC="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+DTC=$ac_cv_path_DTC
+if test -n "$DTC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DTC" >&5
+$as_echo "$DTC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define DTC "$DTC"
+_ACEOF
+
 
 
 ac_ext=cpp
@@ -4605,6 +4669,32 @@ if test "x$enable_histogram" = "xyes"; then :
 $as_echo "#define RISCV_ENABLE_HISTOGRAM /**/" >>confdefs.h
 
 
+fi
+
+# Check whether --enable-dirty was given.
+if test "${enable_dirty+set}" = set; then :
+  enableval=$enable_dirty;
+fi
+
+if test "x$enable_dirty" = "xyes"; then :
+
+
+$as_echo "#define RISCV_ENABLE_DIRTY /**/" >>confdefs.h
+
+
+fi
+
+# Check whether --enable-misaligned was given.
+if test "${enable_misaligned+set}" = set; then :
+  enableval=$enable_misaligned;
+fi
+
+if test "x$enable_misaligned" = "xyes"; then :
+
+
+$as_echo "#define RISCV_ENABLE_MISALIGNED /**/" >>confdefs.h
+
+
 fi
 
 
index dbf50c94cb5e52879c1cbb75d29e550f919cf589..ea64de74830fdd22615463e93634ecd2a146b0eb 100644 (file)
@@ -51,6 +51,8 @@ AC_PROG_CC
 AC_PROG_CXX
 AC_CHECK_TOOL([AR],[ar])
 AC_CHECK_TOOL([RANLIB],[ranlib])
+AC_PATH_PROG([DTC],[dtc])
+AC_DEFINE_UNQUOTED(DTC, ["$DTC"], [Path to the device-tree-compiler])
 
 AC_C_BIGENDIAN(AC_MSG_ERROR([Spike requires a little-endian host]))
 
diff --git a/remote_bitbang.cc b/remote_bitbang.cc
new file mode 100644 (file)
index 0000000..9d0ca90
--- /dev/null
@@ -0,0 +1,174 @@
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+
+#include "remote_bitbang.h"
+
+#if 1
+#  define D(x) x
+#else
+#  define D(x)
+#endif
+
+/////////// remote_bitbang_t
+
+remote_bitbang_t::remote_bitbang_t(uint16_t port, jtag_dtm_t *tap) :
+  tap(tap),
+  socket_fd(0),
+  client_fd(0),
+  recv_start(0),
+  recv_end(0)
+{
+  socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+  if (socket_fd == -1) {
+    fprintf(stderr, "remote_bitbang failed to make socket: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  fcntl(socket_fd, F_SETFL, O_NONBLOCK);
+  int reuseaddr = 1;
+  if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
+        sizeof(int)) == -1) {
+    fprintf(stderr, "remote_bitbang failed setsockopt: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  struct sockaddr_in addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = INADDR_ANY;
+  addr.sin_port = htons(port);
+
+  if (bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
+    fprintf(stderr, "remote_bitbang failed to bind socket: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  if (listen(socket_fd, 1) == -1) {
+    fprintf(stderr, "remote_bitbang failed to listen on socket: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  socklen_t addrlen = sizeof(addr);
+  if (getsockname(socket_fd, (struct sockaddr *) &addr, &addrlen) == -1) {
+    fprintf(stderr, "remote_bitbang getsockname failed: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  printf("Listening for remote bitbang connection on port %d.\n",
+      ntohs(addr.sin_port));
+  fflush(stdout);
+}
+
+void remote_bitbang_t::accept()
+{
+  client_fd = ::accept(socket_fd, NULL, NULL);
+  if (client_fd == -1) {
+    if (errno == EAGAIN) {
+      // No client waiting to connect right now.
+    } else {
+      fprintf(stderr, "failed to accept on socket: %s (%d)\n", strerror(errno),
+          errno);
+      abort();
+    }
+  } else {
+    fcntl(client_fd, F_SETFL, O_NONBLOCK);
+  }
+}
+
+void remote_bitbang_t::tick()
+{
+  if (client_fd > 0) {
+    execute_commands();
+  } else {
+    this->accept();
+  }
+}
+
+void remote_bitbang_t::execute_commands()
+{
+  static char send_buf[buf_size];
+  unsigned total_processed = 0;
+  bool quit = false;
+  bool in_rti = tap->state() == RUN_TEST_IDLE;
+  bool entered_rti = false;
+  while (1) {
+    if (recv_start < recv_end) {
+      unsigned send_offset = 0;
+      while (recv_start < recv_end) {
+        uint8_t command = recv_buf[recv_start];
+
+        switch (command) {
+          case 'B': /* fprintf(stderr, "*BLINK*\n"); */ break;
+          case 'b': /* fprintf(stderr, "_______\n"); */ break;
+          case 'r': tap->reset(); break;
+          case '0': tap->set_pins(0, 0, 0); break;
+          case '1': tap->set_pins(0, 0, 1); break;
+          case '2': tap->set_pins(0, 1, 0); break;
+          case '3': tap->set_pins(0, 1, 1); break;
+          case '4': tap->set_pins(1, 0, 0); break;
+          case '5': tap->set_pins(1, 0, 1); break;
+          case '6': tap->set_pins(1, 1, 0); break;
+          case '7': tap->set_pins(1, 1, 1); break;
+          case 'R': send_buf[send_offset++] = tap->tdo() ? '1' : '0'; break;
+          case 'Q': quit = true; break;
+          default:
+                    fprintf(stderr, "remote_bitbang got unsupported command '%c'\n",
+                        command);
+        }
+        recv_start++;
+        total_processed++;
+        if (!in_rti && tap->state() == RUN_TEST_IDLE) {
+          entered_rti = true;
+          break;
+        }
+        in_rti = false;
+      }
+      unsigned sent = 0;
+      while (sent < send_offset) {
+        ssize_t bytes = write(client_fd, send_buf + sent, send_offset);
+        if (bytes == -1) {
+          fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno);
+          abort();
+        }
+        sent += bytes;
+      }
+    }
+
+    if (total_processed > buf_size || quit || entered_rti) {
+      // Don't go forever, because that could starve the main simulation.
+      break;
+    }
+
+    recv_start = 0;
+    recv_end = read(client_fd, recv_buf, buf_size);
+
+    if (recv_end == -1) {
+      if (errno == EAGAIN) {
+        // We'll try again the next call.
+      } else {
+        fprintf(stderr, "remote_bitbang failed to read on socket: %s (%d)\n",
+            strerror(errno), errno);
+        abort();
+      }
+    }
+    if (recv_end == 0 || quit) {
+      // The remote disconnected.
+      close(client_fd);
+      client_fd = 0;
+      break;
+    }
+  }
+}
diff --git a/remote_bitbang.h b/remote_bitbang.h
new file mode 100644 (file)
index 0000000..1db4d55
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef REMOTE_BITBANG_H
+#define REMOTE_BITBANG_H
+
+#include <stdint.h>
+
+#include "jtag_dtm.h"
+
+class remote_bitbang_t
+{
+public:
+  // Create a new server, listening for connections from localhost on the given
+  // port.
+  remote_bitbang_t(uint16_t port, jtag_dtm_t *tap);
+
+  // Do a bit of work.
+  void tick();
+
+private:
+  jtag_dtm_t *tap;
+
+  int socket_fd;
+  int client_fd;
+
+  static const ssize_t buf_size = 64 * 1024;
+  char recv_buf[buf_size];
+  ssize_t recv_start, recv_end;
+
+  // Check for a client connecting, and accept if there is one.
+  void accept();
+  // Execute any commands the client has for us.
+  void execute_commands();
+};
+
+#endif
diff --git a/riscv/clint.cc b/riscv/clint.cc
new file mode 100644 (file)
index 0000000..08508b4
--- /dev/null
@@ -0,0 +1,72 @@
+#include "devices.h"
+#include "processor.h"
+
+clint_t::clint_t(std::vector<processor_t*>& procs)
+  : procs(procs), mtimecmp(procs.size())
+{
+}
+
+/* 0000 msip hart 0
+ * 0004 msip hart 1
+ * 4000 mtimecmp hart 0 lo
+ * 4004 mtimecmp hart 0 hi
+ * 4008 mtimecmp hart 1 lo
+ * 400c mtimecmp hart 1 hi
+ * bff8 mtime lo
+ * bffc mtime hi
+ */
+
+#define MSIP_BASE      0x0
+#define MTIMECMP_BASE  0x4000
+#define MTIME_BASE     0xbff8
+
+bool clint_t::load(reg_t addr, size_t len, uint8_t* bytes)
+{
+  if (addr >= MSIP_BASE && addr + len <= MSIP_BASE + procs.size()*sizeof(msip_t)) {
+    std::vector<msip_t> msip(procs.size());
+    for (size_t i = 0; i < procs.size(); ++i)
+      msip[i] = !!(procs[i]->state.mip & MIP_MSIP);
+    memcpy(bytes, (uint8_t*)&msip[0] + addr - MSIP_BASE, len);
+  } else if (addr >= MTIMECMP_BASE && addr + len <= MTIMECMP_BASE + procs.size()*sizeof(mtimecmp_t)) {
+    memcpy(bytes, (uint8_t*)&mtimecmp[0] + addr - MTIMECMP_BASE, len);
+  } else if (addr >= MTIME_BASE && addr + len <= MTIME_BASE + sizeof(mtime_t)) {
+    memcpy(bytes, (uint8_t*)&mtime + addr - MTIME_BASE, len);
+  } else {
+    return false;
+  }
+  return true;
+}
+
+bool clint_t::store(reg_t addr, size_t len, const uint8_t* bytes)
+{
+  if (addr >= MSIP_BASE && addr + len <= MSIP_BASE + procs.size()*sizeof(msip_t)) {
+    std::vector<msip_t> msip(procs.size());
+    std::vector<msip_t> mask(procs.size(), 0);
+    memcpy((uint8_t*)&msip[0] + addr - MSIP_BASE, bytes, len);
+    memset((uint8_t*)&mask[0] + addr - MSIP_BASE, 0xff, len);
+    for (size_t i = 0; i < procs.size(); ++i) {
+      if (!(mask[i] & 0xFF)) continue;
+      procs[i]->state.mip &= ~MIP_MSIP;
+      if (!!(msip[i] & 1))
+        procs[i]->state.mip |= MIP_MSIP;
+    }
+  } else if (addr >= MTIMECMP_BASE && addr + len <= MTIMECMP_BASE + procs.size()*sizeof(mtimecmp_t)) {
+    memcpy((uint8_t*)&mtimecmp[0] + addr - MTIMECMP_BASE, bytes, len);
+  } else if (addr >= MTIME_BASE && addr + len <= MTIME_BASE + sizeof(mtime_t)) {
+    memcpy((uint8_t*)&mtime + addr - MTIME_BASE, bytes, len);
+  } else {
+    return false;
+  }
+  increment(0);
+  return true;
+}
+
+void clint_t::increment(reg_t inc)
+{
+  mtime += inc;
+  for (size_t i = 0; i < procs.size(); i++) {
+    procs[i]->state.mip &= ~MIP_MTIP;
+    if (mtime >= mtimecmp[i])
+      procs[i]->state.mip |= MIP_MTIP;
+  }
+}
index e78a587ef7da9d8b9ef848e2ddc0bc71417d4ba1..7667b273a7339af4a3d23413a807062b901779aa 100644 (file)
@@ -7,17 +7,22 @@
 # error spike requires a two''s-complement c++ implementation
 #endif
 
+#ifdef WORDS_BIGENDIAN
+# error spike requires a little-endian host
+#endif
+
 #include <cstdint>
 #include <string.h>
 #include <strings.h>
 #include "encoding.h"
 #include "config.h"
 #include "common.h"
+#include "softfloat_types.h"
+#include "specialize.h"
 #include <cinttypes>
 
 typedef int64_t sreg_t;
 typedef uint64_t reg_t;
-typedef uint64_t freg_t;
 
 const int NXPR = 32;
 const int NFPR = 32;
@@ -130,7 +135,7 @@ private:
 
 #ifndef RISCV_ENABLE_COMMITLOG
 # define WRITE_REG(reg, value) STATE.XPR.write(reg, value)
-# define WRITE_FREG(reg, value) DO_WRITE_FREG(reg, value)
+# define WRITE_FREG(reg, value) DO_WRITE_FREG(reg, freg(value))
 #else
 # define WRITE_REG(reg, value) ({ \
     reg_t wdata = (value); /* value may have side effects */ \
@@ -138,7 +143,7 @@ private:
     STATE.XPR.write(reg, wdata); \
   })
 # define WRITE_FREG(reg, value) ({ \
-    freg_t wdata = (value); /* value may have side effects */ \
+    freg_t wdata = freg(value); /* value may have side effects */ \
     STATE.log_reg_write = (commit_log_reg_t){((reg) << 1) | 1, wdata}; \
     DO_WRITE_FREG(reg, wdata); \
   })
@@ -170,13 +175,13 @@ private:
 #define JUMP_TARGET (pc + insn.uj_imm())
 #define RM ({ int rm = insn.rm(); \
               if(rm == 7) rm = STATE.frm; \
-              if(rm > 4) throw trap_illegal_instruction(); \
+              if(rm > 4) throw trap_illegal_instruction(0); \
               rm; })
 
 #define get_field(reg, mask) (((reg) & (decltype(reg))(mask)) / ((mask) & ~((mask) << 1)))
 #define set_field(reg, mask, val) (((reg) & ~(decltype(reg))(mask)) | (((decltype(reg))(val) * ((mask) & ~((mask) << 1))) & (decltype(reg))(mask)))
 
-#define require(x) if (unlikely(!(x))) throw trap_illegal_instruction()
+#define require(x) if (unlikely(!(x))) throw trap_illegal_instruction(0)
 #define require_privilege(p) require(STATE.prv >= (p))
 #define require_rv64 require(xlen == 64)
 #define require_rv32 require(xlen == 32)
@@ -202,9 +207,10 @@ private:
      } while(0)
 
 #define set_pc_and_serialize(x) \
-  do { set_pc(x); /* check alignment */ \
+  do { reg_t __npc = (x); \
+       set_pc(__npc); /* check alignment */ \
        npc = PC_SERIALIZE_AFTER; \
-       STATE.pc = (x); \
+       STATE.pc = __npc; \
      } while(0)
 
 /* Sentinel PC values to serialize simulator pipeline */
@@ -213,8 +219,23 @@ private:
 #define invalid_pc(pc) ((pc) & 1)
 
 /* Convenience wrappers to simplify softfloat code sequences */
-#define f32(x) ((float32_t){(uint32_t)x})
-#define f64(x) ((float64_t){(uint64_t)x})
+#define isBoxedF32(r) (((r) & 0xffffffff00000000) == 0xffffffff00000000)
+#define unboxF32(r) (isBoxedF32(r) ? (r) : defaultNaNF32UI)
+#define unboxF64(r) (r)
+struct freg_t { uint64_t v; };
+inline float32_t f32(uint32_t v) { return { v }; }
+inline float64_t f64(uint64_t v) { return { v }; }
+inline float32_t f32(freg_t r) { return f32(unboxF32(r.v)); }
+inline float64_t f64(freg_t r) { return f64(unboxF64(r.v)); }
+inline freg_t freg(float32_t f) { return { ((decltype(freg_t::v))-1 << 32) | f.v }; }
+inline freg_t freg(float64_t f) { return { f.v }; }
+inline freg_t freg(freg_t f) { return f; }
+#define F64_SIGN ((decltype(freg_t::v))1 << 63)
+#define F32_SIGN ((decltype(freg_t::v))1 << 31)
+#define fsgnj32(a, b, n, x) \
+  f32((f32(a).v & ~F32_SIGN) | ((((x) ? f32(a).v : (n) ? F32_SIGN : 0) ^ f32(b).v) & F32_SIGN))
+#define fsgnj64(a, b, n, x) \
+  f64((f64(a).v & ~F64_SIGN) | ((((x) ? f64(a).v : (n) ? F64_SIGN : 0) ^ f64(b).v) & F64_SIGN))
 
 #define validate_csr(which, write) ({ \
   if (!STATE.serialized) return PC_SERIALIZE_BEFORE; \
@@ -222,7 +243,7 @@ private:
   unsigned csr_priv = get_field((which), 0x300); \
   unsigned csr_read_only = get_field((which), 0xC00) == 3; \
   if (((write) && csr_read_only) || STATE.prv < csr_priv) \
-    throw trap_illegal_instruction(); \
+    throw trap_illegal_instruction(0); \
   (which); })
 
 #define DEBUG_START             0x20000
index cb3b6d962cbe8c649c4e35560f1358c27839137f..f3ecb67a3c7f3ac46c5385aee18bb175ea93395c 100644 (file)
@@ -34,17 +34,20 @@ class rom_device_t : public abstract_device_t {
   std::vector<char> data;
 };
 
-class rtc_t : public abstract_device_t {
+class clint_t : public abstract_device_t {
  public:
-  rtc_t(std::vector<processor_t*>&);
+  clint_t(std::vector<processor_t*>&);
   bool load(reg_t addr, size_t len, uint8_t* bytes);
   bool store(reg_t addr, size_t len, const uint8_t* bytes);
-  size_t size() { return regs.size() * sizeof(regs[0]); }
+  size_t size() { return CLINT_SIZE; }
   void increment(reg_t inc);
  private:
+  typedef uint64_t mtime_t;
+  typedef uint64_t mtimecmp_t;
+  typedef uint32_t msip_t;
   std::vector<processor_t*>& procs;
-  std::vector<uint64_t> regs;
-  uint64_t time() { return regs[0]; }
+  mtime_t mtime;
+  std::vector<mtimecmp_t> mtimecmp;
 };
 
 #endif
index 35e0f9fe05006a46704e40940cae1265d734913f..55f8461026fa9e122cf076adade3675bdbe25b6a 100644 (file)
 #define MSTATUS_FS          0x00006000
 #define MSTATUS_XS          0x00018000
 #define MSTATUS_MPRV        0x00020000
-#define MSTATUS_PUM         0x00040000
+#define MSTATUS_SUM         0x00040000
 #define MSTATUS_MXR         0x00080000
-#define MSTATUS_VM          0x1F000000
+#define MSTATUS_TVM         0x00100000
+#define MSTATUS_TW          0x00200000
+#define MSTATUS_TSR         0x00400000
 #define MSTATUS32_SD        0x80000000
 #define MSTATUS64_SD        0x8000000000000000
 
@@ -30,7 +32,8 @@
 #define SSTATUS_SPP         0x00000100
 #define SSTATUS_FS          0x00006000
 #define SSTATUS_XS          0x00018000
-#define SSTATUS_PUM         0x00040000
+#define SSTATUS_SUM         0x00040000
+#define SSTATUS_MXR         0x00080000
 #define SSTATUS32_SD        0x80000000
 #define SSTATUS64_SD        0x8000000000000000
 
 #define PRV_H 2
 #define PRV_M 3
 
-#define VM_MBARE 0
-#define VM_MBB   1
-#define VM_MBBID 2
-#define VM_SV32  8
-#define VM_SV39  9
-#define VM_SV48  10
+#define SPTBR32_MODE 0x80000000
+#define SPTBR32_ASID 0x7FC00000
+#define SPTBR32_PPN  0x003FFFFF
+#define SPTBR64_MODE 0xF000000000000000
+#define SPTBR64_ASID 0x0FFFF00000000000
+#define SPTBR64_PPN  0x00000FFFFFFFFFFF
+
+#define SPTBR_MODE_OFF  0
+#define SPTBR_MODE_SV32 1
+#define SPTBR_MODE_SV39 8
+#define SPTBR_MODE_SV48 9
+#define SPTBR_MODE_SV57 10
+#define SPTBR_MODE_SV64 11
+
+#define PMP_R     0x01
+#define PMP_W     0x02
+#define PMP_X     0x04
+#define PMP_A     0x18
+#define PMP_L     0x80
+#define PMP_SHIFT 2
+
+#define PMP_TOR   0x08
+#define PMP_NA4   0x10
+#define PMP_NAPOT 0x18
 
 #define IRQ_S_SOFT   1
 #define IRQ_H_SOFT   2
 #define IRQ_HOST     13
 
 #define DEFAULT_RSTVEC     0x00001000
-#define DEFAULT_NMIVEC     0x00001004
-#define DEFAULT_MTVEC      0x00001010
-#define CONFIG_STRING_ADDR 0x0000100C
+#define CLINT_BASE         0x02000000
+#define CLINT_SIZE         0x000c0000
 #define EXT_IO_BASE        0x40000000
 #define DRAM_BASE          0x80000000
 
 
 #ifdef __riscv
 
-#ifdef __riscv64
+#if __riscv_xlen == 64
 # define MSTATUS_SD MSTATUS64_SD
 # define SSTATUS_SD SSTATUS64_SD
 # define RISCV_PGLEVEL_BITS 9
+# define SPTBR_MODE SPTBR64_MODE
 #else
 # define MSTATUS_SD MSTATUS32_SD
 # define SSTATUS_SD SSTATUS32_SD
 # define RISCV_PGLEVEL_BITS 10
+# define SPTBR_MODE SPTBR32_MODE
 #endif
 #define RISCV_PGSHIFT 12
 #define RISCV_PGSIZE (1 << RISCV_PGSHIFT)
   __tmp; })
 
 #define write_csr(reg, val) ({ \
-  if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
-    asm volatile ("csrw " #reg ", %0" :: "i"(val)); \
-  else \
-    asm volatile ("csrw " #reg ", %0" :: "r"(val)); })
+  asm volatile ("csrw " #reg ", %0" :: "rK"(val)); })
 
 #define swap_csr(reg, val) ({ unsigned long __tmp; \
-  if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
-    asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "i"(val)); \
-  else \
-    asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \
+  asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \
   __tmp; })
 
 #define set_csr(reg, bit) ({ unsigned long __tmp; \
-  if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \
-    asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
-  else \
-    asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
+  asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \
   __tmp; })
 
 #define clear_csr(reg, bit) ({ unsigned long __tmp; \
-  if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \
-    asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
-  else \
-    asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
+  asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \
   __tmp; })
 
 #define rdtime() read_csr(time)
 #endif
 
 #endif
-/* Automatically generated by parse-opcodes */
+/* Automatically generated by parse-opcodes */
 #ifndef RISCV_ENCODING_H
 #define RISCV_ENCODING_H
 #define MATCH_BEQ 0x63
 #define MASK_MRET  0xffffffff
 #define MATCH_DRET 0x7b200073
 #define MASK_DRET  0xffffffff
-#define MATCH_SFENCE_VM 0x10400073
-#define MASK_SFENCE_VM  0xfff07fff
+#define MATCH_SFENCE_VMA 0x12000073
+#define MASK_SFENCE_VMA  0xfe007fff
 #define MATCH_WFI 0x10500073
 #define MASK_WFI  0xffffffff
 #define MATCH_CSRRW 0x1073
 #define MASK_FCVT_D_S  0xfff0007f
 #define MATCH_FSQRT_D 0x5a000053
 #define MASK_FSQRT_D  0xfff0007f
+#define MATCH_FADD_Q 0x6000053
+#define MASK_FADD_Q  0xfe00007f
+#define MATCH_FSUB_Q 0xe000053
+#define MASK_FSUB_Q  0xfe00007f
+#define MATCH_FMUL_Q 0x16000053
+#define MASK_FMUL_Q  0xfe00007f
+#define MATCH_FDIV_Q 0x1e000053
+#define MASK_FDIV_Q  0xfe00007f
+#define MATCH_FSGNJ_Q 0x26000053
+#define MASK_FSGNJ_Q  0xfe00707f
+#define MATCH_FSGNJN_Q 0x26001053
+#define MASK_FSGNJN_Q  0xfe00707f
+#define MATCH_FSGNJX_Q 0x26002053
+#define MASK_FSGNJX_Q  0xfe00707f
+#define MATCH_FMIN_Q 0x2e000053
+#define MASK_FMIN_Q  0xfe00707f
+#define MATCH_FMAX_Q 0x2e001053
+#define MASK_FMAX_Q  0xfe00707f
+#define MATCH_FCVT_S_Q 0x40300053
+#define MASK_FCVT_S_Q  0xfff0007f
+#define MATCH_FCVT_Q_S 0x46000053
+#define MASK_FCVT_Q_S  0xfff0007f
+#define MATCH_FCVT_D_Q 0x42300053
+#define MASK_FCVT_D_Q  0xfff0007f
+#define MATCH_FCVT_Q_D 0x46100053
+#define MASK_FCVT_Q_D  0xfff0007f
+#define MATCH_FSQRT_Q 0x5e000053
+#define MASK_FSQRT_Q  0xfff0007f
 #define MATCH_FLE_S 0xa0000053
 #define MASK_FLE_S  0xfe00707f
 #define MATCH_FLT_S 0xa0001053
 #define MASK_FLT_D  0xfe00707f
 #define MATCH_FEQ_D 0xa2002053
 #define MASK_FEQ_D  0xfe00707f
+#define MATCH_FLE_Q 0xa6000053
+#define MASK_FLE_Q  0xfe00707f
+#define MATCH_FLT_Q 0xa6001053
+#define MASK_FLT_Q  0xfe00707f
+#define MATCH_FEQ_Q 0xa6002053
+#define MASK_FEQ_Q  0xfe00707f
 #define MATCH_FCVT_W_S 0xc0000053
 #define MASK_FCVT_W_S  0xfff0007f
 #define MATCH_FCVT_WU_S 0xc0100053
 #define MASK_FMV_X_D  0xfff0707f
 #define MATCH_FCLASS_D 0xe2001053
 #define MASK_FCLASS_D  0xfff0707f
+#define MATCH_FCVT_W_Q 0xc6000053
+#define MASK_FCVT_W_Q  0xfff0007f
+#define MATCH_FCVT_WU_Q 0xc6100053
+#define MASK_FCVT_WU_Q  0xfff0007f
+#define MATCH_FCVT_L_Q 0xc6200053
+#define MASK_FCVT_L_Q  0xfff0007f
+#define MATCH_FCVT_LU_Q 0xc6300053
+#define MASK_FCVT_LU_Q  0xfff0007f
+#define MATCH_FMV_X_Q 0xe6000053
+#define MASK_FMV_X_Q  0xfff0707f
+#define MATCH_FCLASS_Q 0xe6001053
+#define MASK_FCLASS_Q  0xfff0707f
 #define MATCH_FCVT_S_W 0xd0000053
 #define MASK_FCVT_S_W  0xfff0007f
 #define MATCH_FCVT_S_WU 0xd0100053
 #define MASK_FCVT_D_LU  0xfff0007f
 #define MATCH_FMV_D_X 0xf2000053
 #define MASK_FMV_D_X  0xfff0707f
+#define MATCH_FCVT_Q_W 0xd6000053
+#define MASK_FCVT_Q_W  0xfff0007f
+#define MATCH_FCVT_Q_WU 0xd6100053
+#define MASK_FCVT_Q_WU  0xfff0007f
+#define MATCH_FCVT_Q_L 0xd6200053
+#define MASK_FCVT_Q_L  0xfff0007f
+#define MATCH_FCVT_Q_LU 0xd6300053
+#define MASK_FCVT_Q_LU  0xfff0007f
+#define MATCH_FMV_Q_X 0xf6000053
+#define MASK_FMV_Q_X  0xfff0707f
 #define MATCH_FLW 0x2007
 #define MASK_FLW  0x707f
 #define MATCH_FLD 0x3007
 #define MASK_FLD  0x707f
+#define MATCH_FLQ 0x4007
+#define MASK_FLQ  0x707f
 #define MATCH_FSW 0x2027
 #define MASK_FSW  0x707f
 #define MATCH_FSD 0x3027
 #define MASK_FSD  0x707f
+#define MATCH_FSQ 0x4027
+#define MASK_FSQ  0x707f
 #define MATCH_FMADD_S 0x43
 #define MASK_FMADD_S  0x600007f
 #define MATCH_FMSUB_S 0x47
 #define MASK_FNMSUB_D  0x600007f
 #define MATCH_FNMADD_D 0x200004f
 #define MASK_FNMADD_D  0x600007f
+#define MATCH_FMADD_Q 0x6000043
+#define MASK_FMADD_Q  0x600007f
+#define MATCH_FMSUB_Q 0x6000047
+#define MASK_FMSUB_Q  0x600007f
+#define MATCH_FNMSUB_Q 0x600004b
+#define MASK_FNMSUB_Q  0x600007f
+#define MATCH_FNMADD_Q 0x600004f
+#define MASK_FNMADD_Q  0x600007f
 #define MATCH_C_NOP 0x1
 #define MASK_C_NOP  0xffff
 #define MATCH_C_ADDI16SP 0x6101
 #define CSR_SSTATUS 0x100
 #define CSR_SIE 0x104
 #define CSR_STVEC 0x105
+#define CSR_SCOUNTEREN 0x106
 #define CSR_SSCRATCH 0x140
 #define CSR_SEPC 0x141
 #define CSR_SCAUSE 0x142
 #define CSR_MIDELEG 0x303
 #define CSR_MIE 0x304
 #define CSR_MTVEC 0x305
+#define CSR_MCOUNTEREN 0x306
 #define CSR_MSCRATCH 0x340
 #define CSR_MEPC 0x341
 #define CSR_MCAUSE 0x342
 #define CSR_MBADADDR 0x343
 #define CSR_MIP 0x344
+#define CSR_PMPCFG0 0x3a0
+#define CSR_PMPCFG1 0x3a1
+#define CSR_PMPCFG2 0x3a2
+#define CSR_PMPCFG3 0x3a3
+#define CSR_PMPADDR0 0x3b0
+#define CSR_PMPADDR1 0x3b1
+#define CSR_PMPADDR2 0x3b2
+#define CSR_PMPADDR3 0x3b3
+#define CSR_PMPADDR4 0x3b4
+#define CSR_PMPADDR5 0x3b5
+#define CSR_PMPADDR6 0x3b6
+#define CSR_PMPADDR7 0x3b7
+#define CSR_PMPADDR8 0x3b8
+#define CSR_PMPADDR9 0x3b9
+#define CSR_PMPADDR10 0x3ba
+#define CSR_PMPADDR11 0x3bb
+#define CSR_PMPADDR12 0x3bc
+#define CSR_PMPADDR13 0x3bd
+#define CSR_PMPADDR14 0x3be
+#define CSR_PMPADDR15 0x3bf
 #define CSR_TSELECT 0x7a0
 #define CSR_TDATA1 0x7a1
 #define CSR_TDATA2 0x7a2
 #define CSR_MHPMCOUNTER29 0xb1d
 #define CSR_MHPMCOUNTER30 0xb1e
 #define CSR_MHPMCOUNTER31 0xb1f
-#define CSR_MUCOUNTEREN 0x320
-#define CSR_MSCOUNTEREN 0x321
 #define CSR_MHPMEVENT3 0x323
 #define CSR_MHPMEVENT4 0x324
 #define CSR_MHPMEVENT5 0x325
 #define CSR_MHPMCOUNTER30H 0xb9e
 #define CSR_MHPMCOUNTER31H 0xb9f
 #define CAUSE_MISALIGNED_FETCH 0x0
-#define CAUSE_FAULT_FETCH 0x1
+#define CAUSE_FETCH_ACCESS 0x1
 #define CAUSE_ILLEGAL_INSTRUCTION 0x2
 #define CAUSE_BREAKPOINT 0x3
 #define CAUSE_MISALIGNED_LOAD 0x4
-#define CAUSE_FAULT_LOAD 0x5
+#define CAUSE_LOAD_ACCESS 0x5
 #define CAUSE_MISALIGNED_STORE 0x6
-#define CAUSE_FAULT_STORE 0x7
+#define CAUSE_STORE_ACCESS 0x7
 #define CAUSE_USER_ECALL 0x8
 #define CAUSE_SUPERVISOR_ECALL 0x9
 #define CAUSE_HYPERVISOR_ECALL 0xa
 #define CAUSE_MACHINE_ECALL 0xb
+#define CAUSE_FETCH_PAGE_FAULT 0xc
+#define CAUSE_LOAD_PAGE_FAULT 0xd
+#define CAUSE_STORE_PAGE_FAULT 0xf
 #endif
 #ifdef DECLARE_INSN
 DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ)
@@ -967,7 +1068,7 @@ DECLARE_INSN(sret, MATCH_SRET, MASK_SRET)
 DECLARE_INSN(hret, MATCH_HRET, MASK_HRET)
 DECLARE_INSN(mret, MATCH_MRET, MASK_MRET)
 DECLARE_INSN(dret, MATCH_DRET, MASK_DRET)
-DECLARE_INSN(sfence_vm, MATCH_SFENCE_VM, MASK_SFENCE_VM)
+DECLARE_INSN(sfence_vma, MATCH_SFENCE_VMA, MASK_SFENCE_VMA)
 DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI)
 DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW)
 DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS)
@@ -997,12 +1098,29 @@ DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D)
 DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D)
 DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S)
 DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D)
+DECLARE_INSN(fadd_q, MATCH_FADD_Q, MASK_FADD_Q)
+DECLARE_INSN(fsub_q, MATCH_FSUB_Q, MASK_FSUB_Q)
+DECLARE_INSN(fmul_q, MATCH_FMUL_Q, MASK_FMUL_Q)
+DECLARE_INSN(fdiv_q, MATCH_FDIV_Q, MASK_FDIV_Q)
+DECLARE_INSN(fsgnj_q, MATCH_FSGNJ_Q, MASK_FSGNJ_Q)
+DECLARE_INSN(fsgnjn_q, MATCH_FSGNJN_Q, MASK_FSGNJN_Q)
+DECLARE_INSN(fsgnjx_q, MATCH_FSGNJX_Q, MASK_FSGNJX_Q)
+DECLARE_INSN(fmin_q, MATCH_FMIN_Q, MASK_FMIN_Q)
+DECLARE_INSN(fmax_q, MATCH_FMAX_Q, MASK_FMAX_Q)
+DECLARE_INSN(fcvt_s_q, MATCH_FCVT_S_Q, MASK_FCVT_S_Q)
+DECLARE_INSN(fcvt_q_s, MATCH_FCVT_Q_S, MASK_FCVT_Q_S)
+DECLARE_INSN(fcvt_d_q, MATCH_FCVT_D_Q, MASK_FCVT_D_Q)
+DECLARE_INSN(fcvt_q_d, MATCH_FCVT_Q_D, MASK_FCVT_Q_D)
+DECLARE_INSN(fsqrt_q, MATCH_FSQRT_Q, MASK_FSQRT_Q)
 DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S)
 DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S)
 DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S)
 DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D)
 DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D)
 DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D)
+DECLARE_INSN(fle_q, MATCH_FLE_Q, MASK_FLE_Q)
+DECLARE_INSN(flt_q, MATCH_FLT_Q, MASK_FLT_Q)
+DECLARE_INSN(feq_q, MATCH_FEQ_Q, MASK_FEQ_Q)
 DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S)
 DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S)
 DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S)
@@ -1015,6 +1133,12 @@ DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D)
 DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D)
 DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D)
 DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D)
+DECLARE_INSN(fcvt_w_q, MATCH_FCVT_W_Q, MASK_FCVT_W_Q)
+DECLARE_INSN(fcvt_wu_q, MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q)
+DECLARE_INSN(fcvt_l_q, MATCH_FCVT_L_Q, MASK_FCVT_L_Q)
+DECLARE_INSN(fcvt_lu_q, MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q)
+DECLARE_INSN(fmv_x_q, MATCH_FMV_X_Q, MASK_FMV_X_Q)
+DECLARE_INSN(fclass_q, MATCH_FCLASS_Q, MASK_FCLASS_Q)
 DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W)
 DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU)
 DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L)
@@ -1025,10 +1149,17 @@ DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU)
 DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L)
 DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU)
 DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X)
+DECLARE_INSN(fcvt_q_w, MATCH_FCVT_Q_W, MASK_FCVT_Q_W)
+DECLARE_INSN(fcvt_q_wu, MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU)
+DECLARE_INSN(fcvt_q_l, MATCH_FCVT_Q_L, MASK_FCVT_Q_L)
+DECLARE_INSN(fcvt_q_lu, MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU)
+DECLARE_INSN(fmv_q_x, MATCH_FMV_Q_X, MASK_FMV_Q_X)
 DECLARE_INSN(flw, MATCH_FLW, MASK_FLW)
 DECLARE_INSN(fld, MATCH_FLD, MASK_FLD)
+DECLARE_INSN(flq, MATCH_FLQ, MASK_FLQ)
 DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW)
 DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD)
+DECLARE_INSN(fsq, MATCH_FSQ, MASK_FSQ)
 DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S)
 DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S)
 DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S)
@@ -1037,6 +1168,10 @@ DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D)
 DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D)
 DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D)
 DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D)
+DECLARE_INSN(fmadd_q, MATCH_FMADD_Q, MASK_FMADD_Q)
+DECLARE_INSN(fmsub_q, MATCH_FMSUB_Q, MASK_FMSUB_Q)
+DECLARE_INSN(fnmsub_q, MATCH_FNMSUB_Q, MASK_FNMSUB_Q)
+DECLARE_INSN(fnmadd_q, MATCH_FNMADD_Q, MASK_FNMADD_Q)
 DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP)
 DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP)
 DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR)
@@ -1143,6 +1278,7 @@ DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31)
 DECLARE_CSR(sstatus, CSR_SSTATUS)
 DECLARE_CSR(sie, CSR_SIE)
 DECLARE_CSR(stvec, CSR_STVEC)
+DECLARE_CSR(scounteren, CSR_SCOUNTEREN)
 DECLARE_CSR(sscratch, CSR_SSCRATCH)
 DECLARE_CSR(sepc, CSR_SEPC)
 DECLARE_CSR(scause, CSR_SCAUSE)
@@ -1155,11 +1291,32 @@ DECLARE_CSR(medeleg, CSR_MEDELEG)
 DECLARE_CSR(mideleg, CSR_MIDELEG)
 DECLARE_CSR(mie, CSR_MIE)
 DECLARE_CSR(mtvec, CSR_MTVEC)
+DECLARE_CSR(mcounteren, CSR_MCOUNTEREN)
 DECLARE_CSR(mscratch, CSR_MSCRATCH)
 DECLARE_CSR(mepc, CSR_MEPC)
 DECLARE_CSR(mcause, CSR_MCAUSE)
 DECLARE_CSR(mbadaddr, CSR_MBADADDR)
 DECLARE_CSR(mip, CSR_MIP)
+DECLARE_CSR(pmpcfg0, CSR_PMPCFG0)
+DECLARE_CSR(pmpcfg1, CSR_PMPCFG1)
+DECLARE_CSR(pmpcfg2, CSR_PMPCFG2)
+DECLARE_CSR(pmpcfg3, CSR_PMPCFG3)
+DECLARE_CSR(pmpaddr0, CSR_PMPADDR0)
+DECLARE_CSR(pmpaddr1, CSR_PMPADDR1)
+DECLARE_CSR(pmpaddr2, CSR_PMPADDR2)
+DECLARE_CSR(pmpaddr3, CSR_PMPADDR3)
+DECLARE_CSR(pmpaddr4, CSR_PMPADDR4)
+DECLARE_CSR(pmpaddr5, CSR_PMPADDR5)
+DECLARE_CSR(pmpaddr6, CSR_PMPADDR6)
+DECLARE_CSR(pmpaddr7, CSR_PMPADDR7)
+DECLARE_CSR(pmpaddr8, CSR_PMPADDR8)
+DECLARE_CSR(pmpaddr9, CSR_PMPADDR9)
+DECLARE_CSR(pmpaddr10, CSR_PMPADDR10)
+DECLARE_CSR(pmpaddr11, CSR_PMPADDR11)
+DECLARE_CSR(pmpaddr12, CSR_PMPADDR12)
+DECLARE_CSR(pmpaddr13, CSR_PMPADDR13)
+DECLARE_CSR(pmpaddr14, CSR_PMPADDR14)
+DECLARE_CSR(pmpaddr15, CSR_PMPADDR15)
 DECLARE_CSR(tselect, CSR_TSELECT)
 DECLARE_CSR(tdata1, CSR_TDATA1)
 DECLARE_CSR(tdata2, CSR_TDATA2)
@@ -1198,8 +1355,6 @@ DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28)
 DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29)
 DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30)
 DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31)
-DECLARE_CSR(mucounteren, CSR_MUCOUNTEREN)
-DECLARE_CSR(mscounteren, CSR_MSCOUNTEREN)
 DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3)
 DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4)
 DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5)
@@ -1299,15 +1454,18 @@ DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H)
 #endif
 #ifdef DECLARE_CAUSE
 DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH)
-DECLARE_CAUSE("fault fetch", CAUSE_FAULT_FETCH)
+DECLARE_CAUSE("fetch access", CAUSE_FETCH_ACCESS)
 DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION)
 DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT)
 DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD)
-DECLARE_CAUSE("fault load", CAUSE_FAULT_LOAD)
+DECLARE_CAUSE("load access", CAUSE_LOAD_ACCESS)
 DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE)
-DECLARE_CAUSE("fault store", CAUSE_FAULT_STORE)
+DECLARE_CAUSE("store access", CAUSE_STORE_ACCESS)
 DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL)
 DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL)
 DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL)
 DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL)
+DECLARE_CAUSE("fetch page fault", CAUSE_FETCH_PAGE_FAULT)
+DECLARE_CAUSE("load page fault", CAUSE_LOAD_PAGE_FAULT)
+DECLARE_CAUSE("store page fault", CAUSE_STORE_PAGE_FAULT)
 #endif
index 0ac0e0ac43c729cfa08f5c6a7b3dd079b1f2177e..7734ca2749d6756ca2270e6c359a3d28db712ec9 100644 (file)
@@ -79,7 +79,7 @@ void processor_t::step(size_t n)
      if (unlikely(invalid_pc(pc))) { \
        switch (pc) { \
          case PC_SERIALIZE_BEFORE: state.serialized = true; break; \
-         case PC_SERIALIZE_AFTER: instret++; break; \
+         case PC_SERIALIZE_AFTER: n = ++instret; break; \
          default: abort(); \
        } \
        pc = state.pc; \
@@ -91,7 +91,7 @@ void processor_t::step(size_t n)
 
     try
     {
-      take_interrupt();
+      take_pending_interrupt();
 
       if (unlikely(slow_path()))
       {
index 5321c42c17d96b5f7a985716f36691cc1215ecb2..520c2ed578c3964c4cfba8c9f7da394a48c1bc5d 100644 (file)
@@ -9,17 +9,12 @@ extension_t::~extension_t()
 
 void extension_t::illegal_instruction()
 {
-  throw trap_illegal_instruction();
+  throw trap_illegal_instruction(0);
 }
 
 void extension_t::raise_interrupt()
 {
-  reg_t prv = p->get_state()->prv;
-  reg_t mie = get_field(p->get_state()->mstatus, MSTATUS_MIE);
-
-  if (prv < PRV_M || (prv == PRV_M && mie))
-    p->raise_interrupt(IRQ_COP);
-
+  p->take_interrupt((reg_t)1 << IRQ_COP); // must not return
   throw std::logic_error("a COP exception was posted, but interrupts are disabled!");
 }
 
index 0dd0aa1942d34b7dfff6b08329c9518137aee9fe..07aa16ba05ab7dc24be90239ce720ccc1dc55fc4 100644 (file)
@@ -4,5 +4,6 @@
 #include "mulhi.h"
 #include "softfloat.h"
 #include "internals.h"
+#include "specialize.h"
 #include "tracer.h"
 #include <assert.h>
index a17200fa4dec4a6b3fd2d7fb4e2be078fd133d71..128b86b22c55beefbd0eb8ca43f3c3a3708676b7 100644 (file)
@@ -1,2 +1,2 @@
 require_extension('C');
-throw trap_breakpoint();
+throw trap_breakpoint(pc);
index 10d14f86075f5385471757a523f9cdd5357e4458..319615b8e4303bf952cd0306a526f8d7fa68f5cd 100644 (file)
@@ -1,4 +1,4 @@
 require_extension('C');
 require_extension('D');
 require_fp;
-WRITE_RVC_FRS2S(MMU.load_int64(RVC_RS1S + insn.rvc_ld_imm()));
+WRITE_RVC_FRS2S(f64(MMU.load_uint64(RVC_RS1S + insn.rvc_ld_imm())));
index 8b1e19fceb1eaf15a41be2282d9f3d64ca8c7163..534eef7d2877967ca9963a5eb67dace673073435 100644 (file)
@@ -1,4 +1,4 @@
 require_extension('C');
 require_extension('D');
 require_fp;
-WRITE_FRD(MMU.load_int64(RVC_SP + insn.rvc_ldsp_imm()));
+WRITE_FRD(f64(MMU.load_uint64(RVC_SP + insn.rvc_ldsp_imm())));
index 0be27a94a4cc1d16cba37f9ac34cd38ddf258437..682566c705b764366f4681b6eff3dd85a2c27efa 100644 (file)
@@ -2,7 +2,7 @@ require_extension('C');
 if (xlen == 32) {
   require_extension('F');
   require_fp;
-  WRITE_RVC_FRS2S(MMU.load_int32(RVC_RS1S + insn.rvc_lw_imm()));
+  WRITE_RVC_FRS2S(f32(MMU.load_uint32(RVC_RS1S + insn.rvc_lw_imm())));
 } else { // c.ld
   WRITE_RVC_RS2S(MMU.load_int64(RVC_RS1S + insn.rvc_ld_imm()));
 }
index 26a47216b88cac42afca46367ba051a72758e455..79058c40a37d7b971640fc9877dc4be9ee91303b 100644 (file)
@@ -2,7 +2,7 @@ require_extension('C');
 if (xlen == 32) {
   require_extension('F');
   require_fp;
-  WRITE_FRD(MMU.load_int32(RVC_SP + insn.rvc_lwsp_imm()));
+  WRITE_FRD(f32(MMU.load_uint32(RVC_SP + insn.rvc_lwsp_imm())));
 } else { // c.ldsp
   require(insn.rvc_rd() != 0);
   WRITE_RD(MMU.load_int64(RVC_SP + insn.rvc_ldsp_imm()));
index 84f1a7f16f9f597c22184e91442a798dce70aa98..874326683a670e59dbfb665a0eb37a057c073d02 100644 (file)
@@ -1,4 +1,4 @@
 require_extension('C');
 require_extension('D');
 require_fp;
-MMU.store_uint64(RVC_RS1S + insn.rvc_ld_imm(), RVC_FRS2S);
+MMU.store_uint64(RVC_RS1S + insn.rvc_ld_imm(), RVC_FRS2S.v);
index 5c5c680f830569187430fcfcc7ccd5da6e4cc084..f62f8ff24c55c26d7432647267e3d3d2b7897a84 100644 (file)
@@ -1,4 +1,4 @@
 require_extension('C');
 require_extension('D');
 require_fp;
-MMU.store_uint64(RVC_SP + insn.rvc_sdsp_imm(), RVC_FRS2);
+MMU.store_uint64(RVC_SP + insn.rvc_sdsp_imm(), RVC_FRS2.v);
index 8923fef38fb1a5f88780cb1d893736809126b16a..b924a4689dc58dc4b0e7352c135d5eecefbac6d2 100644 (file)
@@ -2,7 +2,7 @@ require_extension('C');
 if (xlen == 32) {
   require_extension('F');
   require_fp;
-  MMU.store_uint32(RVC_RS1S + insn.rvc_lw_imm(), RVC_FRS2S);
+  MMU.store_uint32(RVC_RS1S + insn.rvc_lw_imm(), RVC_FRS2S.v);
 } else { // c.sd
   MMU.store_uint64(RVC_RS1S + insn.rvc_ld_imm(), RVC_RS2S);
 }
index c13aa12f8908c1819402319dc5c09e416420d7cf..011de555f3de08cb426f41e01b8c65931b2eca44 100644 (file)
@@ -2,7 +2,7 @@ require_extension('C');
 if (xlen == 32) {
   require_extension('F');
   require_fp;
-  MMU.store_uint32(RVC_SP + insn.rvc_swsp_imm(), RVC_FRS2);
+  MMU.store_uint32(RVC_SP + insn.rvc_swsp_imm(), RVC_FRS2.v);
 } else { // c.sdsp
   MMU.store_uint64(RVC_SP + insn.rvc_sdsp_imm(), RVC_RS2);
 }
index c22776c80278f7cd4dab81cba331f52c75fa08b8..736cebef4b63e8a98674b836aebe06a341e972c9 100644 (file)
@@ -1 +1 @@
-throw trap_breakpoint();
+throw trap_breakpoint(pc);
index 9990174d5a48a1202058db0e129925ee55b4a85d..4a436e24874aa052d61c177c3b6a53502b6ae46d 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('D');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f64_add(f64(FRS1), f64(FRS2)).v);
+WRITE_FRD(f64_add(f64(FRS1), f64(FRS2)));
 set_fp_exceptions;
index cdef36adb4a78b935018755e0901525754bc0278..cc18d58cd6f4495f40fe72c065a8f025225c7d8d 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('F');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f32_add(f32(FRS1), f32(FRS2)).v);
+WRITE_FRD(f32_add(f32(FRS1), f32(FRS2)));
 set_fp_exceptions;
index fece2277a6cf5a3359b40eaca378215f165fee02..08716cffe2d6af6f3f6844381c84b56c40e8d4fe 100644 (file)
@@ -2,5 +2,5 @@ require_extension('D');
 require_rv64;
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(i64_to_f64(RS1).v);
+WRITE_FRD(i64_to_f64(RS1));
 set_fp_exceptions;
index 775c7aef2c5d361e4d6c237ce3ab1edf9eca7b81..306d7fedd8c9889f6255ab12c5da2867ac734daa 100644 (file)
@@ -2,5 +2,5 @@ require_extension('D');
 require_rv64;
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(ui64_to_f64(RS1).v);
+WRITE_FRD(ui64_to_f64(RS1));
 set_fp_exceptions;
index ec778cc92f475446212fca675014dff066076b26..5f805b061472c89dabdb25af51fb69a3fe1eefa1 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('D');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f32_to_f64(f32(FRS1)).v);
+WRITE_FRD(f32_to_f64(f32(FRS1)));
 set_fp_exceptions;
index 753250d6d5ea903c049c0ec7de4c53d4083b3263..4c4861c1555c48c9e136086de2890a568e9ddb2e 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('D');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(i32_to_f64((int32_t)RS1).v);
+WRITE_FRD(i32_to_f64((int32_t)RS1));
 set_fp_exceptions;
index af893b32dd75352bf94c4106bfca23dcdd7c9da6..1dbf218a1cfa95a4799bb9606e0d35d3f89c9e7f 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('D');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(ui32_to_f64((uint32_t)RS1).v);
+WRITE_FRD(ui32_to_f64((uint32_t)RS1));
 set_fp_exceptions;
index 211bbba2a83f0d0a3b2698cd00e9f876cdb18fae..40333359f371b97c5fe9cda14bcdbfae5c8f3690 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('D');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f64_to_f32(f64(FRS1)).v);
+WRITE_FRD(f64_to_f32(f64(FRS1)));
 set_fp_exceptions;
index 1c0581a83fabef71c5f2ea34279136bd798a2993..9abcc80509eaac8d7b256e6edb98180d48659716 100644 (file)
@@ -2,5 +2,5 @@ require_extension('F');
 require_rv64;
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(i64_to_f32(RS1).v);
+WRITE_FRD(i64_to_f32(RS1));
 set_fp_exceptions;
index e9bf78e0324f8abc340bb33e234473ae60845588..70c676edf410ba60fdc3be0599a03077ea8f6d48 100644 (file)
@@ -2,5 +2,5 @@ require_extension('F');
 require_rv64;
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(ui64_to_f32(RS1).v);
+WRITE_FRD(ui64_to_f32(RS1));
 set_fp_exceptions;
index 9411cbd59bab8fceaa8d329cbd956447426c5cea..1ddabd87c12cda406cc3e924ba9c3103815d8298 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('F');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(i32_to_f32((int32_t)RS1).v);
+WRITE_FRD(i32_to_f32((int32_t)RS1));
 set_fp_exceptions;
index a6cf8367f99d5a1f15b6d0e10bfdf237e053443f..c1394c3fd04af3f078f9cd29d201a52c63e199e4 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('F');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(ui32_to_f32((uint32_t)RS1).v);
+WRITE_FRD(ui32_to_f32((uint32_t)RS1));
 set_fp_exceptions;
index d8943de7e6b3199f854e06d04a24aaa61ac61bc9..ae7911ae9ae57b314fd1bca5daba43f4af231331 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('D');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f64_div(f64(FRS1), f64(FRS2)).v);
+WRITE_FRD(f64_div(f64(FRS1), f64(FRS2)));
 set_fp_exceptions;
index 66ac48da24a325c8081a8e179398b754236a6fc6..c74ff0415cb7026e58f87af4e8c9a056c6eb0310 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('F');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f32_div(f32(FRS1), f32(FRS2)).v);
+WRITE_FRD(f32_div(f32(FRS1), f32(FRS2)));
 set_fp_exceptions;
index 0b50b8a5ac147dd0112f0bb9ca05c5300a532f03..4dea1d47e92476ee8de3aec2119243c566d09ee9 100644 (file)
@@ -1,3 +1,3 @@
 require_extension('D');
 require_fp;
-WRITE_FRD(MMU.load_int64(RS1 + insn.i_imm()));
+WRITE_FRD(f64(MMU.load_uint64(RS1 + insn.i_imm())));
index 489e743249a4ccb37f83c2a4960da6c7aa663529..61297544405cb65b65da17122e98247fccafa2ff 100644 (file)
@@ -1,3 +1,3 @@
 require_extension('F');
 require_fp;
-WRITE_FRD(MMU.load_uint32(RS1 + insn.i_imm()));
+WRITE_FRD(f32(MMU.load_uint32(RS1 + insn.i_imm())));
index 98f1cbc25cc5b2a99b438bb8b4d1362415b72a47..ab22bebbf609948ad7f862e9391b50d86b026684 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('D');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f64_mulAdd(f64(FRS1), f64(FRS2), f64(FRS3)).v);
+WRITE_FRD(f64_mulAdd(f64(FRS1), f64(FRS2), f64(FRS3)));
 set_fp_exceptions;
index a78ed25c04c3767bca5ff8645f400698fc714c71..e919190caaa04608acc04e172614bfcd432ad2e3 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('F');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f32_mulAdd(f32(FRS1), f32(FRS2), f32(FRS3)).v);
+WRITE_FRD(f32_mulAdd(f32(FRS1), f32(FRS2), f32(FRS3)));
 set_fp_exceptions;
index f0bea9bb2dbf679729f359a7af99fd9ff0b5a11c..9c8e5b3983b470e5b85cce1f26b8e773bd8ee6e7 100644 (file)
@@ -1,4 +1,6 @@
 require_extension('D');
 require_fp;
-WRITE_FRD(isNaNF64UI(FRS2) || f64_le_quiet(f64(FRS2), f64(FRS1)) ? FRS1 : FRS2);
+WRITE_FRD(f64_le_quiet(f64(FRS2), f64(FRS1)) || isNaNF64UI(f64(FRS2).v) ? FRS1 : FRS2);
+if ((isNaNF64UI(f64(FRS1).v) && isNaNF64UI(f64(FRS2).v)) || softfloat_exceptionFlags)
+  WRITE_FRD(f64(defaultNaNF64UI));
 set_fp_exceptions;
index 33b2bc618f602525e1c5686996e01cdbdea6cba2..2f570ead5432c040bb29459c8f84efbd4ea00e60 100644 (file)
@@ -1,4 +1,6 @@
 require_extension('F');
 require_fp;
-WRITE_FRD(isNaNF32UI(FRS2) || f32_le_quiet(f32(FRS2), f32(FRS1)) ? FRS1 : FRS2);
+WRITE_FRD(f32_le_quiet(f32(FRS2), f32(FRS1)) || isNaNF32UI(f32(FRS2).v) ? FRS1 : FRS2);
+if ((isNaNF32UI(f32(FRS1).v) && isNaNF32UI(f32(FRS2).v)) || softfloat_exceptionFlags)
+  WRITE_FRD(f32(defaultNaNF32UI));
 set_fp_exceptions;
index e22b6eaf42dbaf367325d39eb06340a446c3b446..cd40e159984ab7c7953bf82aeaf213bad47b06bf 100644 (file)
@@ -1,4 +1,6 @@
 require_extension('D');
 require_fp;
-WRITE_FRD(isNaNF64UI(FRS2) || f64_lt_quiet(f64(FRS1), f64(FRS2)) ? FRS1 : FRS2);
+WRITE_FRD(f64_lt_quiet(f64(FRS1), f64(FRS2)) || isNaNF64UI(f64(FRS2).v) ? FRS1 : FRS2);
+if ((isNaNF64UI(f64(FRS1).v) && isNaNF64UI(f64(FRS2).v)) || softfloat_exceptionFlags)
+  WRITE_FRD(f64(defaultNaNF64UI));
 set_fp_exceptions;
index 0ebb3a88e65bce3701d1607545c820afe695480d..b813f45d7440cb638470e7b0f3a2e970156597bb 100644 (file)
@@ -1,4 +1,6 @@
 require_extension('F');
 require_fp;
-WRITE_FRD(isNaNF32UI(FRS2) || f32_lt_quiet(f32(FRS1), f32(FRS2)) ? FRS1 : FRS2);
+WRITE_FRD(f32_lt_quiet(f32(FRS1), f32(FRS2)) || isNaNF32UI(f32(FRS2).v) ? FRS1 : FRS2);
+if ((isNaNF32UI(f32(FRS1).v) && isNaNF32UI(f32(FRS2).v)) || softfloat_exceptionFlags)
+  WRITE_FRD(f32(defaultNaNF32UI));
 set_fp_exceptions;
index afcea88e693d77b3c90d6a7351304d29bff8e43a..5b5bc0f75e4c9c26a42b35409df98d6de063c9c3 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('D');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f64_mulAdd(f64(FRS1), f64(FRS2), f64(FRS3 ^ (uint64_t)INT64_MIN)).v);
+WRITE_FRD(f64_mulAdd(f64(FRS1), f64(FRS2), f64(f64(FRS3).v ^ F64_SIGN)));
 set_fp_exceptions;
index 45945dac4a48fd1230ddc5174e94a9915c896a24..d46c887e7c746137aebe24e64880fadb3fa34fdb 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('F');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f32_mulAdd(f32(FRS1), f32(FRS2), f32(FRS3 ^ (uint32_t)INT32_MIN)).v);
+WRITE_FRD(f32_mulAdd(f32(FRS1), f32(FRS2), f32(f32(FRS3).v ^ F32_SIGN)));
 set_fp_exceptions;
index 04e74025781ae817d2127174af23c16eaf25141f..9189d8d9ed4ffad7f9aff7dbc7f939076b092274 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('D');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f64_mul(f64(FRS1), f64(FRS2)).v);
+WRITE_FRD(f64_mul(f64(FRS1), f64(FRS2)));
 set_fp_exceptions;
index 9ae7b3c64edbbd65c971055607937b54c0e96a9a..145d5ce4d96fcc4e9d387f9817359ea1baa6f6f9 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('F');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f32_mul(f32(FRS1), f32(FRS2)).v);
+WRITE_FRD(f32_mul(f32(FRS1), f32(FRS2)));
 set_fp_exceptions;
index c3f6049316b1f3be58a6d9305ba9419f913c8f20..0bff5fb7540b347aeba01b0aff264f5d922161b0 100644 (file)
@@ -1,4 +1,4 @@
 require_extension('D');
 require_rv64;
 require_fp;
-WRITE_FRD(RS1);
+WRITE_FRD(f64(RS1));
index 2daf6dabe06be573999a3f1abf6012de47904102..5f713231cb36ac3a6b32d8a6fc6276ef97b6f3db 100644 (file)
@@ -1,3 +1,3 @@
 require_extension('F');
 require_fp;
-WRITE_FRD(zext32(RS1));
+WRITE_FRD(f32(RS1));
index b97d7f59bacefafcaad9f0e964b96098c8f1c0a2..da8e72a82ecd0d04eac3e9ab40e9860dcff23872 100644 (file)
@@ -1,4 +1,4 @@
 require_extension('D');
 require_rv64;
 require_fp;
-WRITE_RD(FRS1);
+WRITE_RD(FRS1.v);
index 1bee87f4aa5fa61cd98bf1a70dde5b51f9bcf169..b72247958c762237a2316ab7ed7f4a9d29eaf1fd 100644 (file)
@@ -1,3 +1,3 @@
 require_extension('F');
 require_fp;
-WRITE_RD(sext32(FRS1));
+WRITE_RD(sext32(FRS1.v));
index d6e1f04ac749d27453ee10f4f2ca874a4b9e3211..e8dd743233cdf7ff7ef6dcc07231c003b8b98eb2 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('D');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f64_mulAdd(f64(FRS1 ^ (uint64_t)INT64_MIN), f64(FRS2), f64(FRS3 ^ (uint64_t)INT64_MIN)).v);
+WRITE_FRD(f64_mulAdd(f64(f64(FRS1).v ^ F64_SIGN), f64(FRS2), f64(f64(FRS3).v ^ F64_SIGN)));
 set_fp_exceptions;
index 0d0b2e96bf08f6c65d76994a4431818e426ef45e..1c2996e3125909af3f6408f1798c5b717df4ae66 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('F');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f32_mulAdd(f32(FRS1 ^ (uint32_t)INT32_MIN), f32(FRS2), f32(FRS3 ^ (uint32_t)INT32_MIN)).v);
+WRITE_FRD(f32_mulAdd(f32(f32(FRS1).v ^ F32_SIGN), f32(FRS2), f32(f32(FRS3).v ^ F32_SIGN)));
 set_fp_exceptions;
index ee74cab2724ee190fb91b7ab58a9fc113f601233..c29a0b93ca059d7dc74cfc7e399185941bf59ecc 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('D');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f64_mulAdd(f64(FRS1 ^ (uint64_t)INT64_MIN), f64(FRS2), f64(FRS3)).v);
+WRITE_FRD(f64_mulAdd(f64(f64(FRS1).v ^ F64_SIGN), f64(FRS2), f64(FRS3)));
 set_fp_exceptions;
index 3e0b8ea7ce37c85e1c6220fdefcc717e0a9cd9ba..4c61fc7c81170175929bd556095ed97481e9c135 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('F');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f32_mulAdd(f32(FRS1 ^ (uint32_t)INT32_MIN), f32(FRS2), f32(FRS3)).v);
+WRITE_FRD(f32_mulAdd(f32(f32(FRS1).v ^ F32_SIGN), f32(FRS2), f32(FRS3)));
 set_fp_exceptions;
index 63cc8e5fc00eae9fefaa954db7a0b09cddce3039..679cc95fb7c5fd1f28c65dcb16b18ffc25f07940 100644 (file)
@@ -1,3 +1,3 @@
 require_extension('D');
 require_fp;
-MMU.store_uint64(RS1 + insn.s_imm(), FRS2);
+MMU.store_uint64(RS1 + insn.s_imm(), FRS2.v);
index 52648a1a78649b790df944dc86f15d4d04986642..78f9ce78745c83c69b9f3df1b89a9079046e6eef 100644 (file)
@@ -1,3 +1,3 @@
 require_extension('D');
 require_fp;
-WRITE_FRD((FRS1 &~ INT64_MIN) | (FRS2 & INT64_MIN));
+WRITE_FRD(fsgnj64(FRS1, FRS2, false, false));
index 4c91ff327531125047d006ee24a563bc7b02838c..c1a70cb7979bf7be59cc299ce64f0e736a308e64 100644 (file)
@@ -1,3 +1,3 @@
 require_extension('F');
 require_fp;
-WRITE_FRD((FRS1 &~ (uint32_t)INT32_MIN) | (FRS2 & (uint32_t)INT32_MIN));
+WRITE_FRD(fsgnj32(FRS1, FRS2, false, false));
index cdec924ba8042c4b06ad8ccbffaf0c66bc1542ae..f02c3116b78da8bc11574bab282bf2f7143a1598 100644 (file)
@@ -1,3 +1,3 @@
 require_extension('D');
 require_fp;
-WRITE_FRD((FRS1 &~ INT64_MIN) | ((~FRS2) & INT64_MIN));
+WRITE_FRD(fsgnj64(FRS1, FRS2, true, false));
index f91a7b0a43c72482d9c8600e5678c8590a5986ad..35906d6576159d47311f27dbe8debfde6c07446e 100644 (file)
@@ -1,3 +1,3 @@
 require_extension('F');
 require_fp;
-WRITE_FRD((FRS1 &~ (uint32_t)INT32_MIN) | ((~FRS2) & (uint32_t)INT32_MIN));
+WRITE_FRD(fsgnj32(FRS1, FRS2, true, false));
index b09d24cb8fe48b9394e2589afc165b2ef717ccf5..c12173719b79c51d84d4a7fc9a0db5effa4aebd1 100644 (file)
@@ -1,3 +1,3 @@
 require_extension('D');
 require_fp;
-WRITE_FRD(FRS1 ^ (FRS2 & INT64_MIN));
+WRITE_FRD(fsgnj64(FRS1, FRS2, false, true));
index 1fd2de6b94b3af36241e956077050a5e77b7adc8..4d5c624b65c152b0435d1e0591732db91807d58e 100644 (file)
@@ -1,3 +1,3 @@
 require_extension('F');
 require_fp;
-WRITE_FRD(FRS1 ^ (FRS2 & (uint32_t)INT32_MIN));
+WRITE_FRD(fsgnj32(FRS1, FRS2, false, true));
index 45f37ce00ae010d2e3b7733e7334084d0d7e9b16..da138ba1937f53070d05f81beb096a765580c457 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('D');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f64_sqrt(f64(FRS1)).v);
+WRITE_FRD(f64_sqrt(f64(FRS1)));
 set_fp_exceptions;
index f3b39564f80968badfe7f7cc3f07a325665db408..747684664e7c9b7b2ac7d8abd0917aadaca041e5 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('F');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f32_sqrt(f32(FRS1)).v);
+WRITE_FRD(f32_sqrt(f32(FRS1)));
 set_fp_exceptions;
index 487743e0d60826a5a9ba73e2022361c23b54f660..1418a063d6ebc1a2925e0884e1faf3c94167f92d 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('D');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f64_sub(f64(FRS1), f64(FRS2)).v);
+WRITE_FRD(f64_sub(f64(FRS1), f64(FRS2)));
 set_fp_exceptions;
index e7a7cf1824ccb7e5d57575e621c39514e98e6c00..f6183ea000965c87f50db9491a9242a5139cef53 100644 (file)
@@ -1,5 +1,5 @@
 require_extension('F');
 require_fp;
 softfloat_roundingMode = RM;
-WRITE_FRD(f32_sub(f32(FRS1), f32(FRS2)).v);
+WRITE_FRD(f32_sub(f32(FRS1), f32(FRS2)));
 set_fp_exceptions;
index 3135e9b7dace76cc7866b46d6415965ade82a84f..42fc68373f5370635a58327a27980c9f5bfda620 100644 (file)
@@ -1,3 +1,3 @@
 require_extension('F');
 require_fp;
-MMU.store_uint32(RS1 + insn.s_imm(), FRS2);
+MMU.store_uint32(RS1 + insn.s_imm(), FRS2.v);
index fa97b2c6b1b6400f4090711b393d51192607c958..96933cf67262567c2e5cdf39ea73a4f9836d57cc 100644 (file)
@@ -2,8 +2,8 @@ require_privilege(PRV_M);
 set_pc_and_serialize(p->get_state()->mepc);
 reg_t s = STATE.mstatus;
 reg_t prev_prv = get_field(s, MSTATUS_MPP);
-s = set_field(s, MSTATUS_UIE << prev_prv, get_field(s, MSTATUS_MPIE));
-s = set_field(s, MSTATUS_MPIE, 0);
+s = set_field(s, MSTATUS_MIE, get_field(s, MSTATUS_MPIE));
+s = set_field(s, MSTATUS_MPIE, 1);
 s = set_field(s, MSTATUS_MPP, PRV_U);
 p->set_privilege(prev_prv);
 p->set_csr(CSR_MSTATUS, s);
diff --git a/riscv/insns/sfence_vm.h b/riscv/insns/sfence_vm.h
deleted file mode 100644 (file)
index 35ff5dd..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-require_privilege(PRV_S);
-MMU.flush_tlb();
diff --git a/riscv/insns/sfence_vma.h b/riscv/insns/sfence_vma.h
new file mode 100644 (file)
index 0000000..fc4625f
--- /dev/null
@@ -0,0 +1,2 @@
+require_privilege(get_field(STATE.mstatus, MSTATUS_TVM) ? PRV_M : PRV_S);
+MMU.flush_tlb();
index f5e89e44686e740860c60c9c7d317826add6febe..ae841de93f19cc1111761e545780947f4d95fb41 100644 (file)
@@ -1,9 +1,9 @@
-require_privilege(PRV_S);
+require_privilege(get_field(STATE.mstatus, MSTATUS_TSR) ? PRV_M : PRV_S);
 set_pc_and_serialize(p->get_state()->sepc);
 reg_t s = STATE.mstatus;
 reg_t prev_prv = get_field(s, MSTATUS_SPP);
-s = set_field(s, MSTATUS_UIE << prev_prv, get_field(s, MSTATUS_SPIE));
-s = set_field(s, MSTATUS_SPIE, 0);
+s = set_field(s, MSTATUS_SIE, get_field(s, MSTATUS_SPIE));
+s = set_field(s, MSTATUS_SPIE, 1);
 s = set_field(s, MSTATUS_SPP, PRV_U);
 p->set_privilege(prev_prv);
 p->set_csr(CSR_MSTATUS, s);
index 6f037f8a9c689c7b5df689470d60c1f0b9e80427..16de594408522bc52c89589bb899b6ac1a6e8a43 100644 (file)
@@ -1 +1,2 @@
-// nop
+require_privilege(get_field(STATE.mstatus, MSTATUS_TW) ? PRV_M : PRV_S);
+set_pc_and_serialize(npc);
index 748f454e0ae682c80967289dfa95c05e427e2328..31b91622720f5f7e2efcc5fe00a41e523e5a7a00 100644 (file)
 #include <vector>
 #include <algorithm>
 
+DECLARE_TRAP(-1, interactive)
+
 processor_t *sim_t::get_core(const std::string& i)
 {
   char *ptr;
   unsigned long p = strtoul(i.c_str(), &ptr, 10);
-  if (*ptr || p >= num_cores())
-    throw trap_illegal_instruction();
+  if (*ptr || p >= procs.size())
+    throw trap_interactive();
   return get_core(p);
 }
 
@@ -64,6 +66,7 @@ void sim_t::interactive()
   funcs["r"] = funcs["run"];
   funcs["rs"] = &sim_t::interactive_run_silent;
   funcs["reg"] = &sim_t::interactive_reg;
+  funcs["freg"] = &sim_t::interactive_freg;
   funcs["fregs"] = &sim_t::interactive_fregs;
   funcs["fregd"] = &sim_t::interactive_fregd;
   funcs["pc"] = &sim_t::interactive_pc;
@@ -161,7 +164,7 @@ void sim_t::interactive_quit(const std::string& cmd, const std::vector<std::stri
 reg_t sim_t::get_pc(const std::vector<std::string>& args)
 {
   if(args.size() != 1)
-    throw trap_illegal_instruction();
+    throw trap_interactive();
 
   processor_t *p = get_core(args[0]);
   return p->state.pc;
@@ -175,7 +178,7 @@ void sim_t::interactive_pc(const std::string& cmd, const std::vector<std::string
 reg_t sim_t::get_reg(const std::vector<std::string>& args)
 {
   if(args.size() != 2)
-    throw trap_illegal_instruction();
+    throw trap_interactive();
 
   processor_t *p = get_core(args[0]);
 
@@ -192,22 +195,22 @@ reg_t sim_t::get_reg(const std::vector<std::string>& args)
   }
 
   if (r >= NXPR)
-    throw trap_illegal_instruction();
+    throw trap_interactive();
 
   return p->state.XPR[r];
 }
 
-reg_t sim_t::get_freg(const std::vector<std::string>& args)
+freg_t sim_t::get_freg(const std::vector<std::string>& args)
 {
   if(args.size() != 2)
-    throw trap_illegal_instruction();
+    throw trap_interactive();
 
   processor_t *p = get_core(args[0]);
   int r = std::find(fpr_name, fpr_name + NFPR, args[1]) - fpr_name;
   if (r == NFPR)
     r = atoi(args[1].c_str());
   if (r >= NFPR)
-    throw trap_illegal_instruction();
+    throw trap_interactive();
 
   return p->state.FPR[r];
 }
@@ -229,11 +232,16 @@ void sim_t::interactive_reg(const std::string& cmd, const std::vector<std::strin
 
 union fpr
 {
-  reg_t r;
+  freg_t r;
   float s;
   double d;
 };
 
+void sim_t::interactive_freg(const std::string& cmd, const std::vector<std::string>& args)
+{
+  fprintf(stderr, "0x%016" PRIx64 "\n", get_freg(args).v);
+}
+
 void sim_t::interactive_fregs(const std::string& cmd, const std::vector<std::string>& args)
 {
   fpr f;
@@ -251,7 +259,7 @@ void sim_t::interactive_fregd(const std::string& cmd, const std::vector<std::str
 reg_t sim_t::get_mem(const std::vector<std::string>& args)
 {
   if(args.size() != 1 && args.size() != 2)
-    throw trap_illegal_instruction();
+    throw trap_interactive();
 
   std::string addr_str = args[0];
   mmu_t* mmu = debug_mmu;
@@ -293,7 +301,7 @@ void sim_t::interactive_mem(const std::string& cmd, const std::vector<std::strin
 void sim_t::interactive_str(const std::string& cmd, const std::vector<std::string>& args)
 {
   if(args.size() != 1)
-    throw trap_illegal_instruction();
+    throw trap_interactive();
 
   reg_t addr = strtol(args[0].c_str(),NULL,16);
 
index 878d849d7ecaed30521bb8053a23389500743a2b..8df38e5e9d2ebf1a1ce352bf193441f1dab64fac 100644 (file)
@@ -43,13 +43,7 @@ reg_t mmu_t::translate(reg_t addr, access_type type)
     if (!proc->state.dcsr.cause && get_field(proc->state.mstatus, MSTATUS_MPRV))
       mode = get_field(proc->state.mstatus, MSTATUS_MPP);
   }
-  if (get_field(proc->state.mstatus, MSTATUS_VM) == VM_MBARE)
-    mode = PRV_M;
 
-  if (mode == PRV_M) {
-    reg_t msb_mask = (reg_t(2) << (proc->xlen-1))-1; // zero-extend from xlen
-    return addr & msb_mask;
-  }
   return walk(addr, type, mode) | (addr & (PGSIZE-1));
 }
 
@@ -57,12 +51,6 @@ const uint16_t* mmu_t::fetch_slow_path(reg_t vaddr)
 {
   reg_t paddr = translate(vaddr, FETCH);
 
-  // mmu_t::walk() returns -1 if it can't find a match. Of course -1 could also
-  // be a valid address.
-  if (paddr == ~(reg_t) 0 && vaddr != ~(reg_t) 0) {
-    throw trap_instruction_access_fault(vaddr);
-  }
-
   if (sim->addr_is_mem(paddr)) {
     refill_tlb(vaddr, paddr, FETCH);
     return (const uint16_t*)sim->addr_to_mem(paddr);
@@ -169,43 +157,38 @@ void mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, access_type type)
 
 reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode)
 {
-  int levels, ptidxbits, ptesize;
-  switch (get_field(proc->get_state()->mstatus, MSTATUS_VM))
-  {
-    case VM_SV32: levels = 2; ptidxbits = 10; ptesize = 4; break;
-    case VM_SV39: levels = 3; ptidxbits = 9; ptesize = 8; break;
-    case VM_SV48: levels = 4; ptidxbits = 9; ptesize = 8; break;
-    default: abort();
-  }
+  vm_info vm = decode_vm_info(proc->max_xlen, mode, proc->get_state()->sptbr);
+  if (vm.levels == 0)
+    return addr & ((reg_t(2) << (proc->xlen-1))-1); // zero-extend from xlen
 
   bool supervisor = mode == PRV_S;
-  bool pum = get_field(proc->state.mstatus, MSTATUS_PUM);
+  bool sum = get_field(proc->state.mstatus, MSTATUS_SUM);
   bool mxr = get_field(proc->state.mstatus, MSTATUS_MXR);
 
   // verify bits xlen-1:va_bits-1 are all equal
-  int va_bits = PGSHIFT + levels * ptidxbits;
+  int va_bits = PGSHIFT + vm.levels * vm.idxbits;
   reg_t mask = (reg_t(1) << (proc->xlen - (va_bits-1))) - 1;
   reg_t masked_msbs = (addr >> (va_bits-1)) & mask;
   if (masked_msbs != 0 && masked_msbs != mask)
-    return -1;
+    vm.levels = 0;
 
-  reg_t base = proc->get_state()->sptbr << PGSHIFT;
-  int ptshift = (levels - 1) * ptidxbits;
-  for (int i = 0; i < levels; i++, ptshift -= ptidxbits) {
-    reg_t idx = (addr >> (PGSHIFT + ptshift)) & ((1 << ptidxbits) - 1);
+  reg_t base = vm.ptbase;
+  for (int i = vm.levels - 1; i >= 0; i--) {
+    int ptshift = i * vm.idxbits;
+    reg_t idx = (addr >> (PGSHIFT + ptshift)) & ((1 << vm.idxbits) - 1);
 
     // check that physical address of PTE is legal
-    reg_t pte_addr = base + idx * ptesize;
+    reg_t pte_addr = base + idx * vm.ptesize;
     if (!sim->addr_is_mem(pte_addr))
-      break;
+      throw trap_load_access_fault(addr);
 
     void* ppte = sim->addr_to_mem(pte_addr);
-    reg_t pte = ptesize == 4 ? *(uint32_t*)ppte : *(uint64_t*)ppte;
+    reg_t pte = vm.ptesize == 4 ? *(uint32_t*)ppte : *(uint64_t*)ppte;
     reg_t ppn = pte >> PTE_PPN_SHIFT;
 
     if (PTE_TABLE(pte)) { // next level of page table
       base = ppn << PGSHIFT;
-    } else if ((pte & PTE_U) ? supervisor && pum : !supervisor) {
+    } else if ((pte & PTE_U) ? supervisor && !sum : !supervisor) {
       break;
     } else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) {
       break;
@@ -214,8 +197,15 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode)
                                !((pte & PTE_R) && (pte & PTE_W))) {
       break;
     } else {
+      reg_t ad = PTE_A | ((type == STORE) * PTE_D);
+#ifdef RISCV_ENABLE_DIRTY
       // set accessed and possibly dirty bits.
-      *(uint32_t*)ppte |= PTE_A | ((type == STORE) * PTE_D);
+      *(uint32_t*)ppte |= ad;
+#else
+      // take exception if access or possibly dirty bit is not set.
+      if ((pte & ad) != ad)
+        break;
+#endif
       // for superpage mappings, make a fake leaf PTE for the TLB's benefit.
       reg_t vpn = addr >> PGSHIFT;
       reg_t value = (ppn | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT;
@@ -223,7 +213,13 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode)
     }
   }
 
-  return -1;
+fail:
+  switch (type) {
+    case FETCH: throw trap_instruction_page_fault(addr);
+    case LOAD: throw trap_load_page_fault(addr);
+    case STORE: throw trap_store_page_fault(addr);
+    default: abort();
+  }
 }
 
 void mmu_t::register_memtracer(memtracer_t* t)
index 34bcf99be27b187946774ac5dd41aeb66b2bd21c..a8d9675b402ad421eb8b7ab70528062e66250f4f 100644 (file)
@@ -51,11 +51,33 @@ public:
   mmu_t(sim_t* sim, processor_t* proc);
   ~mmu_t();
 
+  inline reg_t misaligned_load(reg_t addr, size_t size)
+  {
+#ifdef RISCV_ENABLE_MISALIGNED
+    reg_t res = 0;
+    for (size_t i = 0; i < size; i++)
+      res += (reg_t)load_uint8(addr + i) << (i * 8);
+    return res;
+#else
+    throw trap_load_address_misaligned(addr);
+#endif
+  }
+
+  inline void misaligned_store(reg_t addr, reg_t data, size_t size)
+  {
+#ifdef RISCV_ENABLE_MISALIGNED
+    for (size_t i = 0; i < size; i++)
+      store_uint8(addr + i, data >> (i * 8));
+#else
+    throw trap_store_address_misaligned(addr);
+#endif
+  }
+
   // template for functions that load an aligned value from memory
   #define load_func(type) \
     inline type##_t load_##type(reg_t addr) { \
-      if (addr & (sizeof(type##_t)-1)) \
-        throw trap_load_address_misaligned(addr); \
+      if (unlikely(addr & (sizeof(type##_t)-1))) \
+        return misaligned_load(addr, sizeof(type##_t)); \
       reg_t vpn = addr >> PGSHIFT; \
       if (likely(tlb_load_tag[vpn % TLB_ENTRIES] == vpn)) \
         return *(type##_t*)(tlb_data[vpn % TLB_ENTRIES] + addr); \
@@ -88,8 +110,8 @@ public:
   // template for functions that store an aligned value to memory
   #define store_func(type) \
     void store_##type(reg_t addr, type##_t val) { \
-      if (addr & (sizeof(type##_t)-1)) \
-        throw trap_store_address_misaligned(addr); \
+      if (unlikely(addr & (sizeof(type##_t)-1))) \
+        return misaligned_store(addr, val, sizeof(type##_t)); \
       reg_t vpn = addr >> PGSHIFT; \
       if (likely(tlb_store_tag[vpn % TLB_ENTRIES] == vpn)) \
         *(type##_t*)(tlb_data[vpn % TLB_ENTRIES] + addr) = val; \
@@ -115,6 +137,9 @@ public:
         auto lhs = load_##type(addr); \
         store_##type(addr, f(lhs)); \
         return lhs; \
+      } catch (trap_load_page_fault& t) { \
+        /* AMO faults should be reported as store faults */ \
+        throw trap_store_page_fault(t.get_badaddr()); \
       } catch (trap_load_access_fault& t) { \
         /* AMO faults should be reported as store faults */ \
         throw trap_store_access_fault(t.get_badaddr()); \
@@ -260,4 +285,35 @@ private:
   friend class processor_t;
 };
 
+struct vm_info {
+  int levels;
+  int idxbits;
+  int ptesize;
+  reg_t ptbase;
+};
+
+inline vm_info decode_vm_info(int xlen, reg_t prv, reg_t sptbr)
+{
+  if (prv == PRV_M) {
+    return {0, 0, 0, 0};
+  } else if (prv <= PRV_S && xlen == 32) {
+    switch (get_field(sptbr, SPTBR32_MODE)) {
+      case SPTBR_MODE_OFF: return {0, 0, 0, 0};
+      case SPTBR_MODE_SV32: return {2, 10, 4, (sptbr & SPTBR32_PPN) << PGSHIFT};
+      default: abort();
+    }
+  } else if (prv <= PRV_S && xlen == 64) {
+    switch (get_field(sptbr, SPTBR64_MODE)) {
+      case SPTBR_MODE_OFF: return {0, 0, 0, 0};
+      case SPTBR_MODE_SV39: return {3, 9, 8, (sptbr & SPTBR64_PPN) << PGSHIFT};
+      case SPTBR_MODE_SV48: return {4, 9, 8, (sptbr & SPTBR64_PPN) << PGSHIFT};
+      case SPTBR_MODE_SV57: return {5, 9, 8, (sptbr & SPTBR64_PPN) << PGSHIFT};
+      case SPTBR_MODE_SV64: return {6, 9, 8, (sptbr & SPTBR64_PPN) << PGSHIFT};
+      default: abort();
+    }
+  } else {
+    abort();
+  }
+}
+
 #endif
index 58837d12fa14c87673b5515c140a9be646f989cb..ef529fc20c1d6d885b2fc7b22abad7060302a68c 100644 (file)
@@ -118,7 +118,6 @@ void state_t::reset()
   memset(this, 0, sizeof(*this));
   prv = PRV_M;
   pc = DEFAULT_RSTVEC;
-  mtvec = DEFAULT_MTVEC;
   load_reservation = -1;
   tselect = 0;
   for (unsigned int i = 0; i < num_triggers; i++)
@@ -154,11 +153,6 @@ void processor_t::reset()
     ext->reset(); // reset the extension
 }
 
-void processor_t::raise_interrupt(reg_t which)
-{
-  throw trap_t(((reg_t)1 << (max_xlen-1)) | which);
-}
-
 // Count number of contiguous 0 bits starting from the LSB.
 static int ctz(reg_t val)
 {
@@ -169,20 +163,19 @@ static int ctz(reg_t val)
   return res;
 }
 
-void processor_t::take_interrupt()
+void processor_t::take_interrupt(reg_t pending_interrupts)
 {
-  reg_t pending_interrupts = state.mip & state.mie;
-
   reg_t mie = get_field(state.mstatus, MSTATUS_MIE);
   reg_t m_enabled = state.prv < PRV_M || (state.prv == PRV_M && mie);
   reg_t enabled_interrupts = pending_interrupts & ~state.mideleg & -m_enabled;
 
   reg_t sie = get_field(state.mstatus, MSTATUS_SIE);
   reg_t s_enabled = state.prv < PRV_S || (state.prv == PRV_S && sie);
-  enabled_interrupts |= pending_interrupts & state.mideleg & -s_enabled;
+  if (enabled_interrupts == 0)
+    enabled_interrupts = pending_interrupts & state.mideleg & -s_enabled;
 
   if (enabled_interrupts)
-    raise_interrupt(ctz(enabled_interrupts));
+    throw trap_t(((reg_t)1 << (max_xlen-1)) | ctz(enabled_interrupts));
 }
 
 void processor_t::set_privilege(reg_t prv)
@@ -234,7 +227,8 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
   // by default, trap to M-mode, unless delegated to S-mode
   reg_t bit = t.cause();
   reg_t deleg = state.medeleg;
-  if (bit & ((reg_t)1 << (max_xlen-1)))
+  bool interrupt = (bit & ((reg_t)1 << (max_xlen-1))) != 0;
+  if (interrupt)
     deleg = state.mideleg, bit &= ~((reg_t)1 << (max_xlen-1));
   if (state.prv <= PRV_S && bit < max_xlen && ((deleg >> bit) & 1)) {
     // handle the trap in S-mode
@@ -245,20 +239,21 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
       state.sbadaddr = t.get_badaddr();
 
     reg_t s = state.mstatus;
-    s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_UIE << state.prv));
+    s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_SIE));
     s = set_field(s, MSTATUS_SPP, state.prv);
     s = set_field(s, MSTATUS_SIE, 0);
     set_csr(CSR_MSTATUS, s);
     set_privilege(PRV_S);
   } else {
-    state.pc = state.mtvec;
+    reg_t vector = (state.mtvec & 1) && interrupt ? 4*bit : 0;
+    state.pc = (state.mtvec & ~(reg_t)1) + vector;
     state.mepc = epc;
     state.mcause = t.cause();
     if (t.has_badaddr())
       state.mbadaddr = t.get_badaddr();
 
     reg_t s = state.mstatus;
-    s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_UIE << state.prv));
+    s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE));
     s = set_field(s, MSTATUS_MPP, state.prv);
     s = set_field(s, MSTATUS_MIE, 0);
     set_csr(CSR_MSTATUS, s);
@@ -289,15 +284,6 @@ void processor_t::disasm(insn_t insn)
   }
 }
 
-static bool validate_vm(int max_xlen, reg_t vm)
-{
-  if (max_xlen == 64 && (vm == VM_SV39 || vm == VM_SV48))
-    return true;
-  if (max_xlen == 32 && vm == VM_SV32)
-    return true;
-  return vm == VM_MBARE;
-}
-
 int processor_t::paddr_bits()
 {
   assert(xlen == max_xlen);
@@ -326,15 +312,13 @@ void processor_t::set_csr(int which, reg_t val)
       break;
     case CSR_MSTATUS: {
       if ((val ^ state.mstatus) &
-          (MSTATUS_VM | MSTATUS_MPP | MSTATUS_MPRV | MSTATUS_PUM | MSTATUS_MXR))
+          (MSTATUS_MPP | MSTATUS_MPRV | MSTATUS_SUM | MSTATUS_MXR))
         mmu->flush_tlb();
 
       reg_t mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE
-                 | MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_PUM
-                 | MSTATUS_MPP | MSTATUS_MXR | (ext ? MSTATUS_XS : 0);
-
-      if (validate_vm(max_xlen, get_field(val, MSTATUS_VM)))
-        mask |= MSTATUS_VM;
+                 | MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM
+                 | MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TW | MSTATUS_TVM
+                 | MSTATUS_TSR | (ext ? MSTATUS_XS : 0);
 
       state.mstatus = (state.mstatus & ~mask) | (val & mask);
 
@@ -380,15 +364,15 @@ void processor_t::set_csr(int which, reg_t val)
     case CSR_MCYCLEH:
       state.minstret = (val << 32) | (state.minstret << 32 >> 32);
       break;
-    case CSR_MUCOUNTEREN:
-      state.mucounteren = val;
+    case CSR_SCOUNTEREN:
+      state.scounteren = val;
       break;
-    case CSR_MSCOUNTEREN:
-      state.mscounteren = val;
+    case CSR_MCOUNTEREN:
+      state.mcounteren = val;
       break;
     case CSR_SSTATUS: {
       reg_t mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP | SSTATUS_FS
-                 | SSTATUS_XS | SSTATUS_PUM;
+                 | SSTATUS_XS | SSTATUS_SUM | SSTATUS_MXR;
       return set_csr(CSR_MSTATUS, (state.mstatus & ~mask) | (val & mask));
     }
     case CSR_SIP: {
@@ -399,8 +383,13 @@ void processor_t::set_csr(int which, reg_t val)
       return set_csr(CSR_MIE,
                      (state.mie & ~state.mideleg) | (val & state.mideleg));
     case CSR_SPTBR: {
-      // upper bits of sptbr are the ASID; we only support ASID = 0
-      state.sptbr = val & (((reg_t)1 << (paddr_bits() - PGSHIFT)) - 1);
+      mmu->flush_tlb();
+      if (max_xlen == 32)
+        state.sptbr = val & (SPTBR32_PPN | SPTBR32_MODE);
+      if (max_xlen == 64 && (get_field(val, SPTBR64_MODE) == SPTBR_MODE_OFF ||
+                             get_field(val, SPTBR64_MODE) == SPTBR_MODE_SV39 ||
+                             get_field(val, SPTBR64_MODE) == SPTBR_MODE_SV48))
+        state.sptbr = val & (SPTBR64_PPN | SPTBR64_MODE);
       break;
     }
     case CSR_SEPC: state.sepc = val; break;
@@ -409,7 +398,7 @@ void processor_t::set_csr(int which, reg_t val)
     case CSR_SCAUSE: state.scause = val; break;
     case CSR_SBADADDR: state.sbadaddr = val; break;
     case CSR_MEPC: state.mepc = val; break;
-    case CSR_MTVEC: state.mtvec = val >> 2 << 2; break;
+    case CSR_MTVEC: state.mtvec = val & ~(reg_t)2; break;
     case CSR_MSCRATCH: state.mscratch = val; break;
     case CSR_MCAUSE: state.mcause = val; break;
     case CSR_MBADADDR: state.mbadaddr = val; break;
@@ -488,8 +477,11 @@ void processor_t::set_csr(int which, reg_t val)
 
 reg_t processor_t::get_csr(int which)
 {
-  reg_t ctr_en = state.prv == PRV_U ? state.mucounteren :
-                 state.prv == PRV_S ? state.mscounteren : -1U;
+  uint32_t ctr_en = -1;
+  if (state.prv < PRV_M)
+    ctr_en &= state.mcounteren;
+  if (state.prv < PRV_S)
+    ctr_en &= state.scounteren;
   bool ctr_ok = (ctr_en >> (which & 31)) & 1;
 
   if (ctr_ok) {
@@ -500,7 +492,7 @@ reg_t processor_t::get_csr(int which)
   }
   if (which >= CSR_MHPMCOUNTER3 && which <= CSR_MHPMCOUNTER31)
     return 0;
-  if (xlen == 32 && which >= CSR_MHPMCOUNTER3 && which <= CSR_MHPMCOUNTER31)
+  if (xlen == 32 && which >= CSR_MHPMCOUNTER3H && which <= CSR_MHPMCOUNTER31H)
     return 0;
   if (which >= CSR_MHPMEVENT3 && which <= CSR_MHPMEVENT31)
     return 0;
@@ -535,11 +527,11 @@ reg_t processor_t::get_csr(int which)
       if (xlen == 32)
         return state.minstret >> 32;
       break;
-    case CSR_MUCOUNTEREN: return state.mucounteren;
-    case CSR_MSCOUNTEREN: return state.mscounteren;
+    case CSR_SCOUNTEREN: return state.scounteren;
+    case CSR_MCOUNTEREN: return state.mcounteren;
     case CSR_SSTATUS: {
       reg_t mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP | SSTATUS_FS
-                 | SSTATUS_XS | SSTATUS_PUM;
+                 | SSTATUS_XS | SSTATUS_SUM;
       reg_t sstatus = state.mstatus & mask;
       if ((sstatus & SSTATUS_FS) == SSTATUS_FS ||
           (sstatus & SSTATUS_XS) == SSTATUS_XS)
@@ -555,7 +547,10 @@ reg_t processor_t::get_csr(int which)
       if (max_xlen > xlen)
         return state.scause | ((state.scause >> (max_xlen-1)) << (xlen-1));
       return state.scause;
-    case CSR_SPTBR: return state.sptbr;
+    case CSR_SPTBR:
+      if (get_field(state.mstatus, MSTATUS_TVM))
+        require_privilege(PRV_M);
+      return state.sptbr;
     case CSR_SSCRATCH: return state.sscratch;
     case CSR_MSTATUS: return state.mstatus;
     case CSR_MIP: return state.mip;
@@ -625,12 +620,12 @@ reg_t processor_t::get_csr(int which)
     case CSR_DSCRATCH:
       return state.dscratch;
   }
-  throw trap_illegal_instruction();
+  throw trap_illegal_instruction(0);
 }
 
 reg_t illegal_instruction(processor_t* p, insn_t insn, reg_t pc)
 {
-  throw trap_illegal_instruction();
+  throw trap_illegal_instruction(0);
 }
 
 insn_func_t processor_t::decode_insn(insn_t insn)
@@ -713,6 +708,17 @@ void processor_t::register_base_instructions()
 
 bool processor_t::load(reg_t addr, size_t len, uint8_t* bytes)
 {
+  switch (addr)
+  {
+    case 0:
+      if (len <= 4) {
+        memset(bytes, 0, len);
+        bytes[0] = get_field(state.mip, MIP_MSIP);
+        return true;
+      }
+      break;
+  }
+
   return false;
 }
 
@@ -721,14 +727,14 @@ bool processor_t::store(reg_t addr, size_t len, const uint8_t* bytes)
   switch (addr)
   {
     case 0:
-      state.mip &= ~MIP_MSIP;
-      if (bytes[0] & 1)
-        state.mip |= MIP_MSIP;
-      return true;
-
-    default:
-      return false;
+      if (len <= 4) {
+        state.mip = set_field(state.mip, MIP_MSIP, bytes[0]);
+        return true;
+      }
+      break;
   }
+
+  return false;
 }
 
 void processor_t::trigger_updated()
index 3268029e458d5832bd09b274bace4a88ca05a249..4d94d5b42a9a181886c4a520fead3cd0edf67a97 100644 (file)
@@ -105,8 +105,8 @@ struct state_t
   reg_t mip;
   reg_t medeleg;
   reg_t mideleg;
-  uint32_t mucounteren;
-  uint32_t mscounteren;
+  uint32_t mcounteren;
+  uint32_t scounteren;
   reg_t sepc;
   reg_t sbadaddr;
   reg_t sscratch;
@@ -167,7 +167,6 @@ public:
   void reset();
   void step(size_t n); // run for n cycles
   void set_csr(int which, reg_t val);
-  void raise_interrupt(reg_t which);
   reg_t get_csr(int which);
   mmu_t* get_mmu() { return mmu; }
   state_t* get_state() { return &state; }
@@ -304,8 +303,8 @@ private:
   static const size_t OPCODE_CACHE_SIZE = 8191;
   insn_desc_t opcode_cache[OPCODE_CACHE_SIZE];
 
-  void check_timer();
-  void take_interrupt(); // take a trap if any interrupts are pending
+  void take_pending_interrupt() { take_interrupt(state.mip & state.mie); }
+  void take_interrupt(reg_t mask); // take first enabled interrupt in mask
   void take_trap(trap_t& t, reg_t epc); // take an exception
   void disasm(insn_t insn); // disassemble and print an instruction
   int paddr_bits();
@@ -314,7 +313,7 @@ private:
 
   friend class sim_t;
   friend class mmu_t;
-  friend class rtc_t;
+  friend class clint_t;
   friend class extension_t;
 
   void parse_isa_string(const char* isa);
index 7b48be64d800bf9b6fd914004909431226e7609c..68bcdb55d17f175ca1c8a52a0d2df768375d475d 100644 (file)
@@ -32,3 +32,13 @@ AC_ARG_ENABLE([histogram], AS_HELP_STRING([--enable-histogram], [Enable PC histo
 AS_IF([test "x$enable_histogram" = "xyes"], [
   AC_DEFINE([RISCV_ENABLE_HISTOGRAM],,[Enable PC histogram generation])
 ])
+
+AC_ARG_ENABLE([dirty], AS_HELP_STRING([--enable-dirty], [Enable hardware management of PTE accessed and dirty bits]))
+AS_IF([test "x$enable_dirty" = "xyes"], [
+  AC_DEFINE([RISCV_ENABLE_DIRTY],,[Enable hardware management of PTE accessed and dirty bits])
+])
+
+AC_ARG_ENABLE([misaligned], AS_HELP_STRING([--enable-misaligned], [Enable hardware support for misaligned loads and stores]))
+AS_IF([test "x$enable_misaligned" = "xyes"], [
+  AC_DEFINE([RISCV_ENABLE_MISALIGNED],,[Enable hardware support for misaligned loads and stores])
+])
index 6f12b846a5f30935709e6a3d8a3f9aae1257c250..9cd8f4dbef2c08599371c3880e0498d260e19eaf 100644 (file)
@@ -46,6 +46,8 @@ riscv_srcs = \
        devices.cc \
        rom.cc \
        rtc.cc \
+       clint.cc \
+       gdbserver.cc \
        debug_module.cc \
        remote_bitbang.cc \
        jtag_dtm.cc \
@@ -229,7 +231,7 @@ riscv_insn_list = \
        sc_d \
        sc_w \
        sd \
-       sfence_vm \
+       sfence_vma \
        sh \
        sll \
        slli \
diff --git a/riscv/rtc.cc b/riscv/rtc.cc
deleted file mode 100644 (file)
index 22f318c..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#include "devices.h"
-#include "processor.h"
-
-rtc_t::rtc_t(std::vector<processor_t*>& procs)
-  : procs(procs), regs(1 + procs.size())
-{
-}
-
-bool rtc_t::load(reg_t addr, size_t len, uint8_t* bytes)
-{
-  if (addr + len > size())
-    return false;
-  memcpy(bytes, (uint8_t*)&regs[0] + addr, len);
-  return true;
-}
-
-bool rtc_t::store(reg_t addr, size_t len, const uint8_t* bytes)
-{
-  if (addr + len > size() || addr < 8)
-    return false;
-  memcpy((uint8_t*)&regs[0] + addr, bytes, len);
-  increment(0);
-  return true;
-}
-
-void rtc_t::increment(reg_t inc)
-{
-  regs[0] += inc;
-  for (size_t i = 0; i < procs.size(); i++) {
-    procs[i]->state.mip &= ~MIP_MTIP;
-    if (regs[0] >= regs[1+i])
-      procs[i]->state.mip |= MIP_MTIP;
-  }
-}
index 033f12bc40983c211e09693037d56fcc8dcc2e26..a44ced6a832a67950bd4d620b1b66cccde310c15 100644 (file)
@@ -10,6 +10,9 @@
 #include <cstdlib>
 #include <cassert>
 #include <signal.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
 
 volatile bool ctrlc_pressed = false;
 static void handle_signal(int sig)
@@ -31,7 +34,7 @@ sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb, bool halted,
   size_t memsz0 = (size_t)mem_mb << 20;
   size_t quantum = 1L << 20;
   if (memsz0 == 0)
-    memsz0 = (size_t)((sizeof(size_t) == 8 ? 4096 : 2048) - 256) << 20;
+    memsz0 = (size_t)2048 << 20;
 
   memsz = memsz0;
   while ((mem = (char*)calloc(1, memsz)) == NULL)
@@ -49,8 +52,10 @@ sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb, bool halted,
     procs[i] = new processor_t(isa, this, i, halted);
   }
 
-  rtc.reset(new rtc_t(procs));
-  make_config_string();
+  clint.reset(new clint_t(procs));
+  bus.add_device(CLINT_BASE, clint.get());
+
+  make_dtb();
 }
 
 sim_t::~sim_t()
@@ -104,7 +109,7 @@ void sim_t::step(size_t n)
       procs[current_proc]->yield_load_reservation();
       if (++current_proc == procs.size()) {
         current_proc = 0;
-        rtc->increment(INTERLEAVE / INSNS_PER_RTC_TICK);
+        clint->increment(INTERLEAVE / INSNS_PER_RTC_TICK);
       }
 
       host->switch_to();
@@ -150,59 +155,162 @@ bool sim_t::mmio_store(reg_t addr, size_t len, const uint8_t* bytes)
   return bus.store(addr, len, bytes);
 }
 
-void sim_t::make_config_string()
+static std::string dts_compile(const std::string& dts)
 {
-  reg_t rtc_addr = EXT_IO_BASE;
-  bus.add_device(rtc_addr, rtc.get());
+  // Convert the DTS to DTB
+  int dts_pipe[2];
+  pid_t dts_pid;
 
-  const int align = 0x1000;
-  reg_t cpu_addr = rtc_addr + ((rtc->size() - 1) / align + 1) * align;
-  reg_t cpu_size = align;
-
-  uint32_t reset_vec[8] = {
-    0x297 + DRAM_BASE - DEFAULT_RSTVEC, // reset vector
-    0x00028067,                         //   jump straight to DRAM_BASE
-    0x00000000,                         // reserved
-    0,                                  // config string pointer
-    0, 0, 0, 0                          // trap vector
+  if (pipe(dts_pipe) != 0 || (dts_pid = fork()) < 0) {
+    std::cerr << "Failed to fork dts child: " << strerror(errno) << std::endl;
+    exit(1);
+  }
+
+  // Child process to output dts
+  if (dts_pid == 0) {
+    close(dts_pipe[0]);
+    int step, len = dts.length();
+    const char *buf = dts.c_str();
+    for (int done = 0; done < len; done += step) {
+      step = write(dts_pipe[1], buf+done, len-done);
+      if (step == -1) {
+        std::cerr << "Failed to write dts: " << strerror(errno) << std::endl;
+        exit(1);
+      }
+    }
+    close(dts_pipe[1]);
+    exit(0);
+  }
+
+  pid_t dtb_pid;
+  int dtb_pipe[2];
+  if (pipe(dtb_pipe) != 0 || (dtb_pid = fork()) < 0) {
+    std::cerr << "Failed to fork dtb child: " << strerror(errno) << std::endl;
+    exit(1);
+  }
+
+  // Child process to output dtb
+  if (dtb_pid == 0) {
+    dup2(dts_pipe[0], 0);
+    dup2(dtb_pipe[1], 1);
+    close(dts_pipe[0]);
+    close(dts_pipe[1]);
+    close(dtb_pipe[0]);
+    close(dtb_pipe[1]);
+    execl(DTC, DTC, "-O", "dtb", 0);
+    std::cerr << "Failed to run " DTC ": " << strerror(errno) << std::endl;
+    exit(1);
+  }
+
+  close(dts_pipe[1]);
+  close(dts_pipe[0]);
+  close(dtb_pipe[1]);
+
+  // Read-out dtb
+  std::stringstream dtb;
+
+  int got;
+  char buf[4096];
+  while ((got = read(dtb_pipe[0], buf, sizeof(buf))) > 0) {
+    dtb.write(buf, got);
+  }
+  if (got == -1) {
+    std::cerr << "Failed to read dtb: " << strerror(errno) << std::endl;
+    exit(1);
+  }
+  close(dtb_pipe[0]);
+
+  // Reap children
+  int status;
+  waitpid(dts_pid, &status, 0);
+  if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+    std::cerr << "Child dts process failed" << std::endl;
+    exit(1);
+  }
+  waitpid(dtb_pid, &status, 0);
+  if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+    std::cerr << "Child dtb process failed" << std::endl;
+    exit(1);
+  }
+
+  return dtb.str();
+}
+
+void sim_t::make_dtb()
+{
+  uint32_t reset_vec[] = {
+    0x297 + DRAM_BASE - DEFAULT_RSTVEC, // auipc t0, DRAM_BASE
+    0x597,                              // auipc a1, 0
+    0x58593,                            // addi a1, a1, 0
+    0xf1402573,                                // csrr a0,mhartid
+    0x00028067                          // jalr zero, t0, 0 (jump straight to DRAM_BASE)
   };
-  reset_vec[3] = DEFAULT_RSTVEC + sizeof(reset_vec); // config string pointer
+  reset_vec[2] += (sizeof(reset_vec) - 4) << 20; // addi a1, a1, sizeof(reset_vec) - 4 = DTB start
 
   std::vector<char> rom((char*)reset_vec, (char*)reset_vec + sizeof(reset_vec));
 
   std::stringstream s;
-  s << std::hex <<
-        "platform {\n"
-        "  vendor ucb;\n"
-        "  arch spike;\n"
-        "};\n"
-        "rtc {\n"
-        "  addr 0x" << rtc_addr << ";\n"
-        "};\n"
-        "ram {\n"
-        "  0 {\n"
-        "    addr 0x" << DRAM_BASE << ";\n"
-        "    size 0x" << memsz << ";\n"
-        "  };\n"
-        "};\n"
-        "core {\n";
+  s << std::dec <<
+         "/dts-v1/;\n"
+         "\n"
+         "/ {\n"
+         "  #address-cells = <2>;\n"
+         "  #size-cells = <2>;\n"
+         "  compatible = \"ucbbar,spike-bare-dev\";\n"
+         "  model = \"ucbbar,spike-bare\";\n"
+         "  cpus {\n"
+         "    #address-cells = <1>;\n"
+         "    #size-cells = <0>;\n"
+         "    timebase-frequency = <" << (CPU_HZ/INSNS_PER_RTC_TICK) << ">;\n";
   for (size_t i = 0; i < procs.size(); i++) {
-    s <<
-        "  " << i << " {\n"
-        "    " << "0 {\n" << // hart 0 on core i
-        "      isa " << procs[i]->isa_string << ";\n"
-        "      timecmp 0x" << (rtc_addr + 8*(1+i)) << ";\n"
-        "      ipi 0x" << cpu_addr << ";\n"
-        "    };\n"
-        "  };\n";
-    bus.add_device(cpu_addr, procs[i]);
-    cpu_addr += cpu_size;
+    s << "    CPU" << i << ": cpu@" << i << " {\n"
+         "      device_type = \"cpu\";\n"
+         "      reg = <" << i << ">;\n"
+         "      status = \"okay\";\n"
+         "      compatible = \"riscv\";\n"
+         "      riscv,isa = \"" << procs[i]->isa_string << "\";\n"
+         "      mmu-type = \"riscv," << (procs[i]->max_xlen <= 32 ? "sv32" : "sv48") << "\";\n"
+         "      clock-frequency = <" << CPU_HZ << ">;\n"
+         "      CPU" << i << "_intc: interrupt-controller {\n"
+         "        #interrupt-cells = <1>;\n"
+         "        interrupt-controller;\n"
+         "        compatible = \"riscv,cpu-intc\";\n"
+         "      };\n"
+         "    };\n";
   }
-  s <<  "};\n";
-
-  config_string = s.str();
-  rom.insert(rom.end(), config_string.begin(), config_string.end());
-  rom.resize((rom.size() / align + 1) * align);
+  reg_t membs = DRAM_BASE;
+  s << std::hex <<
+         "  };\n"
+         "  memory@" << DRAM_BASE << " {\n"
+         "    device_type = \"memory\";\n"
+         "    reg = <0x" << (membs >> 32) << " 0x" << (membs & (uint32_t)-1) <<
+                   " 0x" << (memsz >> 32) << " 0x" << (memsz & (uint32_t)-1) << ">;\n"
+         "  };\n"
+         "  soc {\n"
+         "    #address-cells = <2>;\n"
+         "    #size-cells = <2>;\n"
+         "    compatible = \"ucbbar,spike-bare-soc\", \"simple-bus\";\n"
+         "    ranges;\n"
+         "    clint@" << CLINT_BASE << " {\n"
+         "      compatible = \"riscv,clint0\";\n"
+         "      interrupts-extended = <" << std::dec;
+  for (size_t i = 0; i < procs.size(); i++)
+    s << "&CPU" << i << "_intc 3 &CPU" << i << "_intc 7 ";
+  reg_t clintbs = CLINT_BASE;
+  reg_t clintsz = CLINT_SIZE;
+  s << std::hex << ">;\n"
+         "      reg = <0x" << (clintbs >> 32) << " 0x" << (clintbs & (uint32_t)-1) <<
+                     " 0x" << (clintsz >> 32) << " 0x" << (clintsz & (uint32_t)-1) << ">;\n"
+         "    };\n"
+         "  };\n"
+         "};\n";
+
+  dts = s.str();
+  std::string dtb = dts_compile(dts);
+
+  rom.insert(rom.end(), dtb.begin(), dtb.end());
+  const int align = 0x1000;
+  rom.resize((rom.size() + align - 1) / align * align);
 
   boot_rom.reset(new rom_device_t(rom));
   bus.add_device(DEFAULT_RSTVEC, boot_rom.get());
index 4cb70b4d47deee29839968be430810be2e75e4d2..d3353a1bbcfd4cebb79abcfddadd11c552b14ea1 100644 (file)
@@ -32,7 +32,7 @@ public:
   void set_remote_bitbang(remote_bitbang_t* remote_bitbang) {
     this->remote_bitbang = remote_bitbang;
   }
-  const char* get_config_string() { return config_string.c_str(); }
+  const char* get_dts() { return dts.c_str(); }
   processor_t* get_core(size_t i) { return procs.at(i); }
   unsigned nprocs() const { return procs.size(); }
 
@@ -43,15 +43,16 @@ private:
   size_t memsz; // memory size in bytes
   mmu_t* debug_mmu;  // debug port into main memory
   std::vector<processor_t*> procs;
-  std::string config_string;
+  std::string dts;
   std::unique_ptr<rom_device_t> boot_rom;
-  std::unique_ptr<rtc_t> rtc;
+  std::unique_ptr<clint_t> clint;
   bus_t bus;
 
   processor_t* get_core(const std::string& i);
   void step(size_t n); // step through simulation
   static const size_t INTERLEAVE = 5000;
   static const size_t INSNS_PER_RTC_TICK = 100; // 10 MHz clock for 1 BIPS core
+  static const size_t CPU_HZ = 1000000000; // 1GHz CPU
   size_t current_step;
   size_t current_proc;
   bool debug;
@@ -67,7 +68,7 @@ private:
   reg_t mem_to_addr(char* x) { return x - mem + DRAM_BASE; }
   bool mmio_load(reg_t addr, size_t len, uint8_t* bytes);
   bool mmio_store(reg_t addr, size_t len, const uint8_t* bytes);
-  void make_config_string();
+  void make_dtb();
 
   // presents a prompt for introspection into the simulation
   void interactive();
@@ -79,6 +80,7 @@ private:
   void interactive_run_noisy(const std::string& cmd, const std::vector<std::string>& args);
   void interactive_run_silent(const std::string& cmd, const std::vector<std::string>& args);
   void interactive_reg(const std::string& cmd, const std::vector<std::string>& args);
+  void interactive_freg(const std::string& cmd, const std::vector<std::string>& args);
   void interactive_fregs(const std::string& cmd, const std::vector<std::string>& args);
   void interactive_fregd(const std::string& cmd, const std::vector<std::string>& args);
   void interactive_pc(const std::string& cmd, const std::vector<std::string>& args);
@@ -86,7 +88,7 @@ private:
   void interactive_str(const std::string& cmd, const std::vector<std::string>& args);
   void interactive_until(const std::string& cmd, const std::vector<std::string>& args);
   reg_t get_reg(const std::vector<std::string>& args);
-  reg_t get_freg(const std::vector<std::string>& args);
+  freg_t get_freg(const std::vector<std::string>& args);
   reg_t get_mem(const std::vector<std::string>& args);
   reg_t get_pc(const std::vector<std::string>& args);
 
index 7f35c5f69c40669e9be6f3495a57340789640193..91e522396b42d9887372897ed19fe30252672c4a 100644 (file)
@@ -45,16 +45,19 @@ class mem_trap_t : public trap_t
 };
 
 DECLARE_MEM_TRAP(CAUSE_MISALIGNED_FETCH, instruction_address_misaligned)
-DECLARE_MEM_TRAP(CAUSE_FAULT_FETCH, instruction_access_fault)
-DECLARE_TRAP(CAUSE_ILLEGAL_INSTRUCTION, illegal_instruction)
-DECLARE_TRAP(CAUSE_BREAKPOINT, breakpoint)
+DECLARE_MEM_TRAP(CAUSE_FETCH_ACCESS, instruction_access_fault)
+DECLARE_MEM_TRAP(CAUSE_ILLEGAL_INSTRUCTION, illegal_instruction)
+DECLARE_MEM_TRAP(CAUSE_BREAKPOINT, breakpoint)
 DECLARE_MEM_TRAP(CAUSE_MISALIGNED_LOAD, load_address_misaligned)
 DECLARE_MEM_TRAP(CAUSE_MISALIGNED_STORE, store_address_misaligned)
-DECLARE_MEM_TRAP(CAUSE_FAULT_LOAD, load_access_fault)
-DECLARE_MEM_TRAP(CAUSE_FAULT_STORE, store_access_fault)
+DECLARE_MEM_TRAP(CAUSE_LOAD_ACCESS, load_access_fault)
+DECLARE_MEM_TRAP(CAUSE_STORE_ACCESS, store_access_fault)
 DECLARE_TRAP(CAUSE_USER_ECALL, user_ecall)
 DECLARE_TRAP(CAUSE_SUPERVISOR_ECALL, supervisor_ecall)
 DECLARE_TRAP(CAUSE_HYPERVISOR_ECALL, hypervisor_ecall)
 DECLARE_TRAP(CAUSE_MACHINE_ECALL, machine_ecall)
+DECLARE_MEM_TRAP(CAUSE_FETCH_PAGE_FAULT, instruction_page_fault)
+DECLARE_MEM_TRAP(CAUSE_LOAD_PAGE_FAULT, load_page_fault)
+DECLARE_MEM_TRAP(CAUSE_STORE_PAGE_FAULT, store_page_fault)
 
 #endif
index 846b1d9bdbd51ff8daec6715337427b69a395572..38529b2504e3297e2101e7594cd63ec9c6db305a 100644 (file)
@@ -31,7 +31,7 @@ static void help()
   fprintf(stderr, "  --extension=<name>    Specify RoCC Extension\n");
   fprintf(stderr, "  --extlib=<name>       Shared library to load\n");
   fprintf(stderr, "  --rbb-port=<port>     Listen on <port> for remote bitbang connection\n");
-  fprintf(stderr, "  --dump-config-string  Print platform configuration string and exit\n");
+  fprintf(stderr, "  --dump-dts  Print device tree string and exit\n");
   exit(1);
 }
 
@@ -41,7 +41,7 @@ int main(int argc, char** argv)
   bool halted = false;
   bool histogram = false;
   bool log = false;
-  bool dump_config_string = false;
+  bool dump_dts = false;
   size_t nprocs = 1;
   size_t mem_mb = 0;
   std::unique_ptr<icache_sim_t> ic;
@@ -68,7 +68,7 @@ int main(int argc, char** argv)
   parser.option(0, "l2", 1, [&](const char* s){l2.reset(cache_sim_t::construct(s, "L2$"));});
   parser.option(0, "isa", 1, [&](const char* s){isa = s;});
   parser.option(0, "extension", 1, [&](const char* s){extension = find_extension(s);});
-  parser.option(0, "dump-config-string", 0, [&](const char *s){dump_config_string = true;});
+  parser.option(0, "dump-dts", 0, [&](const char *s){dump_dts = true;});
   parser.option(0, "extlib", 1, [&](const char *s){
     void *lib = dlopen(s, RTLD_NOW | RTLD_GLOBAL);
     if (lib == NULL) {
@@ -87,8 +87,8 @@ int main(int argc, char** argv)
     s.set_remote_bitbang(&(*remote_bitbang));
   }
 
-  if (dump_config_string) {
-    printf("%s", s.get_config_string());
+  if (dump_dts) {
+    printf("%s", s.get_dts());
     return 0;
   }