Merge remote-tracking branch 'origin/priv-1.10'
authorPalmer Dabbelt <palmer@dabbelt.com>
Wed, 17 May 2017 20:07:47 +0000 (13:07 -0700)
committerPalmer Dabbelt <palmer@dabbelt.com>
Wed, 17 May 2017 20:07:47 +0000 (13:07 -0700)
105 files changed:
LICENSE
README.md
config.h.in
configure
configure.ac
debug_rom/Makefile
debug_rom/debug_rom.S
debug_rom/debug_rom.h
debug_rom/debug_rom_defines.h [new file with mode: 0644]
debug_rom/link.ld
riscv/clint.cc [new file with mode: 0644]
riscv/debug_defines.h [new file with mode: 0644]
riscv/debug_module.cc
riscv/debug_module.h
riscv/decode.h
riscv/devices.cc
riscv/devices.h
riscv/encoding.h
riscv/execute.cc
riscv/extension.cc
riscv/gdbserver.cc [deleted file]
riscv/gdbserver.h [deleted file]
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/c_li.h
riscv/insns/c_lui.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 [deleted file]
riscv/insns/fmv_w_x.h [new file with mode: 0644]
riscv/insns/fmv_x_d.h
riscv/insns/fmv_x_s.h [deleted file]
riscv/insns/fmv_x_w.h [new file with mode: 0644]
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/jtag_dtm.cc [new file with mode: 0644]
riscv/jtag_dtm.h [new file with mode: 0644]
riscv/mmu.cc
riscv/mmu.h
riscv/opcodes.h [new file with mode: 0644]
riscv/processor.cc
riscv/processor.h
riscv/remote_bitbang.cc [new file with mode: 0644]
riscv/remote_bitbang.h [new file with mode: 0644]
riscv/riscv.ac
riscv/riscv.mk.in
riscv/rtc.cc [deleted file]
riscv/sim.cc
riscv/sim.h
riscv/trap.h
spike_main/disasm.cc
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]))
 
index b72f37db7b6193bff825d0e0974302bc4aab66a8..4e9093cd943173630bdbc027cf4aefc6969f95d8 100644 (file)
@@ -6,8 +6,8 @@ OBJCOPY = $(RISCV)/bin/riscv64-unknown-elf-objcopy
 
 COMPILE = $(CC) -nostdlib -nostartfiles -I.. -Tlink.ld
 
-ELFS = debug_rom debug_rom32 debug_rom64
-DEPS = debug_rom.S link.ld
+ELFS = debug_rom
+DEPS = debug_rom.S link.ld debug_rom_defines.h
 
 all: $(patsubst %,%.h,$(ELFS))
 
@@ -18,13 +18,7 @@ all: $(patsubst %,%.h,$(ELFS))
        $(OBJCOPY) -O binary --only-section .text $^ $@
 
 debug_rom:     $(DEPS)
-       $(COMPILE) -DRV32 -DRV64 -o $@ $^
-
-debug_rom32:   $(DEPS)
-       $(COMPILE) -DRV32 -DDEBUG_RAM_SIZE=28 -o $@ $^
-
-debug_rom64:   $(DEPS)
-       $(COMPILE) -DRV64 -o $@ $^
+       $(COMPILE) -o $@ $^
 
 clean:
        rm -f $(ELFS) debug_rom*.raw debug_rom*.h
index 74a934b201a94a31be63b24dd7c68a1149dcdecc..2ee7a31c539508558e959d5d8cc1d3227a5de6e5 100755 (executable)
-# This code should be functional. Doesn't have to be optimal.
-# I'm writing it to prove that it can be done.
-
-#include "riscv/encoding.h"
-
-# TODO: Update these constants once they're finalized in the doc.
-
-#define DEBUG_RAM               0x400
-#ifndef DEBUG_RAM_SIZE
-# define DEBUG_RAM_SIZE          64
-#endif
-
-#define CLEARDEBINT             0x100
-#define SETHALTNOT              0x10c
-
-#if (defined(RV32) + defined(RV64) + defined(RV128)) > 1
-# define MULTI_XLEN
-#elif (defined(RV32) + defined(RV64) + defined(RV128)) == 0
-# error define one or more of RV32, RV64, RV128
-#endif
+// See LICENSE.SiFive for license details.
 
+#include "spike/encoding.h"
+#include "debug_rom_defines.h"
+        
+        .option norvc
         .global entry
-        .global resume
         .global exception
 
-        # Automatically called when Debug Mode is first entered.
-entry:  j       _entry
-        # Should be called by Debug RAM code that has finished execution and
-        # wants to return to Debug Mode.
+        // Entry location on ebreak, Halt, or Breakpoint
+        // It is the same for all harts. They branch when 
+        // their GO or RESUME bit is set.
+
+entry:
+       jal zero, _entry
 resume:
-        j       _resume
+       jal zero, _resume
 exception:
-        # Set the last word of Debug RAM to all ones, to indicate that we hit
-        # an exception.
-        li      s0, ~0
-        j       _resume2
+       jal zero, _exception
 
-_resume:
-        li      s0, 0
-_resume2:
+_entry:
+        // This fence is required because the execution may have written something
+        // into the Abstract Data or Program Buffer registers.
         fence
+        csrw CSR_DSCRATCH, s0  // Save s0 to allow signaling MHARTID
+
+        // We continue to let the hart know that we are halted in order that
+        // a DM which was reset is still made aware that a hart is halted.
+        // We keep checking both whether there is something the debugger wants
+        // us to do, or whether we should resume.
+entry_loop:
+        csrr s0, CSR_MHARTID
+        sw   s0, DEBUG_ROM_HALTED(zero)
+        lbu  s0, DEBUG_ROM_FLAGS(s0) // 1 byte flag per hart. Only one hart advances here.
+        andi s0, s0, (1 << DEBUG_ROM_FLAG_GO)
+        bnez s0, going
+        csrr s0, CSR_MHARTID
+        lbu  s0, DEBUG_ROM_FLAGS(s0) // multiple harts can resume  here
+        andi s0, s0, (1 << DEBUG_ROM_FLAG_RESUME)
+        bnez s0, resume
+        jal  zero, entry_loop
+
+_exception:
+        sw      zero, DEBUG_ROM_EXCEPTION(zero) // Let debug module know you got an exception.
+        ebreak
+
+going:
+        csrr s0, CSR_DSCRATCH            // Restore s0 here
+        sw zero, DEBUG_ROM_GOING(zero)   // When debug module sees this write, the GO flag is reset.
+        fence
+        fence.i
+        jalr zero, zero, %lo(whereto)    // Debug module will put different instructions and data in the RAM, 
+                                         // so we use fence and fence.i for safety. (rocket-chip doesn't have this
+                                         // because jalr is special there)
 
-        # Restore s1.
-#ifdef MULTI_XLEN
-        csrr    s1, CSR_MISA
-#endif
-
-#ifdef RV32
-# ifdef MULTI_XLEN
-        bltz    s1, restore_not_32
-# endif
-
-restore_32:
-        lw      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 4)(zero)
-# if defined(RV64) || defined(RV128)
-        j       finish_restore
-# endif
-#endif
-
-restore_not_32:
-#if defined(RV64) && defined(RV128)
-        slli    s1, s1, 1
-        bltz    s1, restore_128
-#endif
-
-#ifdef RV64
-restore_64:
-        ld      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 8)(zero)
-#endif
-#if defined(RV64) && defined(RV128)
-        j       finish_restore
-#endif
-#ifdef RV128
-restore_128:
-        lq      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 16)(zero)
-#endif
-
-finish_restore:
-        # s0 contains ~0 if we got here through an exception, and 0 otherwise.
-        # Store this to the last word in Debug RAM so the debugger can tell if
-        # an exception occurred.
-        sw      s0, (DEBUG_RAM + DEBUG_RAM_SIZE - 4)(zero)
-
-        # Clear debug interrupt.
-        csrr    s0, CSR_MHARTID
-        sw      s0, CLEARDEBINT(zero)
-
-check_halt:
-        csrr    s0, CSR_DCSR
-        andi    s0, s0, DCSR_HALT
-        bnez    s0, wait_for_interrupt
-
-exit:
-        # Restore s0.
-        csrr    s0, CSR_DSCRATCH
+_resume:
+        csrr s0, CSR_MHARTID
+        sw   s0, DEBUG_ROM_RESUMING(zero) // When Debug Module sees this write, the RESUME flag is reset.
+        csrr s0, CSR_DSCRATCH   // Restore s0
         dret
 
-_entry:
-        # Save s0 in DSCRATCH
-        csrw    CSR_DSCRATCH, s0
-
-        # Check why we're here
-        csrr    s0, CSR_DCSR
-        # cause is in bits 8:6 of dcsr
-        andi    s0, s0, DCSR_CAUSE
-        addi    s0, s0, -(DCSR_CAUSE_DEBUGINT<<6)
-        bnez    s0, spontaneous_halt
-
-jdebugram:
-        # Save s1 so that the debug program can use two registers.
-#ifdef MULTI_XLEN
-        csrr    s0, CSR_MISA
-#endif
-
-#ifdef RV32
-# ifdef MULTI_XLEN
-        bltz    s0, save_not_32
-# endif
-save_32:
-        sw      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 4)(zero)
-        jr      zero, DEBUG_RAM
-#endif
-
-save_not_32:
-#if defined(RV64) && defined(RV128)
-        slli    s0, s0, 1
-        bltz    s0, save_128
-#endif
-
-#ifdef RV64
-save_64:
-        sd      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 8)(zero)
-        jr      zero, DEBUG_RAM
-#endif
-
-#ifdef RV128
-save_128:
-        sq      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 16)(zero)
-        jr      zero, DEBUG_RAM
-#endif
-
-spontaneous_halt:
-        csrr    s0, CSR_MHARTID
-        sw      s0, SETHALTNOT(zero)
-        csrsi   CSR_DCSR, DCSR_HALT
-
-wait_for_interrupt:
-        csrr    s0, CSR_DCSR
-        andi    s0, s0, DCSR_DEBUGINT
-        beqz    s0, wait_for_interrupt
-
-        j       jdebugram
+        // END OF ACTUAL "ROM" CONTENTS. BELOW IS JUST FOR LINKER SCRIPT.
+
+.section .whereto
+whereto:
+        nop
+        // Variable "ROM" This is : jal x0 abstract, jal x0 program_buffer,
+        //                or jal x0 resume, as desired.
+        //                Debug Module state machine tracks what is 'desired'.
+        //                We don't need/want to use jalr here because all of the
+        //                Variable ROM contents are set by
+        //                Debug Module before setting the OK_GO byte.
index b1e3beaef653d5d91de4b8a9dc942add69ef0d79..d21e1669c715213b087f0a80ec270051bbe29f96 100644 (file)
@@ -1,16 +1,12 @@
 static const unsigned char debug_rom_raw[] = {
-  0x6f, 0x00, 0xc0, 0x04, 0x6f, 0x00, 0xc0, 0x00, 0x13, 0x04, 0xf0, 0xff,
-  0x6f, 0x00, 0x80, 0x00, 0x13, 0x04, 0x00, 0x00, 0x0f, 0x00, 0xf0, 0x0f,
-  0xf3, 0x24, 0x10, 0x30, 0x63, 0xc6, 0x04, 0x00, 0x83, 0x24, 0xc0, 0x43,
-  0x6f, 0x00, 0x80, 0x00, 0x83, 0x34, 0x80, 0x43, 0x23, 0x2e, 0x80, 0x42,
-  0x73, 0x24, 0x40, 0xf1, 0x23, 0x20, 0x80, 0x10, 0x73, 0x24, 0x00, 0x7b,
-  0x13, 0x74, 0x84, 0x00, 0x63, 0x12, 0x04, 0x04, 0x73, 0x24, 0x20, 0x7b,
-  0x73, 0x00, 0x20, 0x7b, 0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x00, 0x7b,
-  0x13, 0x74, 0x04, 0x1c, 0x13, 0x04, 0x04, 0xf4, 0x63, 0x1e, 0x04, 0x00,
-  0x73, 0x24, 0x10, 0x30, 0x63, 0x46, 0x04, 0x00, 0x23, 0x2e, 0x90, 0x42,
-  0x67, 0x00, 0x00, 0x40, 0x23, 0x3c, 0x90, 0x42, 0x67, 0x00, 0x00, 0x40,
-  0x73, 0x24, 0x40, 0xf1, 0x23, 0x26, 0x80, 0x10, 0x73, 0x60, 0x04, 0x7b,
-  0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x04, 0x02, 0xe3, 0x0c, 0x04, 0xfe,
-  0x6f, 0xf0, 0x1f, 0xfd
+  0x6f, 0x00, 0xc0, 0x00, 0x6f, 0x00, 0x40, 0x05, 0x6f, 0x00, 0x40, 0x03,
+  0x0f, 0x00, 0xf0, 0x0f, 0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x40, 0xf1,
+  0x23, 0x20, 0x80, 0x10, 0x03, 0x44, 0x04, 0x40, 0x13, 0x74, 0x14, 0x00,
+  0x63, 0x10, 0x04, 0x02, 0x73, 0x24, 0x40, 0xf1, 0x03, 0x44, 0x04, 0x40,
+  0x13, 0x74, 0x24, 0x00, 0xe3, 0x18, 0x04, 0xfc, 0x6f, 0xf0, 0xdf, 0xfd,
+  0x23, 0x26, 0x00, 0x10, 0x73, 0x00, 0x10, 0x00, 0x73, 0x24, 0x20, 0x7b,
+  0x23, 0x22, 0x00, 0x10, 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x10, 0x00, 0x00,
+  0x67, 0x00, 0x00, 0x30, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x24, 0x80, 0x10,
+  0x73, 0x24, 0x20, 0x7b, 0x73, 0x00, 0x20, 0x7b
 };
-static const unsigned int debug_rom_raw_len = 148;
+static const unsigned int debug_rom_raw_len = 104;
diff --git a/debug_rom/debug_rom_defines.h b/debug_rom/debug_rom_defines.h
new file mode 100644 (file)
index 0000000..616cf59
--- /dev/null
@@ -0,0 +1,23 @@
+// See LICENSE file for license details.
+
+#ifndef DEBUG_ROM_DEFINES_H
+#define DEBUG_ROM_DEFINES_H
+
+// These are implementation-specific addresses in the Debug Module
+#define DEBUG_ROM_HALTED    0x100
+#define DEBUG_ROM_GOING     0x104
+#define DEBUG_ROM_RESUMING  0x108
+#define DEBUG_ROM_EXCEPTION 0x10C
+
+// Region of memory where each hart has 1
+// byte to read.
+#define DEBUG_ROM_FLAGS 0x400
+#define DEBUG_ROM_FLAG_GO     0
+#define DEBUG_ROM_FLAG_RESUME 1
+
+// These needs to match the link.ld         
+#define DEBUG_ROM_WHERETO 0x300
+#define DEBUG_ROM_ENTRY   0x800
+#define DEBUG_ROM_TVEC    0x808
+
+#endif
index aba6ae802e13f23a2c8edaf656f8535255a0fd53..897c42da001d1009bceb3bee32a83b7693d019cd 100644 (file)
@@ -2,6 +2,10 @@ OUTPUT_ARCH( "riscv" )
 ENTRY( entry )
 SECTIONS
 {
+    .whereto 0x300 :
+    {
+        *(.whereto)
+    }   
     . = 0x800;
     .text :
     {
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;
+  }
+}
diff --git a/riscv/debug_defines.h b/riscv/debug_defines.h
new file mode 100644 (file)
index 0000000..cb07ec2
--- /dev/null
@@ -0,0 +1,1413 @@
+#define DTM_IDCODE                          0x01
+/*
+* Identifies the release version of this part.
+ */
+#define DTM_IDCODE_VERSION_OFFSET           28
+#define DTM_IDCODE_VERSION_LENGTH           4
+#define DTM_IDCODE_VERSION                  (0xf << DTM_IDCODE_VERSION_OFFSET)
+/*
+* Identifies the designer's part number of this part.
+ */
+#define DTM_IDCODE_PARTNUMBER_OFFSET        12
+#define DTM_IDCODE_PARTNUMBER_LENGTH        16
+#define DTM_IDCODE_PARTNUMBER               (0xffff << DTM_IDCODE_PARTNUMBER_OFFSET)
+/*
+* Identifies the designer/manufacturer of this part. Bits 6:0 must be
+* bits 6:0 of the designer/manufacturer's Identification Code as
+* assigned by JEDEC Standard JEP106. Bits 10:7 contain the modulo-16
+* count of the number of continuation characters (0x7f) in that same
+* Identification Code.
+ */
+#define DTM_IDCODE_MANUFID_OFFSET           1
+#define DTM_IDCODE_MANUFID_LENGTH           11
+#define DTM_IDCODE_MANUFID                  (0x7ff << DTM_IDCODE_MANUFID_OFFSET)
+#define DTM_IDCODE_1_OFFSET                 0
+#define DTM_IDCODE_1_LENGTH                 1
+#define DTM_IDCODE_1                        (0x1 << DTM_IDCODE_1_OFFSET)
+#define DTM_DTMCS                           0x10
+/*
+* Writing 1 to this bit does a hard reset of the DTM,
+* causing the DTM to forget about any outstanding DMI transactions.
+* In general this should only be used when the Debugger has
+* reason to expect that the outstanding DMI transaction will never
+* complete (e.g. a reset condition caused an inflight DMI transaction to
+* be cancelled).
+ */
+#define DTM_DTMCS_DMIHARDRESET_OFFSET       17
+#define DTM_DTMCS_DMIHARDRESET_LENGTH       1
+#define DTM_DTMCS_DMIHARDRESET              (0x1 << DTM_DTMCS_DMIHARDRESET_OFFSET)
+/*
+* Writing 1 to this bit clears the sticky error state
+* and allows the DTM to retry or complete the previous
+* transaction.
+ */
+#define DTM_DTMCS_DMIRESET_OFFSET           16
+#define DTM_DTMCS_DMIRESET_LENGTH           1
+#define DTM_DTMCS_DMIRESET                  (0x1 << DTM_DTMCS_DMIRESET_OFFSET)
+/*
+* This is a hint to the debugger of the minimum number of
+* cycles a debugger should spend in
+* Run-Test/Idle after every DMI scan to avoid a `busy'
+* return code (\Fdmistat of 3). A debugger must still
+* check \Fdmistat when necessary.
+*
+* 0: It is not necessary to enter Run-Test/Idle at all.
+*
+* 1: Enter Run-Test/Idle and leave it immediately.
+*
+* 2: Enter Run-Test/Idle and stay there for 1 cycle before leaving.
+*
+* And so on.
+ */
+#define DTM_DTMCS_IDLE_OFFSET               12
+#define DTM_DTMCS_IDLE_LENGTH               3
+#define DTM_DTMCS_IDLE                      (0x7 << DTM_DTMCS_IDLE_OFFSET)
+/*
+* 0: No error.
+*
+* 1: Reserved. Interpret the same as 2.
+*
+* 2: An operation failed (resulted in \Fop of 2).
+*
+* 3: An operation was attempted while a DMI access was still in
+* progress (resulted in \Fop of 3).
+ */
+#define DTM_DTMCS_DMISTAT_OFFSET            10
+#define DTM_DTMCS_DMISTAT_LENGTH            2
+#define DTM_DTMCS_DMISTAT                   (0x3 << DTM_DTMCS_DMISTAT_OFFSET)
+/*
+* The size of \Faddress in \Rdmi.
+ */
+#define DTM_DTMCS_ABITS_OFFSET              4
+#define DTM_DTMCS_ABITS_LENGTH              6
+#define DTM_DTMCS_ABITS                     (0x3f << DTM_DTMCS_ABITS_OFFSET)
+/*
+* 0: Version described in spec version 0.11.
+*
+* 1: Version described in spec version 0.12 (and later?), which
+* reduces the DMI data width to 32 bits.
+*
+* Other values are reserved for future use.
+ */
+#define DTM_DTMCS_VERSION_OFFSET            0
+#define DTM_DTMCS_VERSION_LENGTH            4
+#define DTM_DTMCS_VERSION                   (0xf << DTM_DTMCS_VERSION_OFFSET)
+#define DTM_DMI                             0x11
+/*
+* Address used for DMI access. In Update-DR this value is used
+* to access the DM over the DMI.
+ */
+#define DTM_DMI_ADDRESS_OFFSET              34
+#define DTM_DMI_ADDRESS_LENGTH              abits
+#define DTM_DMI_ADDRESS                     (((1L<<abits)-1) << DTM_DMI_ADDRESS_OFFSET)
+/*
+* The data to send to the DM over the DMI during Update-DR, and
+* the data returned from the DM as a result of the previous operation.
+ */
+#define DTM_DMI_DATA_OFFSET                 2
+#define DTM_DMI_DATA_LENGTH                 32
+#define DTM_DMI_DATA                        (0xffffffffL << DTM_DMI_DATA_OFFSET)
+/*
+* When the debugger writes this field, it has the following meaning:
+*
+* 0: Ignore \Fdata. (nop)
+*
+* 1: Read from \Faddress. (read)
+*
+* 2: Write \Fdata to \Faddress. (write)
+*
+* 3: Reserved.
+*
+* When the debugger reads this field, it means the following:
+*
+* 0: The previous operation completed successfully.
+*
+* 1: Reserved.
+*
+* 2: A previous operation failed.  The data scanned into \Rdmi in
+* this access will be ignored.  This status is sticky and can be
+* cleared by writing \Fdmireset in \Rdtmcs.
+*
+* This indicates that the DM itself responded with an error, e.g.
+* in the System Bus and Serial Port overflow/underflow cases.
+*
+* 3: An operation was attempted while a DMI request is still in
+* progress. The data scanned into \Rdmi in this access will be
+* ignored. This status is sticky and can be cleared by writing
+* \Fdmireset in \Rdtmcs. If a debugger sees this status, it
+* needs to give the target more TCK edges between Update-DR and
+* Capture-DR. The simplest way to do that is to add extra transitions
+* in Run-Test/Idle.
+*
+* (The DTM, DM, and/or component may be in different clock domains,
+* so synchronization may be required. Some relatively fixed number of
+* TCK ticks may be needed for the request to reach the DM, complete,
+* and for the response to be synchronized back into the TCK domain.)
+ */
+#define DTM_DMI_OP_OFFSET                   0
+#define DTM_DMI_OP_LENGTH                   2
+#define DTM_DMI_OP                          (0x3L << DTM_DMI_OP_OFFSET)
+#define CSR_DCSR                            0x7b0
+/*
+* 0: There is no external debug support.
+*
+* 1: External debug support exists as it is described in this document.
+*
+* Other values are reserved for future standards.
+ */
+#define CSR_DCSR_XDEBUGVER_OFFSET           30
+#define CSR_DCSR_XDEBUGVER_LENGTH           2
+#define CSR_DCSR_XDEBUGVER                  (0x3 << CSR_DCSR_XDEBUGVER_OFFSET)
+/*
+* When 1, {\tt ebreak} instructions in Machine Mode enter Debug Mode.
+ */
+#define CSR_DCSR_EBREAKM_OFFSET             15
+#define CSR_DCSR_EBREAKM_LENGTH             1
+#define CSR_DCSR_EBREAKM                    (0x1 << CSR_DCSR_EBREAKM_OFFSET)
+/*
+* When 1, {\tt ebreak} instructions in Hypervisor Mode enter Debug Mode.
+ */
+#define CSR_DCSR_EBREAKH_OFFSET             14
+#define CSR_DCSR_EBREAKH_LENGTH             1
+#define CSR_DCSR_EBREAKH                    (0x1 << CSR_DCSR_EBREAKH_OFFSET)
+/*
+* When 1, {\tt ebreak} instructions in Supervisor Mode enter Debug Mode.
+ */
+#define CSR_DCSR_EBREAKS_OFFSET             13
+#define CSR_DCSR_EBREAKS_LENGTH             1
+#define CSR_DCSR_EBREAKS                    (0x1 << CSR_DCSR_EBREAKS_OFFSET)
+/*
+* When 1, {\tt ebreak} instructions in User/Application Mode enter
+* Debug Mode.
+ */
+#define CSR_DCSR_EBREAKU_OFFSET             12
+#define CSR_DCSR_EBREAKU_LENGTH             1
+#define CSR_DCSR_EBREAKU                    (0x1 << CSR_DCSR_EBREAKU_OFFSET)
+/*
+* 0: Increment counters as usual.
+*
+* 1: Don't increment any counters while in Debug Mode.  This includes
+* the {\tt cycle} and {\tt instret} CSRs. This is preferred for most
+* debugging scenarios.
+*
+* An implementation may choose not to support writing to this bit.
+* The debugger must read back the value it writes to check whether
+* the feature is supported.
+ */
+#define CSR_DCSR_STOPCOUNT_OFFSET           10
+#define CSR_DCSR_STOPCOUNT_LENGTH           1
+#define CSR_DCSR_STOPCOUNT                  (0x1 << CSR_DCSR_STOPCOUNT_OFFSET)
+/*
+* 0: Increment timers as usual.
+*
+* 1: Don't increment any hart-local timers while in Debug Mode.
+*
+* An implementation may choose not to support writing to this bit.
+* The debugger must read back the value it writes to check whether
+* the feature is supported.
+ */
+#define CSR_DCSR_STOPTIME_OFFSET            9
+#define CSR_DCSR_STOPTIME_LENGTH            1
+#define CSR_DCSR_STOPTIME                   (0x1 << CSR_DCSR_STOPTIME_OFFSET)
+/*
+* Explains why Debug Mode was entered.
+*
+* When there are multiple reasons to enter Debug Mode in a single
+* cycle, the cause with the highest priority is the one written.
+*
+* 1: An {\tt ebreak} instruction was executed. (priority 3)
+*
+* 2: The Trigger Module caused a halt. (priority 4)
+*
+* 3: \Fhaltreq was set. (priority 2)
+*
+* 4: The hart single stepped because \Fstep was set. (priority 1)
+*
+* Other values are reserved for future use.
+ */
+#define CSR_DCSR_CAUSE_OFFSET               6
+#define CSR_DCSR_CAUSE_LENGTH               3
+#define CSR_DCSR_CAUSE                      (0x7 << CSR_DCSR_CAUSE_OFFSET)
+/*
+* When set and not in Debug Mode, the hart will only execute a single
+* instruction and then enter Debug Mode.
+* Interrupts are disabled when this bit is set.
+* If the instruction does not complete due to an exception,
+* the hart will immediately enter Debug Mode before executing
+* the trap handler, with appropriate exception registers set.
+ */
+#define CSR_DCSR_STEP_OFFSET                2
+#define CSR_DCSR_STEP_LENGTH                1
+#define CSR_DCSR_STEP                       (0x1 << CSR_DCSR_STEP_OFFSET)
+/*
+* Contains the privilege level the hart was operating in when Debug
+* Mode was entered. The encoding is described in Table
+* \ref{tab:privlevel}.  A debugger can change this value to change
+* the hart's privilege level when exiting Debug Mode.
+*
+* Not all privilege levels are supported on all harts. If the
+* encoding written is not supported or the debugger is not allowed to
+* change to it, the hart may change to any supported privilege level.
+ */
+#define CSR_DCSR_PRV_OFFSET                 0
+#define CSR_DCSR_PRV_LENGTH                 2
+#define CSR_DCSR_PRV                        (0x3 << CSR_DCSR_PRV_OFFSET)
+#define CSR_DPC                             0x7b1
+#define CSR_DPC_DPC_OFFSET                  0
+#define CSR_DPC_DPC_LENGTH                  XLEN
+#define CSR_DPC_DPC                         (((1L<<XLEN)-1) << CSR_DPC_DPC_OFFSET)
+#define CSR_DSCRATCH0                       0x7b2
+#define CSR_DSCRATCH1                       0x7b3
+#define CSR_PRIV                            virtual
+/*
+* Contains the privilege level the hart was operating in when Debug
+* Mode was entered. The encoding is described in Table
+* \ref{tab:privlevel}. A user can write this value to change the
+* hart's privilege level when exiting Debug Mode.
+ */
+#define CSR_PRIV_PRV_OFFSET                 0
+#define CSR_PRIV_PRV_LENGTH                 2
+#define CSR_PRIV_PRV                        (0x3 << CSR_PRIV_PRV_OFFSET)
+#define CSR_TSELECT                         0x7a0
+#define CSR_TSELECT_INDEX_OFFSET            0
+#define CSR_TSELECT_INDEX_LENGTH            XLEN
+#define CSR_TSELECT_INDEX                   (((1L<<XLEN)-1) << CSR_TSELECT_INDEX_OFFSET)
+#define CSR_TDATA1                          0x7a1
+/*
+* 0: There is no trigger at this \Rtselect.
+*
+* 1: The trigger is a legacy SiFive address match trigger. These
+* should not be implemented and aren't further documented here.
+*
+* 2: The trigger is an address/data match trigger. The remaining bits
+* in this register act as described in \Rmcontrol.
+*
+* 3: The trigger is an instruction count trigger. The remaining bits
+* in this register act as described in \Ricount.
+*
+* 15: This trigger exists (so enumeration shouldn't terminate), but
+* is not currently available.
+*
+* Other values are reserved for future use.
+ */
+#define CSR_TDATA1_TYPE_OFFSET              XLEN-4
+#define CSR_TDATA1_TYPE_LENGTH              4
+#define CSR_TDATA1_TYPE                     (0xfL << CSR_TDATA1_TYPE_OFFSET)
+/*
+* 0: Both Debug and M Mode can write the {\tt tdata} registers at the
+* selected \Rtselect.
+*
+* 1: Only Debug Mode can write the {\tt tdata} registers at the
+* selected \Rtselect.  Writes from other modes are ignored.
+*
+* This bit is only writable from Debug Mode.
+ */
+#define CSR_TDATA1_HMODE_OFFSET             XLEN-5
+#define CSR_TDATA1_HMODE_LENGTH             1
+#define CSR_TDATA1_HMODE                    (0x1L << CSR_TDATA1_HMODE_OFFSET)
+/*
+* Trigger-specific data.
+ */
+#define CSR_TDATA1_DATA_OFFSET              0
+#define CSR_TDATA1_DATA_LENGTH              XLEN - 5
+#define CSR_TDATA1_DATA                     (((1L<<XLEN - 5)-1) << CSR_TDATA1_DATA_OFFSET)
+#define CSR_TDATA2                          0x7a2
+#define CSR_TDATA2_DATA_OFFSET              0
+#define CSR_TDATA2_DATA_LENGTH              XLEN
+#define CSR_TDATA2_DATA                     (((1L<<XLEN)-1) << CSR_TDATA2_DATA_OFFSET)
+#define CSR_TDATA3                          0x7a3
+#define CSR_TDATA3_DATA_OFFSET              0
+#define CSR_TDATA3_DATA_LENGTH              XLEN
+#define CSR_TDATA3_DATA                     (((1L<<XLEN)-1) << CSR_TDATA3_DATA_OFFSET)
+#define CSR_MCONTROL                        0x7a1
+#define CSR_MCONTROL_TYPE_OFFSET            XLEN-4
+#define CSR_MCONTROL_TYPE_LENGTH            4
+#define CSR_MCONTROL_TYPE                   (0xfL << CSR_MCONTROL_TYPE_OFFSET)
+#define CSR_MCONTROL_DMODE_OFFSET           XLEN-5
+#define CSR_MCONTROL_DMODE_LENGTH           1
+#define CSR_MCONTROL_DMODE                  (0x1L << CSR_MCONTROL_DMODE_OFFSET)
+/*
+* Specifies the largest naturally aligned powers-of-two (NAPOT) range
+* supported by the hardware. The value is the logarithm base 2 of the
+* number of bytes in that range.  A value of 0 indicates that only
+* exact value matches are supported (one byte range). A value of 63
+* corresponds to the maximum NAPOT range, which is $2^{63}$ bytes in
+* size.
+ */
+#define CSR_MCONTROL_MASKMAX_OFFSET         XLEN-11
+#define CSR_MCONTROL_MASKMAX_LENGTH         6
+#define CSR_MCONTROL_MASKMAX                (0x3fL << CSR_MCONTROL_MASKMAX_OFFSET)
+/*
+* 0: Perform a match on the virtual address.
+*
+* 1: Perform a match on the data value loaded/stored, or the
+* instruction executed.
+ */
+#define CSR_MCONTROL_SELECT_OFFSET          19
+#define CSR_MCONTROL_SELECT_LENGTH          1
+#define CSR_MCONTROL_SELECT                 (0x1L << CSR_MCONTROL_SELECT_OFFSET)
+/*
+* 0: The action for this trigger will be taken just before the
+* instruction that triggered it is executed, but after all preceding
+* instructions are are committed.
+*
+* 1: The action for this trigger will be taken after the instruction
+* that triggered it is executed. It should be taken before the next
+* instruction is executed, but it is better to implement triggers and
+* not implement that suggestion than to not implement them at all.
+*
+* Most hardware will only implement one timing or the other, possibly
+* dependent on \Fselect, \Fexecute, \Fload, and \Fstore. This bit
+* primarily exists for the hardware to communicate to the debugger
+* what will happen. Hardware may implement the bit fully writable, in
+* which case the debugger has a little more control.
+*
+* Data load triggers with \Ftiming of 0 will result in the same load
+* happening again when the debugger lets the core run. For data load
+* triggers, debuggers must first attempt to set the breakpoint with
+* \Ftiming of 1.
+*
+* A chain of triggers that don't all have the same \Ftiming value
+* will never fire (unless consecutive instructions match the
+* appropriate triggers).
+ */
+#define CSR_MCONTROL_TIMING_OFFSET          18
+#define CSR_MCONTROL_TIMING_LENGTH          1
+#define CSR_MCONTROL_TIMING                 (0x1L << CSR_MCONTROL_TIMING_OFFSET)
+/*
+* Determines what happens when this trigger matches.
+*
+* 0: Raise a breakpoint exception. (Used when software wants to use
+* the trigger module without an external debugger attached.)
+*
+* 1: Enter Debug Mode. (Only supported when \Fhmode is 1.)
+*
+* 2: Start tracing.
+*
+* 3: Stop tracing.
+*
+* 4: Emit trace data for this match. If it is a data access match,
+* emit appropriate Load/Store Address/Data. If it is an instruction
+* execution, emit its PC.
+*
+* Other values are reserved for future use.
+ */
+#define CSR_MCONTROL_ACTION_OFFSET          12
+#define CSR_MCONTROL_ACTION_LENGTH          6
+#define CSR_MCONTROL_ACTION                 (0x3fL << CSR_MCONTROL_ACTION_OFFSET)
+/*
+* 0: When this trigger matches, the configured action is taken.
+*
+* 1: While this trigger does not match, it prevents the trigger with
+* the next index from matching.
+ */
+#define CSR_MCONTROL_CHAIN_OFFSET           11
+#define CSR_MCONTROL_CHAIN_LENGTH           1
+#define CSR_MCONTROL_CHAIN                  (0x1L << CSR_MCONTROL_CHAIN_OFFSET)
+/*
+* 0: Matches when the value equals \Rtdatatwo.
+*
+* 1: Matches when the top M bits of the value match the top M bits of
+* \Rtdatatwo. M is XLEN-1 minus the index of the least-significant
+* bit containing 0 in \Rtdatatwo.
+*
+* 2: Matches when the value is greater than or equal to \Rtdatatwo.
+*
+* 3: Matches when the value is less than \Rtdatatwo.
+*
+* 4: Matches when the lower half of the value equals the lower half
+* of \Rtdatatwo after the lower half of the value is ANDed with the
+* upper half of \Rtdatatwo.
+*
+* 5: Matches when the upper half of the value equals the lower half
+* of \Rtdatatwo after the upper half of the value is ANDed with the
+* upper half of \Rtdatatwo.
+*
+* Other values are reserved for future use.
+ */
+#define CSR_MCONTROL_MATCH_OFFSET           7
+#define CSR_MCONTROL_MATCH_LENGTH           4
+#define CSR_MCONTROL_MATCH                  (0xfL << CSR_MCONTROL_MATCH_OFFSET)
+/*
+* When set, enable this trigger in M mode.
+ */
+#define CSR_MCONTROL_M_OFFSET               6
+#define CSR_MCONTROL_M_LENGTH               1
+#define CSR_MCONTROL_M                      (0x1L << CSR_MCONTROL_M_OFFSET)
+/*
+* When set, enable this trigger in H mode.
+ */
+#define CSR_MCONTROL_H_OFFSET               5
+#define CSR_MCONTROL_H_LENGTH               1
+#define CSR_MCONTROL_H                      (0x1L << CSR_MCONTROL_H_OFFSET)
+/*
+* When set, enable this trigger in S mode.
+ */
+#define CSR_MCONTROL_S_OFFSET               4
+#define CSR_MCONTROL_S_LENGTH               1
+#define CSR_MCONTROL_S                      (0x1L << CSR_MCONTROL_S_OFFSET)
+/*
+* When set, enable this trigger in U mode.
+ */
+#define CSR_MCONTROL_U_OFFSET               3
+#define CSR_MCONTROL_U_LENGTH               1
+#define CSR_MCONTROL_U                      (0x1L << CSR_MCONTROL_U_OFFSET)
+/*
+* When set, the trigger fires on the virtual address or opcode of an
+* instruction that is executed.
+ */
+#define CSR_MCONTROL_EXECUTE_OFFSET         2
+#define CSR_MCONTROL_EXECUTE_LENGTH         1
+#define CSR_MCONTROL_EXECUTE                (0x1L << CSR_MCONTROL_EXECUTE_OFFSET)
+/*
+* When set, the trigger fires on the virtual address or data of a store.
+ */
+#define CSR_MCONTROL_STORE_OFFSET           1
+#define CSR_MCONTROL_STORE_LENGTH           1
+#define CSR_MCONTROL_STORE                  (0x1L << CSR_MCONTROL_STORE_OFFSET)
+/*
+* When set, the trigger fires on the virtual address or data of a load.
+ */
+#define CSR_MCONTROL_LOAD_OFFSET            0
+#define CSR_MCONTROL_LOAD_LENGTH            1
+#define CSR_MCONTROL_LOAD                   (0x1L << CSR_MCONTROL_LOAD_OFFSET)
+#define CSR_ICOUNT                          0x7a1
+#define CSR_ICOUNT_TYPE_OFFSET              XLEN-4
+#define CSR_ICOUNT_TYPE_LENGTH              4
+#define CSR_ICOUNT_TYPE                     (0xfL << CSR_ICOUNT_TYPE_OFFSET)
+#define CSR_ICOUNT_DMODE_OFFSET             XLEN-5
+#define CSR_ICOUNT_DMODE_LENGTH             1
+#define CSR_ICOUNT_DMODE                    (0x1L << CSR_ICOUNT_DMODE_OFFSET)
+/*
+* When count is decremented to 0, the trigger fires. Instead of
+* changing \Fcount from 1 to 0, it is also acceptable for hardware to
+* clear \Fm, \Fh, \Fs, and \Fu. This allows \Fcount to be hard-wired
+* to 1 if this register just exists for single step.
+ */
+#define CSR_ICOUNT_COUNT_OFFSET             10
+#define CSR_ICOUNT_COUNT_LENGTH             14
+#define CSR_ICOUNT_COUNT                    (0x3fffL << CSR_ICOUNT_COUNT_OFFSET)
+/*
+* When set, every instruction completed or exception taken in M mode decrements \Fcount
+* by 1.
+ */
+#define CSR_ICOUNT_M_OFFSET                 9
+#define CSR_ICOUNT_M_LENGTH                 1
+#define CSR_ICOUNT_M                        (0x1L << CSR_ICOUNT_M_OFFSET)
+/*
+* When set, every instruction completed or exception taken in in H mode decrements \Fcount
+* by 1.
+ */
+#define CSR_ICOUNT_H_OFFSET                 8
+#define CSR_ICOUNT_H_LENGTH                 1
+#define CSR_ICOUNT_H                        (0x1L << CSR_ICOUNT_H_OFFSET)
+/*
+* When set, every instruction completed or exception taken in S mode decrements \Fcount
+* by 1.
+ */
+#define CSR_ICOUNT_S_OFFSET                 7
+#define CSR_ICOUNT_S_LENGTH                 1
+#define CSR_ICOUNT_S                        (0x1L << CSR_ICOUNT_S_OFFSET)
+/*
+* When set, every instruction completed or exception taken in U mode decrements \Fcount
+* by 1.
+ */
+#define CSR_ICOUNT_U_OFFSET                 6
+#define CSR_ICOUNT_U_LENGTH                 1
+#define CSR_ICOUNT_U                        (0x1L << CSR_ICOUNT_U_OFFSET)
+/*
+* Determines what happens when this trigger matches.
+*
+* 0: Raise a breakpoint exception. (Used when software wants to use the
+* trigger module without an external debugger attached.)
+*
+* 1: Enter Debug Mode. (Only supported when \Fhmode is 1.)
+*
+* 2: Start tracing.
+*
+* 3: Stop tracing.
+*
+* 4: Emit trace data for this match. If it is a data access match,
+* emit appropriate Load/Store Address/Data. If it is an instruction
+* execution, emit its PC.
+*
+* Other values are reserved for future use.
+ */
+#define CSR_ICOUNT_ACTION_OFFSET            0
+#define CSR_ICOUNT_ACTION_LENGTH            6
+#define CSR_ICOUNT_ACTION                   (0x3fL << CSR_ICOUNT_ACTION_OFFSET)
+#define DMI_DMSTATUS                        0x11
+/*
+* This field is 1 when all currently selected harts have acknowledged the previous \Fresumereq.
+ */
+#define DMI_DMSTATUS_ALLRESUMEACK_OFFSET    17
+#define DMI_DMSTATUS_ALLRESUMEACK_LENGTH    1
+#define DMI_DMSTATUS_ALLRESUMEACK           (0x1 << DMI_DMSTATUS_ALLRESUMEACK_OFFSET)
+/*
+* This field is 1 when any currently selected hart has acknowledged the previous \Fresumereq.
+ */
+#define DMI_DMSTATUS_ANYRESUMEACK_OFFSET    16
+#define DMI_DMSTATUS_ANYRESUMEACK_LENGTH    1
+#define DMI_DMSTATUS_ANYRESUMEACK           (0x1 << DMI_DMSTATUS_ANYRESUMEACK_OFFSET)
+/*
+* This field is 1 when all currently selected harts do not exist in this system.
+ */
+#define DMI_DMSTATUS_ALLNONEXISTENT_OFFSET  15
+#define DMI_DMSTATUS_ALLNONEXISTENT_LENGTH  1
+#define DMI_DMSTATUS_ALLNONEXISTENT         (0x1 << DMI_DMSTATUS_ALLNONEXISTENT_OFFSET)
+/*
+* This field is 1 when any currently selected hart does not exist in this system.
+ */
+#define DMI_DMSTATUS_ANYNONEXISTENT_OFFSET  14
+#define DMI_DMSTATUS_ANYNONEXISTENT_LENGTH  1
+#define DMI_DMSTATUS_ANYNONEXISTENT         (0x1 << DMI_DMSTATUS_ANYNONEXISTENT_OFFSET)
+/*
+* This field is 1 when all currently selected harts are unavailable.
+ */
+#define DMI_DMSTATUS_ALLUNAVAIL_OFFSET      13
+#define DMI_DMSTATUS_ALLUNAVAIL_LENGTH      1
+#define DMI_DMSTATUS_ALLUNAVAIL             (0x1 << DMI_DMSTATUS_ALLUNAVAIL_OFFSET)
+/*
+* This field is 1 when any currently selected hart is unavailable.
+ */
+#define DMI_DMSTATUS_ANYUNAVAIL_OFFSET      12
+#define DMI_DMSTATUS_ANYUNAVAIL_LENGTH      1
+#define DMI_DMSTATUS_ANYUNAVAIL             (0x1 << DMI_DMSTATUS_ANYUNAVAIL_OFFSET)
+/*
+* This field is 1 when all currently selected harts are running.
+ */
+#define DMI_DMSTATUS_ALLRUNNING_OFFSET      11
+#define DMI_DMSTATUS_ALLRUNNING_LENGTH      1
+#define DMI_DMSTATUS_ALLRUNNING             (0x1 << DMI_DMSTATUS_ALLRUNNING_OFFSET)
+/*
+* This field is 1 when any currently selected hart is running.
+ */
+#define DMI_DMSTATUS_ANYRUNNING_OFFSET      10
+#define DMI_DMSTATUS_ANYRUNNING_LENGTH      1
+#define DMI_DMSTATUS_ANYRUNNING             (0x1 << DMI_DMSTATUS_ANYRUNNING_OFFSET)
+/*
+* This field is 1 when all currently selected harts are halted.
+ */
+#define DMI_DMSTATUS_ALLHALTED_OFFSET       9
+#define DMI_DMSTATUS_ALLHALTED_LENGTH       1
+#define DMI_DMSTATUS_ALLHALTED              (0x1 << DMI_DMSTATUS_ALLHALTED_OFFSET)
+/*
+* This field is 1 when any currently selected hart is halted.
+ */
+#define DMI_DMSTATUS_ANYHALTED_OFFSET       8
+#define DMI_DMSTATUS_ANYHALTED_LENGTH       1
+#define DMI_DMSTATUS_ANYHALTED              (0x1 << DMI_DMSTATUS_ANYHALTED_OFFSET)
+/*
+* 0 when authentication is required before using the DM.  1 when the
+* authentication check has passed. On components that don't implement
+* authentication, this bit must be preset as 1.
+ */
+#define DMI_DMSTATUS_AUTHENTICATED_OFFSET   7
+#define DMI_DMSTATUS_AUTHENTICATED_LENGTH   1
+#define DMI_DMSTATUS_AUTHENTICATED          (0x1 << DMI_DMSTATUS_AUTHENTICATED_OFFSET)
+/*
+* 0: The authentication module is ready to process the next
+* read/write to \Rauthdata.
+*
+* 1: The authentication module is busy. Accessing \Rauthdata results
+* in unspecified behavior.
+*
+* \Fauthbusy only becomes set in immediate response to an access to
+* \Rauthdata.
+ */
+#define DMI_DMSTATUS_AUTHBUSY_OFFSET        6
+#define DMI_DMSTATUS_AUTHBUSY_LENGTH        1
+#define DMI_DMSTATUS_AUTHBUSY               (0x1 << DMI_DMSTATUS_AUTHBUSY_OFFSET)
+#define DMI_DMSTATUS_CFGSTRVALID_OFFSET     4
+#define DMI_DMSTATUS_CFGSTRVALID_LENGTH     1
+#define DMI_DMSTATUS_CFGSTRVALID            (0x1 << DMI_DMSTATUS_CFGSTRVALID_OFFSET)
+/*
+* Reserved for future use. Reads as 0.
+ */
+#define DMI_DMSTATUS_VERSIONHI_OFFSET       2
+#define DMI_DMSTATUS_VERSIONHI_LENGTH       2
+#define DMI_DMSTATUS_VERSIONHI              (0x3 << DMI_DMSTATUS_VERSIONHI_OFFSET)
+/*
+* 00: There is no Debug Module present.
+*
+* 01: There is a Debug Module and it conforms to version 0.11 of this
+* specification.
+*
+* 10: There is a Debug Module and it conforms to version 0.13 of this
+* specification.
+*
+* 11: Reserved for future use.
+ */
+#define DMI_DMSTATUS_VERSIONLO_OFFSET       0
+#define DMI_DMSTATUS_VERSIONLO_LENGTH       2
+#define DMI_DMSTATUS_VERSIONLO              (0x3 << DMI_DMSTATUS_VERSIONLO_OFFSET)
+#define DMI_DMCONTROL                       0x10
+/*
+* Halt request signal for all currently selected harts. When set to 1, the
+* hart will halt if it is not currently halted.
+* Setting both \Fhaltreq and \Fresumereq leads to undefined behavior.
+*
+* Writes apply to the new value of \Fhartsel and \Fhasel.
+ */
+#define DMI_DMCONTROL_HALTREQ_OFFSET        31
+#define DMI_DMCONTROL_HALTREQ_LENGTH        1
+#define DMI_DMCONTROL_HALTREQ               (0x1 << DMI_DMCONTROL_HALTREQ_OFFSET)
+/*
+* Resume request signal for all currently selected harts. When set to 1,
+* the hart will resume if it is currently halted.
+* Setting both \Fhaltreq and \Fresumereq leads to undefined behavior.
+*
+* Writes apply to the new value of \Fhartsel and \Fhasel.
+ */
+#define DMI_DMCONTROL_RESUMEREQ_OFFSET      30
+#define DMI_DMCONTROL_RESUMEREQ_LENGTH      1
+#define DMI_DMCONTROL_RESUMEREQ             (0x1 << DMI_DMCONTROL_RESUMEREQ_OFFSET)
+/*
+* This optional bit controls reset to all the currently selected harts.
+* To perform a reset the debugger writes 1, and then writes 0 to
+* deassert the reset signal.
+*
+* If this feature is not implemented, the bit always stays 0, so
+* after writing 1 the debugger can read the register back to see if
+* the feature is supported.
+*
+* Writes apply to the new value of \Fhartsel and \Fhasel.
+ */
+#define DMI_DMCONTROL_HARTRESET_OFFSET      29
+#define DMI_DMCONTROL_HARTRESET_LENGTH      1
+#define DMI_DMCONTROL_HARTRESET             (0x1 << DMI_DMCONTROL_HARTRESET_OFFSET)
+/*
+* Selects the  definition of currently selected harts.
+*
+* 0: There is a single currently selected hart, that selected by \Fhartsel.
+*
+* 1: There may be multiple currently selected harts -- that selected by \Fhartsel,
+* plus those selected by the hart array mask register.
+*
+* An implementation which does not implement the hart array mask register
+* should tie this field to 0. A debugger which wishes to use the hart array
+* mask register feature should set this bit and read back to see if the functionality
+* is supported.
+ */
+#define DMI_DMCONTROL_HASEL_OFFSET          26
+#define DMI_DMCONTROL_HASEL_LENGTH          1
+#define DMI_DMCONTROL_HASEL                 (0x1 << DMI_DMCONTROL_HASEL_OFFSET)
+/*
+* The DM-specific index of the hart to select. This hart is always part of the
+* currently selected harts.
+ */
+#define DMI_DMCONTROL_HARTSEL_OFFSET        16
+#define DMI_DMCONTROL_HARTSEL_LENGTH        10
+#define DMI_DMCONTROL_HARTSEL               (0x3ff << DMI_DMCONTROL_HARTSEL_OFFSET)
+/*
+* This bit controls the reset signal from the DM to the rest of the
+* system. To perform a reset the debugger writes 1, and then writes 0
+* to deassert the reset.
+ */
+#define DMI_DMCONTROL_NDMRESET_OFFSET       1
+#define DMI_DMCONTROL_NDMRESET_LENGTH       1
+#define DMI_DMCONTROL_NDMRESET              (0x1 << DMI_DMCONTROL_NDMRESET_OFFSET)
+/*
+* This bit serves as a reset signal for the Debug Module itself.
+*
+* 0: The module's state, including authentication mechanism,
+* takes its reset values (the \Fdmactive bit is the only bit which can
+* be written to something other than its reset value).
+*
+* 1: The module functions normally.
+*
+* No other mechanism should exist that may result in resetting the
+* Debug Module after power up, including the platform's system reset
+* or Debug Transport reset signals.
+*
+* A debugger should pulse this bit low to ensure that the Debug
+* Module is fully reset and ready to use.
+*
+* Implementations may use this bit to aid debugging, for example by
+* preventing the Debug Module from being power gated while debugging
+* is active.
+ */
+#define DMI_DMCONTROL_DMACTIVE_OFFSET       0
+#define DMI_DMCONTROL_DMACTIVE_LENGTH       1
+#define DMI_DMCONTROL_DMACTIVE              (0x1 << DMI_DMCONTROL_DMACTIVE_OFFSET)
+#define DMI_HARTINFO                        0x12
+/*
+* Number of {\tt dscratch} registers available for the debugger
+* to use during program buffer execution, starting from \Rdscratchzero.
+* The debugger can make no assumptions about the contents of these
+* registers between commands.
+ */
+#define DMI_HARTINFO_NSCRATCH_OFFSET        20
+#define DMI_HARTINFO_NSCRATCH_LENGTH        4
+#define DMI_HARTINFO_NSCRATCH               (0xf << DMI_HARTINFO_NSCRATCH_OFFSET)
+/*
+* 0: The {\tt data} registers are shadowed in the hart by CSR
+* registers. Each CSR register is XLEN bits in size, and corresponds
+* to a single argument, per Table~\ref{tab:datareg}.
+*
+* 1: The {\tt data} registers are shadowed in the hart's memory map.
+* Each register takes up 4 bytes in the memory map.
+ */
+#define DMI_HARTINFO_DATAACCESS_OFFSET      16
+#define DMI_HARTINFO_DATAACCESS_LENGTH      1
+#define DMI_HARTINFO_DATAACCESS             (0x1 << DMI_HARTINFO_DATAACCESS_OFFSET)
+/*
+* If \Fdataaccess is 0: Number of CSR registers dedicated to
+* shadowing the {\tt data} registers.
+*
+* If \Fdataaccess is 1: Number of 32-bit words in the memory map
+* dedicated to shadowing the {\tt data} registers.
+ */
+#define DMI_HARTINFO_DATASIZE_OFFSET        12
+#define DMI_HARTINFO_DATASIZE_LENGTH        4
+#define DMI_HARTINFO_DATASIZE               (0xf << DMI_HARTINFO_DATASIZE_OFFSET)
+/*
+* If \Fdataaccess is 0: The number of the first CSR dedicated to
+* shadowing the {\tt data} registers.
+*
+* If \Fdataaccess is 1: Signed address of RAM where the {\tt data}
+* registers are shadowed.
+ */
+#define DMI_HARTINFO_DATAADDR_OFFSET        0
+#define DMI_HARTINFO_DATAADDR_LENGTH        12
+#define DMI_HARTINFO_DATAADDR               (0xfff << DMI_HARTINFO_DATAADDR_OFFSET)
+#define DMI_HALTSUM                         0x13
+#define DMI_HALTSUM_HALT1023_992_OFFSET     31
+#define DMI_HALTSUM_HALT1023_992_LENGTH     1
+#define DMI_HALTSUM_HALT1023_992            (0x1 << DMI_HALTSUM_HALT1023_992_OFFSET)
+#define DMI_HALTSUM_HALT991_960_OFFSET      30
+#define DMI_HALTSUM_HALT991_960_LENGTH      1
+#define DMI_HALTSUM_HALT991_960             (0x1 << DMI_HALTSUM_HALT991_960_OFFSET)
+#define DMI_HALTSUM_HALT959_928_OFFSET      29
+#define DMI_HALTSUM_HALT959_928_LENGTH      1
+#define DMI_HALTSUM_HALT959_928             (0x1 << DMI_HALTSUM_HALT959_928_OFFSET)
+#define DMI_HALTSUM_HALT927_896_OFFSET      28
+#define DMI_HALTSUM_HALT927_896_LENGTH      1
+#define DMI_HALTSUM_HALT927_896             (0x1 << DMI_HALTSUM_HALT927_896_OFFSET)
+#define DMI_HALTSUM_HALT895_864_OFFSET      27
+#define DMI_HALTSUM_HALT895_864_LENGTH      1
+#define DMI_HALTSUM_HALT895_864             (0x1 << DMI_HALTSUM_HALT895_864_OFFSET)
+#define DMI_HALTSUM_HALT863_832_OFFSET      26
+#define DMI_HALTSUM_HALT863_832_LENGTH      1
+#define DMI_HALTSUM_HALT863_832             (0x1 << DMI_HALTSUM_HALT863_832_OFFSET)
+#define DMI_HALTSUM_HALT831_800_OFFSET      25
+#define DMI_HALTSUM_HALT831_800_LENGTH      1
+#define DMI_HALTSUM_HALT831_800             (0x1 << DMI_HALTSUM_HALT831_800_OFFSET)
+#define DMI_HALTSUM_HALT799_768_OFFSET      24
+#define DMI_HALTSUM_HALT799_768_LENGTH      1
+#define DMI_HALTSUM_HALT799_768             (0x1 << DMI_HALTSUM_HALT799_768_OFFSET)
+#define DMI_HALTSUM_HALT767_736_OFFSET      23
+#define DMI_HALTSUM_HALT767_736_LENGTH      1
+#define DMI_HALTSUM_HALT767_736             (0x1 << DMI_HALTSUM_HALT767_736_OFFSET)
+#define DMI_HALTSUM_HALT735_704_OFFSET      22
+#define DMI_HALTSUM_HALT735_704_LENGTH      1
+#define DMI_HALTSUM_HALT735_704             (0x1 << DMI_HALTSUM_HALT735_704_OFFSET)
+#define DMI_HALTSUM_HALT703_672_OFFSET      21
+#define DMI_HALTSUM_HALT703_672_LENGTH      1
+#define DMI_HALTSUM_HALT703_672             (0x1 << DMI_HALTSUM_HALT703_672_OFFSET)
+#define DMI_HALTSUM_HALT671_640_OFFSET      20
+#define DMI_HALTSUM_HALT671_640_LENGTH      1
+#define DMI_HALTSUM_HALT671_640             (0x1 << DMI_HALTSUM_HALT671_640_OFFSET)
+#define DMI_HALTSUM_HALT639_608_OFFSET      19
+#define DMI_HALTSUM_HALT639_608_LENGTH      1
+#define DMI_HALTSUM_HALT639_608             (0x1 << DMI_HALTSUM_HALT639_608_OFFSET)
+#define DMI_HALTSUM_HALT607_576_OFFSET      18
+#define DMI_HALTSUM_HALT607_576_LENGTH      1
+#define DMI_HALTSUM_HALT607_576             (0x1 << DMI_HALTSUM_HALT607_576_OFFSET)
+#define DMI_HALTSUM_HALT575_544_OFFSET      17
+#define DMI_HALTSUM_HALT575_544_LENGTH      1
+#define DMI_HALTSUM_HALT575_544             (0x1 << DMI_HALTSUM_HALT575_544_OFFSET)
+#define DMI_HALTSUM_HALT543_512_OFFSET      16
+#define DMI_HALTSUM_HALT543_512_LENGTH      1
+#define DMI_HALTSUM_HALT543_512             (0x1 << DMI_HALTSUM_HALT543_512_OFFSET)
+#define DMI_HALTSUM_HALT511_480_OFFSET      15
+#define DMI_HALTSUM_HALT511_480_LENGTH      1
+#define DMI_HALTSUM_HALT511_480             (0x1 << DMI_HALTSUM_HALT511_480_OFFSET)
+#define DMI_HALTSUM_HALT479_448_OFFSET      14
+#define DMI_HALTSUM_HALT479_448_LENGTH      1
+#define DMI_HALTSUM_HALT479_448             (0x1 << DMI_HALTSUM_HALT479_448_OFFSET)
+#define DMI_HALTSUM_HALT447_416_OFFSET      13
+#define DMI_HALTSUM_HALT447_416_LENGTH      1
+#define DMI_HALTSUM_HALT447_416             (0x1 << DMI_HALTSUM_HALT447_416_OFFSET)
+#define DMI_HALTSUM_HALT415_384_OFFSET      12
+#define DMI_HALTSUM_HALT415_384_LENGTH      1
+#define DMI_HALTSUM_HALT415_384             (0x1 << DMI_HALTSUM_HALT415_384_OFFSET)
+#define DMI_HALTSUM_HALT383_352_OFFSET      11
+#define DMI_HALTSUM_HALT383_352_LENGTH      1
+#define DMI_HALTSUM_HALT383_352             (0x1 << DMI_HALTSUM_HALT383_352_OFFSET)
+#define DMI_HALTSUM_HALT351_320_OFFSET      10
+#define DMI_HALTSUM_HALT351_320_LENGTH      1
+#define DMI_HALTSUM_HALT351_320             (0x1 << DMI_HALTSUM_HALT351_320_OFFSET)
+#define DMI_HALTSUM_HALT319_288_OFFSET      9
+#define DMI_HALTSUM_HALT319_288_LENGTH      1
+#define DMI_HALTSUM_HALT319_288             (0x1 << DMI_HALTSUM_HALT319_288_OFFSET)
+#define DMI_HALTSUM_HALT287_256_OFFSET      8
+#define DMI_HALTSUM_HALT287_256_LENGTH      1
+#define DMI_HALTSUM_HALT287_256             (0x1 << DMI_HALTSUM_HALT287_256_OFFSET)
+#define DMI_HALTSUM_HALT255_224_OFFSET      7
+#define DMI_HALTSUM_HALT255_224_LENGTH      1
+#define DMI_HALTSUM_HALT255_224             (0x1 << DMI_HALTSUM_HALT255_224_OFFSET)
+#define DMI_HALTSUM_HALT223_192_OFFSET      6
+#define DMI_HALTSUM_HALT223_192_LENGTH      1
+#define DMI_HALTSUM_HALT223_192             (0x1 << DMI_HALTSUM_HALT223_192_OFFSET)
+#define DMI_HALTSUM_HALT191_160_OFFSET      5
+#define DMI_HALTSUM_HALT191_160_LENGTH      1
+#define DMI_HALTSUM_HALT191_160             (0x1 << DMI_HALTSUM_HALT191_160_OFFSET)
+#define DMI_HALTSUM_HALT159_128_OFFSET      4
+#define DMI_HALTSUM_HALT159_128_LENGTH      1
+#define DMI_HALTSUM_HALT159_128             (0x1 << DMI_HALTSUM_HALT159_128_OFFSET)
+#define DMI_HALTSUM_HALT127_96_OFFSET       3
+#define DMI_HALTSUM_HALT127_96_LENGTH       1
+#define DMI_HALTSUM_HALT127_96              (0x1 << DMI_HALTSUM_HALT127_96_OFFSET)
+#define DMI_HALTSUM_HALT95_64_OFFSET        2
+#define DMI_HALTSUM_HALT95_64_LENGTH        1
+#define DMI_HALTSUM_HALT95_64               (0x1 << DMI_HALTSUM_HALT95_64_OFFSET)
+#define DMI_HALTSUM_HALT63_32_OFFSET        1
+#define DMI_HALTSUM_HALT63_32_LENGTH        1
+#define DMI_HALTSUM_HALT63_32               (0x1 << DMI_HALTSUM_HALT63_32_OFFSET)
+#define DMI_HALTSUM_HALT31_0_OFFSET         0
+#define DMI_HALTSUM_HALT31_0_LENGTH         1
+#define DMI_HALTSUM_HALT31_0                (0x1 << DMI_HALTSUM_HALT31_0_OFFSET)
+#define DMI_HAWINDOWSEL                     0x14
+#define DMI_HAWINDOWSEL_HAWINDOWSEL_OFFSET  0
+#define DMI_HAWINDOWSEL_HAWINDOWSEL_LENGTH  5
+#define DMI_HAWINDOWSEL_HAWINDOWSEL         (0x1f << DMI_HAWINDOWSEL_HAWINDOWSEL_OFFSET)
+#define DMI_HAWINDOW                        0x15
+#define DMI_HAWINDOW_MASKDATA_OFFSET        0
+#define DMI_HAWINDOW_MASKDATA_LENGTH        32
+#define DMI_HAWINDOW_MASKDATA               (0xffffffff << DMI_HAWINDOW_MASKDATA_OFFSET)
+#define DMI_ABSTRACTCS                      0x16
+/*
+* Size of the Program Buffer, in 32-bit words. Valid sizes are 0 - 16.
+*
+* TODO: Explain what can be done with each size of the buffer, to suggest
+* why you would want more or less words.
+ */
+#define DMI_ABSTRACTCS_PROGSIZE_OFFSET      24
+#define DMI_ABSTRACTCS_PROGSIZE_LENGTH      5
+#define DMI_ABSTRACTCS_PROGSIZE             (0x1f << DMI_ABSTRACTCS_PROGSIZE_OFFSET)
+/*
+* 1: An abstract command is currently being executed.
+*
+* This bit is set as soon as \Rcommand is written, and is
+* not cleared until that command has completed.
+ */
+#define DMI_ABSTRACTCS_BUSY_OFFSET          12
+#define DMI_ABSTRACTCS_BUSY_LENGTH          1
+#define DMI_ABSTRACTCS_BUSY                 (0x1 << DMI_ABSTRACTCS_BUSY_OFFSET)
+/*
+* Gets set if an abstract command fails. The bits in this field remain set until
+* they are cleared by writing 1 to them. No abstract command is
+* started until the value is reset to 0.
+*
+* 0 (none): No error.
+*
+* 1 (busy): An abstract command was executing while \Rcommand or one
+* of the {\tt data} registers was accessed.
+*
+* 2 (not supported): The requested command is not supported. A
+* command that is not supported while the hart is running may be
+* supported when it is halted.
+*
+* 3 (exception): An exception occurred while executing the command
+* (eg. while executing the Program Buffer).
+*
+* 4 (halt/resume): An abstract command couldn't execute because the
+* hart wasn't in the expected state (running/halted).
+*
+* 7 (other): The command failed for another reason.
+ */
+#define DMI_ABSTRACTCS_CMDERR_OFFSET        8
+#define DMI_ABSTRACTCS_CMDERR_LENGTH        3
+#define DMI_ABSTRACTCS_CMDERR               (0x7 << DMI_ABSTRACTCS_CMDERR_OFFSET)
+/*
+* Number of {\tt data} registers that are implemented as part of the
+* abstract command interface. Valid sizes are 0 - 8.
+ */
+#define DMI_ABSTRACTCS_DATACOUNT_OFFSET     0
+#define DMI_ABSTRACTCS_DATACOUNT_LENGTH     5
+#define DMI_ABSTRACTCS_DATACOUNT            (0x1f << DMI_ABSTRACTCS_DATACOUNT_OFFSET)
+#define DMI_COMMAND                         0x17
+/*
+* The type determines the overall functionality of this
+* abstract command.
+ */
+#define DMI_COMMAND_CMDTYPE_OFFSET          24
+#define DMI_COMMAND_CMDTYPE_LENGTH          8
+#define DMI_COMMAND_CMDTYPE                 (0xff << DMI_COMMAND_CMDTYPE_OFFSET)
+/*
+* This field is interpreted in a command-specific manner,
+* described for each abstract command.
+ */
+#define DMI_COMMAND_CONTROL_OFFSET          0
+#define DMI_COMMAND_CONTROL_LENGTH          24
+#define DMI_COMMAND_CONTROL                 (0xffffff << DMI_COMMAND_CONTROL_OFFSET)
+#define DMI_ABSTRACTAUTO                    0x18
+/*
+* When a bit in this field is 1, read or write accesses the corresponding {\tt progbuf} word
+* cause the command in \Rcommand to be executed again.
+ */
+#define DMI_ABSTRACTAUTO_AUTOEXECPROGBUF_OFFSET 16
+#define DMI_ABSTRACTAUTO_AUTOEXECPROGBUF_LENGTH 16
+#define DMI_ABSTRACTAUTO_AUTOEXECPROGBUF    (0xffff << DMI_ABSTRACTAUTO_AUTOEXECPROGBUF_OFFSET)
+/*
+* When a bit in this field is 1, read or write accesses the corresponding {\tt data} word
+* cause the command in \Rcommand to be executed again.
+ */
+#define DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET 0
+#define DMI_ABSTRACTAUTO_AUTOEXECDATA_LENGTH 12
+#define DMI_ABSTRACTAUTO_AUTOEXECDATA       (0xfff << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET)
+#define DMI_CFGSTRADDR0                     0x19
+#define DMI_CFGSTRADDR0_ADDR_OFFSET         0
+#define DMI_CFGSTRADDR0_ADDR_LENGTH         32
+#define DMI_CFGSTRADDR0_ADDR                (0xffffffff << DMI_CFGSTRADDR0_ADDR_OFFSET)
+#define DMI_CFGSTRADDR1                     0x1a
+#define DMI_CFGSTRADDR2                     0x1b
+#define DMI_CFGSTRADDR3                     0x1c
+#define DMI_DATA0                           0x04
+#define DMI_DATA0_DATA_OFFSET               0
+#define DMI_DATA0_DATA_LENGTH               32
+#define DMI_DATA0_DATA                      (0xffffffff << DMI_DATA0_DATA_OFFSET)
+#define DMI_DATA11                          0x0f
+#define DMI_PROGBUF0                        0x20
+#define DMI_PROGBUF0_DATA_OFFSET            0
+#define DMI_PROGBUF0_DATA_LENGTH            32
+#define DMI_PROGBUF0_DATA                   (0xffffffff << DMI_PROGBUF0_DATA_OFFSET)
+#define DMI_PROGBUF15                       0x2f
+#define DMI_AUTHDATA                        0x30
+#define DMI_AUTHDATA_DATA_OFFSET            0
+#define DMI_AUTHDATA_DATA_LENGTH            32
+#define DMI_AUTHDATA_DATA                   (0xffffffff << DMI_AUTHDATA_DATA_OFFSET)
+#define DMI_SERCS                           0x34
+/*
+* Number of supported serial ports.
+ */
+#define DMI_SERCS_SERIALCOUNT_OFFSET        28
+#define DMI_SERCS_SERIALCOUNT_LENGTH        4
+#define DMI_SERCS_SERIALCOUNT               (0xf << DMI_SERCS_SERIALCOUNT_OFFSET)
+/*
+* Select which serial port is accessed by \Rserrx and \Rsertx.
+ */
+#define DMI_SERCS_SERIAL_OFFSET             24
+#define DMI_SERCS_SERIAL_LENGTH             3
+#define DMI_SERCS_SERIAL                    (0x7 << DMI_SERCS_SERIAL_OFFSET)
+#define DMI_SERCS_ERROR7_OFFSET             23
+#define DMI_SERCS_ERROR7_LENGTH             1
+#define DMI_SERCS_ERROR7                    (0x1 << DMI_SERCS_ERROR7_OFFSET)
+#define DMI_SERCS_VALID7_OFFSET             22
+#define DMI_SERCS_VALID7_LENGTH             1
+#define DMI_SERCS_VALID7                    (0x1 << DMI_SERCS_VALID7_OFFSET)
+#define DMI_SERCS_FULL7_OFFSET              21
+#define DMI_SERCS_FULL7_LENGTH              1
+#define DMI_SERCS_FULL7                     (0x1 << DMI_SERCS_FULL7_OFFSET)
+#define DMI_SERCS_ERROR6_OFFSET             20
+#define DMI_SERCS_ERROR6_LENGTH             1
+#define DMI_SERCS_ERROR6                    (0x1 << DMI_SERCS_ERROR6_OFFSET)
+#define DMI_SERCS_VALID6_OFFSET             19
+#define DMI_SERCS_VALID6_LENGTH             1
+#define DMI_SERCS_VALID6                    (0x1 << DMI_SERCS_VALID6_OFFSET)
+#define DMI_SERCS_FULL6_OFFSET              18
+#define DMI_SERCS_FULL6_LENGTH              1
+#define DMI_SERCS_FULL6                     (0x1 << DMI_SERCS_FULL6_OFFSET)
+#define DMI_SERCS_ERROR5_OFFSET             17
+#define DMI_SERCS_ERROR5_LENGTH             1
+#define DMI_SERCS_ERROR5                    (0x1 << DMI_SERCS_ERROR5_OFFSET)
+#define DMI_SERCS_VALID5_OFFSET             16
+#define DMI_SERCS_VALID5_LENGTH             1
+#define DMI_SERCS_VALID5                    (0x1 << DMI_SERCS_VALID5_OFFSET)
+#define DMI_SERCS_FULL5_OFFSET              15
+#define DMI_SERCS_FULL5_LENGTH              1
+#define DMI_SERCS_FULL5                     (0x1 << DMI_SERCS_FULL5_OFFSET)
+#define DMI_SERCS_ERROR4_OFFSET             14
+#define DMI_SERCS_ERROR4_LENGTH             1
+#define DMI_SERCS_ERROR4                    (0x1 << DMI_SERCS_ERROR4_OFFSET)
+#define DMI_SERCS_VALID4_OFFSET             13
+#define DMI_SERCS_VALID4_LENGTH             1
+#define DMI_SERCS_VALID4                    (0x1 << DMI_SERCS_VALID4_OFFSET)
+#define DMI_SERCS_FULL4_OFFSET              12
+#define DMI_SERCS_FULL4_LENGTH              1
+#define DMI_SERCS_FULL4                     (0x1 << DMI_SERCS_FULL4_OFFSET)
+#define DMI_SERCS_ERROR3_OFFSET             11
+#define DMI_SERCS_ERROR3_LENGTH             1
+#define DMI_SERCS_ERROR3                    (0x1 << DMI_SERCS_ERROR3_OFFSET)
+#define DMI_SERCS_VALID3_OFFSET             10
+#define DMI_SERCS_VALID3_LENGTH             1
+#define DMI_SERCS_VALID3                    (0x1 << DMI_SERCS_VALID3_OFFSET)
+#define DMI_SERCS_FULL3_OFFSET              9
+#define DMI_SERCS_FULL3_LENGTH              1
+#define DMI_SERCS_FULL3                     (0x1 << DMI_SERCS_FULL3_OFFSET)
+#define DMI_SERCS_ERROR2_OFFSET             8
+#define DMI_SERCS_ERROR2_LENGTH             1
+#define DMI_SERCS_ERROR2                    (0x1 << DMI_SERCS_ERROR2_OFFSET)
+#define DMI_SERCS_VALID2_OFFSET             7
+#define DMI_SERCS_VALID2_LENGTH             1
+#define DMI_SERCS_VALID2                    (0x1 << DMI_SERCS_VALID2_OFFSET)
+#define DMI_SERCS_FULL2_OFFSET              6
+#define DMI_SERCS_FULL2_LENGTH              1
+#define DMI_SERCS_FULL2                     (0x1 << DMI_SERCS_FULL2_OFFSET)
+#define DMI_SERCS_ERROR1_OFFSET             5
+#define DMI_SERCS_ERROR1_LENGTH             1
+#define DMI_SERCS_ERROR1                    (0x1 << DMI_SERCS_ERROR1_OFFSET)
+#define DMI_SERCS_VALID1_OFFSET             4
+#define DMI_SERCS_VALID1_LENGTH             1
+#define DMI_SERCS_VALID1                    (0x1 << DMI_SERCS_VALID1_OFFSET)
+#define DMI_SERCS_FULL1_OFFSET              3
+#define DMI_SERCS_FULL1_LENGTH              1
+#define DMI_SERCS_FULL1                     (0x1 << DMI_SERCS_FULL1_OFFSET)
+/*
+* 1 when the debugger-to-core queue for serial port 0 has
+* over or underflowed. This bit will remain set until it is reset by
+* writing 1 to this bit.
+ */
+#define DMI_SERCS_ERROR0_OFFSET             2
+#define DMI_SERCS_ERROR0_LENGTH             1
+#define DMI_SERCS_ERROR0                    (0x1 << DMI_SERCS_ERROR0_OFFSET)
+/*
+* 1 when the core-to-debugger queue for serial port 0 is not empty.
+ */
+#define DMI_SERCS_VALID0_OFFSET             1
+#define DMI_SERCS_VALID0_LENGTH             1
+#define DMI_SERCS_VALID0                    (0x1 << DMI_SERCS_VALID0_OFFSET)
+/*
+* 1 when the debugger-to-core queue for serial port 0 is full.
+ */
+#define DMI_SERCS_FULL0_OFFSET              0
+#define DMI_SERCS_FULL0_LENGTH              1
+#define DMI_SERCS_FULL0                     (0x1 << DMI_SERCS_FULL0_OFFSET)
+#define DMI_SERTX                           0x35
+#define DMI_SERTX_DATA_OFFSET               0
+#define DMI_SERTX_DATA_LENGTH               32
+#define DMI_SERTX_DATA                      (0xffffffff << DMI_SERTX_DATA_OFFSET)
+#define DMI_SERRX                           0x36
+#define DMI_SERRX_DATA_OFFSET               0
+#define DMI_SERRX_DATA_LENGTH               32
+#define DMI_SERRX_DATA                      (0xffffffff << DMI_SERRX_DATA_OFFSET)
+#define DMI_SBCS                            0x38
+/*
+* When a 1 is written here, triggers a read at the address in {\tt
+* sbaddress} using the access size set by \Fsbaccess.
+ */
+#define DMI_SBCS_SBSINGLEREAD_OFFSET        20
+#define DMI_SBCS_SBSINGLEREAD_LENGTH        1
+#define DMI_SBCS_SBSINGLEREAD               (0x1 << DMI_SBCS_SBSINGLEREAD_OFFSET)
+/*
+* Select the access size to use for system bus accesses triggered by
+* writes to the {\tt sbaddress} registers or \Rsbdatazero.
+*
+* 0: 8-bit
+*
+* 1: 16-bit
+*
+* 2: 32-bit
+*
+* 3: 64-bit
+*
+* 4: 128-bit
+*
+* If an unsupported system bus access size is written here,
+* the DM may not perform the access, or may perform the access
+* with any access size.
+ */
+#define DMI_SBCS_SBACCESS_OFFSET            17
+#define DMI_SBCS_SBACCESS_LENGTH            3
+#define DMI_SBCS_SBACCESS                   (0x7 << DMI_SBCS_SBACCESS_OFFSET)
+/*
+* When 1, the internal address value (used by the system bus master)
+* is incremented by the access size (in bytes) selected in \Fsbaccess
+* after every system bus access.
+ */
+#define DMI_SBCS_SBAUTOINCREMENT_OFFSET     16
+#define DMI_SBCS_SBAUTOINCREMENT_LENGTH     1
+#define DMI_SBCS_SBAUTOINCREMENT            (0x1 << DMI_SBCS_SBAUTOINCREMENT_OFFSET)
+/*
+* When 1, every read from \Rsbdatazero automatically triggers a system
+* bus read at the new address.
+ */
+#define DMI_SBCS_SBAUTOREAD_OFFSET          15
+#define DMI_SBCS_SBAUTOREAD_LENGTH          1
+#define DMI_SBCS_SBAUTOREAD                 (0x1 << DMI_SBCS_SBAUTOREAD_OFFSET)
+/*
+* When the debug module's system bus
+* master causes a bus error, this field gets set. The bits in this
+* field remain set until they are cleared by writing 1 to them.
+* While this field is non-zero, no more system bus accesses can be
+* initiated by the debug module.
+*
+* 0: There was no bus error.
+*
+* 1: There was a timeout.
+*
+* 2: A bad address was accessed.
+*
+* 3: There was some other error (eg. alignment).
+*
+* 4: The system bus master was busy when a one of the
+* {\tt sbaddress} or {\tt sbdata} registers was written,
+* or the {\tt sbdata} register was read when it had
+* stale data.
+ */
+#define DMI_SBCS_SBERROR_OFFSET             12
+#define DMI_SBCS_SBERROR_LENGTH             3
+#define DMI_SBCS_SBERROR                    (0x7 << DMI_SBCS_SBERROR_OFFSET)
+/*
+* Width of system bus addresses in bits. (0 indicates there is no bus
+* access support.)
+ */
+#define DMI_SBCS_SBASIZE_OFFSET             5
+#define DMI_SBCS_SBASIZE_LENGTH             7
+#define DMI_SBCS_SBASIZE                    (0x7f << DMI_SBCS_SBASIZE_OFFSET)
+/*
+* 1 when 128-bit system bus accesses are supported.
+ */
+#define DMI_SBCS_SBACCESS128_OFFSET         4
+#define DMI_SBCS_SBACCESS128_LENGTH         1
+#define DMI_SBCS_SBACCESS128                (0x1 << DMI_SBCS_SBACCESS128_OFFSET)
+/*
+* 1 when 64-bit system bus accesses are supported.
+ */
+#define DMI_SBCS_SBACCESS64_OFFSET          3
+#define DMI_SBCS_SBACCESS64_LENGTH          1
+#define DMI_SBCS_SBACCESS64                 (0x1 << DMI_SBCS_SBACCESS64_OFFSET)
+/*
+* 1 when 32-bit system bus accesses are supported.
+ */
+#define DMI_SBCS_SBACCESS32_OFFSET          2
+#define DMI_SBCS_SBACCESS32_LENGTH          1
+#define DMI_SBCS_SBACCESS32                 (0x1 << DMI_SBCS_SBACCESS32_OFFSET)
+/*
+* 1 when 16-bit system bus accesses are supported.
+ */
+#define DMI_SBCS_SBACCESS16_OFFSET          1
+#define DMI_SBCS_SBACCESS16_LENGTH          1
+#define DMI_SBCS_SBACCESS16                 (0x1 << DMI_SBCS_SBACCESS16_OFFSET)
+/*
+* 1 when 8-bit system bus accesses are supported.
+ */
+#define DMI_SBCS_SBACCESS8_OFFSET           0
+#define DMI_SBCS_SBACCESS8_LENGTH           1
+#define DMI_SBCS_SBACCESS8                  (0x1 << DMI_SBCS_SBACCESS8_OFFSET)
+#define DMI_SBADDRESS0                      0x39
+/*
+* Accesses bits 31:0 of the internal address.
+ */
+#define DMI_SBADDRESS0_ADDRESS_OFFSET       0
+#define DMI_SBADDRESS0_ADDRESS_LENGTH       32
+#define DMI_SBADDRESS0_ADDRESS              (0xffffffff << DMI_SBADDRESS0_ADDRESS_OFFSET)
+#define DMI_SBADDRESS1                      0x3a
+/*
+* Accesses bits 63:32 of the internal address (if the system address
+* bus is that wide).
+ */
+#define DMI_SBADDRESS1_ADDRESS_OFFSET       0
+#define DMI_SBADDRESS1_ADDRESS_LENGTH       32
+#define DMI_SBADDRESS1_ADDRESS              (0xffffffff << DMI_SBADDRESS1_ADDRESS_OFFSET)
+#define DMI_SBADDRESS2                      0x3b
+/*
+* Accesses bits 95:64 of the internal address (if the system address
+* bus is that wide).
+ */
+#define DMI_SBADDRESS2_ADDRESS_OFFSET       0
+#define DMI_SBADDRESS2_ADDRESS_LENGTH       32
+#define DMI_SBADDRESS2_ADDRESS              (0xffffffff << DMI_SBADDRESS2_ADDRESS_OFFSET)
+#define DMI_SBDATA0                         0x3c
+/*
+* Accesses bits 31:0 of the internal data.
+ */
+#define DMI_SBDATA0_DATA_OFFSET             0
+#define DMI_SBDATA0_DATA_LENGTH             32
+#define DMI_SBDATA0_DATA                    (0xffffffff << DMI_SBDATA0_DATA_OFFSET)
+#define DMI_SBDATA1                         0x3d
+/*
+* Accesses bits 63:32 of the internal data (if the system bus is
+* that wide).
+ */
+#define DMI_SBDATA1_DATA_OFFSET             0
+#define DMI_SBDATA1_DATA_LENGTH             32
+#define DMI_SBDATA1_DATA                    (0xffffffff << DMI_SBDATA1_DATA_OFFSET)
+#define DMI_SBDATA2                         0x3e
+/*
+* Accesses bits 95:64 of the internal data (if the system bus is
+* that wide).
+ */
+#define DMI_SBDATA2_DATA_OFFSET             0
+#define DMI_SBDATA2_DATA_LENGTH             32
+#define DMI_SBDATA2_DATA                    (0xffffffff << DMI_SBDATA2_DATA_OFFSET)
+#define DMI_SBDATA3                         0x3f
+/*
+* Accesses bits 127:96 of the internal data (if the system bus is
+* that wide).
+ */
+#define DMI_SBDATA3_DATA_OFFSET             0
+#define DMI_SBDATA3_DATA_LENGTH             32
+#define DMI_SBDATA3_DATA                    (0xffffffff << DMI_SBDATA3_DATA_OFFSET)
+#define TRACE                               0x728
+/*
+* 1 if the trace buffer has wrapped since the last time \Fdiscard was
+* written. 0 otherwise.
+ */
+#define TRACE_WRAPPED_OFFSET                24
+#define TRACE_WRAPPED_LENGTH                1
+#define TRACE_WRAPPED                       (0x1 << TRACE_WRAPPED_OFFSET)
+/*
+* Emit Timestamp trace sequences.
+ */
+#define TRACE_EMITTIMESTAMP_OFFSET          23
+#define TRACE_EMITTIMESTAMP_LENGTH          1
+#define TRACE_EMITTIMESTAMP                 (0x1 << TRACE_EMITTIMESTAMP_OFFSET)
+/*
+* Emit Store Data trace sequences.
+ */
+#define TRACE_EMITSTOREDATA_OFFSET          22
+#define TRACE_EMITSTOREDATA_LENGTH          1
+#define TRACE_EMITSTOREDATA                 (0x1 << TRACE_EMITSTOREDATA_OFFSET)
+/*
+* Emit Load Data trace sequences.
+ */
+#define TRACE_EMITLOADDATA_OFFSET           21
+#define TRACE_EMITLOADDATA_LENGTH           1
+#define TRACE_EMITLOADDATA                  (0x1 << TRACE_EMITLOADDATA_OFFSET)
+/*
+* Emit Store Address trace sequences.
+ */
+#define TRACE_EMITSTOREADDR_OFFSET          20
+#define TRACE_EMITSTOREADDR_LENGTH          1
+#define TRACE_EMITSTOREADDR                 (0x1 << TRACE_EMITSTOREADDR_OFFSET)
+/*
+* Emit Load Address trace sequences.
+ */
+#define TRACE_EMITLOADADDR_OFFSET           19
+#define TRACE_EMITLOADADDR_LENGTH           1
+#define TRACE_EMITLOADADDR                  (0x1 << TRACE_EMITLOADADDR_OFFSET)
+/*
+* Emit Privilege Level trace sequences.
+ */
+#define TRACE_EMITPRIV_OFFSET               18
+#define TRACE_EMITPRIV_LENGTH               1
+#define TRACE_EMITPRIV                      (0x1 << TRACE_EMITPRIV_OFFSET)
+/*
+* Emit Branch Taken and Branch Not Taken trace sequences.
+ */
+#define TRACE_EMITBRANCH_OFFSET             17
+#define TRACE_EMITBRANCH_LENGTH             1
+#define TRACE_EMITBRANCH                    (0x1 << TRACE_EMITBRANCH_OFFSET)
+/*
+* Emit PC trace sequences.
+ */
+#define TRACE_EMITPC_OFFSET                 16
+#define TRACE_EMITPC_LENGTH                 1
+#define TRACE_EMITPC                        (0x1 << TRACE_EMITPC_OFFSET)
+/*
+* Determine what happens when the trace buffer is full.  0 means wrap
+* and overwrite. 1 means turn off trace until \Fdiscard is written as 1.
+* 2 means cause a trace full exception. 3 is reserved for future use.
+ */
+#define TRACE_FULLACTION_OFFSET             8
+#define TRACE_FULLACTION_LENGTH             2
+#define TRACE_FULLACTION                    (0x3 << TRACE_FULLACTION_OFFSET)
+/*
+* 0: Trace to a dedicated on-core RAM (which is not further defined in
+* this spec).
+*
+* 1: Trace to RAM on the system bus.
+*
+* 2: Send trace data to a dedicated off-chip interface (which is not
+* defined in this spec). This does not affect execution speed.
+*
+* 3: Reserved for future use.
+*
+* Options 0 and 1 slow down execution (eg. because of system bus
+* contention).
+ */
+#define TRACE_DESTINATION_OFFSET            4
+#define TRACE_DESTINATION_LENGTH            2
+#define TRACE_DESTINATION                   (0x3 << TRACE_DESTINATION_OFFSET)
+/*
+* When 1, the trace logic may stall processor execution to ensure it
+* can emit all the trace sequences required. When 0 individual trace
+* sequences may be dropped.
+ */
+#define TRACE_STALL_OFFSET                  2
+#define TRACE_STALL_LENGTH                  1
+#define TRACE_STALL                         (0x1 << TRACE_STALL_OFFSET)
+/*
+* Writing 1 to this bit tells the trace logic that any trace
+* collected is no longer required. When tracing to RAM, it resets the
+* trace write pointer to the start of the memory, as well as
+* \Fwrapped.
+ */
+#define TRACE_DISCARD_OFFSET                1
+#define TRACE_DISCARD_LENGTH                1
+#define TRACE_DISCARD                       (0x1 << TRACE_DISCARD_OFFSET)
+#define TRACE_SUPPORTED_OFFSET              0
+#define TRACE_SUPPORTED_LENGTH              1
+#define TRACE_SUPPORTED                     (0x1 << TRACE_SUPPORTED_OFFSET)
+#define TBUFSTART                           0x729
+#define TBUFEND                             0x72a
+#define TBUFWRITE                           0x72b
+#define SHORTNAME                           0x123
+/*
+* Description of what this field is used for.
+ */
+#define SHORTNAME_FIELD_OFFSET              0
+#define SHORTNAME_FIELD_LENGTH              8
+#define SHORTNAME_FIELD                     (0xff << SHORTNAME_FIELD_OFFSET)
+#define AC_ACCESS_REGISTER                  None
+/*
+* This is 0 to indicate Access Register Command.
+ */
+#define AC_ACCESS_REGISTER_CMDTYPE_OFFSET   24
+#define AC_ACCESS_REGISTER_CMDTYPE_LENGTH   8
+#define AC_ACCESS_REGISTER_CMDTYPE          (0xff << AC_ACCESS_REGISTER_CMDTYPE_OFFSET)
+/*
+* 2: Access the lowest 32 bits of the register.
+*
+* 3: Access the lowest 64 bits of the register.
+*
+* 4: Access the lowest 128 bits of the register.
+*
+* If \Fsize specifies a size larger than the register's actual size,
+* then the access must fail. If a register is accessible, then reads of \Fsize
+* less than or equal to the register's actual size must be supported.
+ */
+#define AC_ACCESS_REGISTER_SIZE_OFFSET      20
+#define AC_ACCESS_REGISTER_SIZE_LENGTH      3
+#define AC_ACCESS_REGISTER_SIZE             (0x7 << AC_ACCESS_REGISTER_SIZE_OFFSET)
+/*
+* When 1, execute the program in the Program Buffer exactly once
+* after performing the transfer, if any.
+ */
+#define AC_ACCESS_REGISTER_POSTEXEC_OFFSET  18
+#define AC_ACCESS_REGISTER_POSTEXEC_LENGTH  1
+#define AC_ACCESS_REGISTER_POSTEXEC         (0x1 << AC_ACCESS_REGISTER_POSTEXEC_OFFSET)
+/*
+* 0: Don't do the operation specified by \Fwrite.
+*
+* 1: Do the operation specified by \Fwrite.
+ */
+#define AC_ACCESS_REGISTER_TRANSFER_OFFSET  17
+#define AC_ACCESS_REGISTER_TRANSFER_LENGTH  1
+#define AC_ACCESS_REGISTER_TRANSFER         (0x1 << AC_ACCESS_REGISTER_TRANSFER_OFFSET)
+/*
+* When \Ftransfer is set:
+* 0: Copy data from the specified register into {\tt arg0} portion
+* of {\tt data}.
+*
+* 1: Copy data from {\tt arg0} portion of {\tt data} into the
+* specified register.
+ */
+#define AC_ACCESS_REGISTER_WRITE_OFFSET     16
+#define AC_ACCESS_REGISTER_WRITE_LENGTH     1
+#define AC_ACCESS_REGISTER_WRITE            (0x1 << AC_ACCESS_REGISTER_WRITE_OFFSET)
+/*
+* Number of the register to access, as described in Table~\ref{tab:regno}.
+ */
+#define AC_ACCESS_REGISTER_REGNO_OFFSET     0
+#define AC_ACCESS_REGISTER_REGNO_LENGTH     16
+#define AC_ACCESS_REGISTER_REGNO            (0xffff << AC_ACCESS_REGISTER_REGNO_OFFSET)
+#define AC_QUICK_ACCESS                     None
+/*
+* This is 1 to indicate Quick Access command.
+ */
+#define AC_QUICK_ACCESS_CMDTYPE_OFFSET      24
+#define AC_QUICK_ACCESS_CMDTYPE_LENGTH      8
+#define AC_QUICK_ACCESS_CMDTYPE             (0xff << AC_QUICK_ACCESS_CMDTYPE_OFFSET)
index 8bcc60eada8d9eb5fbbdd8833e2463a16ae72c09..db035e3313d42d2cf0d4b1386c44cc815fa1911f 100644 (file)
 #include <cassert>
 
 #include "debug_module.h"
+#include "debug_defines.h"
+#include "opcodes.h"
 #include "mmu.h"
 
 #include "debug_rom/debug_rom.h"
+#include "debug_rom/debug_rom_defines.h"
+
+#if 1
+#  define D(x) x
+#else
+#  define D(x)
+#endif
+
+///////////////////////// debug_module_t
+
+debug_module_t::debug_module_t(sim_t *sim) : sim(sim)
+{
+  dmcontrol = {0};
+
+  dmstatus = {0};
+  dmstatus.authenticated = 1;
+  dmstatus.versionlo = 2;
+
+  abstractcs = {0};
+  abstractcs.progsize = progsize;
+
+  abstractauto = {0};
+
+  memset(halted, 0, sizeof(halted));
+  memset(debug_rom_flags, 0, sizeof(debug_rom_flags));
+  memset(resumeack, 0, sizeof(resumeack));
+  memset(program_buffer, 0, sizeof(program_buffer));
+  memset(dmdata, 0, sizeof(dmdata));
+
+  write32(debug_rom_whereto, 0,
+          jal(ZERO, debug_abstract_start - DEBUG_ROM_WHERETO));
+
+  memset(debug_abstract, 0, sizeof(debug_abstract));
+}
+
+void debug_module_t::reset()
+{
+  for (unsigned i = 0; i < sim->nprocs(); i++) {
+    processor_t *proc = sim->get_core(i);
+    if (proc)
+      proc->halt_request = false;
+  }
+
+  dmcontrol = {0};
+
+  dmstatus = {0};
+  dmstatus.authenticated = 1;
+  dmstatus.versionlo = 2;
+
+  abstractcs = {0};
+  abstractcs.datacount = sizeof(dmdata) / 4;
+  abstractcs.progsize = progsize;
+
+  abstractauto = {0};
+}
+
+void debug_module_t::add_device(bus_t *bus) {
+  bus->add_device(DEBUG_START, this);
+}
 
 bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes)
 {
   addr = DEBUG_START + addr;
 
-  if (addr >= DEBUG_RAM_START && addr + len <= DEBUG_RAM_END) {
-    memcpy(bytes, debug_ram + addr - DEBUG_RAM_START, len);
+  if (addr >= DEBUG_ROM_ENTRY &&
+      (addr + len) <= (DEBUG_ROM_ENTRY + debug_rom_raw_len)) {
+    memcpy(bytes, debug_rom_raw + addr - DEBUG_ROM_ENTRY, len);
     return true;
   }
 
-  if (addr >= DEBUG_ROM_START && addr + len <= DEBUG_ROM_END) {
-    memcpy(bytes, debug_rom_raw + addr - DEBUG_ROM_START, len);
+  if (addr >= DEBUG_ROM_WHERETO && (addr + len) <= (DEBUG_ROM_WHERETO + 4)) {
+    memcpy(bytes, debug_rom_whereto + addr - DEBUG_ROM_WHERETO, len);
+    return true;
+  }
+
+  if (addr >= DEBUG_ROM_FLAGS && ((addr + len) <= DEBUG_ROM_FLAGS + 1024)) {
+    memcpy(bytes, debug_rom_flags + addr - DEBUG_ROM_FLAGS, len);
+    return true;
+  }
+
+  if (addr >= debug_abstract_start && ((addr + len) <= (debug_abstract_start + sizeof(debug_abstract)))) {
+    memcpy(bytes, debug_abstract + addr - debug_abstract_start, len);
+    return true;
+  }
+
+  if (addr >= debug_data_start && (addr + len) <= (debug_data_start + sizeof(dmdata))) {
+    memcpy(bytes, dmdata + addr - debug_data_start, len);
+    return true;
+  }
+  
+  if (addr >= debug_progbuf_start && ((addr + len) <= (debug_progbuf_start + sizeof(program_buffer)))) {
+    memcpy(bytes, program_buffer + addr - debug_progbuf_start, len);
     return true;
   }
 
   fprintf(stderr, "ERROR: invalid load from debug module: %zd bytes at 0x%016"
           PRIx64 "\n", len, addr);
+
   return false;
 }
 
 bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
 {
+
+  uint8_t id_bytes[4];
+  uint32_t id = 0;
+  if (len == 4) {
+    memcpy(id_bytes, bytes, 4);
+    id = read32(id_bytes, 0);
+  }
+
   addr = DEBUG_START + addr;
+  
+  if (addr >= debug_data_start && (addr + len) <= (debug_data_start + sizeof(dmdata))) {
+    memcpy(dmdata + addr - debug_data_start, bytes, len);
+    return true;
+  }
+  
+  if (addr >= debug_progbuf_start && ((addr + len) <= (debug_progbuf_start + sizeof(program_buffer)))) {
+    fprintf(stderr, "Successful write to program buffer %d bytes at %x\n", (int) len, (int) addr);
+    memcpy(program_buffer + addr - debug_progbuf_start, bytes, len);
+    
+    return true;
+  }
 
-  if (addr & (len-1)) {
-    fprintf(stderr, "ERROR: unaligned store to debug module: %zd bytes at 0x%016"
-            PRIx64 "\n", len, addr);
-    return false;
+  if (addr == DEBUG_ROM_HALTED) {
+    assert (len == 4);
+    halted[id] = true;
+    if (dmcontrol.hartsel == id) {
+        if (0 == (debug_rom_flags[id] & (1 << DEBUG_ROM_FLAG_GO))){
+          if (dmcontrol.hartsel == id) {
+              abstractcs.busy = false;
+          }
+        }
+    }
+    return true;
   }
 
-  if (addr >= DEBUG_RAM_START && addr + len <= DEBUG_RAM_END) {
-    memcpy(debug_ram + addr - DEBUG_RAM_START, bytes, len);
+  if (addr == DEBUG_ROM_GOING) {
+    debug_rom_flags[dmcontrol.hartsel] &= ~(1 << DEBUG_ROM_FLAG_GO);
     return true;
-  } else if (len == 4 && addr == DEBUG_CLEARDEBINT) {
-    clear_interrupt(bytes[0] | (bytes[1] << 8) |
-        (bytes[2] << 16) | (bytes[3] << 24));
+  }
+
+  if (addr == DEBUG_ROM_RESUMING) {
+    assert (len == 4);
+    halted[id] = false;
+    resumeack[id] = true;
+    debug_rom_flags[id] &= ~(1 << DEBUG_ROM_FLAG_RESUME);
     return true;
-  } else if (len == 4 && addr == DEBUG_SETHALTNOT) {
-    set_halt_notification(bytes[0] | (bytes[1] << 8) |
-        (bytes[2] << 16) | (bytes[3] << 24));
+  }
+
+  if (addr == DEBUG_ROM_EXCEPTION) {
+    if (abstractcs.cmderr == CMDERR_NONE) {
+      abstractcs.cmderr = CMDERR_EXCEPTION;
+    }
     return true;
   }
 
@@ -52,23 +170,303 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
   return false;
 }
 
-void debug_module_t::ram_write32(unsigned int index, uint32_t value)
+void debug_module_t::write32(uint8_t *memory, unsigned int index, uint32_t value)
 {
-  char* base = debug_ram + index * 4;
+  uint8_t* base = memory + index * 4;
   base[0] = value & 0xff;
   base[1] = (value >> 8) & 0xff;
   base[2] = (value >> 16) & 0xff;
   base[3] = (value >> 24) & 0xff;
 }
 
-uint32_t debug_module_t::ram_read32(unsigned int index)
+uint32_t debug_module_t::read32(uint8_t *memory, unsigned int index)
 {
-  // It'd be better for raw_page (and all memory) to be unsigned chars, but mem
-  // in sim_t is just chars, so I'm following that convention.
-  unsigned char* base = (unsigned char*) (debug_ram + index * 4);
+  uint8_t* base = memory + index * 4;
   uint32_t value = ((uint32_t) base[0]) |
     (((uint32_t) base[1]) << 8) |
     (((uint32_t) base[2]) << 16) |
     (((uint32_t) base[3]) << 24);
   return value;
 }
+
+processor_t *debug_module_t::current_proc() const
+{
+  processor_t *proc = NULL;
+  try {
+    proc = sim->get_core(dmcontrol.hartsel);
+  } catch (const std::out_of_range&) {
+  }
+  return proc;
+}
+
+bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
+{
+  uint32_t result = 0;
+  D(fprintf(stderr, "dmi_read(0x%x) -> ", address));
+  if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) {
+    unsigned i = address - DMI_DATA0;
+    result = read32(dmdata, i);
+    if (abstractcs.busy) {
+      result = -1;
+      fprintf(stderr, "\ndmi_read(0x%02x (data[%d]) -> -1 because abstractcs.busy==true\n", address, i);
+    }
+
+    if (abstractcs.busy && abstractcs.cmderr == CMDERR_NONE) {
+      abstractcs.cmderr = CMDERR_BUSY;
+    }
+
+    if (!abstractcs.busy && ((abstractauto.autoexecdata >> i) & 1)) {
+      perform_abstract_command();
+    }
+  } else if (address >= DMI_PROGBUF0 && address < DMI_PROGBUF0 + progsize) {
+    unsigned i = address - DMI_PROGBUF0;
+    result = read32(program_buffer, i);
+    if (abstractcs.busy) {
+      result = -1;
+      fprintf(stderr, "\ndmi_read(0x%02x (progbuf[%d]) -> -1 because abstractcs.busy==true\n", address, i);
+    }
+    if (!abstractcs.busy && ((abstractauto.autoexecprogbuf >> i) & 1)) {
+      perform_abstract_command();
+    }
+
+  } else {
+    switch (address) {
+      case DMI_DMCONTROL:
+        {
+          processor_t *proc = current_proc();
+          if (proc)
+            dmcontrol.haltreq = proc->halt_request;
+
+          result = set_field(result, DMI_DMCONTROL_HALTREQ, dmcontrol.haltreq);
+          result = set_field(result, DMI_DMCONTROL_RESUMEREQ, dmcontrol.resumereq);
+          result = set_field(result, DMI_DMCONTROL_HARTSEL, dmcontrol.hartsel);
+          result = set_field(result, DMI_DMCONTROL_HARTRESET, dmcontrol.hartreset);
+         result = set_field(result, DMI_DMCONTROL_NDMRESET, dmcontrol.ndmreset);
+          result = set_field(result, DMI_DMCONTROL_DMACTIVE, dmcontrol.dmactive);
+        }
+        break;
+      case DMI_DMSTATUS:
+        {
+          processor_t *proc = current_proc();
+
+         dmstatus.allnonexistant = false;
+         dmstatus.allunavail = false;
+         dmstatus.allrunning = false;
+         dmstatus.allhalted = false;
+          dmstatus.allresumeack = false;
+          if (proc) {
+            if (halted[dmcontrol.hartsel]) {
+              dmstatus.allhalted = true;
+            } else {
+              dmstatus.allrunning = true;
+            }
+          } else {
+           dmstatus.allnonexistant = true;
+          }
+         dmstatus.anynonexistant = dmstatus.allnonexistant;
+         dmstatus.anyunavail = dmstatus.allunavail;
+         dmstatus.anyrunning = dmstatus.allrunning;
+         dmstatus.anyhalted = dmstatus.allhalted;
+          if (proc) {
+            if (resumeack[dmcontrol.hartsel]) {
+              dmstatus.allresumeack = true;
+            } else {
+              dmstatus.allresumeack = false;
+            }
+          } else {
+            dmstatus.allresumeack = false;
+          }
+          
+         result = set_field(result, DMI_DMSTATUS_ALLNONEXISTENT, dmstatus.allnonexistant);
+         result = set_field(result, DMI_DMSTATUS_ALLUNAVAIL, dmstatus.allunavail);
+         result = set_field(result, DMI_DMSTATUS_ALLRUNNING, dmstatus.allrunning);
+         result = set_field(result, DMI_DMSTATUS_ALLHALTED, dmstatus.allhalted);
+          result = set_field(result, DMI_DMSTATUS_ALLRESUMEACK, dmstatus.allresumeack);
+         result = set_field(result, DMI_DMSTATUS_ANYNONEXISTENT, dmstatus.anynonexistant);
+         result = set_field(result, DMI_DMSTATUS_ANYUNAVAIL, dmstatus.anyunavail);
+         result = set_field(result, DMI_DMSTATUS_ANYRUNNING, dmstatus.anyrunning);
+         result = set_field(result, DMI_DMSTATUS_ANYHALTED, dmstatus.anyhalted);
+          result = set_field(result, DMI_DMSTATUS_ANYRESUMEACK, dmstatus.anyresumeack);
+          result = set_field(result, DMI_DMSTATUS_AUTHENTICATED, dmstatus.authenticated);
+          result = set_field(result, DMI_DMSTATUS_AUTHBUSY, dmstatus.authbusy);
+          result = set_field(result, DMI_DMSTATUS_VERSIONHI, dmstatus.versionhi);
+          result = set_field(result, DMI_DMSTATUS_VERSIONLO, dmstatus.versionlo);
+        }
+       break;
+      case DMI_ABSTRACTCS:
+        result = set_field(result, DMI_ABSTRACTCS_CMDERR, abstractcs.cmderr);
+        result = set_field(result, DMI_ABSTRACTCS_BUSY, abstractcs.busy);
+        result = set_field(result, DMI_ABSTRACTCS_DATACOUNT, abstractcs.datacount);
+        result = set_field(result, DMI_ABSTRACTCS_PROGSIZE, abstractcs.progsize);
+        break;
+      case DMI_ABSTRACTAUTO:
+        result = set_field(result, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF, abstractauto.autoexecprogbuf);
+        result = set_field(result, DMI_ABSTRACTAUTO_AUTOEXECDATA, abstractauto.autoexecdata);
+        break;
+      case DMI_COMMAND:
+        result = 0;
+        break;
+      case DMI_HARTINFO:
+        result = set_field(result, DMI_HARTINFO_NSCRATCH, 1);
+        result = set_field(result, DMI_HARTINFO_DATAACCESS, 1);
+        result = set_field(result, DMI_HARTINFO_DATASIZE, abstractcs.datacount);
+        result = set_field(result, DMI_HARTINFO_DATAADDR, debug_data_start);
+        break;
+      default:
+        result = 0;
+        D(fprintf(stderr, "Unexpected. Returning Error."));
+        return false;
+    }
+  }
+  D(fprintf(stderr, "0x%x\n", result));
+  *value = result;
+  return true;
+}
+
+bool debug_module_t::perform_abstract_command()
+{
+  if (abstractcs.cmderr != CMDERR_NONE)
+    return true;
+  if (abstractcs.busy) {
+    abstractcs.cmderr = CMDERR_BUSY;
+    return true;
+  }
+
+  if ((command >> 24) == 0) {
+    // register access
+    unsigned size = get_field(command, AC_ACCESS_REGISTER_SIZE);
+    bool write = get_field(command, AC_ACCESS_REGISTER_WRITE);
+    unsigned regno = get_field(command, AC_ACCESS_REGISTER_REGNO);
+
+    if (!halted[dmcontrol.hartsel]) {
+      abstractcs.cmderr = CMDERR_HALTRESUME;
+      return true;
+    }
+
+    if (get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
+
+      if (regno < 0x1000 || regno >= 0x1020) {
+        abstractcs.cmderr = CMDERR_NOTSUP;
+        return true;
+      }
+
+      unsigned regnum = regno - 0x1000;
+
+      switch (size) {
+      case 2:
+        if (write)
+          write32(debug_abstract, 0, lw(regnum, ZERO, debug_data_start));
+        else
+          write32(debug_abstract, 0, sw(regnum, ZERO, debug_data_start));
+        break;
+      case 3:
+        if (write)
+          write32(debug_abstract, 0, ld(regnum, ZERO, debug_data_start));
+        else
+          write32(debug_abstract, 0, sd(regnum, ZERO, debug_data_start));
+        break;
+        /*
+          case 4:
+          if (write)
+          write32(debug_rom_code, 0, lq(regnum, ZERO, debug_data_start));
+          else
+          write32(debug_rom_code, 0, sq(regnum, ZERO, debug_data_start));
+          break;
+        */
+      default:
+        abstractcs.cmderr = CMDERR_NOTSUP;
+        return true;
+      }
+    } else {
+      //NOP
+      write32(debug_abstract, 0, addi(ZERO, ZERO, 0));
+    }
+    
+    if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) {
+      // Since the next instruction is what we will use, just use nother NOP
+      // to get there.
+      write32(debug_abstract, 1, addi(ZERO, ZERO, 0));
+    } else {
+      write32(debug_abstract, 1, ebreak());
+    }
+
+    debug_rom_flags[dmcontrol.hartsel] |= 1 << DEBUG_ROM_FLAG_GO;
+    
+    abstractcs.busy = true;
+  } else {
+    abstractcs.cmderr = CMDERR_NOTSUP;
+  }
+  return true;
+}
+
+bool debug_module_t::dmi_write(unsigned address, uint32_t value)
+{
+  D(fprintf(stderr, "dmi_write(0x%x, 0x%x)\n", address, value));
+  if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) {
+    unsigned i = address - DMI_DATA0;
+    if (!abstractcs.busy)
+      write32(dmdata, address - DMI_DATA0, value);
+
+    if (abstractcs.busy && abstractcs.cmderr == CMDERR_NONE) {
+      abstractcs.cmderr = CMDERR_BUSY;
+    }
+
+    if (!abstractcs.busy && ((abstractauto.autoexecdata >> i) & 1)) {
+      perform_abstract_command();
+    }
+    return true;
+
+  } else if (address >= DMI_PROGBUF0 && address < DMI_PROGBUF0 + progsize) {
+    unsigned i = address - DMI_PROGBUF0;
+    
+    if (!abstractcs.busy)
+      write32(program_buffer, i, value);
+
+    if (!abstractcs.busy && ((abstractauto.autoexecprogbuf >> i) & 1)) {
+      perform_abstract_command();
+    }
+    return true;
+    
+  } else {
+    switch (address) {
+      case DMI_DMCONTROL:
+        {
+          dmcontrol.dmactive = get_field(value, DMI_DMCONTROL_DMACTIVE);
+          if (dmcontrol.dmactive) {
+            dmcontrol.haltreq = get_field(value, DMI_DMCONTROL_HALTREQ);
+            dmcontrol.resumereq = get_field(value, DMI_DMCONTROL_RESUMEREQ);
+            dmcontrol.ndmreset = get_field(value, DMI_DMCONTROL_NDMRESET);
+            dmcontrol.hartsel = get_field(value, DMI_DMCONTROL_HARTSEL);
+          } else {
+            reset();
+          }
+          processor_t *proc = current_proc();
+          if (proc) {
+            proc->halt_request = dmcontrol.haltreq;
+            if (dmcontrol.resumereq) {
+              debug_rom_flags[dmcontrol.hartsel] |= (1 << DEBUG_ROM_FLAG_RESUME);
+              resumeack[dmcontrol.hartsel] = false;
+            }
+           if (dmcontrol.ndmreset) {
+             proc->reset();
+           }
+          }
+        }
+        return true;
+
+      case DMI_COMMAND:
+        command = value;
+        return perform_abstract_command();
+
+      case DMI_ABSTRACTCS:
+        abstractcs.cmderr = (cmderr_t) (((uint32_t) (abstractcs.cmderr)) & (~(uint32_t)(get_field(value, DMI_ABSTRACTCS_CMDERR))));
+        return true;
+
+      case DMI_ABSTRACTAUTO:
+        abstractauto.autoexecprogbuf = get_field(value, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF);
+        abstractauto.autoexecdata = get_field(value, DMI_ABSTRACTAUTO_AUTOEXECDATA);
+        break;
+    }
+  }
+  return false;
+}
index 53b32db9a8e6eebadaa88f3c1d2e7ead2c6b0949..f0d2a475ad976afea9e321cfdb8978a90b2d429c 100644 (file)
 
 #include "devices.h"
 
+class sim_t;
+
+typedef struct {
+  bool haltreq;
+  bool resumereq;
+  unsigned hartsel;
+  bool hartreset;
+  bool dmactive;
+  bool ndmreset;
+} dmcontrol_t;
+
+typedef struct {
+  bool allnonexistant;
+  bool anynonexistant;
+  bool allunavail;
+  bool anyunavail;
+  bool allrunning;
+  bool anyrunning;
+  bool allhalted;
+  bool anyhalted;
+  bool allresumeack;
+  bool anyresumeack;
+  bool authenticated;
+  bool authbusy;
+  bool cfgstrvalid;
+  unsigned versionhi;
+  unsigned versionlo;
+} dmstatus_t;
+
+typedef enum cmderr {
+    CMDERR_NONE = 0,
+    CMDERR_BUSY = 1,
+    CMDERR_NOTSUP = 2,
+    CMDERR_EXCEPTION = 3,
+    CMDERR_HALTRESUME = 4,
+    CMDERR_OTHER = 7  
+} cmderr_t;
+
+typedef struct {
+  bool busy;
+  unsigned datacount;
+  unsigned progsize;
+  cmderr_t cmderr;
+} abstractcs_t;
+
+typedef struct {
+  unsigned autoexecprogbuf;
+  unsigned autoexecdata;
+} abstractauto_t;
+
 class debug_module_t : public abstract_device_t
 {
   public:
+    debug_module_t(sim_t *sim);
+
+    void add_device(bus_t *bus);
+
     bool load(reg_t addr, size_t len, uint8_t* bytes);
     bool store(reg_t addr, size_t len, const uint8_t* bytes);
 
-    void ram_write32(unsigned int index, uint32_t value);
-    uint32_t ram_read32(unsigned int index);
-
-    void set_interrupt(uint32_t hartid) {
-      interrupt.insert(hartid);
-    }
-    void clear_interrupt(uint32_t hartid) {
-      interrupt.erase(hartid);
-    }
-    bool get_interrupt(uint32_t hartid) const {
-      return interrupt.find(hartid) != interrupt.end();
-    }
-
-    void set_halt_notification(uint32_t hartid) {
-      halt_notification.insert(hartid);
-    }
-    void clear_halt_notification(uint32_t hartid) {
-      halt_notification.erase(hartid);
-    }
-    bool get_halt_notification(uint32_t hartid) const {
-      return halt_notification.find(hartid) != halt_notification.end();
-    }
+    // Debug Module Interface that the debugger (in our case through JTAG DTM)
+    // uses to access the DM.
+    // Return true for success, false for failure.
+    bool dmi_read(unsigned address, uint32_t *value);
+    bool dmi_write(unsigned address, uint32_t value);
 
   private:
-    // Track which interrupts from module to debugger are set.
-    std::set<uint32_t> interrupt;
-    // Track which halt notifications from debugger to module are set.
-    std::set<uint32_t> halt_notification;
-    char debug_ram[DEBUG_RAM_SIZE];
+    static const unsigned datasize = 2;
+    static const unsigned progsize = 16;
+    static const unsigned debug_data_start = 0x380;
+    static const unsigned debug_progbuf_start = debug_data_start - progsize*4;
+
+    static const unsigned debug_abstract_size = 2;
+    static const unsigned debug_abstract_start = debug_progbuf_start - debug_abstract_size*4;
+        
+    sim_t *sim;
+
+    uint8_t debug_rom_whereto[4];
+    uint8_t debug_abstract[debug_abstract_size * 4];
+    uint8_t program_buffer[progsize * 4];
+    uint8_t dmdata[datasize * 4];
+    
+    bool halted[1024];
+    bool resumeack[1024];
+    uint8_t debug_rom_flags[1024];
+
+    void write32(uint8_t *rom, unsigned int index, uint32_t value);
+    uint32_t read32(uint8_t *rom, unsigned int index);
+
+    dmcontrol_t dmcontrol;
+    dmstatus_t dmstatus;
+    abstractcs_t abstractcs;
+    abstractauto_t abstractauto;
+    uint32_t command;
+
+    processor_t *current_proc() const;
+    void reset();
+    bool perform_abstract_command();
 };
 
 #endif
index b607bf38a02daccce1b90daafa71b89eb38a8c4c..9dcd809eb70261e448f0deac980f1f74472b81c6 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,8 +143,8 @@ private:
     STATE.XPR.write(reg, wdata); \
   })
 # define WRITE_FREG(reg, value) ({ \
-    freg_t wdata = (value); /* value may have side effects */ \
-    STATE.log_reg_write = (commit_log_reg_t){((reg) << 1) | 1, wdata}; \
+    freg_t wdata = freg(value); /* value may have side effects */ \
+    STATE.log_reg_write = (commit_log_reg_t){((reg) << 1) | 1, wdata.v}; \
     DO_WRITE_FREG(reg, wdata); \
   })
 #endif
@@ -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,20 +243,11 @@ 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); })
 
+// Seems that 0x0 doesn't work.
 #define DEBUG_START             0x100
-#define DEBUG_ROM_START         0x800
-#define DEBUG_ROM_RESUME        (DEBUG_ROM_START + 4)
-#define DEBUG_ROM_EXCEPTION     (DEBUG_ROM_START + 8)
-#define DEBUG_ROM_END           (DEBUG_ROM_START + debug_rom_raw_len)
-#define DEBUG_RAM_START         0x400
-#define DEBUG_RAM_SIZE          64
-#define DEBUG_RAM_END           (DEBUG_RAM_START + DEBUG_RAM_SIZE)
-#define DEBUG_END               0xfff
-#define DEBUG_CLEARDEBINT       0x100
-#define DEBUG_SETHALTNOT        0x10c
-#define DEBUG_SIZE              (DEBUG_END - DEBUG_START + 1)
+#define DEBUG_END                 (0x1000 - 1)
 
 #endif
index c7a63b0044b87e5a9a5dbd3df2958abd95699cd5..15115c8a6ccd5ec13ece8c125c8625fad7cd55be 100644 (file)
@@ -20,3 +20,11 @@ bool bus_t::store(reg_t addr, size_t len, const uint8_t* bytes)
     return false;
   return it->second->store(addr - -it->first, len, bytes);
 }
+
+std::pair<reg_t, abstract_device_t*> bus_t::find_device(reg_t addr)
+{
+  auto it = devices.lower_bound(-addr);
+  if (it == devices.end() || addr < -it->first)
+    return std::make_pair((reg_t)0, (abstract_device_t*)NULL);
+  return std::make_pair(-it->first, it->second);
+}
index 64ab79b96946e8c6337650aae3935d60964b06cc..e4df6c9858862a3f7421e0162e5538dfa009e925 100644 (file)
@@ -22,6 +22,8 @@ class bus_t : public abstract_device_t {
   bool store(reg_t addr, size_t len, const uint8_t* bytes);
   void add_device(reg_t addr, abstract_device_t* dev);
 
+  std::pair<reg_t, abstract_device_t*> find_device(reg_t addr);
+
  private:
   std::map<reg_t, abstract_device_t*> devices;
 };
@@ -36,17 +38,40 @@ class rom_device_t : public abstract_device_t {
   std::vector<char> data;
 };
 
-class rtc_t : public abstract_device_t {
+class mem_t : public abstract_device_t {
+ public:
+  mem_t(size_t size) : len(size) {
+    data = (char*)calloc(1, size);
+    if (!data)
+      throw std::runtime_error("couldn't allocate " + std::to_string(size) + " bytes of target memory");
+  }
+  mem_t(const mem_t& that) = delete;
+  ~mem_t() { free(data); }
+
+  bool load(reg_t addr, size_t len, uint8_t* bytes) { return false; }
+  bool store(reg_t addr, size_t len, const uint8_t* bytes) { return false; }
+  char* contents() { return data; }
+  size_t size() { return len; }
+
+ private:
+  char* data;
+  size_t len;
+};
+
+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..8ec134596e9497d739897772eba81bd9e9566d31 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 MSTATUS_UXL         0x0000000300000000
+#define MSTATUS_SXL         0x0000000C00000000
 #define MSTATUS64_SD        0x8000000000000000
 
 #define SSTATUS_UIE         0x00000001
 #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 SSTATUS_UXL         0x0000000300000000
 #define SSTATUS64_SD        0x8000000000000000
 
 #define DCSR_XDEBUGVER      (3U<<30)
 #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_URET  0xffffffff
 #define MATCH_SRET 0x10200073
 #define MASK_SRET  0xffffffff
-#define MATCH_HRET 0x20200073
-#define MASK_HRET  0xffffffff
 #define MATCH_MRET 0x30200073
 #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_FCVT_L_S  0xfff0007f
 #define MATCH_FCVT_LU_S 0xc0300053
 #define MASK_FCVT_LU_S  0xfff0007f
-#define MATCH_FMV_X_S 0xe0000053
-#define MASK_FMV_X_S  0xfff0707f
+#define MATCH_FMV_X_W 0xe0000053
+#define MASK_FMV_X_W  0xfff0707f
 #define MATCH_FCLASS_S 0xe0001053
 #define MASK_FCLASS_S  0xfff0707f
 #define MATCH_FCVT_W_D 0xc2000053
 #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_S_L  0xfff0007f
 #define MATCH_FCVT_S_LU 0xd0300053
 #define MASK_FCVT_S_LU  0xfff0007f
-#define MATCH_FMV_S_X 0xf0000053
-#define MASK_FMV_S_X  0xfff0707f
+#define MATCH_FMV_W_X 0xf0000053
+#define MASK_FMV_W_X  0xfff0707f
 #define MATCH_FCVT_D_W 0xd2000053
 #define MASK_FCVT_D_W  0xfff0007f
 #define MATCH_FCVT_D_WU 0xd2100053
 #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)
@@ -964,10 +1066,9 @@ DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL)
 DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK)
 DECLARE_INSN(uret, MATCH_URET, MASK_URET)
 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,17 +1098,34 @@ 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)
 DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S)
-DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S)
+DECLARE_INSN(fmv_x_w, MATCH_FMV_X_W, MASK_FMV_X_W)
 DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S)
 DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D)
 DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D)
@@ -1015,20 +1133,33 @@ 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)
 DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU)
-DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X)
+DECLARE_INSN(fmv_w_x, MATCH_FMV_W_X, MASK_FMV_W_X)
 DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W)
 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 ebc9dc7e79e12474e4a6735d248a2d2a9fb85103..303effee84ae4f9c3851c5ec0788683fbe007d95 100644 (file)
@@ -63,16 +63,12 @@ bool processor_t::slow_path()
 void processor_t::step(size_t n)
 {
   if (state.dcsr.cause == DCSR_CAUSE_NONE) {
-    // TODO: get_interrupt() isn't super fast. Does that matter?
-    if (sim->debug_module.get_interrupt(id)) {
+    if (halt_request) {
       enter_debug_mode(DCSR_CAUSE_DEBUGINT);
-    } else if (state.dcsr.halt) {
+    } // !!!The halt bit in DCSR is deprecated.
+    else if (state.dcsr.halt) {
       enter_debug_mode(DCSR_CAUSE_HALT);
     }
-  } else {
-    // In Debug Mode, just do 11 steps at a time. Otherwise we're going to be
-    // spinning the rest of the time anyway.
-    n = std::min(n, (size_t) 11);
   }
 
   while (n > 0) {
@@ -84,7 +80,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; \
@@ -120,6 +116,15 @@ void processor_t::step(size_t n)
             // enter_debug_mode changed state.pc, so we can't just continue.
             break;
           }
+
+          if (unlikely(state.pc >= DEBUG_START &&
+                       state.pc < DEBUG_END)) {
+            // We're waiting for the debugger to tell us something.
+            return;
+          }
+
+          
+          
         }
       }
       else while (instret < n)
index a34dd8040ced3a7f97f4e3f8deac64f9529f982e..520c2ed578c3964c4cfba8c9f7da394a48c1bc5d 100644 (file)
@@ -9,7 +9,7 @@ extension_t::~extension_t()
 
 void extension_t::illegal_instruction()
 {
-  throw trap_illegal_instruction();
+  throw trap_illegal_instruction(0);
 }
 
 void extension_t::raise_interrupt()
diff --git a/riscv/gdbserver.cc b/riscv/gdbserver.cc
deleted file mode 100644 (file)
index 79284eb..0000000
+++ /dev/null
@@ -1,2232 +0,0 @@
-#include <arpa/inet.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <cassert>
-#include <cinttypes>
-#include <cstdio>
-#include <vector>
-
-#include "disasm.h"
-#include "sim.h"
-#include "gdbserver.h"
-#include "mmu.h"
-#include "encoding.h"
-
-//////////////////////////////////////// Utility Functions
-
-#undef DEBUG
-#ifdef DEBUG
-#  define D(x) x
-#else
-#  define D(x)
-#endif // DEBUG
-
-void die(const char* msg)
-{
-  fprintf(stderr, "gdbserver code died: %s\n", msg);
-  abort();
-}
-
-// gdb's register list is defined in riscv_gdb_reg_names gdb/riscv-tdep.c in
-// its source tree. We must interpret the numbers the same here.
-enum {
-  REG_XPR0 = 0,
-  REG_XPR31 = 31,
-  REG_PC = 32,
-  REG_FPR0 = 33,
-  REG_FPR31 = 64,
-  REG_CSR0 = 65,
-  REG_MSTATUS = CSR_MSTATUS + REG_CSR0,
-  REG_CSR4095 = 4160,
-  REG_PRIV = 4161
-};
-
-//////////////////////////////////////// Functions to generate RISC-V opcodes.
-
-// TODO: Does this already exist somewhere?
-
-#define ZERO    0
-// Using regnames.cc as source. The RVG Calling Convention of the 2.0 RISC-V
-// spec says it should be 2 and 3.
-#define S0      8
-#define S1      9
-static uint32_t bits(uint32_t value, unsigned int hi, unsigned int lo) {
-  return (value >> lo) & ((1 << (hi+1-lo)) - 1);
-}
-
-static uint32_t bit(uint32_t value, unsigned int b) {
-  return (value >> b) & 1;
-}
-
-static uint32_t jal(unsigned int rd, uint32_t imm) {
-  return (bit(imm, 20) << 31) |
-    (bits(imm, 10, 1) << 21) |
-    (bit(imm, 11) << 20) |
-    (bits(imm, 19, 12) << 12) |
-    (rd << 7) |
-    MATCH_JAL;
-}
-
-static uint32_t csrsi(unsigned int csr, uint16_t imm) {
-  return (csr << 20) |
-    (bits(imm, 4, 0) << 15) |
-    MATCH_CSRRSI;
-}
-
-static uint32_t csrci(unsigned int csr, uint16_t imm) {
-  return (csr << 20) |
-    (bits(imm, 4, 0) << 15) |
-    MATCH_CSRRCI;
-}
-
-static uint32_t csrr(unsigned int rd, unsigned int csr) {
-  return (csr << 20) | (rd << 7) | MATCH_CSRRS;
-}
-
-static uint32_t csrw(unsigned int source, unsigned int csr) {
-  return (csr << 20) | (source << 15) | MATCH_CSRRW;
-}
-
-static uint32_t fence_i()
-{
-  return MATCH_FENCE_I;
-}
-
-static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 5) << 25) |
-    (src << 20) |
-    (base << 15) |
-    (bits(offset, 4, 0) << 7) |
-    MATCH_SB;
-}
-
-static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 5) << 25) |
-    (src << 20) |
-    (base << 15) |
-    (bits(offset, 4, 0) << 7) |
-    MATCH_SH;
-}
-
-static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 5) << 25) |
-    (src << 20) |
-    (base << 15) |
-    (bits(offset, 4, 0) << 7) |
-    MATCH_SW;
-}
-
-static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 5) << 25) |
-    (bits(src, 4, 0) << 20) |
-    (base << 15) |
-    (bits(offset, 4, 0) << 7) |
-    MATCH_SD;
-}
-
-static uint32_t sq(unsigned int src, unsigned int base, uint16_t offset)
-{
-#if 0
-  return (bits(offset, 11, 5) << 25) |
-    (bits(src, 4, 0) << 20) |
-    (base << 15) |
-    (bits(offset, 4, 0) << 7) |
-    MATCH_SQ;
-#else
-  abort();
-#endif
-}
-
-static uint32_t lq(unsigned int rd, unsigned int base, uint16_t offset)
-{
-#if 0
-  return (bits(offset, 11, 0) << 20) |
-    (base << 15) |
-    (bits(rd, 4, 0) << 7) |
-    MATCH_LQ;
-#else
-  abort();
-#endif
-}
-
-static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 0) << 20) |
-    (base << 15) |
-    (bits(rd, 4, 0) << 7) |
-    MATCH_LD;
-}
-
-static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 0) << 20) |
-    (base << 15) |
-    (bits(rd, 4, 0) << 7) |
-    MATCH_LW;
-}
-
-static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 0) << 20) |
-    (base << 15) |
-    (bits(rd, 4, 0) << 7) |
-    MATCH_LH;
-}
-
-static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 0) << 20) |
-    (base << 15) |
-    (bits(rd, 4, 0) << 7) |
-    MATCH_LB;
-}
-
-static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 5) << 25) |
-    (bits(src, 4, 0) << 20) |
-    (base << 15) |
-    (bits(offset, 4, 0) << 7) |
-    MATCH_FSW;
-}
-
-static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 5) << 25) |
-    (bits(src, 4, 0) << 20) |
-    (base << 15) |
-    (bits(offset, 4, 0) << 7) |
-    MATCH_FSD;
-}
-
-static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 0) << 20) |
-    (base << 15) |
-    (bits(dest, 4, 0) << 7) |
-    MATCH_FLW;
-}
-
-static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 0) << 20) |
-    (base << 15) |
-    (bits(dest, 4, 0) << 7) |
-    MATCH_FLD;
-}
-
-static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm)
-{
-  return (bits(imm, 11, 0) << 20) |
-    (src << 15) |
-    (dest << 7) |
-    MATCH_ADDI;
-}
-
-static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm)
-{
-  return (bits(imm, 11, 0) << 20) |
-    (src << 15) |
-    (dest << 7) |
-    MATCH_ORI;
-}
-
-static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm)
-{
-  return (bits(imm, 11, 0) << 20) |
-    (src << 15) |
-    (dest << 7) |
-    MATCH_XORI;
-}
-
-static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt)
-{
-  return (bits(shamt, 4, 0) << 20) |
-    (src << 15) |
-    (dest << 7) |
-    MATCH_SRLI;
-}
-
-
-static uint32_t nop()
-{
-  return addi(0, 0, 0);
-}
-
-template <typename T>
-unsigned int circular_buffer_t<T>::size() const
-{
-  if (end >= start)
-    return end - start;
-  else
-    return end + capacity - start;
-}
-
-template <typename T>
-void circular_buffer_t<T>::consume(unsigned int bytes)
-{
-  start = (start + bytes) % capacity;
-}
-
-template <typename T>
-unsigned int circular_buffer_t<T>::contiguous_empty_size() const
-{
-  if (end >= start)
-    if (start == 0)
-      return capacity - end - 1;
-    else
-      return capacity - end;
-  else
-    return start - end - 1;
-}
-
-template <typename T>
-unsigned int circular_buffer_t<T>::contiguous_data_size() const
-{
-  if (end >= start)
-    return end - start;
-  else
-    return capacity - start;
-}
-
-template <typename T>
-void circular_buffer_t<T>::data_added(unsigned int bytes)
-{
-  end += bytes;
-  assert(end <= capacity);
-  if (end == capacity)
-    end = 0;
-}
-
-template <typename T>
-void circular_buffer_t<T>::reset()
-{
-  start = 0;
-  end = 0;
-}
-
-template <typename T>
-void circular_buffer_t<T>::append(const T *src, unsigned int count)
-{
-  unsigned int copy = std::min(count, contiguous_empty_size());
-  memcpy(contiguous_empty(), src, copy * sizeof(T));
-  data_added(copy);
-  count -= copy;
-  if (count > 0) {
-    assert(count < contiguous_empty_size());
-    memcpy(contiguous_empty(), src+copy, count * sizeof(T));
-    data_added(count);
-  }
-}
-
-////////////////////////////// Debug Operations
-
-class halt_op_t : public operation_t
-{
-  public:
-    halt_op_t(gdbserver_t& gdbserver, bool send_status=false) :
-      operation_t(gdbserver), send_status(send_status),
-      state(ST_ENTER) {};
-
-    void write_dpc_program() {
-      gs.dr_write32(0, csrsi(CSR_DCSR, DCSR_HALT));
-      gs.dr_write32(1, csrr(S0, CSR_DPC));
-      gs.dr_write_store(2, S0, SLOT_DATA0);
-      gs.dr_write_jump(3);
-      gs.set_interrupt(0);
-    }
-
-    bool perform_step(unsigned int step) {
-      switch (state) {
-        gs.tselect_valid = false;
-        case ST_ENTER:
-          if (gs.xlen == 0) {
-            gs.dr_write32(0, xori(S1, ZERO, -1));
-            gs.dr_write32(1, srli(S1, S1, 31));
-            // 0x00000001  0x00000001:ffffffff  0x00000001:ffffffff:ffffffff:ffffffff
-            gs.dr_write32(2, sw(S1, ZERO, DEBUG_RAM_START));
-            gs.dr_write32(3, srli(S1, S1, 31));
-            // 0x00000000  0x00000000:00000003  0x00000000:00000003:ffffffff:ffffffff
-            gs.dr_write32(4, sw(S1, ZERO, DEBUG_RAM_START + 4));
-            gs.dr_write_jump(5);
-            gs.set_interrupt(0);
-            state = ST_XLEN;
-
-          } else {
-            write_dpc_program();
-            state = ST_DPC;
-          }
-          return false;
-
-        case ST_XLEN:
-          {
-            uint32_t word0 = gs.dr_read32(0);
-            uint32_t word1 = gs.dr_read32(1);
-
-            if (word0 == 1 && word1 == 0) {
-              gs.xlen = 32;
-            } else if (word0 == 0xffffffff && word1 == 3) {
-              gs.xlen = 64;
-            } else if (word0 == 0xffffffff && word1 == 0xffffffff) {
-              gs.xlen = 128;
-            }
-
-            write_dpc_program();
-            state = ST_DPC;
-            return false;
-          }
-
-        case ST_DPC:
-          gs.dpc = gs.dr_read(SLOT_DATA0);
-          gs.dr_write32(0, csrr(S0, CSR_MSTATUS));
-          gs.dr_write_store(1, S0, SLOT_DATA0);
-          gs.dr_write_jump(2);
-          gs.set_interrupt(0);
-          state = ST_MSTATUS;
-          return false;
-
-        case ST_MSTATUS:
-          gs.mstatus = gs.dr_read(SLOT_DATA0);
-          gs.mstatus_dirty = false;
-          gs.dr_write32(0, csrr(S0, CSR_DCSR));
-          gs.dr_write32(1, sw(S0, 0, (uint16_t) DEBUG_RAM_START + 16));
-          gs.dr_write_jump(2);
-          gs.set_interrupt(0);
-          state = ST_DCSR;
-          return false;
-
-        case ST_DCSR:
-          gs.dcsr = gs.dr_read32(4);
-
-          gs.sptbr_valid = false;
-          gs.pte_cache.clear();
-
-          if (send_status) {
-            switch (get_field(gs.dcsr, DCSR_CAUSE)) {
-              case DCSR_CAUSE_NONE:
-                fprintf(stderr, "Internal error. Processor halted without reason.\n");
-                abort();
-
-              case DCSR_CAUSE_DEBUGINT:
-                gs.send_packet("S02");   // Pretend program received SIGINT.
-                break;
-
-              case DCSR_CAUSE_HWBP:
-              case DCSR_CAUSE_STEP:
-              case DCSR_CAUSE_HALT:
-                // There's no gdb code for this.
-                gs.send_packet("T05");
-                break;
-              case DCSR_CAUSE_SWBP:
-                gs.send_packet("T05swbreak:;");
-                break;
-            }
-          }
-
-          return true;
-
-        default:
-          assert(0);
-      }
-    }
-
-  private:
-    bool send_status;
-    enum {
-      ST_ENTER,
-      ST_XLEN,
-      ST_DPC,
-      ST_MSTATUS,
-      ST_DCSR
-    } state;
-};
-
-class continue_op_t : public operation_t
-{
-  public:
-    continue_op_t(gdbserver_t& gdbserver, bool single_step) :
-      operation_t(gdbserver), single_step(single_step) {};
-
-    bool perform_step(unsigned int step) {
-      D(fprintf(stderr, "continue step %d\n", step));
-      switch (step) {
-        case 0:
-          gs.dr_write_load(0, S0, SLOT_DATA0);
-          gs.dr_write32(1, csrw(S0, CSR_DPC));
-          // TODO: Isn't there a fence.i in Debug ROM already?
-          if (gs.fence_i_required) {
-            gs.dr_write32(2, fence_i());
-            gs.dr_write_jump(3);
-            gs.fence_i_required = false;
-          } else {
-            gs.dr_write_jump(2);
-          }
-          gs.dr_write(SLOT_DATA0, gs.dpc);
-          gs.set_interrupt(0);
-          return false;
-
-        case 1:
-          gs.dr_write_load(0, S0, SLOT_DATA0);
-          gs.dr_write32(1, csrw(S0, CSR_MSTATUS));
-          gs.dr_write_jump(2);
-          gs.dr_write(SLOT_DATA0, gs.mstatus);
-          gs.set_interrupt(0);
-          return false;
-
-        case 2:
-          gs.dr_write32(0, lw(S0, 0, (uint16_t) DEBUG_RAM_START+16));
-          gs.dr_write32(1, csrw(S0, CSR_DCSR));
-          gs.dr_write_jump(2);
-
-          reg_t dcsr = set_field(gs.dcsr, DCSR_HALT, 0);
-          dcsr = set_field(dcsr, DCSR_STEP, single_step);
-          // Software breakpoints should go here.
-          dcsr = set_field(dcsr, DCSR_EBREAKM, 1);
-          dcsr = set_field(dcsr, DCSR_EBREAKH, 1);
-          dcsr = set_field(dcsr, DCSR_EBREAKS, 1);
-          dcsr = set_field(dcsr, DCSR_EBREAKU, 1);
-          gs.dr_write32(4, dcsr);
-
-          gs.set_interrupt(0);
-          return true;
-      }
-      return false;
-    }
-
-  private:
-    bool single_step;
-};
-
-class general_registers_read_op_t : public operation_t
-{
-  // Register order that gdb expects is:
-  //   "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
-  //   "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
-  //   "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
-  //   "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
-
-  // Each byte of register data is described by two hex digits. The bytes with
-  // the register are transmitted in target byte order. The size of each
-  // register and their position within the â€˜g’ packet are determined by the
-  // gdb internal gdbarch functions DEPRECATED_REGISTER_RAW_SIZE and
-  // gdbarch_register_name.
-
-  public:
-    general_registers_read_op_t(gdbserver_t& gdbserver) :
-      operation_t(gdbserver) {};
-
-    bool perform_step(unsigned int step)
-    {
-      D(fprintf(stderr, "register_read step %d\n", step));
-      if (step == 0) {
-        gs.start_packet();
-
-        // x0 is always zero.
-        if (gs.xlen == 32) {
-          gs.send((uint32_t) 0);
-        } else {
-          gs.send((uint64_t) 0);
-        }
-
-        gs.dr_write_store(0, 1, SLOT_DATA0);
-        gs.dr_write_store(1, 2, SLOT_DATA1);
-        gs.dr_write_jump(2);
-        gs.set_interrupt(0);
-        return false;
-      }
-
-      if (gs.xlen == 32) {
-        gs.send((uint32_t) gs.dr_read(SLOT_DATA0));
-      } else {
-        gs.send((uint64_t) gs.dr_read(SLOT_DATA0));
-      }
-      if (step >= 16) {
-        gs.end_packet();
-        return true;
-      }
-
-      if (gs.xlen == 32) {
-        gs.send((uint32_t) gs.dr_read(SLOT_DATA1));
-      } else {
-        gs.send((uint64_t) gs.dr_read(SLOT_DATA1));
-      }
-
-      unsigned int current_reg = 2 * step + 1;
-      unsigned int i = 0;
-      if (current_reg == S1) {
-        gs.dr_write_load(i++, S1, SLOT_DATA_LAST);
-      }
-      gs.dr_write_store(i++, current_reg, SLOT_DATA0);
-      if (current_reg + 1 == S0) {
-        gs.dr_write32(i++, csrr(S0, CSR_DSCRATCH));
-      }
-      if (step < 15) {
-        gs.dr_write_store(i++, current_reg+1, SLOT_DATA1);
-      }
-      gs.dr_write_jump(i);
-      gs.set_interrupt(0);
-
-      return false;
-    }
-};
-
-class register_read_op_t : public operation_t
-{
-  public:
-    register_read_op_t(gdbserver_t& gdbserver, unsigned int reg) :
-      operation_t(gdbserver), reg(reg) {};
-
-    bool perform_step(unsigned int step)
-    {
-      switch (step) {
-        case 0:
-          if (reg >= REG_XPR0 && reg <= REG_XPR31) {
-            unsigned int i = 0;
-            if (reg == S0) {
-                gs.dr_write32(i++, csrr(S0, CSR_DSCRATCH));
-            }
-            if (gs.xlen == 32) {
-              gs.dr_write32(i++, sw(reg - REG_XPR0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            } else {
-              gs.dr_write32(i++, sd(reg - REG_XPR0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            }
-            gs.dr_write_jump(i);
-          } else if (reg == REG_PC) {
-            gs.start_packet();
-            if (gs.xlen == 32) {
-              gs.send((uint32_t) gs.dpc);
-            } else {
-              gs.send(gs.dpc);
-            }
-            gs.end_packet();
-            return true;
-          } else if (reg >= REG_FPR0 && reg <= REG_FPR31) {
-            gs.dr_write_load(0, S0, SLOT_DATA1);
-            gs.dr_write(SLOT_DATA1, set_field(gs.mstatus, MSTATUS_FS, 1));
-            gs.dr_write32(1, csrw(S0, CSR_MSTATUS));
-            gs.mstatus_dirty = true;
-            if (gs.xlen == 32) {
-              gs.dr_write32(2, fsw(reg - REG_FPR0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            } else {
-              gs.dr_write32(2, fsd(reg - REG_FPR0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            }
-            gs.dr_write_jump(3);
-          } else if (reg == REG_MSTATUS) {
-            gs.start_packet();
-            if (gs.xlen == 32) {
-              gs.send((uint32_t) gs.mstatus);
-            } else {
-              gs.send(gs.mstatus);
-            }
-            gs.end_packet();
-            return true;
-          } else if (reg >= REG_CSR0 && reg <= REG_CSR4095) {
-            gs.dr_write32(0, csrr(S0, reg - REG_CSR0));
-            gs.dr_write_store(1, S0, SLOT_DATA0);
-            gs.dr_write_jump(2);
-            // If we hit an exception reading the CSR, we'll end up returning ~0 as
-            // the register's value, which is what we want. (Right?)
-            gs.dr_write(SLOT_DATA0, ~(uint64_t) 0);
-          } else if (reg == REG_PRIV) {
-            gs.start_packet();
-            gs.send((uint8_t) get_field(gs.dcsr, DCSR_PRV));
-            gs.end_packet();
-            return true;
-          } else {
-            gs.send_packet("E02");
-            return true;
-          }
-          gs.set_interrupt(0);
-          return false;
-
-        case 1:
-          {
-            unsigned result = gs.dr_read32(DEBUG_RAM_SIZE / 4 - 1);
-            if (result) {
-              gs.send_packet("E03");
-              return true;
-            }
-            gs.start_packet();
-            if (gs.xlen == 32) {
-              gs.send(gs.dr_read32(4));
-            } else {
-              gs.send(gs.dr_read(SLOT_DATA0));
-            }
-            gs.end_packet();
-            return true;
-          }
-      }
-      return false;
-    }
-
-  private:
-    unsigned int reg;
-};
-
-class register_write_op_t : public operation_t
-{
-  public:
-    register_write_op_t(gdbserver_t& gdbserver, unsigned int reg, reg_t value) :
-      operation_t(gdbserver), reg(reg), value(value) {};
-
-    bool perform_step(unsigned int step)
-    {
-      switch (step) {
-        case 0:
-          gs.dr_write_load(0, S0, SLOT_DATA0);
-          gs.dr_write(SLOT_DATA0, value);
-          if (reg == S0) {
-            gs.dr_write32(1, csrw(S0, CSR_DSCRATCH));
-            gs.dr_write_jump(2);
-          } else if (reg == S1) {
-            gs.dr_write_store(1, S0, SLOT_DATA_LAST);
-            gs.dr_write_jump(2);
-          } else if (reg >= REG_XPR0 && reg <= REG_XPR31) {
-            gs.dr_write32(1, addi(reg, S0, 0));
-            gs.dr_write_jump(2);
-          } else if (reg == REG_PC) {
-            gs.dpc = value;
-            return true;
-          } else if (reg >= REG_FPR0 && reg <= REG_FPR31) {
-            gs.dr_write_load(0, S0, SLOT_DATA1);
-            gs.dr_write(SLOT_DATA1, set_field(gs.mstatus, MSTATUS_FS, 1));
-            gs.dr_write32(1, csrw(S0, CSR_MSTATUS));
-            gs.mstatus_dirty = true;
-            if (gs.xlen == 32) {
-              gs.dr_write32(2, flw(reg - REG_FPR0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            } else {
-              gs.dr_write32(2, fld(reg - REG_FPR0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            }
-            gs.dr_write_jump(3);
-          } else if (reg == REG_MSTATUS) {
-            gs.mstatus = value;
-            gs.mstatus_dirty = true;
-            return true;
-          } else if (reg >= REG_CSR0 && reg <= REG_CSR4095) {
-            gs.dr_write32(1, csrw(S0, reg - REG_CSR0));
-            gs.dr_write_jump(2);
-            if (reg == REG_CSR0 + CSR_SPTBR) {
-              gs.sptbr = value;
-              gs.sptbr_valid = true;
-            }
-          } else if (reg == REG_PRIV) {
-            gs.dcsr = set_field(gs.dcsr, DCSR_PRV, value);
-            return true;
-          } else {
-            gs.send_packet("E02");
-            return true;
-          }
-          gs.set_interrupt(0);
-          return false;
-
-        case 1:
-          {
-            unsigned result = gs.dr_read32(DEBUG_RAM_SIZE / 4 - 1);
-            if (result) {
-              gs.send_packet("E03");
-              return true;
-            }
-            gs.send_packet("OK");
-            return true;
-          }
-      }
-
-      assert(0);
-    }
-
-  private:
-    unsigned int reg;
-    reg_t value;
-};
-
-class memory_read_op_t : public operation_t
-{
-  public:
-    // Read length bytes from vaddr, storing the result into data.
-    // If data is NULL, send the result straight to gdb.
-    memory_read_op_t(gdbserver_t& gdbserver, reg_t vaddr, unsigned int length,
-        unsigned char *data=NULL) :
-      operation_t(gdbserver), vaddr(vaddr), length(length), data(data), index(0)
-  {
-    buf = new uint8_t[length];
-  };
-
-    ~memory_read_op_t()
-    {
-      delete[] buf;
-    }
-
-    bool perform_step(unsigned int step)
-    {
-      if (step == 0) {
-        // address goes in S0
-        paddr = gs.translate(vaddr);
-        access_size = gs.find_access_size(paddr, length);
-
-        gs.dr_write_load(0, S0, SLOT_DATA0);
-        switch (access_size) {
-          case 1:
-            gs.dr_write32(1, lb(S1, S0, 0));
-            break;
-          case 2:
-            gs.dr_write32(1, lh(S1, S0, 0));
-            break;
-          case 4:
-            gs.dr_write32(1, lw(S1, S0, 0));
-            break;
-          case 8:
-            gs.dr_write32(1, ld(S1, S0, 0));
-            break;
-        }
-        gs.dr_write_store(2, S1, SLOT_DATA1);
-        gs.dr_write_jump(3);
-        gs.dr_write(SLOT_DATA0, paddr);
-        gs.set_interrupt(0);
-
-        return false;
-      }
-
-      if (gs.dr_read32(DEBUG_RAM_SIZE / 4 - 1)) {
-        // Note that OpenOCD doesn't report this error to gdb by default. They
-        // think it can mess up stack tracing. So far I haven't seen any
-        // problems.
-        gs.send_packet("E99");
-        return true;
-      }
-
-      reg_t value = gs.dr_read(SLOT_DATA1);
-      for (unsigned int i = 0; i < access_size; i++) {
-        if (data) {
-          *(data++) = value & 0xff;
-          D(fprintf(stderr, "%02x", (unsigned int) (value & 0xff)));
-        } else {
-          buf[index++] = value & 0xff;
-        }
-        value >>= 8;
-      }
-      if (data) {
-        D(fprintf(stderr, "\n"));
-      }
-      length -= access_size;
-      paddr += access_size;
-
-      if (length == 0) {
-        if (!data) {
-          gs.start_packet();
-          char buffer[3];
-          for (unsigned int i = 0; i < index; i++) {
-            sprintf(buffer, "%02x", (unsigned int) buf[i]);
-            gs.send(buffer);
-          }
-          gs.end_packet();
-        }
-        return true;
-      } else {
-        gs.dr_write(SLOT_DATA0, paddr);
-        gs.set_interrupt(0);
-        return false;
-      }
-    }
-
-  private:
-    reg_t vaddr;
-    unsigned int length;
-    unsigned char* data;
-    reg_t paddr;
-    unsigned int access_size;
-    unsigned int index;
-    uint8_t *buf;
-};
-
-class memory_write_op_t : public operation_t
-{
-  public:
-    memory_write_op_t(gdbserver_t& gdbserver, reg_t vaddr, unsigned int length,
-        const unsigned char *data) :
-      operation_t(gdbserver), vaddr(vaddr), offset(0), length(length), data(data) {};
-
-    ~memory_write_op_t() {
-      delete[] data;
-    }
-
-    bool perform_step(unsigned int step)
-    {
-      reg_t paddr = gs.translate(vaddr);
-
-      unsigned int data_offset;
-      switch (gs.xlen) {
-        case 32:
-          data_offset = slot_offset32[SLOT_DATA1];
-          break;
-        case 64:
-          data_offset = slot_offset64[SLOT_DATA1];
-          break;
-        case 128:
-          data_offset = slot_offset128[SLOT_DATA1];
-          break;
-        default:
-          abort();
-      }
-
-      if (step == 0) {
-        access_size = gs.find_access_size(paddr, length);
-
-        D(fprintf(stderr, "write to 0x%" PRIx64 " -> 0x%" PRIx64 " (access=%d): ",
-              vaddr, paddr, access_size));
-        for (unsigned int i = 0; i < length; i++) {
-          D(fprintf(stderr, "%02x", data[i]));
-        }
-        D(fprintf(stderr, "\n"));
-
-        // address goes in S0
-        gs.dr_write_load(0, S0, SLOT_DATA0);
-        switch (access_size) {
-          case 1:
-            gs.dr_write32(1, lb(S1, 0, (uint16_t) DEBUG_RAM_START + 4*data_offset));
-            gs.dr_write32(2, sb(S1, S0, 0));
-            gs.dr_write32(data_offset, data[0]);
-            break;
-          case 2:
-            gs.dr_write32(1, lh(S1, 0, (uint16_t) DEBUG_RAM_START + 4*data_offset));
-            gs.dr_write32(2, sh(S1, S0, 0));
-            gs.dr_write32(data_offset, data[0] | (data[1] << 8));
-            break;
-          case 4:
-            gs.dr_write32(1, lw(S1, 0, (uint16_t) DEBUG_RAM_START + 4*data_offset));
-            gs.dr_write32(2, sw(S1, S0, 0));
-            gs.dr_write32(data_offset, data[0] | (data[1] << 8) |
-                (data[2] << 16) | (data[3] << 24));
-            break;
-          case 8:
-            gs.dr_write32(1, ld(S1, 0, (uint16_t) DEBUG_RAM_START + 4*data_offset));
-            gs.dr_write32(2, sd(S1, S0, 0));
-            gs.dr_write32(data_offset, data[0] | (data[1] << 8) |
-                (data[2] << 16) | (data[3] << 24));
-            gs.dr_write32(data_offset+1, data[4] | (data[5] << 8) |
-                (data[6] << 16) | (data[7] << 24));
-            break;
-          default:
-            fprintf(stderr, "gdbserver error: write %d bytes to 0x%016" PRIx64
-                    " -> 0x%016" PRIx64 "; access_size=%d\n",
-                    length, vaddr, paddr, access_size);
-            gs.send_packet("E12");
-            return true;
-        }
-        gs.dr_write_jump(3);
-        gs.dr_write(SLOT_DATA0, paddr);
-        gs.set_interrupt(0);
-
-        return false;
-      }
-
-      if (gs.dr_read32(DEBUG_RAM_SIZE / 4 - 1)) {
-        gs.send_packet("E98");
-        return true;
-      }
-
-      offset += access_size;
-      if (offset >= length) {
-        gs.send_packet("OK");
-        return true;
-      } else {
-        const unsigned char *d = data + offset;
-        switch (access_size) {
-          case 1:
-            gs.dr_write32(data_offset, d[0]);
-            break;
-          case 2:
-            gs.dr_write32(data_offset, d[0] | (d[1] << 8));
-            break;
-          case 4:
-            gs.dr_write32(data_offset, d[0] | (d[1] << 8) |
-                (d[2] << 16) | (d[3] << 24));
-            break;
-          case 8:
-            gs.dr_write32(data_offset, d[0] | (d[1] << 8) |
-                (d[2] << 16) | (d[3] << 24));
-            gs.dr_write32(data_offset+1, d[4] | (d[5] << 8) |
-                (d[6] << 16) | (d[7] << 24));
-            break;
-          default:
-            gs.send_packet("E13");
-            return true;
-        }
-        gs.dr_write(SLOT_DATA0, paddr + offset);
-        gs.set_interrupt(0);
-        return false;
-      }
-    }
-
-  private:
-    reg_t vaddr;
-    unsigned int offset;
-    unsigned int length;
-    unsigned int access_size;
-    const unsigned char *data;
-};
-
-class collect_translation_info_op_t : public operation_t
-{
-  public:
-    // Read sufficient information from the target into gdbserver structures so
-    // that it's possible to translate vaddr, vaddr+length, and all addresses
-    // in between to physical addresses.
-    collect_translation_info_op_t(gdbserver_t& gdbserver, reg_t vaddr, size_t length) :
-      operation_t(gdbserver), state(STATE_START), vaddr(vaddr), length(length) {};
-
-    bool perform_step(unsigned int step)
-    {
-      unsigned int vm = gs.virtual_memory();
-
-      if (step == 0) {
-        switch (vm) {
-          case VM_MBARE:
-            // Nothing to be done.
-            return true;
-
-          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:
-            {
-              char buf[100];
-              sprintf(buf, "VM mode %d is not supported by gdbserver.cc.", vm);
-              die(buf);
-              return true;        // die doesn't return, but gcc doesn't know that.
-            }
-        }
-      }
-
-      // Perform any reads from the just-completed action.
-      switch (state) {
-        case STATE_START:
-          break;
-        case STATE_READ_SPTBR:
-          gs.sptbr = gs.dr_read(SLOT_DATA0);
-          gs.sptbr_valid = true;
-          break;
-        case STATE_READ_PTE:
-          if (ptesize == 4) {
-              gs.pte_cache[pte_addr] = gs.dr_read32(4);
-          } else {
-              gs.pte_cache[pte_addr] = ((uint64_t) gs.dr_read32(5) << 32) |
-                  gs.dr_read32(4);
-          }
-          D(fprintf(stderr, "pte_cache[0x%" PRIx64 "] = 0x%" PRIx64 "\n", pte_addr,
-                    gs.pte_cache[pte_addr]));
-          break;
-      }
-
-      // Set up the next action.
-      // We only get here for VM_SV32/39/38.
-
-      if (!gs.sptbr_valid) {
-        state = STATE_READ_SPTBR;
-        gs.dr_write32(0, csrr(S0, CSR_SPTBR));
-        gs.dr_write_store(1, S0, SLOT_DATA0);
-        gs.dr_write_jump(2);
-        gs.set_interrupt(0);
-        return false;
-      }
-
-      reg_t base = gs.sptbr << PGSHIFT;
-      int ptshift = (levels - 1) * ptidxbits;
-      for (unsigned int i = 0; i < levels; i++, ptshift -= ptidxbits) {
-        reg_t idx = (vaddr >> (PGSHIFT + ptshift)) & ((1 << ptidxbits) - 1);
-
-        pte_addr = base + idx * ptesize;
-        auto it = gs.pte_cache.find(pte_addr);
-        if (it == gs.pte_cache.end()) {
-          state = STATE_READ_PTE;
-          if (ptesize == 4) {
-            gs.dr_write32(0, lw(S0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            gs.dr_write32(1, lw(S1, S0, 0));
-            gs.dr_write32(2, sw(S1, 0, (uint16_t) DEBUG_RAM_START + 16));
-          } else {
-            assert(gs.xlen >= 64);
-            gs.dr_write32(0, ld(S0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            gs.dr_write32(1, ld(S1, S0, 0));
-            gs.dr_write32(2, sd(S1, 0, (uint16_t) DEBUG_RAM_START + 16));
-          }
-          gs.dr_write_jump(3);
-          gs.dr_write32(4, pte_addr);
-          gs.dr_write32(5, pte_addr >> 32);
-          gs.set_interrupt(0);
-          return false;
-        }
-
-        reg_t pte = gs.pte_cache[pte_addr];
-        reg_t ppn = pte >> PTE_PPN_SHIFT;
-
-        if (PTE_TABLE(pte)) { // next level of page table
-          base = ppn << PGSHIFT;
-        } else {
-          // We've collected all the data required for the translation.
-          return true;
-        }
-      }
-      fprintf(stderr,
-          "ERROR: gdbserver couldn't find appropriate PTEs to translate 0x%016" PRIx64 "\n",
-          vaddr);
-      return true;
-    }
-
-  private:
-    enum {
-      STATE_START,
-      STATE_READ_SPTBR,
-      STATE_READ_PTE
-    } state;
-    reg_t vaddr;
-    size_t length;
-    unsigned int levels;
-    unsigned int ptidxbits;
-    unsigned int ptesize;
-    reg_t pte_addr;
-};
-
-class hardware_breakpoint_insert_op_t : public operation_t
-{
-  public:
-    hardware_breakpoint_insert_op_t(gdbserver_t& gdbserver,
-        hardware_breakpoint_t bp) :
-      operation_t(gdbserver), state(STATE_START), bp(bp) {};
-
-    void write_new_index_program()
-    {
-      gs.dr_write_load(0, S0, SLOT_DATA1);
-      gs.dr_write32(1, csrw(S0, CSR_TSELECT));
-      gs.dr_write32(2, csrr(S0, CSR_TSELECT));
-      gs.dr_write_store(3, S0, SLOT_DATA1);
-      gs.dr_write_jump(4);
-      gs.dr_write(SLOT_DATA1, bp.index);
-    }
-
-    bool perform_step(unsigned int step)
-    {
-      switch (state) {
-        case STATE_START:
-          bp.index = 0;
-          write_new_index_program();
-          state = STATE_CHECK_INDEX;
-          break;
-
-        case STATE_CHECK_INDEX:
-          if (gs.dr_read(SLOT_DATA1) != bp.index) {
-            // We've exhausted breakpoints without finding an appropriate one.
-            gs.send_packet("E58");
-            return true;
-          }
-
-          gs.dr_write32(0, csrr(S0, CSR_TDATA1));
-          gs.dr_write_store(1, S0, SLOT_DATA0);
-          gs.dr_write_jump(2);
-          state = STATE_CHECK_MCONTROL;
-          break;
-
-        case STATE_CHECK_MCONTROL:
-          {
-            reg_t mcontrol = gs.dr_read(SLOT_DATA0);
-            unsigned int type = mcontrol >> (gs.xlen - 4);
-            if (type == 0) {
-              // We've exhausted breakpoints without finding an appropriate one.
-              gs.send_packet("E58");
-              return true;
-            }
-
-            if (type == 2 &&
-                !get_field(mcontrol, MCONTROL_EXECUTE) &&
-                !get_field(mcontrol, MCONTROL_LOAD) &&
-                !get_field(mcontrol, MCONTROL_STORE)) {
-              // Found an unused trigger.
-              gs.dr_write_load(0, S0, SLOT_DATA1);
-              gs.dr_write32(1, csrw(S0, CSR_TDATA1));
-              gs.dr_write_jump(2);
-              mcontrol = set_field(0, MCONTROL_ACTION, MCONTROL_ACTION_DEBUG_MODE);
-              mcontrol = set_field(mcontrol, MCONTROL_DMODE(gs.xlen), 1);
-              mcontrol = set_field(mcontrol, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL);
-              mcontrol = set_field(mcontrol, MCONTROL_M, 1);
-              mcontrol = set_field(mcontrol, MCONTROL_H, 1);
-              mcontrol = set_field(mcontrol, MCONTROL_S, 1);
-              mcontrol = set_field(mcontrol, MCONTROL_U, 1);
-              mcontrol = set_field(mcontrol, MCONTROL_EXECUTE, bp.execute);
-              mcontrol = set_field(mcontrol, MCONTROL_LOAD, bp.load);
-              mcontrol = set_field(mcontrol, MCONTROL_STORE, bp.store);
-              // For store triggers it's nicer to fire just before the
-              // instruction than just after. However, gdb doesn't clear the
-              // breakpoints and step before resuming from a store trigger.
-              // That means that without extra code, you'll keep hitting the
-              // same watchpoint over and over again. That's not useful at all.
-              // Instead of fixing this the right way, just set timing=1 for
-              // those triggers.
-              if (bp.load || bp.store)
-                mcontrol = set_field(mcontrol, MCONTROL_TIMING, 1);
-
-              gs.dr_write(SLOT_DATA1, mcontrol);
-              state = STATE_WRITE_ADDRESS;
-            } else {
-              bp.index++;
-              write_new_index_program();
-              state = STATE_CHECK_INDEX;
-            }
-          }
-          break;
-
-        case STATE_WRITE_ADDRESS:
-          {
-            gs.dr_write_load(0, S0, SLOT_DATA1);
-            gs.dr_write32(1, csrw(S0, CSR_TDATA2));
-            gs.dr_write_jump(2);
-            gs.dr_write(SLOT_DATA1, bp.vaddr);
-            gs.set_interrupt(0);
-            gs.send_packet("OK");
-
-            gs.hardware_breakpoints.insert(bp);
-
-            return true;
-          }
-      }
-
-      gs.set_interrupt(0);
-      return false;
-    }
-
-  private:
-    enum {
-      STATE_START,
-      STATE_CHECK_INDEX,
-      STATE_CHECK_MCONTROL,
-      STATE_WRITE_ADDRESS
-    } state;
-    hardware_breakpoint_t bp;
-};
-
-class maybe_save_tselect_op_t : public operation_t
-{
-  public:
-    maybe_save_tselect_op_t(gdbserver_t& gdbserver) : operation_t(gdbserver) {};
-    bool perform_step(unsigned int step) {
-      if (gs.tselect_valid)
-        return true;
-
-      switch (step) {
-        case 0:
-          gs.dr_write32(0, csrr(S0, CSR_TDATA1));
-          gs.dr_write_store(1, S0, SLOT_DATA0);
-          gs.dr_write_jump(2);
-          gs.set_interrupt(0);
-          return false;
-        case 1:
-          gs.tselect = gs.dr_read(SLOT_DATA0);
-          gs.tselect_valid = true;
-          break;
-      }
-      return true;
-    }
-};
-
-class maybe_restore_tselect_op_t : public operation_t
-{
-  public:
-    maybe_restore_tselect_op_t(gdbserver_t& gdbserver) : operation_t(gdbserver) {};
-    bool perform_step(unsigned int step) {
-      if (gs.tselect_valid) {
-        gs.dr_write_load(0, S0, SLOT_DATA1);
-        gs.dr_write32(1, csrw(S0, CSR_TSELECT));
-        gs.dr_write_jump(2);
-        gs.dr_write(SLOT_DATA1, gs.tselect);
-      }
-      return true;
-    }
-};
-
-class maybe_restore_mstatus_op_t : public operation_t
-{
-  public:
-    maybe_restore_mstatus_op_t(gdbserver_t& gdbserver) : operation_t(gdbserver) {};
-    bool perform_step(unsigned int step) {
-      if (gs.mstatus_dirty) {
-        gs.dr_write_load(0, S0, SLOT_DATA1);
-        gs.dr_write32(1, csrw(S0, CSR_MSTATUS));
-        gs.dr_write_jump(2);
-        gs.dr_write(SLOT_DATA1, gs.mstatus);
-      }
-      return true;
-    }
-};
-
-class hardware_breakpoint_remove_op_t : public operation_t
-{
-  public:
-    hardware_breakpoint_remove_op_t(gdbserver_t& gdbserver,
-        hardware_breakpoint_t bp) :
-      operation_t(gdbserver), bp(bp) {};
-
-    bool perform_step(unsigned int step) {
-      gs.dr_write32(0, addi(S0, ZERO, bp.index));
-      gs.dr_write32(1, csrw(S0, CSR_TSELECT));
-      gs.dr_write32(2, csrw(ZERO, CSR_TDATA1));
-      gs.dr_write_jump(3);
-      gs.set_interrupt(0);
-      return true;
-    }
-
-  private:
-    hardware_breakpoint_t bp;
-};
-
-////////////////////////////// gdbserver itself
-
-gdbserver_t::gdbserver_t(uint16_t port, sim_t *sim) :
-  xlen(0),
-  sim(sim),
-  client_fd(0),
-  // gdb likes to send 0x100000 bytes at once when downloading.
-  recv_buf(0x180000), send_buf(64 * 1024)
-{
-  socket_fd = socket(AF_INET, SOCK_STREAM, 0);
-  if (socket_fd == -1) {
-    fprintf(stderr, "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, "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, "failed to bind socket: %s (%d)\n", strerror(errno), errno);
-    abort();
-  }
-
-  if (listen(socket_fd, 1) == -1) {
-    fprintf(stderr, "failed to listen on socket: %s (%d)\n", strerror(errno), errno);
-    abort();
-  }
-}
-
-unsigned int gdbserver_t::find_access_size(reg_t address, int length)
-{
-  reg_t composite = address | length;
-  if ((composite & 0x7) == 0 && xlen >= 64)
-    return 8;
-  if ((composite & 0x3) == 0)
-    return 4;
-  return 1;
-}
-
-reg_t gdbserver_t::translate(reg_t vaddr)
-{
-  unsigned int vm = virtual_memory();
-  unsigned int levels, ptidxbits, ptesize;
-
-  switch (vm) {
-    case VM_MBARE:
-      return vaddr;
-
-    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:
-      {
-        char buf[100];
-        sprintf(buf, "VM mode %d is not supported by gdbserver.cc.", vm);
-        die(buf);
-        return true;        // die doesn't return, but gcc doesn't know that.
-      }
-  }
-
-  // Handle page tables here. There's a bunch of duplicated code with
-  // collect_translation_info_op_t. :-(
-  reg_t base = sptbr << PGSHIFT;
-  int ptshift = (levels - 1) * ptidxbits;
-  for (unsigned int i = 0; i < levels; i++, ptshift -= ptidxbits) {
-    reg_t idx = (vaddr >> (PGSHIFT + ptshift)) & ((1 << ptidxbits) - 1);
-
-    reg_t pte_addr = base + idx * ptesize;
-    auto it = pte_cache.find(pte_addr);
-    if (it == pte_cache.end()) {
-      fprintf(stderr, "ERROR: gdbserver tried to translate 0x%016" PRIx64
-          " without first collecting the relevant PTEs.\n", vaddr);
-      die("gdbserver_t::translate()");
-    }
-
-    reg_t pte = pte_cache[pte_addr];
-    reg_t ppn = pte >> PTE_PPN_SHIFT;
-
-    if (PTE_TABLE(pte)) { // next level of page table
-      base = ppn << PGSHIFT;
-    } else {
-      // We've collected all the data required for the translation.
-      reg_t vpn = vaddr >> PGSHIFT;
-      reg_t paddr = (ppn | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT;
-      paddr += vaddr & (PGSIZE-1);
-      D(fprintf(stderr, "gdbserver translate 0x%" PRIx64 " -> 0x%" PRIx64 "\n", vaddr, paddr));
-      return paddr;
-    }
-  }
-
-  fprintf(stderr, "ERROR: gdbserver tried to translate 0x%016" PRIx64
-          " but the relevant PTEs are invalid.\n", vaddr);
-  // TODO: Is it better to throw an exception here?
-  return -1;
-}
-
-unsigned int gdbserver_t::privilege_mode()
-{
-  unsigned int mode = get_field(dcsr, DCSR_PRV);
-  if (get_field(mstatus, MSTATUS_MPRV))
-    mode = get_field(mstatus, MSTATUS_MPP);
-  return mode;
-}
-
-unsigned int gdbserver_t::virtual_memory()
-{
-  unsigned int mode = privilege_mode();
-  if (mode == PRV_M)
-    return VM_MBARE;
-  return get_field(mstatus, MSTATUS_VM);
-}
-
-void gdbserver_t::dr_write32(unsigned int index, uint32_t value)
-{
-  sim->debug_module.ram_write32(index, value);
-}
-
-void gdbserver_t::dr_write64(unsigned int index, uint64_t value)
-{
-  dr_write32(index, value);
-  dr_write32(index+1, value >> 32);
-}
-
-void gdbserver_t::dr_write(enum slot slot, uint64_t value)
-{
-  switch (xlen) {
-    case 32:
-      dr_write32(slot_offset32[slot], value);
-      break;
-    case 64:
-      dr_write64(slot_offset64[slot], value);
-      break;
-    case 128:
-    default:
-      abort();
-  }
-}
-
-void gdbserver_t::dr_write_jump(unsigned int index)
-{
-  dr_write32(index, jal(0,
-        (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*index))));
-}
-
-void gdbserver_t::dr_write_store(unsigned int index, unsigned int reg, enum slot slot)
-{
-  assert(slot != SLOT_INST0 || index > 2);
-  assert(slot != SLOT_DATA0 || index < 4 || index > 6);
-  assert(slot != SLOT_DATA1 || index < 5 || index > 10);
-  assert(slot != SLOT_DATA_LAST || index < 6 || index > 14);
-  switch (xlen) {
-    case 32:
-      return dr_write32(index,
-          sw(reg, 0, (uint16_t) DEBUG_RAM_START + 4 * slot_offset32[slot]));
-    case 64:
-      return dr_write32(index,
-          sd(reg, 0, (uint16_t) DEBUG_RAM_START + 4 * slot_offset64[slot]));
-    case 128:
-      return dr_write32(index,
-          sq(reg, 0, (uint16_t) DEBUG_RAM_START + 4 * slot_offset128[slot]));
-    default:
-      fprintf(stderr, "xlen is %d!\n", xlen);
-      abort();
-  }
-}
-
-void gdbserver_t::dr_write_load(unsigned int index, unsigned int reg, enum slot slot)
-{
-  switch (xlen) {
-    case 32:
-      return dr_write32(index,
-          lw(reg, 0, (uint16_t) DEBUG_RAM_START + 4 * slot_offset32[slot]));
-    case 64:
-      return dr_write32(index,
-          ld(reg, 0, (uint16_t) DEBUG_RAM_START + 4 * slot_offset64[slot]));
-    case 128:
-      return dr_write32(index,
-          lq(reg, 0, (uint16_t) DEBUG_RAM_START + 4 * slot_offset128[slot]));
-    default:
-      fprintf(stderr, "xlen is %d!\n", xlen);
-      abort();
-  }
-}
-
-uint32_t gdbserver_t::dr_read32(unsigned int index)
-{
-  uint32_t value = sim->debug_module.ram_read32(index);
-  D(fprintf(stderr, "read32(%d) -> 0x%x\n", index, value));
-  return value;
-}
-
-uint64_t gdbserver_t::dr_read64(unsigned int index)
-{
-  return ((uint64_t) dr_read32(index+1) << 32) | dr_read32(index);
-}
-
-uint64_t gdbserver_t::dr_read(enum slot slot)
-{
-  switch (xlen) {
-    case 32:
-      return dr_read32(slot_offset32[slot]);
-    case 64:
-      return dr_read64(slot_offset64[slot]);
-    case 128:
-      abort();
-    default:
-      abort();
-  }
-}
-
-void gdbserver_t::add_operation(operation_t* operation)
-{
-  operation_queue.push(operation);
-}
-
-void gdbserver_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);
-
-    expect_ack = false;
-    extended_mode = false;
-
-    // gdb wants the core to be halted when it attaches.
-    add_operation(new halt_op_t(*this));
-  }
-}
-
-void gdbserver_t::read()
-{
-  // Reading from a non-blocking socket still blocks if there is no data
-  // available.
-
-  size_t count = recv_buf.contiguous_empty_size();
-  ssize_t bytes = ::read(client_fd, recv_buf.contiguous_empty(), count);
-  if (bytes == -1) {
-    if (errno == EAGAIN) {
-      // We'll try again the next call.
-    } else {
-      fprintf(stderr, "failed to read on socket: %s (%d)\n", strerror(errno), errno);
-      abort();
-    }
-  } else if (bytes == 0) {
-    // The remote disconnected.
-    client_fd = 0;
-    processor_t *p = sim->get_core(0);
-    // TODO p->set_halted(false, HR_NONE);
-    recv_buf.reset();
-    send_buf.reset();
-  } else {
-    recv_buf.data_added(bytes);
-  }
-}
-
-void gdbserver_t::write()
-{
-  if (send_buf.empty())
-    return;
-
-  while (!send_buf.empty()) {
-    unsigned int count = send_buf.contiguous_data_size();
-    assert(count > 0);
-    ssize_t bytes = ::write(client_fd, send_buf.contiguous_data(), count);
-    if (bytes == -1) {
-      fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno);
-      abort();
-    } else if (bytes == 0) {
-      // Client can't take any more data right now.
-      break;
-    } else {
-      D(fprintf(stderr, "wrote %zd bytes: ", bytes));
-      for (int i = 0; i < bytes; i++) {
-        D(fprintf(stderr, "%c", send_buf[i]));
-      }
-      D(fprintf(stderr, "\n"));
-      send_buf.consume(bytes);
-    }
-  }
-}
-
-void print_packet(const std::vector<uint8_t> &packet)
-{
-  for (uint8_t c : packet) {
-    if (c >= ' ' and c <= '~')
-      fprintf(stderr, "%c", c);
-    else
-      fprintf(stderr, "\\x%02x", c);
-  }
-  fprintf(stderr, "\n");
-}
-
-uint8_t compute_checksum(const std::vector<uint8_t> &packet)
-{
-  uint8_t checksum = 0;
-  for (auto i = packet.begin() + 1; i != packet.end() - 3; i++ ) {
-    checksum += *i;
-  }
-  return checksum;
-}
-
-uint8_t character_hex_value(uint8_t character)
-{
-  if (character >= '0' && character <= '9')
-    return character - '0';
-  if (character >= 'a' && character <= 'f')
-    return 10 + character - 'a';
-  if (character >= 'A' && character <= 'F')
-    return 10 + character - 'A';
-  return 0xff;
-}
-
-uint8_t extract_checksum(const std::vector<uint8_t> &packet)
-{
-  return character_hex_value(*(packet.end() - 1)) +
-    16 * character_hex_value(*(packet.end() - 2));
-}
-
-void gdbserver_t::process_requests()
-{
-  // See https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html
-
-  while (!recv_buf.empty()) {
-    std::vector<uint8_t> packet;
-    for (unsigned int i = 0; i < recv_buf.size(); i++) {
-      uint8_t b = recv_buf[i];
-
-      if (packet.empty() && expect_ack && b == '+') {
-        recv_buf.consume(1);
-        break;
-      }
-
-      if (packet.empty() && b == 3) {
-        D(fprintf(stderr, "Received interrupt\n"));
-        recv_buf.consume(1);
-        handle_interrupt();
-        break;
-      }
-
-      if (b == '$') {
-        // Start of new packet.
-        if (!packet.empty()) {
-          fprintf(stderr, "Received malformed %zd-byte packet from debug client: ",
-              packet.size());
-          print_packet(packet);
-          recv_buf.consume(i);
-          break;
-        }
-      }
-
-      packet.push_back(b);
-
-      // Packets consist of $<packet-data>#<checksum>
-      // where <checksum> is 
-      if (packet.size() >= 4 &&
-          packet[packet.size()-3] == '#') {
-        handle_packet(packet);
-        recv_buf.consume(i+1);
-        break;
-      }
-    }
-    // There's a partial packet in the buffer. Wait until we get more data to
-    // process it.
-    if (packet.size()) {
-      break;
-    }
-  }
-
-  if (recv_buf.full()) {
-    fprintf(stderr,
-        "Receive buffer is full, but no complete packet was found!\n");
-    for (unsigned line = 0; line < 8; line++) {
-      for (unsigned i = 0; i < 16; i++) {
-        fprintf(stderr, "%02x ", recv_buf.entry(line * 16 + i));
-      }
-      for (unsigned i = 0; i < 16; i++) {
-        uint8_t e = recv_buf.entry(line * 16 + i);
-        if (e >= ' ' && e <= '~')
-          fprintf(stderr, "%c", e);
-        else
-          fprintf(stderr, ".");
-      }
-      fprintf(stderr, "\n");
-    }
-    assert(!recv_buf.full());
-  }
-}
-
-void gdbserver_t::handle_halt_reason(const std::vector<uint8_t> &packet)
-{
-  send_packet("S00");
-}
-
-void gdbserver_t::handle_general_registers_read(const std::vector<uint8_t> &packet)
-{
-  add_operation(new general_registers_read_op_t(*this));
-}
-
-void gdbserver_t::set_interrupt(uint32_t hartid) {
-  sim->debug_module.set_interrupt(hartid);
-}
-
-// First byte is the most-significant one.
-// Eg. "08675309" becomes 0x08675309.
-uint64_t consume_hex_number(std::vector<uint8_t>::const_iterator &iter,
-    std::vector<uint8_t>::const_iterator end)
-{
-  uint64_t value = 0;
-
-  while (iter != end) {
-    uint8_t c = *iter;
-    uint64_t c_value = character_hex_value(c);
-    if (c_value > 15)
-      break;
-    iter++;
-    value <<= 4;
-    value += c_value;
-  }
-  return value;
-}
-
-// First byte is the least-significant one.
-// Eg. "08675309" becomes 0x09536708
-uint64_t gdbserver_t::consume_hex_number_le(
-    std::vector<uint8_t>::const_iterator &iter,
-    std::vector<uint8_t>::const_iterator end)
-{
-  uint64_t value = 0;
-  unsigned int shift = 4;
-
-  while (iter != end) {
-    uint8_t c = *iter;
-    uint64_t c_value = character_hex_value(c);
-    if (c_value > 15)
-      break;
-    iter++;
-    value |= c_value << shift;
-    if ((shift % 8) == 0)
-      shift += 12;
-    else
-      shift -= 4;
-  }
-  if (shift > (xlen+4)) {
-    fprintf(stderr,
-        "gdb sent too many data bytes. That means it thinks XLEN is greater "
-        "than %d.\nTo fix that, tell gdb: set arch riscv:rv%d\n",
-        xlen, xlen);
-  }
-  return value;
-}
-
-void consume_string(std::string &str, std::vector<uint8_t>::const_iterator &iter,
-    std::vector<uint8_t>::const_iterator end, uint8_t separator)
-{
-  while (iter != end && *iter != separator) {
-    str.append(1, (char) *iter);
-    iter++;
-  }
-}
-
-void gdbserver_t::handle_register_read(const std::vector<uint8_t> &packet)
-{
-  // p n
-
-  std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
-  unsigned int n = consume_hex_number(iter, packet.end());
-  if (*iter != '#')
-    return send_packet("E01");
-
-  add_operation(new register_read_op_t(*this, n));
-}
-
-void gdbserver_t::handle_register_write(const std::vector<uint8_t> &packet)
-{
-  // P n...=r...
-
-  std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
-  unsigned int n = consume_hex_number(iter, packet.end());
-  if (*iter != '=')
-    return send_packet("E05");
-  iter++;
-
-  reg_t value = consume_hex_number_le(iter, packet.end());
-  if (*iter != '#')
-    return send_packet("E06");
-
-  processor_t *p = sim->get_core(0);
-
-  add_operation(new register_write_op_t(*this, n, value));
-}
-
-void gdbserver_t::handle_memory_read(const std::vector<uint8_t> &packet)
-{
-  // m addr,length
-  std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
-  reg_t address = consume_hex_number(iter, packet.end());
-  if (*iter != ',')
-    return send_packet("E10");
-  iter++;
-  reg_t length = consume_hex_number(iter, packet.end());
-  if (*iter != '#')
-    return send_packet("E11");
-
-  add_operation(new collect_translation_info_op_t(*this, address, length));
-  add_operation(new memory_read_op_t(*this, address, length));
-}
-
-void gdbserver_t::handle_memory_binary_write(const std::vector<uint8_t> &packet)
-{
-  // X addr,length:XX...
-  std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
-  reg_t address = consume_hex_number(iter, packet.end());
-  if (*iter != ',')
-    return send_packet("E20");
-  iter++;
-  reg_t length = consume_hex_number(iter, packet.end());
-  if (*iter != ':')
-    return send_packet("E21");
-  iter++;
-
-  if (length == 0) {
-    return send_packet("OK");
-  }
-
-  unsigned char *data = new unsigned char[length];
-  for (unsigned int i = 0; i < length; i++) {
-    if (iter == packet.end()) {
-      return send_packet("E22");
-    }
-    uint8_t c = *iter;
-    iter++;
-    if (c == '}') {
-      // The binary data representation uses 7d (ascii â€˜}’) as an escape
-      // character. Any escaped byte is transmitted as the escape character
-      // followed by the original character XORed with 0x20. For example, the
-      // byte 0x7d would be transmitted as the two bytes 0x7d 0x5d. The bytes
-      // 0x23 (ascii â€˜#’), 0x24 (ascii â€˜$’), and 0x7d (ascii â€˜}’) must always
-      // be escaped.
-      if (iter == packet.end()) {
-        return send_packet("E23");
-      }
-      c = (*iter) ^ 0x20;
-      iter++;
-    }
-    data[i] = c;
-  }
-  if (*iter != '#')
-    return send_packet("E4b"); // EOVERFLOW
-
-  add_operation(new collect_translation_info_op_t(*this, address, length));
-  add_operation(new memory_write_op_t(*this, address, length, data));
-}
-
-void gdbserver_t::handle_continue(const std::vector<uint8_t> &packet)
-{
-  // c [addr]
-  processor_t *p = sim->get_core(0);
-  if (packet[2] != '#') {
-    std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
-    dpc = consume_hex_number(iter, packet.end());
-    if (*iter != '#')
-      return send_packet("E30");
-  }
-
-  add_operation(new maybe_restore_tselect_op_t(*this));
-  add_operation(new maybe_restore_mstatus_op_t(*this));
-  add_operation(new continue_op_t(*this, false));
-}
-
-void gdbserver_t::handle_step(const std::vector<uint8_t> &packet)
-{
-  // s [addr]
-  if (packet[2] != '#') {
-    std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
-    die("handle_step");
-    //p->state.pc = consume_hex_number(iter, packet.end());
-    if (*iter != '#')
-      return send_packet("E40");
-  }
-
-  add_operation(new maybe_restore_tselect_op_t(*this));
-  add_operation(new continue_op_t(*this, true));
-}
-
-void gdbserver_t::handle_kill(const std::vector<uint8_t> &packet)
-{
-  // k
-  // The exact effect of this packet is not specified.
-  // Looks like OpenOCD disconnects?
-  // TODO
-}
-
-void gdbserver_t::handle_extended(const std::vector<uint8_t> &packet)
-{
-  // Enable extended mode. In extended mode, the remote server is made
-  // persistent. The â€˜R’ packet is used to restart the program being debugged.
-  send_packet("OK");
-  extended_mode = true;
-}
-
-void gdbserver_t::software_breakpoint_insert(reg_t vaddr, unsigned int size)
-{
-  fence_i_required = true;
-  add_operation(new collect_translation_info_op_t(*this, vaddr, size));
-  unsigned char* inst = new unsigned char[4];
-  if (size == 2) {
-    inst[0] = MATCH_C_EBREAK & 0xff;
-    inst[1] = (MATCH_C_EBREAK >> 8) & 0xff;
-  } else {
-    inst[0] = MATCH_EBREAK & 0xff;
-    inst[1] = (MATCH_EBREAK >> 8) & 0xff;
-    inst[2] = (MATCH_EBREAK >> 16) & 0xff;
-    inst[3] = (MATCH_EBREAK >> 24) & 0xff;
-  }
-
-  software_breakpoint_t bp = {
-    .vaddr = vaddr,
-    .size = size
-  };
-  software_breakpoints[vaddr] = bp;
-  add_operation(new memory_read_op_t(*this, bp.vaddr, bp.size,
-        software_breakpoints[bp.vaddr].instruction));
-  add_operation(new memory_write_op_t(*this, bp.vaddr, bp.size, inst));
-}
-
-void gdbserver_t::software_breakpoint_remove(reg_t vaddr, unsigned int size)
-{
-  fence_i_required = true;
-  add_operation(new collect_translation_info_op_t(*this, vaddr, size));
-
-  software_breakpoint_t found_bp = software_breakpoints[vaddr];
-  unsigned char* instruction = new unsigned char[4];
-  memcpy(instruction, found_bp.instruction, 4);
-  add_operation(new memory_write_op_t(*this, found_bp.vaddr,
-        found_bp.size, instruction));
-  software_breakpoints.erase(vaddr);
-}
-
-void gdbserver_t::hardware_breakpoint_insert(const hardware_breakpoint_t &bp)
-{
-  add_operation(new maybe_save_tselect_op_t(*this));
-  add_operation(new hardware_breakpoint_insert_op_t(*this, bp));
-}
-
-void gdbserver_t::hardware_breakpoint_remove(const hardware_breakpoint_t &bp)
-{
-  add_operation(new maybe_save_tselect_op_t(*this));
-  hardware_breakpoint_t found = *hardware_breakpoints.find(bp);
-  add_operation(new hardware_breakpoint_remove_op_t(*this, found));
-}
-
-void gdbserver_t::handle_breakpoint(const std::vector<uint8_t> &packet)
-{
-  // insert: Z type,addr,length
-  // remove: z type,addr,length
-
-  // type: 0 - software breakpoint, 1 - hardware breakpoint, 2 - write
-  // watchpoint, 3 - read watchpoint, 4 - access watchpoint; addr is address;
-  // length is in bytes. For a software breakpoint, length specifies the size
-  // of the instruction to be patched. For hardware breakpoints and watchpoints
-  // length specifies the memory region to be monitored. To avoid potential
-  // problems with duplicate packets, the operations should be implemented in
-  // an idempotent way.
-
-  bool insert = (packet[1] == 'Z');
-  std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
-  gdb_breakpoint_type_t type = static_cast<gdb_breakpoint_type_t>(
-      consume_hex_number(iter, packet.end()));
-  if (*iter != ',')
-    return send_packet("E50");
-  iter++;
-  reg_t address = consume_hex_number(iter, packet.end());
-  if (*iter != ',')
-    return send_packet("E51");
-  iter++;
-  unsigned int size = consume_hex_number(iter, packet.end());
-  // There may be more options after a ; here, but we don't support that.
-  if (*iter != '#')
-    return send_packet("E52");
-
-  switch (type) {
-    case GB_SOFTWARE:
-      if (size != 2 && size != 4) {
-        return send_packet("E53");
-      }
-      if (insert) {
-        software_breakpoint_insert(address, size);
-      } else {
-        software_breakpoint_remove(address, size);
-      }
-      break;
-
-    case GB_HARDWARE:
-    case GB_WRITE:
-    case GB_READ:
-    case GB_ACCESS:
-      {
-        hardware_breakpoint_t bp = {
-          .vaddr = address,
-          .size = size
-        };
-        bp.load = (type == GB_READ || type == GB_ACCESS);
-        bp.store = (type == GB_WRITE || type == GB_ACCESS);
-        bp.execute = (type == GB_HARDWARE || type == GB_ACCESS);
-        if (insert) {
-          hardware_breakpoint_insert(bp);
-          // Insert might fail if there's no space, so the insert operation will
-          // send its own OK (or not).
-          return;
-        } else {
-          hardware_breakpoint_remove(bp);
-        }
-      }
-      break;
-
-    default:
-      return send_packet("E56");
-  }
-
-  return send_packet("OK");
-}
-
-void gdbserver_t::handle_query(const std::vector<uint8_t> &packet)
-{
-  std::string name;
-  std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
-
-  consume_string(name, iter, packet.end(), ':');
-  if (iter != packet.end())
-    iter++;
-  if (name == "Supported") {
-    start_packet();
-    while (iter != packet.end()) {
-      std::string feature;
-      consume_string(feature, iter, packet.end(), ';');
-      if (iter != packet.end())
-        iter++;
-      if (feature == "swbreak+") {
-        send("swbreak+;");
-      }
-    }
-    send("PacketSize=131072;");
-    return end_packet();
-  }
-
-  D(fprintf(stderr, "Unsupported query %s\n", name.c_str()));
-  return send_packet("");
-}
-
-void gdbserver_t::handle_packet(const std::vector<uint8_t> &packet)
-{
-  if (compute_checksum(packet) != extract_checksum(packet)) {
-    fprintf(stderr, "Received %zd-byte packet with invalid checksum\n", packet.size());
-    fprintf(stderr, "Computed checksum: %x\n", compute_checksum(packet));
-    print_packet(packet);
-    send("-");
-    return;
-  }
-
-  D(fprintf(stderr, "Received %zd-byte packet from debug client: ", packet.size()));
-  D(print_packet(packet));
-  send("+");
-
-  switch (packet[1]) {
-    case '!':
-      return handle_extended(packet);
-    case '?':
-      return handle_halt_reason(packet);
-    case 'g':
-      return handle_general_registers_read(packet);
-//    case 'k':
-//      return handle_kill(packet);
-    case 'm':
-      return handle_memory_read(packet);
-//    case 'M':
-//      return handle_memory_write(packet);
-    case 'X':
-      return handle_memory_binary_write(packet);
-    case 'p':
-      return handle_register_read(packet);
-    case 'P':
-      return handle_register_write(packet);
-    case 'c':
-      return handle_continue(packet);
-    case 's':
-      return handle_step(packet);
-    case 'z':
-    case 'Z':
-      return handle_breakpoint(packet);
-    case 'q':
-    case 'Q':
-      return handle_query(packet);
-  }
-
-  // Not supported.
-  D(fprintf(stderr, "** Unsupported packet: "));
-  D(print_packet(packet));
-  send_packet("");
-}
-
-void gdbserver_t::handle_interrupt()
-{
-  processor_t *p = sim->get_core(0);
-  add_operation(new halt_op_t(*this, true));
-}
-
-void gdbserver_t::handle()
-{
-  if (client_fd > 0) {
-    processor_t *p = sim->get_core(0);
-
-    bool interrupt = sim->debug_module.get_interrupt(0);
-
-    if (!interrupt && !operation_queue.empty()) {
-      operation_t *operation = operation_queue.front();
-      if (operation->step()) {
-        operation_queue.pop();
-        delete operation;
-      }
-    }
-
-    bool halt_notification = sim->debug_module.get_halt_notification(0);
-    if (halt_notification) {
-      sim->debug_module.clear_halt_notification(0);
-      add_operation(new halt_op_t(*this, true));
-    }
-
-    this->read();
-    this->write();
-
-  } else {
-    this->accept();
-  }
-
-  if (operation_queue.empty()) {
-    this->process_requests();
-  }
-}
-
-void gdbserver_t::send(const char* msg)
-{
-  unsigned int length = strlen(msg);
-  for (const char *c = msg; *c; c++)
-    running_checksum += *c;
-  send_buf.append((const uint8_t *) msg, length);
-}
-
-void gdbserver_t::send(uint64_t value)
-{
-  char buffer[3];
-  for (unsigned int i = 0; i < 8; i++) {
-    sprintf(buffer, "%02x", (int) (value & 0xff));
-    send(buffer);
-    value >>= 8;
-  }
-}
-
-void gdbserver_t::send(uint32_t value)
-{
-  char buffer[3];
-  for (unsigned int i = 0; i < 4; i++) {
-    sprintf(buffer, "%02x", (int) (value & 0xff));
-    send(buffer);
-    value >>= 8;
-  }
-}
-
-void gdbserver_t::send(uint8_t value)
-{
-  char buffer[3];
-  sprintf(buffer, "%02x", (int) value);
-  send(buffer);
-}
-
-void gdbserver_t::send_packet(const char* data)
-{
-  start_packet();
-  send(data);
-  end_packet();
-  expect_ack = true;
-}
-
-void gdbserver_t::start_packet()
-{
-  send("$");
-  running_checksum = 0;
-}
-
-void gdbserver_t::end_packet(const char* data)
-{
-  if (data) {
-    send(data);
-  }
-
-  char checksum_string[4];
-  sprintf(checksum_string, "#%02x", running_checksum);
-  send(checksum_string);
-  expect_ack = true;
-}
diff --git a/riscv/gdbserver.h b/riscv/gdbserver.h
deleted file mode 100644 (file)
index 79748b1..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-#ifndef _RISCV_GDBSERVER_H
-#define _RISCV_GDBSERVER_H
-
-#include <map>
-#include <queue>
-
-#include <stdint.h>
-
-class sim_t;
-
-template <typename T>
-class circular_buffer_t
-{
-public:
-  // The buffer can store capacity-1 data elements.
-  circular_buffer_t(unsigned int capacity) : data(new T[capacity]),
-      start(0), end(0), capacity(capacity) {}
-  circular_buffer_t() : start(0), end(0), capacity(0) {}
-  ~circular_buffer_t() { delete[] data; }
-
-  T *data;
-  unsigned int start;   // Data start, inclusive.
-  unsigned int end;     // Data end, exclusive.
-  unsigned int capacity;    // Size of the buffer.
-  unsigned int size() const;
-  bool empty() const { return start == end; }
-  bool full() const { return ((end+1) % capacity) == start; }
-  T entry(unsigned index) { return data[(start + index) % capacity]; }
-
-  // Return size and address of the block of RAM where more data can be copied
-  // to be added to the buffer.
-  unsigned int contiguous_empty_size() const;
-  T *contiguous_empty() { return data + end; }
-  void data_added(unsigned int bytes);
-
-  unsigned int contiguous_data_size() const;
-  T *contiguous_data() { return data + start; }
-  // Tell the buffer that some bytes were consumed from the start of the
-  // buffer.
-  void consume(unsigned int bytes);
-
-  void reset();
-
-  T operator[](unsigned int i) const { return data[(start + i) % capacity]; }
-
-  void append(const T *src, unsigned int count);
-};
-
-// Class to track software breakpoints that we set.
-class software_breakpoint_t
-{
-  public:
-    reg_t vaddr;
-    unsigned int size;
-    unsigned char instruction[4];
-};
-
-class hardware_breakpoint_t
-{
-  public:
-    reg_t vaddr;
-    unsigned int size;
-    unsigned int index;
-    bool load, store, execute;
-};
-
-struct hardware_breakpoint_compare_t {
-  bool operator()(const hardware_breakpoint_t& a, const hardware_breakpoint_t& b) const {
-    if (a.vaddr != b.vaddr)
-      return a.vaddr < b.vaddr;
-    return a.size < b.size;
-  }
-};
-
-class gdbserver_t;
-
-class operation_t
-{
-  public:
-    operation_t(gdbserver_t& gdbserver) : gs(gdbserver), current_step(0) {}
-    virtual ~operation_t() {}
-
-    bool step() {
-      bool result = perform_step(current_step);
-      current_step++;
-      return result;
-    }
-
-    // Perform the next step of this operation (which is probably to write to
-    // Debug RAM and assert the debug interrupt).
-    // Return true if this operation is complete. In that case the object will
-    // be deleted.
-    // Return false if more steps are required the next time the debug
-    // interrupt is clear.
-    virtual bool perform_step(unsigned int step) = 0;
-
-  protected:
-    gdbserver_t& gs;
-    unsigned int current_step;
-};
-
-/*
- * word 32      64      128
- * 0    inst/0  inst/0  inst/0
- * 1    inst    inst/0  inst/0
- * 2    inst    inst    inst/0
- * 3    inst    inst    inst/0
- * 4    data0   data0   data0
- * 5    data1   data0   data0
- * 6    data2   data1   data0
- * 7            data1   data0
- * 8            data2   data1
- * 9            data2   data1
- * 10                   data1
- * 11                   data1
- * 12                   data2
- * 13                   data2
- * 14                   data2
- * 15                   data2
- */
-enum slot {
-  SLOT_INST0,
-  SLOT_DATA0,
-  SLOT_DATA1,
-  SLOT_DATA_LAST,
-};
-
-static const unsigned int slot_offset32[] = {0, 4, 5, DEBUG_RAM_SIZE/4 - 1};
-static const unsigned int slot_offset64[] = {0, 4, 6, DEBUG_RAM_SIZE/4 - 2};
-static const unsigned int slot_offset128[] = {0, 4, 8, DEBUG_RAM_SIZE/4 - 4};
-
-typedef enum {
-  GB_SOFTWARE = 0,
-  GB_HARDWARE = 1,
-  GB_WRITE = 2,
-  GB_READ = 3,
-  GB_ACCESS = 4,
-} gdb_breakpoint_type_t;
-
-class gdbserver_t
-{
-public:
-  // Create a new server, listening for connections from localhost on the given
-  // port.
-  gdbserver_t(uint16_t port, sim_t *sim);
-
-  // Process all pending messages from a client.
-  void handle();
-
-  void handle_packet(const std::vector<uint8_t> &packet);
-  void handle_interrupt();
-
-  void software_breakpoint_remove(reg_t vaddr, unsigned int size);
-  void software_breakpoint_insert(reg_t vaddr, unsigned int size);
-  void hardware_breakpoint_remove(const hardware_breakpoint_t &bp);
-  void hardware_breakpoint_insert(const hardware_breakpoint_t &bp);
-
-  void handle_breakpoint(const std::vector<uint8_t> &packet);
-  void handle_continue(const std::vector<uint8_t> &packet);
-  void handle_extended(const std::vector<uint8_t> &packet);
-  void handle_general_registers_read(const std::vector<uint8_t> &packet);
-  void continue_general_registers_read();
-  void handle_halt_reason(const std::vector<uint8_t> &packet);
-  void handle_kill(const std::vector<uint8_t> &packet);
-  void handle_memory_binary_write(const std::vector<uint8_t> &packet);
-  void handle_memory_read(const std::vector<uint8_t> &packet);
-  void handle_query(const std::vector<uint8_t> &packet);
-  void handle_register_read(const std::vector<uint8_t> &packet);
-  void continue_register_read();
-  void handle_register_write(const std::vector<uint8_t> &packet);
-  void handle_step(const std::vector<uint8_t> &packet);
-
-  bool connected() const { return client_fd > 0; }
-
-  // TODO: Move this into its own packet sending class?
-  // Add the given message to send_buf.
-  void send(const char* msg);
-  // Hex-encode a 64-bit value, and send it to gcc in target byte order (little
-  // endian).
-  void send(uint64_t value);
-  // Hex-encode a 32-bit value, and send it to gcc in target byte order (little
-  // endian).
-  void send(uint32_t value);
-  // Hex-encode an 8-bit value, and send it to gcc.
-  void send(uint8_t value);
-  void send_packet(const char* data);
-  uint8_t running_checksum;
-  // Send "$" and clear running checksum.
-  void start_packet();
-  // Send "#" and checksum.
-  void end_packet(const char* data=NULL);
-
-  // Write value to the index'th word in Debug RAM.
-  void dr_write32(unsigned int index, uint32_t value);
-  void dr_write64(unsigned int index, uint64_t value);
-  void dr_write(enum slot slot, uint64_t value);
-  // Write jump-to-resume instruction to the index'th word in Debug RAM.
-  void dr_write_jump(unsigned int index);
-  // Write an xlen-bit store instruction.
-  void dr_write_store(unsigned int index, unsigned int reg, enum slot);
-  void dr_write_load(unsigned int index, unsigned int reg, enum slot);
-  uint32_t dr_read32(unsigned int index);
-  uint64_t dr_read64(unsigned int index);
-  uint64_t dr_read(enum slot slot);
-
-  uint64_t consume_hex_number_le(std::vector<uint8_t>::const_iterator &iter,
-      std::vector<uint8_t>::const_iterator end);
-
-  // Return access size to use when writing length bytes to address, so that
-  // every write will be aligned.
-  unsigned int find_access_size(reg_t address, int length);
-
-  void set_interrupt(uint32_t hartid);
-
-  // Members that ought to be privated, but that we'd really like to access
-  // from operation classes.
-  reg_t dpc;
-  reg_t dcsr;
-  reg_t mstatus;
-  bool mstatus_dirty;
-  reg_t sptbr;
-  bool sptbr_valid;
-  reg_t tselect;
-  bool tselect_valid;
-  bool fence_i_required;
-
-  std::map<reg_t, reg_t> pte_cache;
-
-  reg_t translate(reg_t vaddr);
-  // Return the PRV_x that is used when the code under debug performs a memory
-  // access.
-  unsigned int privilege_mode();
-  // Return the VM_x that is used when the code under debug performs a memory
-  // access.
-  unsigned int virtual_memory();
-
-  unsigned int xlen;
-
-  std::set<hardware_breakpoint_t, hardware_breakpoint_compare_t>
-    hardware_breakpoints;
-
-private:
-  sim_t *sim;
-  int socket_fd;
-  int client_fd;
-  circular_buffer_t<uint8_t> recv_buf;
-  circular_buffer_t<uint8_t> send_buf;
-
-  bool expect_ack;
-  bool extended_mode;
-  // Used to track whether we think the target is running. If we think it is
-  // but it isn't, we need to tell gdb about it.
-  bool running;
-
-  std::map<reg_t, software_breakpoint_t> software_breakpoints;
-
-  // Read pending data from the client.
-  void read();
-  void write();
-  // Accept a new client if there isn't one already connected.
-  void accept();
-  // Process all complete requests in recv_buf.
-  void process_requests();
-
-  std::queue<operation_t*> operation_queue;
-  void add_operation(operation_t* operation);
-};
-
-#endif
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 844686dd21d9a595a8c095463eb98fdc6b778a53..f9fd66b2f32ee651f97a76c89ba68da0bce1cc56 100644 (file)
@@ -1,3 +1,2 @@
 require_extension('C');
-require(insn.rvc_rd() != 0);
 WRITE_RD(insn.rvc_imm());
index 130aaed8f4c93bc9cc23b12909bb1a7db5e31d60..75d8eb892fa966dccc966690f3640e124d68ceda 100644 (file)
@@ -3,6 +3,6 @@ if (insn.rvc_rd() == 2) { // c.addi16sp
   require(insn.rvc_addi16sp_imm() != 0);
   WRITE_REG(X_SP, sext_xlen(RVC_SP + insn.rvc_addi16sp_imm()));
 } else {
-  require(insn.rvc_rd() != 0);
+  require(insn.rvc_imm() != 0);
   WRITE_RD(insn.rvc_imm() << 12);
 }
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 56c9c7a4e54a85c65e094d3146b8b490857aabbe..9c8e5b3983b470e5b85cce1f26b8e773bd8ee6e7 100644 (file)
@@ -1,6 +1,6 @@
 require_extension('D');
 require_fp;
-WRITE_FRD(f64_le_quiet(f64(FRS2), f64(FRS1)) || isNaNF64UI(FRS2) ? FRS1 : FRS2);
-if ((isNaNF64UI(FRS1) && isNaNF64UI(FRS2)) || softfloat_exceptionFlags)
-  WRITE_FRD(defaultNaNF64UI);
+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 bf90356b6748c68b22dfb1f5eb4f2b2e3a64f464..2f570ead5432c040bb29459c8f84efbd4ea00e60 100644 (file)
@@ -1,6 +1,6 @@
 require_extension('F');
 require_fp;
-WRITE_FRD(f32_le_quiet(f32(FRS2), f32(FRS1)) || isNaNF32UI(FRS2) ? FRS1 : FRS2);
-if ((isNaNF32UI(FRS1) && isNaNF32UI(FRS2)) || softfloat_exceptionFlags)
-  WRITE_FRD(defaultNaNF32UI);
+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 2a1755e30eb6db78cc1a43cb91e3796344545a82..cd40e159984ab7c7953bf82aeaf213bad47b06bf 100644 (file)
@@ -1,6 +1,6 @@
 require_extension('D');
 require_fp;
-WRITE_FRD(f64_lt_quiet(f64(FRS1), f64(FRS2)) || isNaNF64UI(FRS2) ? FRS1 : FRS2);
-if ((isNaNF64UI(FRS1) && isNaNF64UI(FRS2)) || softfloat_exceptionFlags)
-  WRITE_FRD(defaultNaNF64UI);
+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 831a7a255fed3fb8fd32083554a2255579221877..b813f45d7440cb638470e7b0f3a2e970156597bb 100644 (file)
@@ -1,6 +1,6 @@
 require_extension('F');
 require_fp;
-WRITE_FRD(f32_lt_quiet(f32(FRS1), f32(FRS2)) || isNaNF32UI(FRS2) ? FRS1 : FRS2);
-if ((isNaNF32UI(FRS1) && isNaNF32UI(FRS2)) || softfloat_exceptionFlags)
-  WRITE_FRD(defaultNaNF32UI);
+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));
diff --git a/riscv/insns/fmv_s_x.h b/riscv/insns/fmv_s_x.h
deleted file mode 100644 (file)
index 2daf6da..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-require_extension('F');
-require_fp;
-WRITE_FRD(zext32(RS1));
diff --git a/riscv/insns/fmv_w_x.h b/riscv/insns/fmv_w_x.h
new file mode 100644 (file)
index 0000000..5f71323
--- /dev/null
@@ -0,0 +1,3 @@
+require_extension('F');
+require_fp;
+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);
diff --git a/riscv/insns/fmv_x_s.h b/riscv/insns/fmv_x_s.h
deleted file mode 100644 (file)
index 1bee87f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-require_extension('F');
-require_fp;
-WRITE_RD(sext32(FRS1));
diff --git a/riscv/insns/fmv_x_w.h b/riscv/insns/fmv_x_w.h
new file mode 100644 (file)
index 0000000..b722479
--- /dev/null
@@ -0,0 +1,3 @@
+require_extension('F');
+require_fp;
+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 f3c441406c5cf7af22746c5eb21172660cb679eb..96933cf67262567c2e5cdf39ea73a4f9836d57cc 100644 (file)
@@ -2,7 +2,7 @@ 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_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);
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 b593198514115bbec7d1b3684f9a69d0edd81106..ae841de93f19cc1111761e545780947f4d95fb41 100644 (file)
@@ -1,8 +1,8 @@
-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_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);
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);
 
diff --git a/riscv/jtag_dtm.cc b/riscv/jtag_dtm.cc
new file mode 100644 (file)
index 0000000..cd3f3ee
--- /dev/null
@@ -0,0 +1,180 @@
+#include <stdio.h>
+
+#include "decode.h"
+#include "jtag_dtm.h"
+#include "debug_module.h"
+#include "debug_defines.h"
+
+#if 0
+#  define D(x) x
+#else
+#  define D(x)
+#endif
+
+enum {
+  IR_IDCODE=1,
+  IR_DTMCONTROL=0x10,
+  IR_DBUS=0x11
+};
+
+#define DTMCONTROL_VERSION      0xf
+#define DTMCONTROL_ABITS        (0x3f << 4)
+#define DTMCONTROL_DBUSSTAT     (3<<10)
+#define DTMCONTROL_IDLE         (7<<12)
+#define DTMCONTROL_DBUSRESET    (1<<16)
+
+#define DMI_OP                 3
+#define DMI_DATA               (0xffffffffL<<2)
+#define DMI_ADDRESS            ((1L<<(abits+34)) - (1L<<34))
+
+#define DMI_OP_STATUS_SUCCESS  0
+#define DMI_OP_STATUS_RESERVED 1
+#define DMI_OP_STATUS_FAILED   2
+#define DMI_OP_STATUS_BUSY     3
+
+#define DMI_OP_NOP             0
+#define DMI_OP_READ            1
+#define DMI_OP_WRITE           2
+#define DMI_OP_RESERVED                3
+
+jtag_dtm_t::jtag_dtm_t(debug_module_t *dm) :
+  dm(dm),
+  _tck(false), _tms(false), _tdi(false), _tdo(false),
+  dtmcontrol((abits << DTM_DTMCS_ABITS_OFFSET) | 1),
+  dmi(DMI_OP_STATUS_FAILED << DTM_DMI_OP_OFFSET),
+  _state(TEST_LOGIC_RESET)
+{
+}
+
+void jtag_dtm_t::reset() {
+  _state = TEST_LOGIC_RESET;
+}
+
+void jtag_dtm_t::set_pins(bool tck, bool tms, bool tdi) {
+  const jtag_state_t next[16][2] = {
+    /* TEST_LOGIC_RESET */    { RUN_TEST_IDLE, TEST_LOGIC_RESET },
+    /* RUN_TEST_IDLE */       { RUN_TEST_IDLE, SELECT_DR_SCAN },
+    /* SELECT_DR_SCAN */      { CAPTURE_DR, SELECT_IR_SCAN },
+    /* CAPTURE_DR */          { SHIFT_DR, EXIT1_DR },
+    /* SHIFT_DR */            { SHIFT_DR, EXIT1_DR },
+    /* EXIT1_DR */            { PAUSE_DR, UPDATE_DR },
+    /* PAUSE_DR */            { PAUSE_DR, EXIT2_DR },
+    /* EXIT2_DR */            { SHIFT_DR, UPDATE_DR },
+    /* UPDATE_DR */           { RUN_TEST_IDLE, SELECT_DR_SCAN },
+    /* SELECT_IR_SCAN */      { CAPTURE_IR, TEST_LOGIC_RESET },
+    /* CAPTURE_IR */          { SHIFT_IR, EXIT1_IR },
+    /* SHIFT_IR */            { SHIFT_IR, EXIT1_IR },
+    /* EXIT1_IR */            { PAUSE_IR, UPDATE_IR },
+    /* PAUSE_IR */            { PAUSE_IR, EXIT2_IR },
+    /* EXIT2_IR */            { SHIFT_IR, UPDATE_IR },
+    /* UPDATE_IR */           { RUN_TEST_IDLE, SELECT_DR_SCAN }
+  };
+
+  if (!_tck && tck) {
+    // Positive clock edge.
+
+    switch (_state) {
+      case SHIFT_DR:
+        dr >>= 1;
+        dr |= (uint64_t) _tdi << (dr_length-1);
+        break;
+      case SHIFT_IR:
+        ir >>= 1;
+        ir |= _tdi << (ir_length-1);
+        break;
+      default:
+        break;
+    }
+    _state = next[_state][_tms];
+    switch (_state) {
+      case TEST_LOGIC_RESET:
+        ir = IR_IDCODE;
+        break;
+      case CAPTURE_DR:
+        capture_dr();
+        break;
+      case SHIFT_DR:
+        _tdo = dr & 1;
+        break;
+      case UPDATE_DR:
+        update_dr();
+        break;
+      case CAPTURE_IR:
+        break;
+      case SHIFT_IR:
+        _tdo = ir & 1;
+        break;
+      case UPDATE_IR:
+        break;
+      default:
+        break;
+    }
+  }
+
+  D(fprintf(stderr, "state=%2d, tdi=%d, tdo=%d, tms=%d, tck=%d, ir=0x%02x, "
+        "dr=0x%lx\n",
+        _state, _tdi, _tdo, _tms, _tck, ir, dr));
+
+  _tck = tck;
+  _tms = tms;
+  _tdi = tdi;
+}
+
+void jtag_dtm_t::capture_dr()
+{
+  switch (ir) {
+    case IR_IDCODE:
+      dr = idcode;
+      dr_length = 32;
+      break;
+    case IR_DTMCONTROL:
+      dr = dtmcontrol;
+      dr_length = 32;
+      break;
+    case IR_DBUS:
+      dr = dmi;
+      dr_length = abits + 34;
+      break;
+    default:
+      D(fprintf(stderr, "Unsupported IR: 0x%x\n", ir));
+      break;
+  }
+  D(fprintf(stderr, "Capture DR; IR=0x%x, DR=0x%lx (%d bits)\n",
+        ir, dr, dr_length));
+}
+
+void jtag_dtm_t::update_dr()
+{
+  D(fprintf(stderr, "Update DR; IR=0x%x, DR=0x%lx (%d bits)\n",
+        ir, dr, dr_length));
+  switch (ir) {
+    case IR_DBUS:
+      {
+        unsigned op = get_field(dr, DMI_OP);
+        uint32_t data = get_field(dr, DMI_DATA);
+        unsigned address = get_field(dr, DMI_ADDRESS);
+
+        dmi = dr;
+
+        bool success = true;
+        if (op == DMI_OP_READ) {
+          uint32_t value;
+          if (dm->dmi_read(address, &value)) {
+            dmi = set_field(dmi, DMI_DATA, value);
+          } else {
+            success = false;
+          }
+        } else if (op == DMI_OP_WRITE) {
+          success = dm->dmi_write(address, data);
+        }
+
+        if (success) {
+          dmi = set_field(dmi, DMI_OP, DMI_OP_STATUS_SUCCESS);
+        } else {
+          dmi = set_field(dmi, DMI_OP, DMI_OP_STATUS_FAILED);
+        }
+        D(fprintf(stderr, "dmi=0x%lx\n", dmi));
+      }
+      break;
+  }
+}
diff --git a/riscv/jtag_dtm.h b/riscv/jtag_dtm.h
new file mode 100644 (file)
index 0000000..063e3f4
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef JTAG_DTM_H
+#define JTAG_DTM_H
+
+#include <stdint.h>
+
+class debug_module_t;
+
+typedef enum {
+  TEST_LOGIC_RESET,
+  RUN_TEST_IDLE,
+  SELECT_DR_SCAN,
+  CAPTURE_DR,
+  SHIFT_DR,
+  EXIT1_DR,
+  PAUSE_DR,
+  EXIT2_DR,
+  UPDATE_DR,
+  SELECT_IR_SCAN,
+  CAPTURE_IR,
+  SHIFT_IR,
+  EXIT1_IR,
+  PAUSE_IR,
+  EXIT2_IR,
+  UPDATE_IR
+} jtag_state_t;
+
+class jtag_dtm_t
+{
+  static const unsigned idcode = 0xdeadbeef;
+
+  public:
+    jtag_dtm_t(debug_module_t *dm);
+    void reset();
+
+    void set_pins(bool tck, bool tms, bool tdi);
+
+    bool tdo() const { return _tdo; }
+
+    jtag_state_t state() const { return _state; }
+
+  private:
+    debug_module_t *dm;
+    bool _tck, _tms, _tdi, _tdo;
+    uint32_t ir;
+    const unsigned ir_length = 5;
+    uint64_t dr;
+    unsigned dr_length;
+
+    // abits must come before dtmcontrol so it can easily be used in the
+    // constructor.
+    const unsigned abits = 6;
+    uint32_t dtmcontrol;
+    uint64_t dmi;
+
+    jtag_state_t _state;
+
+    void capture_dr();
+    void update_dr();
+};
+
+#endif
index 878d849d7ecaed30521bb8053a23389500743a2b..76a6ab1d4f685cf142a83d03a87f68847529e266 100644 (file)
@@ -43,33 +43,21 @@ 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));
 }
 
-const uint16_t* mmu_t::fetch_slow_path(reg_t vaddr)
+tlb_entry_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);
+  if (auto host_addr = sim->addr_to_mem(paddr)) {
+    return refill_tlb(vaddr, paddr, host_addr, FETCH);
   } else {
     if (!sim->mmio_load(paddr, sizeof fetch_temp, (uint8_t*)&fetch_temp))
       throw trap_instruction_access_fault(vaddr);
-    return &fetch_temp;
+    tlb_entry_t entry = {(char*)&fetch_temp - vaddr, paddr - vaddr};
+    return entry;
   }
 }
 
@@ -103,12 +91,12 @@ void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes)
 {
   reg_t paddr = translate(addr, LOAD);
 
-  if (sim->addr_is_mem(paddr)) {
-    memcpy(bytes, sim->addr_to_mem(paddr), len);
+  if (auto host_addr = sim->addr_to_mem(paddr)) {
+    memcpy(bytes, host_addr, len);
     if (tracer.interested_in_range(paddr, paddr + PGSIZE, LOAD))
       tracer.trace(paddr, len, LOAD);
     else
-      refill_tlb(addr, paddr, LOAD);
+      refill_tlb(addr, paddr, host_addr, LOAD);
   } else if (!sim->mmio_load(paddr, len, bytes)) {
     throw trap_load_access_fault(addr);
   }
@@ -132,18 +120,18 @@ void mmu_t::store_slow_path(reg_t addr, reg_t len, const uint8_t* bytes)
       throw *matched_trigger;
   }
 
-  if (sim->addr_is_mem(paddr)) {
-    memcpy(sim->addr_to_mem(paddr), bytes, len);
+  if (auto host_addr = sim->addr_to_mem(paddr)) {
+    memcpy(host_addr, bytes, len);
     if (tracer.interested_in_range(paddr, paddr + PGSIZE, STORE))
       tracer.trace(paddr, len, STORE);
     else
-      refill_tlb(addr, paddr, STORE);
+      refill_tlb(addr, paddr, host_addr, STORE);
   } else if (!sim->mmio_store(paddr, len, bytes)) {
     throw trap_store_access_fault(addr);
   }
 }
 
-void mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, access_type type)
+tlb_entry_t mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, char* host_addr, access_type type)
 {
   reg_t idx = (vaddr >> PGSHIFT) % TLB_ENTRIES;
   reg_t expected_tag = vaddr >> PGSHIFT;
@@ -164,48 +152,44 @@ void mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, access_type type)
   else if (type == STORE) tlb_store_tag[idx] = expected_tag;
   else tlb_load_tag[idx] = expected_tag;
 
-  tlb_data[idx] = sim->addr_to_mem(paddr) - vaddr;
+  tlb_entry_t entry = {host_addr - vaddr, paddr - vaddr};
+  tlb_data[idx] = entry;
+  return entry;
 }
 
 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;
-    if (!sim->addr_is_mem(pte_addr))
-      break;
+    auto ppte = sim->addr_to_mem(base + idx * vm.ptesize);
+    if (!ppte)
+      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;
@@ -213,9 +197,18 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode)
                type == LOAD ?  !(pte & PTE_R) && !(mxr && (pte & PTE_X)) :
                                !((pte & PTE_R) && (pte & PTE_W))) {
       break;
+    } else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) {
+      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 +216,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..f70a969be48eba4a148d25c8b9684d789bbb2cb3 100644 (file)
@@ -30,6 +30,11 @@ struct icache_entry_t {
   insn_fetch_t data;
 };
 
+struct tlb_entry_t {
+  char* host_offset;
+  reg_t target_offset;
+};
+
 class trigger_matched_t
 {
   public:
@@ -51,16 +56,38 @@ 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); \
+        return *(type##_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr); \
       if (unlikely(tlb_load_tag[vpn % TLB_ENTRIES] == (vpn | TLB_CHECK_TRIGGERS))) { \
-        type##_t data = *(type##_t*)(tlb_data[vpn % TLB_ENTRIES] + addr); \
+        type##_t data = *(type##_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr); \
         if (!matched_trigger) { \
           matched_trigger = trigger_exception(OPERATION_LOAD, addr, data); \
           if (matched_trigger) \
@@ -88,18 +115,18 @@ 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; \
+        *(type##_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr) = val; \
       else if (unlikely(tlb_store_tag[vpn % TLB_ENTRIES] == (vpn | TLB_CHECK_TRIGGERS))) { \
         if (!matched_trigger) { \
           matched_trigger = trigger_exception(OPERATION_STORE, addr, val); \
           if (matched_trigger) \
             throw *matched_trigger; \
         } \
-        *(type##_t*)(tlb_data[vpn % TLB_ENTRIES] + addr) = val; \
+        *(type##_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr) = val; \
       } \
       else \
         store_slow_path(addr, sizeof(type##_t), (const uint8_t*)&val); \
@@ -115,6 +142,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()); \
@@ -140,29 +170,29 @@ public:
 
   inline icache_entry_t* refill_icache(reg_t addr, icache_entry_t* entry)
   {
-    const uint16_t* iaddr = translate_insn_addr(addr);
-    insn_bits_t insn = *iaddr;
+    auto tlb_entry = translate_insn_addr(addr);
+    insn_bits_t insn = *(uint16_t*)(tlb_entry.host_offset + addr);
     int length = insn_length(insn);
 
     if (likely(length == 4)) {
-      insn |= (insn_bits_t)*(const int16_t*)translate_insn_addr(addr + 2) << 16;
+      insn |= (insn_bits_t)*(const int16_t*)translate_insn_addr_to_host(addr + 2) << 16;
     } else if (length == 2) {
       insn = (int16_t)insn;
     } else if (length == 6) {
-      insn |= (insn_bits_t)*(const int16_t*)translate_insn_addr(addr + 4) << 32;
-      insn |= (insn_bits_t)*(const uint16_t*)translate_insn_addr(addr + 2) << 16;
+      insn |= (insn_bits_t)*(const int16_t*)translate_insn_addr_to_host(addr + 4) << 32;
+      insn |= (insn_bits_t)*(const uint16_t*)translate_insn_addr_to_host(addr + 2) << 16;
     } else {
       static_assert(sizeof(insn_bits_t) == 8, "insn_bits_t must be uint64_t");
-      insn |= (insn_bits_t)*(const int16_t*)translate_insn_addr(addr + 6) << 48;
-      insn |= (insn_bits_t)*(const uint16_t*)translate_insn_addr(addr + 4) << 32;
-      insn |= (insn_bits_t)*(const uint16_t*)translate_insn_addr(addr + 2) << 16;
+      insn |= (insn_bits_t)*(const int16_t*)translate_insn_addr_to_host(addr + 6) << 48;
+      insn |= (insn_bits_t)*(const uint16_t*)translate_insn_addr_to_host(addr + 4) << 32;
+      insn |= (insn_bits_t)*(const uint16_t*)translate_insn_addr_to_host(addr + 2) << 16;
     }
 
     insn_fetch_t fetch = {proc->decode_insn(insn), insn};
     entry->tag = addr;
     entry->data = fetch;
 
-    reg_t paddr = sim->mem_to_addr((char*)iaddr);
+    reg_t paddr = tlb_entry.target_offset + addr;;
     if (tracer.interested_in_range(paddr, paddr + 1, FETCH)) {
       entry->tag = -1;
       tracer.trace(paddr, length, FETCH);
@@ -203,39 +233,43 @@ private:
   // If a TLB tag has TLB_CHECK_TRIGGERS set, then the MMU must check for a
   // trigger match before completing an access.
   static const reg_t TLB_CHECK_TRIGGERS = reg_t(1) << 63;
-  char* tlb_data[TLB_ENTRIES];
+  tlb_entry_t tlb_data[TLB_ENTRIES];
   reg_t tlb_insn_tag[TLB_ENTRIES];
   reg_t tlb_load_tag[TLB_ENTRIES];
   reg_t tlb_store_tag[TLB_ENTRIES];
 
   // finish translation on a TLB miss and update the TLB
-  void refill_tlb(reg_t vaddr, reg_t paddr, access_type type);
+  tlb_entry_t refill_tlb(reg_t vaddr, reg_t paddr, char* host_addr, access_type type);
   const char* fill_from_mmio(reg_t vaddr, reg_t paddr);
 
   // perform a page table walk for a given VA; set referenced/dirty bits
   reg_t walk(reg_t addr, access_type type, reg_t prv);
 
   // handle uncommon cases: TLB misses, page faults, MMIO
-  const uint16_t* fetch_slow_path(reg_t addr);
+  tlb_entry_t fetch_slow_path(reg_t addr);
   void load_slow_path(reg_t addr, reg_t len, uint8_t* bytes);
   void store_slow_path(reg_t addr, reg_t len, const uint8_t* bytes);
   reg_t translate(reg_t addr, access_type type);
 
   // ITLB lookup
-  inline const uint16_t* translate_insn_addr(reg_t addr) {
+  inline tlb_entry_t translate_insn_addr(reg_t addr) {
     reg_t vpn = addr >> PGSHIFT;
     if (likely(tlb_insn_tag[vpn % TLB_ENTRIES] == vpn))
-      return (uint16_t*)(tlb_data[vpn % TLB_ENTRIES] + addr);
+      return tlb_data[vpn % TLB_ENTRIES];
     if (unlikely(tlb_insn_tag[vpn % TLB_ENTRIES] == (vpn | TLB_CHECK_TRIGGERS))) {
-      uint16_t* ptr = (uint16_t*)(tlb_data[vpn % TLB_ENTRIES] + addr);
+      uint16_t* ptr = (uint16_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr);
       int match = proc->trigger_match(OPERATION_EXECUTE, addr, *ptr);
       if (match >= 0)
         throw trigger_matched_t(match, OPERATION_EXECUTE, addr, *ptr);
-      return ptr;
+      return tlb_data[vpn % TLB_ENTRIES];
     }
     return fetch_slow_path(addr);
   }
 
+  inline const uint16_t* translate_insn_addr_to_host(reg_t addr) {
+    return (uint16_t*)(translate_insn_addr(addr).host_offset + addr);
+  }
+
   inline trigger_matched_t *trigger_exception(trigger_operation_t operation,
       reg_t address, reg_t data)
   {
@@ -260,4 +294,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
diff --git a/riscv/opcodes.h b/riscv/opcodes.h
new file mode 100644 (file)
index 0000000..34c089e
--- /dev/null
@@ -0,0 +1,244 @@
+#include "encoding.h"
+
+#define ZERO   0
+#define T0      5
+#define S0      8
+#define S1      9
+
+static uint32_t bits(uint32_t value, unsigned int hi, unsigned int lo) {
+  return (value >> lo) & ((1 << (hi+1-lo)) - 1);
+}
+
+static uint32_t bit(uint32_t value, unsigned int b) {
+  return (value >> b) & 1;
+}
+
+static uint32_t jal(unsigned int rd, uint32_t imm) __attribute__ ((unused));
+static uint32_t jal(unsigned int rd, uint32_t imm) {
+  return (bit(imm, 20) << 31) |
+    (bits(imm, 10, 1) << 21) |
+    (bit(imm, 11) << 20) |
+    (bits(imm, 19, 12) << 12) |
+    (rd << 7) |
+    MATCH_JAL;
+}
+
+static uint32_t csrsi(unsigned int csr, uint16_t imm) __attribute__ ((unused));
+static uint32_t csrsi(unsigned int csr, uint16_t imm) {
+  return (csr << 20) |
+    (bits(imm, 4, 0) << 15) |
+    MATCH_CSRRSI;
+}
+
+static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 5) << 25) |
+    (src << 20) |
+    (base << 15) |
+    (bits(offset, 4, 0) << 7) |
+    MATCH_SW;
+}
+
+static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 5) << 25) |
+    (src << 20) |
+    (base << 15) |
+    (bits(offset, 4, 0) << 7) |
+    MATCH_SD;
+}
+
+static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 5) << 25) |
+    (src << 20) |
+    (base << 15) |
+    (bits(offset, 4, 0) << 7) |
+    MATCH_SH;
+}
+
+static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 5) << 25) |
+    (src << 20) |
+    (base << 15) |
+    (bits(offset, 4, 0) << 7) |
+    MATCH_SB;
+}
+
+static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 0) << 20) |
+    (base << 15) |
+    (bits(rd, 4, 0) << 7) |
+    MATCH_LD;
+}
+
+static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 0) << 20) |
+    (base << 15) |
+    (bits(rd, 4, 0) << 7) |
+    MATCH_LW;
+}
+
+static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 0) << 20) |
+    (base << 15) |
+    (bits(rd, 4, 0) << 7) |
+    MATCH_LH;
+}
+
+static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 0) << 20) |
+    (base << 15) |
+    (bits(rd, 4, 0) << 7) |
+    MATCH_LB;
+}
+
+static uint32_t csrw(unsigned int source, unsigned int csr) __attribute__ ((unused));
+static uint32_t csrw(unsigned int source, unsigned int csr) {
+  return (csr << 20) | (source << 15) | MATCH_CSRRW;
+}
+
+static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
+static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm)
+{
+  return (bits(imm, 11, 0) << 20) |
+    (src << 15) |
+    (dest << 7) |
+    MATCH_ADDI;
+}
+
+static uint32_t csrr(unsigned int rd, unsigned int csr) __attribute__ ((unused));
+static uint32_t csrr(unsigned int rd, unsigned int csr) {
+  return (csr << 20) | (rd << 7) | MATCH_CSRRS;
+}
+
+static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 5) << 25) |
+    (bits(src, 4, 0) << 20) |
+    (base << 15) |
+    (bits(offset, 4, 0) << 7) |
+    MATCH_FSW;
+}
+
+static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 5) << 25) |
+    (bits(src, 4, 0) << 20) |
+    (base << 15) |
+    (bits(offset, 4, 0) << 7) |
+    MATCH_FSD;
+}
+
+static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 0) << 20) |
+    (base << 15) |
+    (bits(dest, 4, 0) << 7) |
+    MATCH_FLW;
+}
+
+static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 0) << 20) |
+    (base << 15) |
+    (bits(dest, 4, 0) << 7) |
+    MATCH_FLD;
+}
+
+static uint32_t ebreak(void) __attribute__ ((unused));
+static uint32_t ebreak(void) { return MATCH_EBREAK; }
+static uint32_t ebreak_c(void) __attribute__ ((unused));
+static uint32_t ebreak_c(void) { return MATCH_C_EBREAK; }
+
+static uint32_t dret(void) __attribute__ ((unused));
+static uint32_t dret(void) { return MATCH_DRET; }
+
+static uint32_t fence_i(void) __attribute__ ((unused));
+static uint32_t fence_i(void)
+{
+  return MATCH_FENCE_I;
+}
+
+/*
+static uint32_t lui(unsigned int dest, uint32_t imm) __attribute__ ((unused));
+static uint32_t lui(unsigned int dest, uint32_t imm)
+{
+  return (bits(imm, 19, 0) << 12) |
+    (dest << 7) |
+    MATCH_LUI;
+}
+
+static uint32_t csrci(unsigned int csr, uint16_t imm) __attribute__ ((unused));
+static uint32_t csrci(unsigned int csr, uint16_t imm) {
+  return (csr << 20) |
+    (bits(imm, 4, 0) << 15) |
+    MATCH_CSRRCI;
+}
+
+static uint32_t li(unsigned int dest, uint16_t imm) __attribute__ ((unused));
+static uint32_t li(unsigned int dest, uint16_t imm)
+{
+       return addi(dest, 0, imm);
+}
+
+static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 5) << 25) |
+    (bits(src, 4, 0) << 20) |
+    (base << 15) |
+    (bits(offset, 4, 0) << 7) |
+    MATCH_FSD;
+}
+
+static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
+static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm)
+{
+  return (bits(imm, 11, 0) << 20) |
+    (src << 15) |
+    (dest << 7) |
+    MATCH_ORI;
+}
+
+static uint32_t nop(void) __attribute__ ((unused));
+static uint32_t nop(void)
+{
+  return addi(0, 0, 0);
+}
+*/
+
+static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
+static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm)
+{
+  return (bits(imm, 11, 0) << 20) |
+    (src << 15) |
+    (dest << 7) |
+    MATCH_XORI;
+}
+
+static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) __attribute__ ((unused));
+static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt)
+{
+       return (bits(shamt, 4, 0) << 20) |
+               (src << 15) |
+               (dest << 7) |
+               MATCH_SRLI;
+}
index 9a6a4e27648232c37fd1309cfb6464ea406c8cc1..1e3573df903e56fc9982bc729baba3a9640f6df1 100644 (file)
@@ -7,7 +7,6 @@
 #include "sim.h"
 #include "mmu.h"
 #include "disasm.h"
-#include "gdbserver.h"
 #include <cinttypes>
 #include <cmath>
 #include <cstdlib>
@@ -22,7 +21,8 @@
 
 processor_t::processor_t(const char* isa, sim_t* sim, uint32_t id,
         bool halt_on_reset)
-  : debug(false), sim(sim), ext(NULL), id(id), halt_on_reset(halt_on_reset)
+  : debug(false), halt_request(false), sim(sim), ext(NULL), id(id),
+  halt_on_reset(halt_on_reset)
 {
   parse_isa_string(isa);
   register_base_instructions();
@@ -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++)
@@ -172,12 +171,22 @@ void processor_t::take_interrupt(reg_t pending_interrupts)
 
   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)
     throw trap_t(((reg_t)1 << (max_xlen-1)) | ctz(enabled_interrupts));
 }
 
+static int xlen_to_uxl(int xlen)
+{
+  if (xlen == 32)
+    return 1;
+  if (xlen == 64)
+    return 2;
+  abort();
+}
+
 void processor_t::set_privilege(reg_t prv)
 {
   assert(prv <= PRV_M);
@@ -193,7 +202,7 @@ void processor_t::enter_debug_mode(uint8_t cause)
   state.dcsr.prv = state.prv;
   set_privilege(PRV_M);
   state.dpc = state.pc;
-  state.pc = DEBUG_ROM_START;
+  state.pc = debug_rom_entry();
 }
 
 void processor_t::take_trap(trap_t& t, reg_t epc)
@@ -206,6 +215,15 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
           t.get_badaddr());
   }
 
+  if (state.dcsr.cause) {
+    if (t.cause() == CAUSE_BREAKPOINT) {
+      state.pc = debug_rom_entry();
+    } else {
+      state.pc = DEBUG_ROM_TVEC;
+    }
+    return;
+  }
+
   if (t.cause() == CAUSE_BREAKPOINT && (
               (state.prv == PRV_M && state.dcsr.ebreakm) ||
               (state.prv == PRV_H && state.dcsr.ebreakh) ||
@@ -215,15 +233,11 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
     return;
   }
 
-  if (state.dcsr.cause) {
-    state.pc = DEBUG_ROM_EXCEPTION;
-    return;
-  }
-
   // 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
@@ -234,20 +248,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);
@@ -259,18 +274,23 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
 
 void processor_t::disasm(insn_t insn)
 {
+  static uint64_t last_pc = 1, last_bits;
+  static uint64_t executions = 1;
+
   uint64_t bits = insn.bits() & ((1ULL << (8 * insn_length(insn.bits()))) - 1);
-  fprintf(stderr, "core %3d: 0x%016" PRIx64 " (0x%08" PRIx64 ") %s\n",
-          id, state.pc, bits, disassembler->disassemble(insn).c_str());
-}
+  if (last_pc != state.pc || last_bits != bits) {
+    if (executions != 1) {
+      fprintf(stderr, "core %3d: Executed %" PRIx64 " times\n", id, executions);
+    }
 
-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;
+    fprintf(stderr, "core %3d: 0x%016" PRIx64 " (0x%08" PRIx64 ") %s\n",
+            id, state.pc, bits, disassembler->disassemble(insn).c_str());
+    last_pc = state.pc;
+    last_bits = bits;
+    executions = 1;
+  } else {
+    executions++;
+  }
 }
 
 int processor_t::paddr_bits()
@@ -301,15 +321,14 @@ 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 | MSTATUS_UXL | MSTATUS_SXL |
+                 (ext ? MSTATUS_XS : 0);
 
       state.mstatus = (state.mstatus & ~mask) | (val & mask);
 
@@ -320,8 +339,9 @@ void processor_t::set_csr(int which, reg_t val)
       else
         state.mstatus = set_field(state.mstatus, MSTATUS64_SD, dirty);
 
-      // spike supports the notion of xlen < max_xlen, but current priv spec
-      // doesn't provide a mechanism to run RV32 software on an RV64 machine
+      state.mstatus = set_field(state.mstatus, MSTATUS_UXL, xlen_to_uxl(max_xlen));
+      state.mstatus = set_field(state.mstatus, MSTATUS_SXL, xlen_to_uxl(max_xlen));
+      // U-XLEN == S-XLEN == M-XLEN
       xlen = max_xlen;
       break;
     }
@@ -355,15 +375,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: {
@@ -374,8 +394,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;
@@ -384,7 +409,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;
@@ -463,8 +488,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) {
@@ -475,7 +503,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;
@@ -510,11 +538,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 | SSTATUS_UXL;
       reg_t sstatus = state.mstatus & mask;
       if ((sstatus & SSTATUS_FS) == SSTATUS_FS ||
           (sstatus & SSTATUS_XS) == SSTATUS_XS)
@@ -530,7 +558,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;
@@ -584,19 +615,15 @@ reg_t processor_t::get_csr(int which)
       {
         uint32_t v = 0;
         v = set_field(v, DCSR_XDEBUGVER, 1);
-        v = set_field(v, DCSR_NDRESET, 0);
-        v = set_field(v, DCSR_FULLRESET, 0);
-        v = set_field(v, DCSR_PRV, state.dcsr.prv);
-        v = set_field(v, DCSR_STEP, state.dcsr.step);
-        v = set_field(v, DCSR_DEBUGINT, sim->debug_module.get_interrupt(id));
-        v = set_field(v, DCSR_STOPCYCLE, 0);
-        v = set_field(v, DCSR_STOPTIME, 0);
         v = set_field(v, DCSR_EBREAKM, state.dcsr.ebreakm);
         v = set_field(v, DCSR_EBREAKH, state.dcsr.ebreakh);
         v = set_field(v, DCSR_EBREAKS, state.dcsr.ebreaks);
         v = set_field(v, DCSR_EBREAKU, state.dcsr.ebreaku);
-        v = set_field(v, DCSR_HALT, state.dcsr.halt);
+        v = set_field(v, DCSR_STOPCYCLE, 0);
+        v = set_field(v, DCSR_STOPTIME, 0);
         v = set_field(v, DCSR_CAUSE, state.dcsr.cause);
+        v = set_field(v, DCSR_STEP, state.dcsr.step);
+        v = set_field(v, DCSR_PRV, state.dcsr.prv);
         return v;
       }
     case CSR_DPC:
@@ -604,12 +631,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)
@@ -692,6 +719,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;
 }
 
@@ -700,14 +738,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 0224f10dc9aaf3afcfec907f395b064644aa9e2a..071f4581f0e8091c6a92016cd8b6f824328843fa 100644 (file)
@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 #include <map>
+#include "debug_rom/debug_rom_defines.h"
 
 class processor_t;
 class mmu_t;
@@ -105,8 +106,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;
@@ -191,6 +192,14 @@ public:
   bool debug;
   // When true, take the slow simulation path.
   bool slow_path();
+  bool halted() { return state.dcsr.cause ? true : false; }
+  bool halt_request;
+  // The unique debug rom address that this hart jumps to when entering debug
+  // mode. Rely on the fact that spike hart IDs start at 0 and are consecutive.
+  uint32_t debug_rom_entry() {
+    fprintf(stderr, "Debug_rom_entry called for id %d = %x\n", id, DEBUG_ROM_ENTRY + 4*id);
+    return DEBUG_ROM_ENTRY + 4 * id;
+  }
 
   // Return the index of a trigger that matched, or -1.
   inline int trigger_match(trigger_operation_t operation, reg_t address, reg_t data)
@@ -306,7 +315,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);
diff --git a/riscv/remote_bitbang.cc b/riscv/remote_bitbang.cc
new file mode 100644 (file)
index 0000000..21306dd
--- /dev/null
@@ -0,0 +1,180 @@
+#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) {
+        break;
+      } else {
+        fprintf(stderr, "remote_bitbang failed to read on socket: %s (%d)\n",
+            strerror(errno), errno);
+        abort();
+      }
+    }
+
+    if (quit) {
+      fprintf(stderr, "Remote Bitbang received 'Q'\n");
+    }
+
+    if (recv_end == 0 || quit) {
+      // The remote disconnected.
+      fprintf(stderr, "Received nothing. Quitting.\n");
+      close(client_fd);
+      client_fd = 0;
+      break;
+    }
+  }
+}
diff --git a/riscv/remote_bitbang.h b/riscv/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
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 552187ab19d077a833c416aaf41c8638140b480f..05e316a438ad4dd68e1e9f2646328afc1d5c1758 100644 (file)
@@ -23,8 +23,9 @@ riscv_hdrs = \
        rocc.h \
        insn_template.h \
        mulhi.h \
-       gdbserver.h \
        debug_module.h \
+       remote_bitbang.h \
+       jtag_dtm.h \
 
 riscv_precompiled_hdrs = \
        insn_template.h \
@@ -44,9 +45,10 @@ riscv_srcs = \
        regnames.cc \
        devices.cc \
        rom.cc \
-       rtc.cc \
-       gdbserver.cc \
+       clint.cc \
        debug_module.cc \
+       remote_bitbang.cc \
+       jtag_dtm.cc \
        $(riscv_gen_srcs) \
 
 riscv_test_srcs =
@@ -180,9 +182,9 @@ riscv_insn_list = \
        fmul_d \
        fmul_s \
        fmv_d_x \
-       fmv_s_x \
+       fmv_w_x \
        fmv_x_d \
-       fmv_x_s \
+       fmv_x_w \
        fnmadd_d \
        fnmadd_s \
        fnmsub_d \
@@ -227,7 +229,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 b455105913531b40712627634f38dad243ef4a62..42d60a13266d6fcafa1503e952e54b4a1e641ecf 100644 (file)
@@ -2,7 +2,7 @@
 
 #include "sim.h"
 #include "mmu.h"
-#include "gdbserver.h"
+#include "remote_bitbang.h"
 #include <map>
 #include <iostream>
 #include <sstream>
@@ -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)
@@ -20,28 +23,19 @@ static void handle_signal(int sig)
   signal(sig, &handle_signal);
 }
 
-sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb, bool halted,
+sim_t::sim_t(const char* isa, size_t nprocs, bool halted, reg_t start_pc,
+             std::vector<std::pair<reg_t, mem_t*>> mems,
              const std::vector<std::string>& args)
-  : htif_t(args), procs(std::max(nprocs, size_t(1))),
-    current_step(0), current_proc(0), debug(false), gdbserver(NULL)
+  : htif_t(args), debug_module(this), mems(mems), procs(std::max(nprocs, size_t(1))),
+    start_pc(start_pc),
+    current_step(0), current_proc(0), debug(false), remote_bitbang(NULL)
 {
   signal(SIGINT, &handle_signal);
-  // allocate target machine's memory, shrinking it as necessary
-  // until the allocation succeeds
-  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;
 
-  memsz = memsz0;
-  while ((mem = (char*)calloc(1, memsz)) == NULL)
-    memsz = (size_t)(memsz*0.9)/quantum*quantum;
+  for (auto& x : mems)
+    bus.add_device(x.first, x.second);
 
-  if (memsz != memsz0)
-    fprintf(stderr, "warning: only got %zu bytes of target mem (wanted %zu)\n",
-            memsz, memsz0);
-
-  bus.add_device(DEBUG_START, &debug_module);
+  debug_module.add_device(&bus);
 
   debug_mmu = new mmu_t(this, NULL);
 
@@ -49,8 +43,8 @@ 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());
 }
 
 sim_t::~sim_t()
@@ -58,7 +52,6 @@ sim_t::~sim_t()
   for (size_t i = 0; i < procs.size(); i++)
     delete procs[i];
   delete debug_mmu;
-  free(mem);
 }
 
 void sim_thread_main(void* arg)
@@ -77,8 +70,8 @@ void sim_t::main()
       interactive();
     else
       step(INTERLEAVE);
-    if (gdbserver) {
-      gdbserver->handle();
+    if (remote_bitbang) {
+      remote_bitbang->tick();
     }
   }
 }
@@ -104,7 +97,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,66 +143,193 @@ 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()
+{
+  const int reset_vec_size = 8;
+
+  start_pc = start_pc == reg_t(-1) ? get_entry_point() : start_pc;
+  reg_t pc_delta = start_pc - DEFAULT_RSTVEC;
+  reg_t pc_delta_hi = (pc_delta + 0x800U) & ~reg_t(0xfffU);
+  reg_t pc_delta_lo = pc_delta - pc_delta_hi;
+  if ((pc_delta_hi >> 31) != 0 && (pc_delta_hi >> 31) != reg_t(-1) >> 31) {
+    fprintf(stderr, "initial pc %" PRIx64 " out of range\n", pc_delta);
+    abort();
+  }
+
+  uint32_t reset_vec[reset_vec_size] = {
+    0x297 + uint32_t(pc_delta_hi),              // auipc t0, &pc
+    0x597,                                      // auipc a1, &dtb
+    0x58593 + ((reset_vec_size - 1) * 4 << 20), // addi a1, a1, &dtb
+    0xf1402573,                                 // csrr a0, mhartid
+    0x28067 + uint32_t(pc_delta_lo << 20)       // jalr zero, t0, &pc
   };
-  reset_vec[3] = DEFAULT_RSTVEC + sizeof(reset_vec); // config string pointer
 
   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);
+  s <<   "  };\n";
+  for (auto& m : mems) {
+    s << std::hex <<
+         "  memory@" << m.first << " {\n"
+         "    device_type = \"memory\";\n"
+         "    reg = <0x" << (m.first >> 32) << " 0x" << (m.first & (uint32_t)-1) <<
+                   " 0x" << (m.second->size() >> 32) << " 0x" << (m.second->size() & (uint32_t)-1) << ">;\n"
+         "  };\n";
+  }
+  s <<   "  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());
 }
 
+char* sim_t::addr_to_mem(reg_t addr) {
+  auto desc = bus.find_device(addr);
+  if (auto mem = dynamic_cast<mem_t*>(desc.second))
+    if (addr - desc.first < mem->size())
+      return mem->contents() + (addr - desc.first);
+  return NULL;
+}
+
 // htif
 
+void sim_t::reset()
+{
+  make_dtb();
+}
+
 void sim_t::idle()
 {
   target.switch_to();
index 5d165c9793532f334f117eb8f5c7b71fffcabd15..9372cc1e2d3207d3015e3c43059e8054a9f13acf 100644 (file)
 #include <memory>
 
 class mmu_t;
-class gdbserver_t;
+class remote_bitbang_t;
 
 // this class encapsulates the processors and memory in a RISC-V machine.
 class sim_t : public htif_t
 {
 public:
-  sim_t(const char* isa, size_t _nprocs, size_t mem_mb, bool halted,
+  sim_t(const char* isa, size_t _nprocs,  bool halted, reg_t start_pc,
+        std::vector<std::pair<reg_t, mem_t*>> mems,
         const std::vector<std::string>& args);
   ~sim_t();
 
@@ -29,41 +30,42 @@ public:
   void set_log(bool value);
   void set_histogram(bool value);
   void set_procs_debug(bool value);
-  void set_gdbserver(gdbserver_t* gdbserver) { this->gdbserver = gdbserver; }
-  const char* get_config_string() { return config_string.c_str(); }
+  void set_remote_bitbang(remote_bitbang_t* remote_bitbang) {
+    this->remote_bitbang = remote_bitbang;
+  }
+  const char* get_dts() { if (dts.empty()) reset(); return dts.c_str(); }
   processor_t* get_core(size_t i) { return procs.at(i); }
+  unsigned nprocs() const { return procs.size(); }
+
+  debug_module_t debug_module;
 
 private:
-  char* mem; // main memory
-  size_t memsz; // memory size in bytes
+  std::vector<std::pair<reg_t, mem_t*>> mems;
   mmu_t* debug_mmu;  // debug port into main memory
   std::vector<processor_t*> procs;
-  std::string config_string;
+  reg_t start_pc;
+  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;
-  debug_module_t debug_module;
 
   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;
   bool log;
   bool histogram_enabled; // provide a histogram of PCs
-  gdbserver_t* gdbserver;
+  remote_bitbang_t* remote_bitbang;
 
   // memory-mapped I/O routines
-  bool addr_is_mem(reg_t addr) {
-    return addr >= DRAM_BASE && addr < DRAM_BASE + memsz;
-  }
-  char* addr_to_mem(reg_t addr) { return mem + addr - DRAM_BASE; }
-  reg_t mem_to_addr(char* x) { return x - mem + DRAM_BASE; }
+  char* addr_to_mem(reg_t addr);
   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();
@@ -75,6 +77,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);
@@ -82,13 +85,12 @@ 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);
 
   friend class processor_t;
   friend class mmu_t;
-  friend class gdbserver_t;
 
   // htif
   friend void sim_thread_main(void*);
@@ -96,7 +98,7 @@ private:
 
   context_t* host;
   context_t target;
-  void reset() { }
+  void reset();
   void idle();
   void read_chunk(addr_t taddr, size_t len, void* dst);
   void write_chunk(addr_t taddr, size_t len, const void* src);
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 bdbef9cef869759a563c7e72b1d41fcbb31d6977..56c6fe62d5d1fbeec86523f4d0123ad7f5784eb1 100644 (file)
@@ -418,7 +418,6 @@ disassembler_t::disassembler_t(int xlen)
   DEFINE_NOARG(ebreak);
   DEFINE_NOARG(uret);
   DEFINE_NOARG(sret);
-  DEFINE_NOARG(hret);
   DEFINE_NOARG(mret);
   DEFINE_NOARG(fence);
   DEFINE_NOARG(fence_i);
@@ -457,13 +456,13 @@ disassembler_t::disassembler_t(int xlen)
   DEFINE_XFTYPE(fcvt_s_w);
   DEFINE_XFTYPE(fcvt_s_wu);
   DEFINE_XFTYPE(fcvt_s_wu);
-  DEFINE_XFTYPE(fmv_s_x);
+  DEFINE_XFTYPE(fmv_w_x);
   DEFINE_FXTYPE(fcvt_l_s);
   DEFINE_FXTYPE(fcvt_lu_s);
   DEFINE_FXTYPE(fcvt_w_s);
   DEFINE_FXTYPE(fcvt_wu_s);
   DEFINE_FXTYPE(fclass_s);
-  DEFINE_FXTYPE(fmv_x_s);
+  DEFINE_FXTYPE(fmv_x_w);
   DEFINE_FXTYPE(feq_s);
   DEFINE_FXTYPE(flt_s);
   DEFINE_FXTYPE(fle_s);
index 424bf37820661cd0a690958c34a35ea282fc8913..23f8e49c0deeca8bffe414cc341353912f244fd4 100644 (file)
@@ -2,7 +2,7 @@
 
 #include "sim.h"
 #include "mmu.h"
-#include "gdbserver.h"
+#include "remote_bitbang.h"
 #include "cachesim.h"
 #include "extension.h"
 #include <dlfcn.h>
@@ -18,38 +18,72 @@ static void help()
   fprintf(stderr, "usage: spike [host options] <target program> [target options]\n");
   fprintf(stderr, "Host Options:\n");
   fprintf(stderr, "  -p<n>                 Simulate <n> processors [default 1]\n");
-  fprintf(stderr, "  -m<n>                 Provide <n> MiB of target memory [default 4096]\n");
+  fprintf(stderr, "  -m<n>                 Provide <n> MiB of target memory [default 2048]\n");
+  fprintf(stderr, "  -m<a:m,b:n,...>       Provide memory regions of size m and n bytes\n");
+  fprintf(stderr, "                          at base addresses a and b (with 4 KiB alignment)\n");
   fprintf(stderr, "  -d                    Interactive debug mode\n");
   fprintf(stderr, "  -g                    Track histogram of PCs\n");
   fprintf(stderr, "  -l                    Generate a log of execution\n");
   fprintf(stderr, "  -h                    Print this help message\n");
   fprintf(stderr, "  -H                 Start halted, allowing a debugger to connect\n");
   fprintf(stderr, "  --isa=<name>          RISC-V ISA string [default %s]\n", DEFAULT_ISA);
+  fprintf(stderr, "  --pc=<address>        Override ELF entry point\n");
   fprintf(stderr, "  --ic=<S>:<W>:<B>      Instantiate a cache model with S sets,\n");
   fprintf(stderr, "  --dc=<S>:<W>:<B>        W ways, and B-byte blocks (with S and\n");
   fprintf(stderr, "  --l2=<S>:<W>:<B>        B both powers of 2).\n");
   fprintf(stderr, "  --extension=<name>    Specify RoCC Extension\n");
   fprintf(stderr, "  --extlib=<name>       Shared library to load\n");
-  fprintf(stderr, "  --gdb-port=<port>  Listen on <port> for gdb to connect\n");
-  fprintf(stderr, "  --dump-config-string  Print platform configuration string and exit\n");
+  fprintf(stderr, "  --rbb-port=<port>     Listen on <port> for remote bitbang connection\n");
+  fprintf(stderr, "  --dump-dts  Print device tree string and exit\n");
   exit(1);
 }
 
+static std::vector<std::pair<reg_t, mem_t*>> make_mems(const char* arg)
+{
+  // handle legacy mem argument
+  char* p;
+  auto mb = strtoull(arg, &p, 0);
+  if (*p == 0) {
+    reg_t size = reg_t(mb) << 20;
+    return std::vector<std::pair<reg_t, mem_t*>>(1, std::make_pair(reg_t(DRAM_BASE), new mem_t(size)));
+  }
+
+  // handle base/size tuples
+  std::vector<std::pair<reg_t, mem_t*>> res;
+  while (true) {
+    auto base = strtoull(arg, &p, 0);
+    if (!*p || *p != ':')
+      help();
+    auto size = strtoull(p + 1, &p, 0);
+    if ((size | base) % PGSIZE != 0)
+      help();
+    res.push_back(std::make_pair(reg_t(base), new mem_t(size)));
+    if (!*p)
+      break;
+    if (*p != ',')
+      help();
+    arg = p + 1;
+  }
+  return res;
+}
+
 int main(int argc, char** argv)
 {
   bool debug = false;
   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;
+  reg_t start_pc = reg_t(-1);
+  std::vector<std::pair<reg_t, mem_t*>> mems;
   std::unique_ptr<icache_sim_t> ic;
   std::unique_ptr<dcache_sim_t> dc;
   std::unique_ptr<cache_sim_t> l2;
   std::function<extension_t*()> extension;
   const char* isa = DEFAULT_ISA;
-  uint16_t gdb_port = 0;
+  uint16_t rbb_port = 0;
+  bool use_rbb = false;
 
   option_parser_t parser;
   parser.help(&help);
@@ -58,16 +92,17 @@ int main(int argc, char** argv)
   parser.option('g', 0, 0, [&](const char* s){histogram = true;});
   parser.option('l', 0, 0, [&](const char* s){log = true;});
   parser.option('p', 0, 1, [&](const char* s){nprocs = atoi(s);});
-  parser.option('m', 0, 1, [&](const char* s){mem_mb = atoi(s);});
+  parser.option('m', 0, 1, [&](const char* s){mems = make_mems(s);});
   // I wanted to use --halted, but for some reason that doesn't work.
   parser.option('H', 0, 0, [&](const char* s){halted = true;});
-  parser.option(0, "gdb-port", 1, [&](const char* s){gdb_port = atoi(s);});
+  parser.option(0, "rbb-port", 1, [&](const char* s){use_rbb = true; rbb_port = atoi(s);});
+  parser.option(0, "pc", 1, [&](const char* s){start_pc = strtoull(s, 0, 0);});
   parser.option(0, "ic", 1, [&](const char* s){ic.reset(new icache_sim_t(s));});
   parser.option(0, "dc", 1, [&](const char* s){dc.reset(new dcache_sim_t(s));});
   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) {
@@ -78,15 +113,19 @@ int main(int argc, char** argv)
 
   auto argv1 = parser.parse(argv);
   std::vector<std::string> htif_args(argv1, (const char*const*)argv + argc);
-  sim_t s(isa, nprocs, mem_mb, halted, htif_args);
-  std::unique_ptr<gdbserver_t> gdbserver;
-  if (gdb_port) {
-    gdbserver = std::unique_ptr<gdbserver_t>(new gdbserver_t(gdb_port, &s));
-    s.set_gdbserver(&(*gdbserver));
+  if (mems.empty())
+    mems = make_mems("2048");
+
+  sim_t s(isa, nprocs, halted, start_pc, mems, htif_args);
+  std::unique_ptr<remote_bitbang_t> remote_bitbang((remote_bitbang_t *) NULL);
+  std::unique_ptr<jtag_dtm_t> jtag_dtm(new jtag_dtm_t(&s.debug_module));
+  if (use_rbb) {
+    remote_bitbang.reset(new remote_bitbang_t(rbb_port, &(*jtag_dtm)));
+    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;
   }