aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPalmer Dabbelt <palmer@dabbelt.com>2017-05-17 13:07:47 -0700
committerPalmer Dabbelt <palmer@dabbelt.com>2017-05-17 13:07:47 -0700
commitb3caeee9858b3417d4110b921305c441d3c87653 (patch)
tree5d6d9b6aa540b2c910aee2d56f0541fe2008fe11
parent68f1a893ec84ca734d83e8626c3abd2c8de78cda (diff)
parenta1f754b2f0ec5fe72c86d6916d7c603e7727e68e (diff)
downloadspike-b3caeee9858b3417d4110b921305c441d3c87653.zip
spike-b3caeee9858b3417d4110b921305c441d3c87653.tar.gz
spike-b3caeee9858b3417d4110b921305c441d3c87653.tar.bz2
Merge remote-tracking branch 'origin/priv-1.10'
-rw-r--r--LICENSE4
-rw-r--r--README.md1
-rw-r--r--config.h.in9
-rwxr-xr-xconfigure92
-rw-r--r--configure.ac2
-rw-r--r--debug_rom/Makefile12
-rwxr-xr-xdebug_rom/debug_rom.S202
-rw-r--r--debug_rom/debug_rom.h24
-rw-r--r--debug_rom/debug_rom_defines.h23
-rw-r--r--debug_rom/link.ld4
-rw-r--r--riscv/clint.cc72
-rw-r--r--riscv/debug_defines.h1413
-rw-r--r--riscv/debug_module.cc442
-rw-r--r--riscv/debug_module.h117
-rw-r--r--riscv/decode.h56
-rw-r--r--riscv/devices.cc8
-rw-r--r--riscv/devices.h35
-rw-r--r--riscv/encoding.h262
-rw-r--r--riscv/execute.cc21
-rw-r--r--riscv/extension.cc2
-rw-r--r--riscv/gdbserver.cc2232
-rw-r--r--riscv/gdbserver.h269
-rw-r--r--riscv/insns/c_ebreak.h2
-rw-r--r--riscv/insns/c_fld.h2
-rw-r--r--riscv/insns/c_fldsp.h2
-rw-r--r--riscv/insns/c_flw.h2
-rw-r--r--riscv/insns/c_flwsp.h2
-rw-r--r--riscv/insns/c_fsd.h2
-rw-r--r--riscv/insns/c_fsdsp.h2
-rw-r--r--riscv/insns/c_fsw.h2
-rw-r--r--riscv/insns/c_fswsp.h2
-rw-r--r--riscv/insns/c_li.h1
-rw-r--r--riscv/insns/c_lui.h2
-rw-r--r--riscv/insns/ebreak.h2
-rw-r--r--riscv/insns/fadd_d.h2
-rw-r--r--riscv/insns/fadd_s.h2
-rw-r--r--riscv/insns/fcvt_d_l.h2
-rw-r--r--riscv/insns/fcvt_d_lu.h2
-rw-r--r--riscv/insns/fcvt_d_s.h2
-rw-r--r--riscv/insns/fcvt_d_w.h2
-rw-r--r--riscv/insns/fcvt_d_wu.h2
-rw-r--r--riscv/insns/fcvt_s_d.h2
-rw-r--r--riscv/insns/fcvt_s_l.h2
-rw-r--r--riscv/insns/fcvt_s_lu.h2
-rw-r--r--riscv/insns/fcvt_s_w.h2
-rw-r--r--riscv/insns/fcvt_s_wu.h2
-rw-r--r--riscv/insns/fdiv_d.h2
-rw-r--r--riscv/insns/fdiv_s.h2
-rw-r--r--riscv/insns/fld.h2
-rw-r--r--riscv/insns/flw.h2
-rw-r--r--riscv/insns/fmadd_d.h2
-rw-r--r--riscv/insns/fmadd_s.h2
-rw-r--r--riscv/insns/fmax_d.h6
-rw-r--r--riscv/insns/fmax_s.h6
-rw-r--r--riscv/insns/fmin_d.h6
-rw-r--r--riscv/insns/fmin_s.h6
-rw-r--r--riscv/insns/fmsub_d.h2
-rw-r--r--riscv/insns/fmsub_s.h2
-rw-r--r--riscv/insns/fmul_d.h2
-rw-r--r--riscv/insns/fmul_s.h2
-rw-r--r--riscv/insns/fmv_d_x.h2
-rw-r--r--riscv/insns/fmv_w_x.h (renamed from riscv/insns/fmv_s_x.h)2
-rw-r--r--riscv/insns/fmv_x_d.h2
-rw-r--r--riscv/insns/fmv_x_w.h (renamed from riscv/insns/fmv_x_s.h)2
-rw-r--r--riscv/insns/fnmadd_d.h2
-rw-r--r--riscv/insns/fnmadd_s.h2
-rw-r--r--riscv/insns/fnmsub_d.h2
-rw-r--r--riscv/insns/fnmsub_s.h2
-rw-r--r--riscv/insns/fsd.h2
-rw-r--r--riscv/insns/fsgnj_d.h2
-rw-r--r--riscv/insns/fsgnj_s.h2
-rw-r--r--riscv/insns/fsgnjn_d.h2
-rw-r--r--riscv/insns/fsgnjn_s.h2
-rw-r--r--riscv/insns/fsgnjx_d.h2
-rw-r--r--riscv/insns/fsgnjx_s.h2
-rw-r--r--riscv/insns/fsqrt_d.h2
-rw-r--r--riscv/insns/fsqrt_s.h2
-rw-r--r--riscv/insns/fsub_d.h2
-rw-r--r--riscv/insns/fsub_s.h2
-rw-r--r--riscv/insns/fsw.h2
-rw-r--r--riscv/insns/mret.h2
-rw-r--r--riscv/insns/sfence_vm.h2
-rw-r--r--riscv/insns/sfence_vma.h2
-rw-r--r--riscv/insns/sret.h4
-rw-r--r--riscv/insns/wfi.h3
-rw-r--r--riscv/interactive.cc30
-rw-r--r--riscv/jtag_dtm.cc180
-rw-r--r--riscv/jtag_dtm.h61
-rw-r--r--riscv/mmu.cc95
-rw-r--r--riscv/mmu.h113
-rw-r--r--riscv/opcodes.h244
-rw-r--r--riscv/processor.cc166
-rw-r--r--riscv/processor.h15
-rw-r--r--riscv/remote_bitbang.cc180
-rw-r--r--riscv/remote_bitbang.h34
-rw-r--r--riscv/riscv.ac10
-rw-r--r--riscv/riscv.mk.in14
-rw-r--r--riscv/rtc.cc34
-rw-r--r--riscv/sim.cc256
-rw-r--r--riscv/sim.h40
-rw-r--r--riscv/trap.h13
-rw-r--r--spike_main/disasm.cc5
-rw-r--r--spike_main/spike.cc73
103 files changed, 3830 insertions, 3179 deletions
diff --git a/LICENSE b/LICENSE
index 53e0e66..34f576b 100644
--- 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:
diff --git a/README.md b/README.md
index 901c7f4..a5ed802 100644
--- 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
diff --git a/config.h.in b/config.h.in
index a4070ff..137f195 100644
--- a/config.h.in
+++ b/config.h.in
@@ -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
@@ -66,9 +69,15 @@
/* 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
diff --git a/configure b/configure
index 2c946e7..77bab30 100755
--- 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
@@ -4607,6 +4671,32 @@ $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
+
diff --git a/configure.ac b/configure.ac
index dbf50c9..ea64de7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -51,6 +51,8 @@ AC_PROG_CC
AC_PROG_CXX
AC_CHECK_TOOL([AR],[ar])
AC_CHECK_TOOL([RANLIB],[ranlib])
+AC_PATH_PROG([DTC],[dtc])
+AC_DEFINE_UNQUOTED(DTC, ["$DTC"], [Path to the device-tree-compiler])
AC_C_BIGENDIAN(AC_MSG_ERROR([Spike requires a little-endian host]))
diff --git a/debug_rom/Makefile b/debug_rom/Makefile
index b72f37d..4e9093c 100644
--- a/debug_rom/Makefile
+++ b/debug_rom/Makefile
@@ -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
diff --git a/debug_rom/debug_rom.S b/debug_rom/debug_rom.S
index 74a934b..2ee7a31 100755
--- a/debug_rom/debug_rom.S
+++ b/debug_rom/debug_rom.S
@@ -1,152 +1,72 @@
-# 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.
diff --git a/debug_rom/debug_rom.h b/debug_rom/debug_rom.h
index b1e3bea..d21e166 100644
--- a/debug_rom/debug_rom.h
+++ b/debug_rom/debug_rom.h
@@ -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
index 0000000..616cf59
--- /dev/null
+++ b/debug_rom/debug_rom_defines.h
@@ -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
diff --git a/debug_rom/link.ld b/debug_rom/link.ld
index aba6ae8..897c42d 100644
--- a/debug_rom/link.ld
+++ b/debug_rom/link.ld
@@ -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
index 0000000..08508b4
--- /dev/null
+++ b/riscv/clint.cc
@@ -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
index 0000000..cb07ec2
--- /dev/null
+++ b/riscv/debug_defines.h
@@ -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)
diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc
index 8bcc60e..db035e3 100644
--- a/riscv/debug_module.cc
+++ b/riscv/debug_module.cc
@@ -1,49 +1,167 @@
#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;
+}
diff --git a/riscv/debug_module.h b/riscv/debug_module.h
index 53b32db..f0d2a47 100644
--- a/riscv/debug_module.h
+++ b/riscv/debug_module.h
@@ -6,41 +6,104 @@
#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
diff --git a/riscv/decode.h b/riscv/decode.h
index b607bf3..9dcd809 100644
--- a/riscv/decode.h
+++ b/riscv/decode.h
@@ -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
diff --git a/riscv/devices.cc b/riscv/devices.cc
index c7a63b0..15115c8 100644
--- a/riscv/devices.cc
+++ b/riscv/devices.cc
@@ -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);
+}
diff --git a/riscv/devices.h b/riscv/devices.h
index 64ab79b..e4df6c9 100644
--- a/riscv/devices.h
+++ b/riscv/devices.h
@@ -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
diff --git a/riscv/encoding.h b/riscv/encoding.h
index 35e0f9f..8ec1345 100644
--- a/riscv/encoding.h
+++ b/riscv/encoding.h
@@ -17,10 +17,14 @@
#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
@@ -30,8 +34,10 @@
#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)
@@ -107,12 +113,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
@@ -127,9 +151,8 @@
#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
@@ -150,14 +173,16 @@
#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)
@@ -171,30 +196,18 @@
__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)
@@ -208,7 +221,7 @@
#endif
#endif
-/* Automatically generated by parse-opcodes */
+/* Automatically generated by parse-opcodes. */
#ifndef RISCV_ENCODING_H
#define RISCV_ENCODING_H
#define MATCH_BEQ 0x63
@@ -391,14 +404,12 @@
#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
@@ -457,6 +468,34 @@
#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
@@ -469,6 +508,12 @@
#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
@@ -477,8 +522,8 @@
#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
@@ -493,6 +538,18 @@
#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
@@ -501,8 +558,8 @@
#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
@@ -513,14 +570,28 @@
#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
@@ -537,6 +608,14 @@
#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
@@ -707,6 +786,7 @@
#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
@@ -719,11 +799,32 @@
#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
@@ -762,8 +863,6 @@
#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
@@ -861,17 +960,20 @@
#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
diff --git a/riscv/execute.cc b/riscv/execute.cc
index ebc9dc7..303effe 100644
--- a/riscv/execute.cc
+++ b/riscv/execute.cc
@@ -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)
diff --git a/riscv/extension.cc b/riscv/extension.cc
index a34dd80..520c2ed 100644
--- a/riscv/extension.cc
+++ b/riscv/extension.cc
@@ -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
index 79284eb..0000000
--- a/riscv/gdbserver.cc
+++ /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
index 79748b1..0000000
--- a/riscv/gdbserver.h
+++ /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
diff --git a/riscv/insns/c_ebreak.h b/riscv/insns/c_ebreak.h
index a17200f..128b86b 100644
--- a/riscv/insns/c_ebreak.h
+++ b/riscv/insns/c_ebreak.h
@@ -1,2 +1,2 @@
require_extension('C');
-throw trap_breakpoint();
+throw trap_breakpoint(pc);
diff --git a/riscv/insns/c_fld.h b/riscv/insns/c_fld.h
index 10d14f8..319615b 100644
--- a/riscv/insns/c_fld.h
+++ b/riscv/insns/c_fld.h
@@ -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())));
diff --git a/riscv/insns/c_fldsp.h b/riscv/insns/c_fldsp.h
index 8b1e19f..534eef7 100644
--- a/riscv/insns/c_fldsp.h
+++ b/riscv/insns/c_fldsp.h
@@ -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())));
diff --git a/riscv/insns/c_flw.h b/riscv/insns/c_flw.h
index 0be27a9..682566c 100644
--- a/riscv/insns/c_flw.h
+++ b/riscv/insns/c_flw.h
@@ -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()));
}
diff --git a/riscv/insns/c_flwsp.h b/riscv/insns/c_flwsp.h
index 26a4721..79058c4 100644
--- a/riscv/insns/c_flwsp.h
+++ b/riscv/insns/c_flwsp.h
@@ -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()));
diff --git a/riscv/insns/c_fsd.h b/riscv/insns/c_fsd.h
index 84f1a7f..8743266 100644
--- a/riscv/insns/c_fsd.h
+++ b/riscv/insns/c_fsd.h
@@ -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);
diff --git a/riscv/insns/c_fsdsp.h b/riscv/insns/c_fsdsp.h
index 5c5c680..f62f8ff 100644
--- a/riscv/insns/c_fsdsp.h
+++ b/riscv/insns/c_fsdsp.h
@@ -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);
diff --git a/riscv/insns/c_fsw.h b/riscv/insns/c_fsw.h
index 8923fef..b924a46 100644
--- a/riscv/insns/c_fsw.h
+++ b/riscv/insns/c_fsw.h
@@ -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);
}
diff --git a/riscv/insns/c_fswsp.h b/riscv/insns/c_fswsp.h
index c13aa12..011de55 100644
--- a/riscv/insns/c_fswsp.h
+++ b/riscv/insns/c_fswsp.h
@@ -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);
}
diff --git a/riscv/insns/c_li.h b/riscv/insns/c_li.h
index 844686d..f9fd66b 100644
--- a/riscv/insns/c_li.h
+++ b/riscv/insns/c_li.h
@@ -1,3 +1,2 @@
require_extension('C');
-require(insn.rvc_rd() != 0);
WRITE_RD(insn.rvc_imm());
diff --git a/riscv/insns/c_lui.h b/riscv/insns/c_lui.h
index 130aaed..75d8eb8 100644
--- a/riscv/insns/c_lui.h
+++ b/riscv/insns/c_lui.h
@@ -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);
}
diff --git a/riscv/insns/ebreak.h b/riscv/insns/ebreak.h
index c22776c..736cebe 100644
--- a/riscv/insns/ebreak.h
+++ b/riscv/insns/ebreak.h
@@ -1 +1 @@
-throw trap_breakpoint();
+throw trap_breakpoint(pc);
diff --git a/riscv/insns/fadd_d.h b/riscv/insns/fadd_d.h
index 9990174..4a436e2 100644
--- a/riscv/insns/fadd_d.h
+++ b/riscv/insns/fadd_d.h
@@ -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;
diff --git a/riscv/insns/fadd_s.h b/riscv/insns/fadd_s.h
index cdef36a..cc18d58 100644
--- a/riscv/insns/fadd_s.h
+++ b/riscv/insns/fadd_s.h
@@ -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;
diff --git a/riscv/insns/fcvt_d_l.h b/riscv/insns/fcvt_d_l.h
index fece227..08716cf 100644
--- a/riscv/insns/fcvt_d_l.h
+++ b/riscv/insns/fcvt_d_l.h
@@ -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;
diff --git a/riscv/insns/fcvt_d_lu.h b/riscv/insns/fcvt_d_lu.h
index 775c7ae..306d7fe 100644
--- a/riscv/insns/fcvt_d_lu.h
+++ b/riscv/insns/fcvt_d_lu.h
@@ -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;
diff --git a/riscv/insns/fcvt_d_s.h b/riscv/insns/fcvt_d_s.h
index ec778cc..5f805b0 100644
--- a/riscv/insns/fcvt_d_s.h
+++ b/riscv/insns/fcvt_d_s.h
@@ -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;
diff --git a/riscv/insns/fcvt_d_w.h b/riscv/insns/fcvt_d_w.h
index 753250d..4c4861c 100644
--- a/riscv/insns/fcvt_d_w.h
+++ b/riscv/insns/fcvt_d_w.h
@@ -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;
diff --git a/riscv/insns/fcvt_d_wu.h b/riscv/insns/fcvt_d_wu.h
index af893b3..1dbf218 100644
--- a/riscv/insns/fcvt_d_wu.h
+++ b/riscv/insns/fcvt_d_wu.h
@@ -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;
diff --git a/riscv/insns/fcvt_s_d.h b/riscv/insns/fcvt_s_d.h
index 211bbba..4033335 100644
--- a/riscv/insns/fcvt_s_d.h
+++ b/riscv/insns/fcvt_s_d.h
@@ -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;
diff --git a/riscv/insns/fcvt_s_l.h b/riscv/insns/fcvt_s_l.h
index 1c0581a..9abcc80 100644
--- a/riscv/insns/fcvt_s_l.h
+++ b/riscv/insns/fcvt_s_l.h
@@ -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;
diff --git a/riscv/insns/fcvt_s_lu.h b/riscv/insns/fcvt_s_lu.h
index e9bf78e..70c676e 100644
--- a/riscv/insns/fcvt_s_lu.h
+++ b/riscv/insns/fcvt_s_lu.h
@@ -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;
diff --git a/riscv/insns/fcvt_s_w.h b/riscv/insns/fcvt_s_w.h
index 9411cbd..1ddabd8 100644
--- a/riscv/insns/fcvt_s_w.h
+++ b/riscv/insns/fcvt_s_w.h
@@ -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;
diff --git a/riscv/insns/fcvt_s_wu.h b/riscv/insns/fcvt_s_wu.h
index a6cf836..c1394c3 100644
--- a/riscv/insns/fcvt_s_wu.h
+++ b/riscv/insns/fcvt_s_wu.h
@@ -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;
diff --git a/riscv/insns/fdiv_d.h b/riscv/insns/fdiv_d.h
index d8943de..ae7911a 100644
--- a/riscv/insns/fdiv_d.h
+++ b/riscv/insns/fdiv_d.h
@@ -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;
diff --git a/riscv/insns/fdiv_s.h b/riscv/insns/fdiv_s.h
index 66ac48d..c74ff04 100644
--- a/riscv/insns/fdiv_s.h
+++ b/riscv/insns/fdiv_s.h
@@ -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;
diff --git a/riscv/insns/fld.h b/riscv/insns/fld.h
index 0b50b8a..4dea1d4 100644
--- a/riscv/insns/fld.h
+++ b/riscv/insns/fld.h
@@ -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())));
diff --git a/riscv/insns/flw.h b/riscv/insns/flw.h
index 489e743..6129754 100644
--- a/riscv/insns/flw.h
+++ b/riscv/insns/flw.h
@@ -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())));
diff --git a/riscv/insns/fmadd_d.h b/riscv/insns/fmadd_d.h
index 98f1cbc..ab22beb 100644
--- a/riscv/insns/fmadd_d.h
+++ b/riscv/insns/fmadd_d.h
@@ -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;
diff --git a/riscv/insns/fmadd_s.h b/riscv/insns/fmadd_s.h
index a78ed25..e919190 100644
--- a/riscv/insns/fmadd_s.h
+++ b/riscv/insns/fmadd_s.h
@@ -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;
diff --git a/riscv/insns/fmax_d.h b/riscv/insns/fmax_d.h
index 56c9c7a..9c8e5b3 100644
--- a/riscv/insns/fmax_d.h
+++ b/riscv/insns/fmax_d.h
@@ -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;
diff --git a/riscv/insns/fmax_s.h b/riscv/insns/fmax_s.h
index bf90356..2f570ea 100644
--- a/riscv/insns/fmax_s.h
+++ b/riscv/insns/fmax_s.h
@@ -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;
diff --git a/riscv/insns/fmin_d.h b/riscv/insns/fmin_d.h
index 2a1755e..cd40e15 100644
--- a/riscv/insns/fmin_d.h
+++ b/riscv/insns/fmin_d.h
@@ -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;
diff --git a/riscv/insns/fmin_s.h b/riscv/insns/fmin_s.h
index 831a7a2..b813f45 100644
--- a/riscv/insns/fmin_s.h
+++ b/riscv/insns/fmin_s.h
@@ -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;
diff --git a/riscv/insns/fmsub_d.h b/riscv/insns/fmsub_d.h
index afcea88..5b5bc0f 100644
--- a/riscv/insns/fmsub_d.h
+++ b/riscv/insns/fmsub_d.h
@@ -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;
diff --git a/riscv/insns/fmsub_s.h b/riscv/insns/fmsub_s.h
index 45945da..d46c887 100644
--- a/riscv/insns/fmsub_s.h
+++ b/riscv/insns/fmsub_s.h
@@ -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;
diff --git a/riscv/insns/fmul_d.h b/riscv/insns/fmul_d.h
index 04e7402..9189d8d 100644
--- a/riscv/insns/fmul_d.h
+++ b/riscv/insns/fmul_d.h
@@ -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;
diff --git a/riscv/insns/fmul_s.h b/riscv/insns/fmul_s.h
index 9ae7b3c..145d5ce 100644
--- a/riscv/insns/fmul_s.h
+++ b/riscv/insns/fmul_s.h
@@ -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;
diff --git a/riscv/insns/fmv_d_x.h b/riscv/insns/fmv_d_x.h
index c3f6049..0bff5fb 100644
--- a/riscv/insns/fmv_d_x.h
+++ b/riscv/insns/fmv_d_x.h
@@ -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_w_x.h
index 2daf6da..5f71323 100644
--- a/riscv/insns/fmv_s_x.h
+++ b/riscv/insns/fmv_w_x.h
@@ -1,3 +1,3 @@
require_extension('F');
require_fp;
-WRITE_FRD(zext32(RS1));
+WRITE_FRD(f32(RS1));
diff --git a/riscv/insns/fmv_x_d.h b/riscv/insns/fmv_x_d.h
index b97d7f5..da8e72a 100644
--- a/riscv/insns/fmv_x_d.h
+++ b/riscv/insns/fmv_x_d.h
@@ -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_w.h
index 1bee87f..b722479 100644
--- a/riscv/insns/fmv_x_s.h
+++ b/riscv/insns/fmv_x_w.h
@@ -1,3 +1,3 @@
require_extension('F');
require_fp;
-WRITE_RD(sext32(FRS1));
+WRITE_RD(sext32(FRS1.v));
diff --git a/riscv/insns/fnmadd_d.h b/riscv/insns/fnmadd_d.h
index d6e1f04..e8dd743 100644
--- a/riscv/insns/fnmadd_d.h
+++ b/riscv/insns/fnmadd_d.h
@@ -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;
diff --git a/riscv/insns/fnmadd_s.h b/riscv/insns/fnmadd_s.h
index 0d0b2e9..1c2996e 100644
--- a/riscv/insns/fnmadd_s.h
+++ b/riscv/insns/fnmadd_s.h
@@ -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;
diff --git a/riscv/insns/fnmsub_d.h b/riscv/insns/fnmsub_d.h
index ee74cab..c29a0b9 100644
--- a/riscv/insns/fnmsub_d.h
+++ b/riscv/insns/fnmsub_d.h
@@ -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;
diff --git a/riscv/insns/fnmsub_s.h b/riscv/insns/fnmsub_s.h
index 3e0b8ea..4c61fc7 100644
--- a/riscv/insns/fnmsub_s.h
+++ b/riscv/insns/fnmsub_s.h
@@ -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;
diff --git a/riscv/insns/fsd.h b/riscv/insns/fsd.h
index 63cc8e5..679cc95 100644
--- a/riscv/insns/fsd.h
+++ b/riscv/insns/fsd.h
@@ -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);
diff --git a/riscv/insns/fsgnj_d.h b/riscv/insns/fsgnj_d.h
index 52648a1..78f9ce7 100644
--- a/riscv/insns/fsgnj_d.h
+++ b/riscv/insns/fsgnj_d.h
@@ -1,3 +1,3 @@
require_extension('D');
require_fp;
-WRITE_FRD((FRS1 &~ INT64_MIN) | (FRS2 & INT64_MIN));
+WRITE_FRD(fsgnj64(FRS1, FRS2, false, false));
diff --git a/riscv/insns/fsgnj_s.h b/riscv/insns/fsgnj_s.h
index 4c91ff3..c1a70cb 100644
--- a/riscv/insns/fsgnj_s.h
+++ b/riscv/insns/fsgnj_s.h
@@ -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));
diff --git a/riscv/insns/fsgnjn_d.h b/riscv/insns/fsgnjn_d.h
index cdec924..f02c311 100644
--- a/riscv/insns/fsgnjn_d.h
+++ b/riscv/insns/fsgnjn_d.h
@@ -1,3 +1,3 @@
require_extension('D');
require_fp;
-WRITE_FRD((FRS1 &~ INT64_MIN) | ((~FRS2) & INT64_MIN));
+WRITE_FRD(fsgnj64(FRS1, FRS2, true, false));
diff --git a/riscv/insns/fsgnjn_s.h b/riscv/insns/fsgnjn_s.h
index f91a7b0..35906d6 100644
--- a/riscv/insns/fsgnjn_s.h
+++ b/riscv/insns/fsgnjn_s.h
@@ -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));
diff --git a/riscv/insns/fsgnjx_d.h b/riscv/insns/fsgnjx_d.h
index b09d24c..c121737 100644
--- a/riscv/insns/fsgnjx_d.h
+++ b/riscv/insns/fsgnjx_d.h
@@ -1,3 +1,3 @@
require_extension('D');
require_fp;
-WRITE_FRD(FRS1 ^ (FRS2 & INT64_MIN));
+WRITE_FRD(fsgnj64(FRS1, FRS2, false, true));
diff --git a/riscv/insns/fsgnjx_s.h b/riscv/insns/fsgnjx_s.h
index 1fd2de6..4d5c624 100644
--- a/riscv/insns/fsgnjx_s.h
+++ b/riscv/insns/fsgnjx_s.h
@@ -1,3 +1,3 @@
require_extension('F');
require_fp;
-WRITE_FRD(FRS1 ^ (FRS2 & (uint32_t)INT32_MIN));
+WRITE_FRD(fsgnj32(FRS1, FRS2, false, true));
diff --git a/riscv/insns/fsqrt_d.h b/riscv/insns/fsqrt_d.h
index 45f37ce..da138ba 100644
--- a/riscv/insns/fsqrt_d.h
+++ b/riscv/insns/fsqrt_d.h
@@ -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;
diff --git a/riscv/insns/fsqrt_s.h b/riscv/insns/fsqrt_s.h
index f3b3956..7476846 100644
--- a/riscv/insns/fsqrt_s.h
+++ b/riscv/insns/fsqrt_s.h
@@ -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;
diff --git a/riscv/insns/fsub_d.h b/riscv/insns/fsub_d.h
index 487743e..1418a06 100644
--- a/riscv/insns/fsub_d.h
+++ b/riscv/insns/fsub_d.h
@@ -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;
diff --git a/riscv/insns/fsub_s.h b/riscv/insns/fsub_s.h
index e7a7cf1..f6183ea 100644
--- a/riscv/insns/fsub_s.h
+++ b/riscv/insns/fsub_s.h
@@ -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;
diff --git a/riscv/insns/fsw.h b/riscv/insns/fsw.h
index 3135e9b..42fc683 100644
--- a/riscv/insns/fsw.h
+++ b/riscv/insns/fsw.h
@@ -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);
diff --git a/riscv/insns/mret.h b/riscv/insns/mret.h
index f3c4414..96933cf 100644
--- a/riscv/insns/mret.h
+++ b/riscv/insns/mret.h
@@ -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
index 35ff5dd..0000000
--- a/riscv/insns/sfence_vm.h
+++ /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
index 0000000..fc4625f
--- /dev/null
+++ b/riscv/insns/sfence_vma.h
@@ -0,0 +1,2 @@
+require_privilege(get_field(STATE.mstatus, MSTATUS_TVM) ? PRV_M : PRV_S);
+MMU.flush_tlb();
diff --git a/riscv/insns/sret.h b/riscv/insns/sret.h
index b593198..ae841de 100644
--- a/riscv/insns/sret.h
+++ b/riscv/insns/sret.h
@@ -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);
diff --git a/riscv/insns/wfi.h b/riscv/insns/wfi.h
index 6f037f8..16de594 100644
--- a/riscv/insns/wfi.h
+++ b/riscv/insns/wfi.h
@@ -1 +1,2 @@
-// nop
+require_privilege(get_field(STATE.mstatus, MSTATUS_TW) ? PRV_M : PRV_S);
+set_pc_and_serialize(npc);
diff --git a/riscv/interactive.cc b/riscv/interactive.cc
index 748f454..31b9162 100644
--- a/riscv/interactive.cc
+++ b/riscv/interactive.cc
@@ -18,12 +18,14 @@
#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
index 0000000..cd3f3ee
--- /dev/null
+++ b/riscv/jtag_dtm.cc
@@ -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
index 0000000..063e3f4
--- /dev/null
+++ b/riscv/jtag_dtm.h
@@ -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
diff --git a/riscv/mmu.cc b/riscv/mmu.cc
index 878d849..76a6ab1 100644
--- a/riscv/mmu.cc
+++ b/riscv/mmu.cc
@@ -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)
diff --git a/riscv/mmu.h b/riscv/mmu.h
index 34bcf99..f70a969 100644
--- a/riscv/mmu.h
+++ b/riscv/mmu.h
@@ -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
index 0000000..34c089e
--- /dev/null
+++ b/riscv/opcodes.h
@@ -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;
+}
diff --git a/riscv/processor.cc b/riscv/processor.cc
index 9a6a4e2..1e3573d 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -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()
diff --git a/riscv/processor.h b/riscv/processor.h
index 0224f10..071f458 100644
--- a/riscv/processor.h
+++ b/riscv/processor.h
@@ -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
index 0000000..21306dd
--- /dev/null
+++ b/riscv/remote_bitbang.cc
@@ -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
index 0000000..1db4d55
--- /dev/null
+++ b/riscv/remote_bitbang.h
@@ -0,0 +1,34 @@
+#ifndef REMOTE_BITBANG_H
+#define REMOTE_BITBANG_H
+
+#include <stdint.h>
+
+#include "jtag_dtm.h"
+
+class remote_bitbang_t
+{
+public:
+ // Create a new server, listening for connections from localhost on the given
+ // port.
+ remote_bitbang_t(uint16_t port, jtag_dtm_t *tap);
+
+ // Do a bit of work.
+ void tick();
+
+private:
+ jtag_dtm_t *tap;
+
+ int socket_fd;
+ int client_fd;
+
+ static const ssize_t buf_size = 64 * 1024;
+ char recv_buf[buf_size];
+ ssize_t recv_start, recv_end;
+
+ // Check for a client connecting, and accept if there is one.
+ void accept();
+ // Execute any commands the client has for us.
+ void execute_commands();
+};
+
+#endif
diff --git a/riscv/riscv.ac b/riscv/riscv.ac
index 7b48be6..68bcdb5 100644
--- a/riscv/riscv.ac
+++ b/riscv/riscv.ac
@@ -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])
+])
diff --git a/riscv/riscv.mk.in b/riscv/riscv.mk.in
index 552187a..05e316a 100644
--- a/riscv/riscv.mk.in
+++ b/riscv/riscv.mk.in
@@ -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
index 22f318c..0000000
--- a/riscv/rtc.cc
+++ /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;
- }
-}
diff --git a/riscv/sim.cc b/riscv/sim.cc
index b455105..42d60a1 100644
--- a/riscv/sim.cc
+++ b/riscv/sim.cc
@@ -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();
diff --git a/riscv/sim.h b/riscv/sim.h
index 5d165c9..9372cc1 100644
--- a/riscv/sim.h
+++ b/riscv/sim.h
@@ -13,13 +13,14 @@
#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);
diff --git a/riscv/trap.h b/riscv/trap.h
index 7f35c5f..91e5223 100644
--- a/riscv/trap.h
+++ b/riscv/trap.h
@@ -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
diff --git a/spike_main/disasm.cc b/spike_main/disasm.cc
index bdbef9c..56c6fe6 100644
--- a/spike_main/disasm.cc
+++ b/spike_main/disasm.cc
@@ -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);
diff --git a/spike_main/spike.cc b/spike_main/spike.cc
index 424bf37..23f8e49 100644
--- a/spike_main/spike.cc
+++ b/spike_main/spike.cc
@@ -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;
}